gridsome
Version:
A JAMstack framework for building blazing fast websites with Vue.js
106 lines (92 loc) • 2.68 kB
JavaScript
const chalk = require('chalk')
const createHTMLRenderer = require('./createHTMLRenderer')
const { createBundleRenderer } = require('vue-server-renderer')
const { error } = require('../utils/log')
const MAX_STATE_SIZE = 25000
module.exports = function createRenderFn ({
htmlTemplate,
clientManifestPath,
serverBundlePath,
shouldPrefetch,
shouldPreload
}) {
const renderHTML = createHTMLRenderer(htmlTemplate)
const clientManifest = require(clientManifestPath)
const serverBundle = require(serverBundlePath)
const renderer = createBundleRenderer(serverBundle, {
clientManifest,
runInNewContext: false,
shouldPrefetch,
shouldPreload
})
return async function render(page, state, stateSize, hash) {
const context = {
path: page.path,
location: page.location,
state: createState(state)
}
let app = ''
try {
app = await renderer.renderToString(context)
} catch (err) {
const location = page.location.name || page.location.path
error(chalk.red(`Could not generate HTML for "${location}":`))
throw err
}
const inject = context.meta.inject()
const htmlAttrs = inject.htmlAttrs.text()
const bodyAttrs = inject.bodyAttrs.text()
const pageTitle = inject.title.text()
const metaBase = inject.base.text()
const gridsomeHash = `<meta name="gridsome:hash" content="${hash}">`
const vueMetaTags = inject.meta.text()
const vueMetaLinks = inject.link.text()
const styles = context.renderStyles()
const noscript = inject.noscript.text()
const vueMetaStyles = inject.style.text()
const vueMetaScripts = inject.script.text()
const resourceHints = context.renderResourceHints()
const head =
'' +
pageTitle +
metaBase +
gridsomeHash +
vueMetaTags +
vueMetaLinks +
resourceHints +
styles +
vueMetaStyles +
vueMetaScripts +
noscript
const renderedState = state && stateSize <= MAX_STATE_SIZE
? context.renderState()
: ''
const scripts = '' +
renderedState +
context.renderScripts() +
inject.script.text({ body: true })
return renderHTML({
htmlAttrs: `data-html-server-rendered="true" ${htmlAttrs}`,
bodyAttrs,
head,
title: pageTitle,
base: metaBase,
hash: gridsomeHash,
vueMetaTags,
vueMetaLinks,
resourceHints,
styles,
vueMetaStyles,
vueMetaScripts,
noscript,
app,
scripts
})
}
}
function createState (state = {}) {
return {
data: state.data || null,
context: state.context || {}
}
}