feat(vue-renderer): support prepend/append body tags during ssr for all allowed tag types (#6134)

This commit is contained in:
Pim 2019-08-19 20:38:13 +02:00 committed by Pooya Parsa
parent 52b98abdd8
commit df424e56cb
2 changed files with 45 additions and 20 deletions

View File

@ -1,6 +1,5 @@
import { extname } from 'path' import { extname } from 'path'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
import Vue from 'vue'
import VueMeta from 'vue-meta' import VueMeta from 'vue-meta'
import { createRenderer } from 'vue-server-renderer' import { createRenderer } from 'vue-server-renderer'
import LRU from 'lru-cache' import LRU from 'lru-cache'
@ -13,29 +12,19 @@ export default class SPARenderer extends BaseRenderer {
this.cache = new LRU() this.cache = new LRU()
// Add VueMeta to Vue (this is only for SPA mode) this.vueMetaConfig = {
// See app/index.js
Vue.use(VueMeta, {
keyName: 'head', keyName: 'head',
attribute: 'data-n-head', attribute: 'data-n-head',
ssrAttribute: 'data-n-head-ssr', ssrAttribute: 'data-n-head-ssr',
ssrAppId: '1',
tagIDKeyName: 'hid' tagIDKeyName: 'hid'
}) }
} }
createRenderer () { createRenderer () {
return createRenderer() return createRenderer()
} }
async getMeta () {
const vm = new Vue({
render: h => h(), // Render empty html tag
head: this.options.head || {}
})
await this.vueRenderer.renderToString(vm)
return vm.$meta().inject()
}
async render (renderContext) { async render (renderContext) {
const { url = '/', req = {}, _generate } = renderContext const { url = '/', req = {}, _generate } = renderContext
const modernMode = this.options.modern const modernMode = this.options.modern
@ -54,11 +43,19 @@ export default class SPARenderer extends BaseRenderer {
HEAD_ATTRS: '', HEAD_ATTRS: '',
BODY_ATTRS: '', BODY_ATTRS: '',
HEAD: '', HEAD: '',
BODY_SCRIPTS_PREPEND: '',
BODY_SCRIPTS: '' BODY_SCRIPTS: ''
} }
// Get vue-meta context // Get vue-meta context
const m = await this.getMeta() let head
if (typeof this.options.head === 'function') {
head = this.options.head()
} else {
head = this.options.head
}
const m = VueMeta.generate(head || {}, this.vueMetaConfig)
// HTML_ATTRS // HTML_ATTRS
meta.HTML_ATTRS = m.htmlAttrs.text() meta.HTML_ATTRS = m.htmlAttrs.text()
@ -78,11 +75,23 @@ export default class SPARenderer extends BaseRenderer {
m.script.text() + m.script.text() +
m.noscript.text() m.noscript.text()
// BODY_SCRIPTS // BODY_SCRIPTS (PREPEND)
meta.BODY_SCRIPTS = m.script.text({ body: true }) + m.noscript.text({ body: true }) meta.BODY_SCRIPTS_PREPEND =
m.meta.text({ pbody: true }) +
m.link.text({ pbody: true }) +
m.style.text({ pbody: true }) +
m.script.text({ pbody: true }) +
m.noscript.text({ pbody: true })
// BODY_SCRIPTS (APPEND)
meta.BODY_SCRIPTS =
m.meta.text({ body: true }) +
m.link.text({ body: true }) +
m.style.text({ body: true }) +
m.script.text({ body: true }) +
m.noscript.text({ body: true })
// Resources Hints // Resources Hints
meta.resourceHints = '' meta.resourceHints = ''
const { resources: { modernManifest, clientManifest } } = this.serverContext const { resources: { modernManifest, clientManifest } } = this.serverContext
@ -131,7 +140,7 @@ export default class SPARenderer extends BaseRenderer {
} }
} }
const APP = `<div id="${this.serverContext.globals.id}">${this.serverContext.resources.loadingHTML}</div>${meta.BODY_SCRIPTS}` const APP = `${meta.BODY_SCRIPTS_PREPEND}<div id="${this.serverContext.globals.id}">${this.serverContext.resources.loadingHTML}</div>${meta.BODY_SCRIPTS}`
// Prepare template params // Prepare template params
const templateParams = { const templateParams = {

View File

@ -109,6 +109,17 @@ export default class SSRRenderer extends BaseRenderer {
// Inject styles // Inject styles
HEAD += renderContext.renderStyles() HEAD += renderContext.renderStyles()
const BODY_PREPEND =
m.meta.text({ pbody: true }) +
m.link.text({ pbody: true }) +
m.style.text({ pbody: true }) +
m.script.text({ pbody: true }) +
m.noscript.text({ pbody: true })
if (BODY_PREPEND) {
APP = `${BODY_PREPEND}${APP}`
}
// Serialize state // Serialize state
const serializedSession = `window.${this.serverContext.globals.context}=${devalue(renderContext.nuxt)};` const serializedSession = `window.${this.serverContext.globals.context}=${devalue(renderContext.nuxt)};`
if (shouldInjectScripts) { if (shouldInjectScripts) {
@ -140,12 +151,17 @@ export default class SSRRenderer extends BaseRenderer {
if (shouldInjectScripts) { if (shouldInjectScripts) {
APP += this.renderScripts(renderContext) APP += this.renderScripts(renderContext)
} }
// Append body scripts
APP += m.meta.text({ body: true })
APP += m.link.text({ body: true })
APP += m.style.text({ body: true })
APP += m.script.text({ body: true }) APP += m.script.text({ body: true })
APP += m.noscript.text({ body: true }) APP += m.noscript.text({ body: true })
// Template params // Template params
const templateParams = { const templateParams = {
HTML_ATTRS: 'data-n-head-ssr ' + m.htmlAttrs.text(), HTML_ATTRS: m.htmlAttrs.text(true /* addSrrAttribute */),
HEAD_ATTRS: m.headAttrs.text(), HEAD_ATTRS: m.headAttrs.text(),
BODY_ATTRS: m.bodyAttrs.text(), BODY_ATTRS: m.bodyAttrs.text(),
HEAD, HEAD,