2019-07-06 15:22:50 +00:00
|
|
|
import { isUrl, urlJoin, safariNoModuleFix } from '@nuxt/utils'
|
2019-04-20 12:02:51 +00:00
|
|
|
import SSRRenderer from './ssr'
|
|
|
|
|
|
|
|
export default class ModernRenderer extends SSRRenderer {
|
2019-07-10 10:45:49 +00:00
|
|
|
constructor (serverContext) {
|
2019-04-20 12:02:51 +00:00
|
|
|
super(serverContext)
|
|
|
|
|
|
|
|
const { build: { publicPath }, router: { base } } = this.options
|
|
|
|
this.publicPath = isUrl(publicPath) ? publicPath : urlJoin(base, publicPath)
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
get assetsMapping () {
|
2019-04-20 12:02:51 +00:00
|
|
|
if (this._assetsMapping) {
|
|
|
|
return this._assetsMapping
|
|
|
|
}
|
|
|
|
|
|
|
|
const { clientManifest, modernManifest } = this.serverContext.resources
|
|
|
|
const legacyAssets = clientManifest.assetsMapping
|
2020-05-17 19:41:07 +00:00
|
|
|
const modernAssets = modernManifest.assetsMapping
|
2019-04-20 12:02:51 +00:00
|
|
|
const mapping = {}
|
|
|
|
|
2020-05-17 19:41:07 +00:00
|
|
|
Object.keys(legacyAssets).forEach((componentHash) => {
|
|
|
|
const modernComponentAssets = modernAssets[componentHash] || []
|
|
|
|
legacyAssets[componentHash].forEach((legacyAssetName, index) => {
|
|
|
|
mapping[legacyAssetName] = modernComponentAssets[index]
|
|
|
|
})
|
|
|
|
})
|
2019-04-20 12:02:51 +00:00
|
|
|
delete clientManifest.assetsMapping
|
|
|
|
delete modernManifest.assetsMapping
|
|
|
|
this._assetsMapping = mapping
|
|
|
|
|
|
|
|
return mapping
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
get isServerMode () {
|
2019-04-20 12:02:51 +00:00
|
|
|
return this.options.modern === 'server'
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
get rendererOptions () {
|
2019-04-20 12:02:51 +00:00
|
|
|
const rendererOptions = super.rendererOptions
|
|
|
|
if (this.isServerMode) {
|
|
|
|
rendererOptions.clientManifest = this.serverContext.resources.modernManifest
|
|
|
|
}
|
|
|
|
return rendererOptions
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
renderScripts (renderContext) {
|
2019-04-20 12:02:51 +00:00
|
|
|
const scripts = super.renderScripts(renderContext)
|
|
|
|
|
|
|
|
if (this.isServerMode) {
|
2020-08-14 21:59:10 +00:00
|
|
|
return scripts.replace('<script', `<script nomodule`)
|
2019-04-20 12:02:51 +00:00
|
|
|
}
|
|
|
|
|
2020-02-24 22:58:24 +00:00
|
|
|
const scriptPattern = /<script[^>]*?src="([^"]*?)" defer><\/script>/g
|
2019-04-20 12:02:51 +00:00
|
|
|
|
2019-07-06 15:22:50 +00:00
|
|
|
const modernScripts = scripts.replace(scriptPattern, (scriptTag, jsFile) => {
|
2019-04-20 12:02:51 +00:00
|
|
|
const legacyJsFile = jsFile.replace(this.publicPath, '')
|
|
|
|
const modernJsFile = this.assetsMapping[legacyJsFile]
|
2020-02-24 22:58:24 +00:00
|
|
|
if (!modernJsFile) {
|
|
|
|
return scriptTag
|
|
|
|
}
|
|
|
|
const moduleTag = scriptTag
|
|
|
|
.replace('<script', `<script type="module"`)
|
|
|
|
.replace(legacyJsFile, modernJsFile)
|
|
|
|
const noModuleTag = scriptTag.replace('<script', `<script nomodule`)
|
2019-04-20 12:02:51 +00:00
|
|
|
|
|
|
|
return noModuleTag + moduleTag
|
|
|
|
})
|
2019-07-06 15:22:50 +00:00
|
|
|
|
|
|
|
const safariNoModuleFixScript = `<script>${safariNoModuleFix}</script>`
|
|
|
|
|
|
|
|
return safariNoModuleFixScript + modernScripts
|
2019-04-20 12:02:51 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
getModernFiles (legacyFiles = []) {
|
2019-04-20 12:02:51 +00:00
|
|
|
const modernFiles = []
|
|
|
|
|
|
|
|
for (const legacyJsFile of legacyFiles) {
|
|
|
|
const modernFile = { ...legacyJsFile, modern: true }
|
|
|
|
if (modernFile.asType === 'script') {
|
|
|
|
const file = this.assetsMapping[legacyJsFile.file]
|
|
|
|
modernFile.file = file
|
|
|
|
modernFile.fileWithoutQuery = file.replace(/\?.*/, '')
|
|
|
|
}
|
|
|
|
modernFiles.push(modernFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
return modernFiles
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
getPreloadFiles (renderContext) {
|
2019-04-20 12:02:51 +00:00
|
|
|
const preloadFiles = super.getPreloadFiles(renderContext)
|
|
|
|
// In eligible server modern mode, preloadFiles are modern bundles from modern renderer
|
|
|
|
return this.isServerMode ? preloadFiles : this.getModernFiles(preloadFiles)
|
|
|
|
}
|
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
renderResourceHints (renderContext) {
|
2019-04-20 12:02:51 +00:00
|
|
|
const resourceHints = super.renderResourceHints(renderContext)
|
|
|
|
if (this.isServerMode) {
|
|
|
|
return resourceHints
|
|
|
|
}
|
|
|
|
|
|
|
|
const linkPattern = /<link[^>]*?href="([^"]*?)"[^>]*?as="script"[^>]*?>/g
|
|
|
|
|
|
|
|
return resourceHints.replace(linkPattern, (linkTag, jsFile) => {
|
|
|
|
const legacyJsFile = jsFile.replace(this.publicPath, '')
|
|
|
|
const modernJsFile = this.assetsMapping[legacyJsFile]
|
|
|
|
if (!modernJsFile) {
|
|
|
|
return ''
|
|
|
|
}
|
2020-02-24 22:58:24 +00:00
|
|
|
return linkTag
|
|
|
|
.replace('rel="preload"', `rel="modulepreload"`)
|
|
|
|
.replace(legacyJsFile, modernJsFile)
|
2019-04-20 12:02:51 +00:00
|
|
|
})
|
|
|
|
}
|
2019-05-25 19:54:00 +00:00
|
|
|
|
2019-07-10 10:45:49 +00:00
|
|
|
render (renderContext) {
|
2019-05-25 19:54:00 +00:00
|
|
|
if (this.isServerMode) {
|
|
|
|
renderContext.res.setHeader('Vary', 'User-Agent')
|
|
|
|
}
|
2019-06-04 14:49:18 +00:00
|
|
|
return super.render(renderContext)
|
2019-05-25 19:54:00 +00:00
|
|
|
}
|
2019-04-20 12:02:51 +00:00
|
|
|
}
|