3

I have a Quasar SSR app that I need to dynamically inject HTML content around the <div id="q-app"> element (ie. custom header and footer content) as the page is rendered on the server. The HTML content in question will be pulled from other snippet files stored on the server.

I have tried adding the content to the ssrContext from within a boot file and then inserting this in index.template.html using {{ }} tags, but this results in HTML-escaped output:

In whitelabeltemplate.js (boot file):

export default ({ app, ssrContext }) => {
    ssrContext.templateHeaderHTML = '<div>This is the header</div>'
}

In index.template.html:

<body>
    <% if (htmlWebpackPlugin.options.ctx.mode.ssr) { %>{{ templateHeaderHTML }}<% } %>
    <!-- DO NOT touch the following DIV -->
    <div id="q-app"></div>
</body>

Results in:

<body class="desktop no-touch body--light" >
    &lt;div&gt;This is the header&lt;/div&gt;
    <!-- DO NOT touch the following DIV -->
    <div id="q-app" ...
        ...
</body>

Is there an alternate method of injecting this content to avoid the escaping?

John Rix
  • 6,271
  • 5
  • 40
  • 46
  • Maybe Meta plugin will help ? https://quasar.dev/quasar-plugins/meta – Maksim Tikhonov Jan 16 '20 at 15:39
  • Thanks... I took a look at that just now on your suggestion. Will likely end up using it for other things, but I don't think it gives enough flexibility to solve this particular requirement as far as I can see. – John Rix Jan 16 '20 at 15:50
  • Which version of vue are you using? with v1 you can use `{{{ unsafeSring }}}` but this was removed in v2. – Moob Feb 06 '20 at 15:38
  • v2. However, Vue is actually outside the scope of what is going on here in any case - see the sections on boot files [here](https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr) and [here](https://quasar.dev/quasar-cli/cli-documentation/boot-files) – John Rix Feb 06 '20 at 15:58

1 Answers1

0

Yes, there is, the v-html attribute serves this exact purpose:

<body>
    <div id="q-app">
        <% if (htmlWebpackPlugin.options.ctx.mode.ssr) { %>
            <div v-html="templateHeaderHTML"></div>
        <% } %>
        <!-- DO NOT touch the following DIV -->
        <div id="content"></div>
    </div>
</body>

You need a tag in order to be able to use v-html, so I suggest stripping the wrapper div from the actual content to inject.

EDIT

Since we are not allowed to work inside the q-app div, let's restore the initial HTML, with a twist:

<body onload="unescapeHTML();">
    <script type="text/javascript">
    function htmlDecode(input){
        var e = document.createElement('textarea');
        e.innerHTML = input;
        // handle case of empty input
        return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
    }

    function unescapeHTML() {
        //Let's select the divs where we want this unescape to occur
        //At this point there is a single element with this property, but
        //let's support plurality
        var divs = document.querySelectorAll("body > div:nth-child(1)");
        for (let div of divs) div.innerHTML = htmlDecode(div.innerHTML);
    }
    </script>
    <% if (htmlWebpackPlugin.options.ctx.mode.ssr) { %>{{ templateHeaderHTML }}<% } %>
    <!-- DO NOT touch the following DIV -->
    <div id="q-app"></div>
</body>

Inspired from here: Unescape HTML entities in Javascript?

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • @JohnRix you can make a div which is wrapped around the header, the content and the footer. If you do so, then you will be able to use v-html for the header, the content and the footer, since in that case they will be children tags of that template. – Lajos Arpad Feb 06 '20 at 14:28
  • As I understand it, Quasar applies the Vue app to the #q-app element. Consequently, anything outside of that is outside the scope of Vue and so will not process v-html attributes there. I have tried exactly as your example above a short while ago and all I get is literally `
    `.
    – John Rix Feb 06 '20 at 14:34
  • @JohnRix understood and edited the answer accordingly. If q-app is wrapped around the header, the content and the footer, then it should work. – Lajos Arpad Feb 06 '20 at 14:38
  • Sadly, I can't do that, per the note above it that is included in the Quasar generated template file: `` – John Rix Feb 06 '20 at 15:04
  • @JohnRix so you are only working on the header and footer and you are not allowed to touch the actual content? – Lajos Arpad Feb 06 '20 at 15:08
  • @JohnRix assuming that the answer to my previous question is yes I have done a further edit. – Lajos Arpad Feb 06 '20 at 15:21
  • Crumbs! :-) Technically, that would result in valid content being rendered, but only within the browser (though you have to admit, it's not a pretty solution). I am specifically using SSR here (its in the title) to also ensure search engines get properly rendered content though, so still a no-go... though I do appreciate all the commentary! – John Rix Feb 06 '20 at 16:01