Vue-meta: Template Interpolation for SSR

Created on 3 Sep 2017  路  2Comments  路  Source: nuxt/vue-meta

The example for using vue-meta with SSR and renderToString() is too brief and somewhat hackish. What is more, you have to give up many autoinjection features of SSR and hot reloading. Some of them can be restored manually with ctx.renderScripts(), ctx.renderStyles()... but others are much more difficult to implement.

I propose to use the template interpolation feature provided by vue-server-renderer. According to the documentation, this feature is used to implement head management.

On server-entry.js

import app from './app'

const router = app.$router
const meta = app.$meta()

export default (context) => {
  router.push(context.url)
  context.meta = meta.inject() // New, look at .inject()
  return app
}

Make sure that the very same context used in server-entry.js is passed to renderToString() in your code.

On your template index.html:

<!DOCTYPE html>
<html data-vue-meta-server-rendered {{{ meta.htmlAttrs.text() }}}>
  <head>
    {{{ meta.meta.text() + meta.title.text() + meta.link.text() + meta.style.text() + meta.script.text() + meta.noscript.text() }}}
  </head>
  <body {{{ meta.bodyAttrs.text() }}}>
    <!--vue-ssr-outlet-->
  </body>
</html>

That's all.

Most helpful comment

Ok, after further testing I've encountered some cases in which the above doesn't work. The problem is that I was calling .inject() too early and some properties were not calculated yet. I'm not aware of any hook that let's you call .inject() after rendering the app and before constructing the template. Properly injecting vue-meta properties into the template is still doable after some changes.

import app from './app'

const router = app.$router
const meta = app.$meta()

export default (context) => {
  router.push(context.url)
  context.meta = { inject: function () { Object.assign(this, meta.inject()) }}
  return app
}

Variable assignment and manipulations aren't allowed in the template, only simple expressions can be used. That is why I created a self injectable object. Just call meta.inject() at the beginning of the template and it will populate itself with the meta properties.

<!DOCTYPE html>{{ meta.inject() }}
<html data-vue-meta-server-rendered {{{ meta.htmlAttrs.text() }}}>
  <head>
    {{{ meta.meta.text() + meta.title.text() + meta.link.text() + meta.style.text() + meta.script.text() + meta.noscript.text() }}}
  </head>
  <body {{{ meta.bodyAttrs.text() }}}>
    <!--vue-ssr-outlet-->
  </body>
</html>

I know that this is rather ugly. It would be great to have more control over vue-server-renderer but so far this is the most that can be done.

All 2 comments

Ok, after further testing I've encountered some cases in which the above doesn't work. The problem is that I was calling .inject() too early and some properties were not calculated yet. I'm not aware of any hook that let's you call .inject() after rendering the app and before constructing the template. Properly injecting vue-meta properties into the template is still doable after some changes.

import app from './app'

const router = app.$router
const meta = app.$meta()

export default (context) => {
  router.push(context.url)
  context.meta = { inject: function () { Object.assign(this, meta.inject()) }}
  return app
}

Variable assignment and manipulations aren't allowed in the template, only simple expressions can be used. That is why I created a self injectable object. Just call meta.inject() at the beginning of the template and it will populate itself with the meta properties.

<!DOCTYPE html>{{ meta.inject() }}
<html data-vue-meta-server-rendered {{{ meta.htmlAttrs.text() }}}>
  <head>
    {{{ meta.meta.text() + meta.title.text() + meta.link.text() + meta.style.text() + meta.script.text() + meta.noscript.text() }}}
  </head>
  <body {{{ meta.bodyAttrs.text() }}}>
    <!--vue-ssr-outlet-->
  </body>
</html>

I know that this is rather ugly. It would be great to have more control over vue-server-renderer but so far this is the most that can be done.

+1

Was this page helpful?
0 / 5 - 0 ratings

Related issues

achen224 picture achen224  路  9Comments

hurradieweltgehtunter picture hurradieweltgehtunter  路  4Comments

lwansbrough picture lwansbrough  路  7Comments

vishr picture vishr  路  5Comments

hvalcourtSerdy picture hvalcourtSerdy  路  3Comments