# Server Side Rendering
If you have an isomorphic/universal web application, you'll likely want to render your metadata on the server side as well. Here's how.
# Add vue-meta to the context
You'll need to expose the results of the $meta method that vue-meta adds to the Vue instance to the bundle render context before you can begin injecting your metadata. You'll need to do this in your server entry file:
server-entry.js:
import app from './app' const router = app.$router const meta = app.$meta() // here export default (context) => { router.push(context.url) context.meta = meta // and here return app } # Inject metadata into page string
Probably the easiest method to wrap your head around is if your Vue server markup is rendered out as a string using renderToString:
server.js:
app.get('*', (req, res) => { const context = { url: req.url } renderer.renderToString(context, (error, html) => { if (error) return res.send(error.stack) const { title, htmlAttrs, headAttrs, bodyAttrs, link, style, script, noscript, meta } = context.meta.inject() return res.send(` <!doctype html> <html ${htmlAttrs.text(true)}> <head ${headAttrs.text()}> ${meta.text()} ${title.text()} ${link.text()} ${style.text()} ${script.text()} ${noscript.text()} </head> <body ${bodyAttrs.text()}> <!-- prepended metaInfo properties --> ${style.text({ pbody: true })} ${script.text({ pbody: true })} ${noscript.text({ pbody: true })} <!-- app --> ${html} <!-- webpack assets --> <script src="/assets/vendor.bundle.js"></script> <script src="/assets/client.bundle.js"></script> <!-- appended metaInfo properties --> ${style.text({ body: true })} ${script.text({ body: true })} ${noscript.text({ body: true })} </body> </html> `) }) }) If you are using a separate template file, edit your head tag with
<head> {{{ meta.inject().title.text() }}} {{{ meta.inject().meta.text() }}} </head> Notice the use of {{{ to avoid double escaping. Be extremely cautious when you use {{{ with __dangerouslyDisableSanitizersByTagID.
# Inject metadata into page stream
A little more complex, but well worth it, is to instead stream your response. vue-meta supports streaming with no effort (on it's part 😜) thanks to Vue's clever bundleRenderer context injection:
server.js
app.get('*', (req, res) => { const context = { url: req.url } const renderStream = renderer.renderToStream(context) renderStream.once('data', () => { const { title, htmlAttrs, headAttrs, bodyAttrs, link, style, script, noscript, meta } = context.meta.inject() res.write(` <!doctype html> <html data-vue-meta-server-rendered ${htmlAttrs.text()}> <head ${headAttrs.text()}> ${meta.text()} ${title.text()} ${link.text()} ${style.text()} ${script.text()} ${noscript.text()} </head> <body ${bodyAttrs.text()}> `) }) renderStream.on('data', (chunk) => { res.write(chunk) }) renderStream.on('end', () => { res.end(` <script src="/assets/vendor.bundle.js"></script> <script src="/assets/client.bundle.js"></script> ${script.text({ body: true })} </body> </html> `) }) renderStream.on('error', (error) => { res.status(500).end(`<pre>${error.stack}</pre>`) }) })