Nuxt/lib/core/meta.js

91 lines
2.5 KiB
JavaScript
Raw Normal View History

2017-08-18 16:05:01 +00:00
const Vue = require('vue')
const VueMeta = require('vue-meta')
const VueServerRenderer = require('vue-server-renderer')
const LRU = require('lru-cache')
2017-08-18 16:05:01 +00:00
module.exports = class MetaRenderer {
constructor(nuxt, renderer) {
2017-08-18 16:05:01 +00:00
this.nuxt = nuxt
this.renderer = renderer
2017-08-18 16:05:01 +00:00
this.options = nuxt.options
2017-08-21 09:38:21 +00:00
this.vueRenderer = VueServerRenderer.createRenderer()
2017-08-18 16:05:01 +00:00
this.cache = LRU({})
2017-08-21 09:38:21 +00:00
// Add VueMeta to Vue (this is only for SPA mode)
// See lib/app/index.js
Vue.use(VueMeta, {
keyName: 'head',
attribute: 'data-n-head',
ssrAttribute: 'data-n-head-ssr',
tagIDKeyName: 'hid'
})
}
2017-08-18 16:05:01 +00:00
2017-11-24 04:11:52 +00:00
async getMeta(url) {
const vm = new Vue({
render: h => h(), // Render empty html tag
head: this.options.head || {}
2017-08-21 09:38:21 +00:00
})
2017-11-24 04:11:52 +00:00
await this.vueRenderer.renderToString(vm)
return vm.$meta().inject()
2017-08-21 09:38:21 +00:00
}
2017-08-18 16:05:01 +00:00
async render({ url = '/' }) {
2017-08-21 09:38:21 +00:00
let meta = this.cache.get(url)
2017-08-18 16:05:01 +00:00
2017-08-21 09:38:21 +00:00
if (meta) {
return meta
2017-08-18 16:05:01 +00:00
}
2017-08-21 09:38:21 +00:00
meta = {
HTML_ATTRS: '',
BODY_ATTRS: '',
HEAD: '',
BODY_SCRIPTS: ''
2017-08-21 09:38:21 +00:00
}
// Get vue-meta context
const m = await this.getMeta(url)
// HTML_ATTRS
2017-09-05 09:04:59 +00:00
meta.HTML_ATTRS = m.htmlAttrs.text()
2017-08-21 09:38:21 +00:00
// BODY_ATTRS
meta.BODY_ATTRS = m.bodyAttrs.text()
// HEAD tags
meta.HEAD = m.meta.text() + m.title.text() + m.link.text() + m.style.text() + m.script.text() + m.noscript.text()
// BODY_SCRIPTS
meta.BODY_SCRIPTS = m.script.text({ body: true })
2017-08-30 12:47:07 +00:00
// Resources Hints
meta.resourceHints = ''
// Resource Hints
const clientManifest = this.renderer.resources.clientManifest
if (this.options.render.resourceHints && clientManifest) {
const publicPath = clientManifest.publicPath || '/_nuxt/'
// Pre-Load initial resources
if (Array.isArray(clientManifest.initial)) {
2017-08-30 12:47:07 +00:00
meta.resourceHints += clientManifest.initial.map(r => `<link rel="preload" href="${publicPath}${r}" as="script" />`).join('')
}
// Pre-Fetch async resources
if (Array.isArray(clientManifest.async)) {
2017-08-30 12:47:07 +00:00
meta.resourceHints += clientManifest.async.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`).join('')
}
// Add them to HEAD
if (meta.resourceHints) {
meta.HEAD += meta.resourceHints
}
}
2018-01-04 22:33:46 +00:00
// Emulate getPreloadFiles from vue-server-renderer (works for JS chunks only)
meta.getPreloadFiles = () => clientManifest.initial.map(r => ({
file: r,
fileWithoutQuery: r,
asType: 'script',
extension: 'js'
}))
2017-08-21 09:38:21 +00:00
// Set meta tags inside cache
this.cache.set(url, meta)
2017-08-18 16:05:01 +00:00
2017-08-21 09:38:21 +00:00
return meta
2017-08-18 16:05:01 +00:00
}
}