mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
feat: preload and push modern resources in modern mode (#4362)
This commit is contained in:
parent
6f78bcdfea
commit
701190d796
@ -51,7 +51,7 @@ export default class VueRenderer {
|
||||
renderScripts(context) {
|
||||
if (this.context.options.modern === 'client') {
|
||||
const publicPath = this.context.options.build.publicPath
|
||||
const scriptPattern = /<script[^>]*?src="([^"]*)"[^>]*>[^<]*<\/script>/g
|
||||
const scriptPattern = /<script[^>]*?src="([^"]*?)"[^>]*?>[^<]*?<\/script>/g
|
||||
return context.renderScripts().replace(scriptPattern, (scriptTag, jsFile) => {
|
||||
const legacyJsFile = jsFile.replace(publicPath, '')
|
||||
const modernJsFile = this.assetsMapping[legacyJsFile]
|
||||
@ -63,17 +63,36 @@ export default class VueRenderer {
|
||||
return context.renderScripts()
|
||||
}
|
||||
|
||||
getModernFiles(legacyFiles = []) {
|
||||
const modernFiles = []
|
||||
for (const legacyJsFile of legacyFiles) {
|
||||
const modernFile = { ...legacyJsFile }
|
||||
if (modernFile.asType === 'script') {
|
||||
const file = this.assetsMapping[legacyJsFile.file]
|
||||
modernFile.file = file
|
||||
modernFile.fileWithoutQuery = file.replace(/\?.*/, '')
|
||||
}
|
||||
modernFiles.push(modernFile)
|
||||
}
|
||||
return modernFiles
|
||||
}
|
||||
|
||||
getPreloadFiles(context) {
|
||||
const preloadFiles = context.getPreloadFiles()
|
||||
const modernMode = this.context.options.modern
|
||||
// In eligible server modern mode, preloadFiles are modern bundles from modern renderer
|
||||
return modernMode === 'client' ? this.getModernFiles(preloadFiles) : preloadFiles
|
||||
}
|
||||
|
||||
renderResourceHints(context) {
|
||||
if (this.context.options.modern === 'client') {
|
||||
const modulePreloadTags = []
|
||||
for (const legacyJsFile of context.getPreloadFiles()) {
|
||||
if (legacyJsFile.asType === 'script') {
|
||||
const publicPath = this.context.options.build.publicPath
|
||||
const modernJsFile = this.assetsMapping[legacyJsFile.file]
|
||||
modulePreloadTags.push(`<link rel="modulepreload" href="${publicPath}${modernJsFile}" as="script">`)
|
||||
}
|
||||
}
|
||||
return modulePreloadTags.join('')
|
||||
const linkPattern = /<link[^>]*?href="([^"]*?)"[^>]*?as="script"[^>]*?>/g
|
||||
return context.renderResourceHints().replace(linkPattern, (linkTag, jsFile) => {
|
||||
const legacyJsFile = jsFile.replace(publicPath, '')
|
||||
const modernJsFile = this.assetsMapping[legacyJsFile]
|
||||
return linkTag.replace('rel="preload"', 'rel="modulepreload"').replace(legacyJsFile, modernJsFile)
|
||||
})
|
||||
}
|
||||
return context.renderResourceHints()
|
||||
}
|
||||
@ -262,7 +281,7 @@ export default class VueRenderer {
|
||||
ENV
|
||||
})
|
||||
|
||||
return { html, getPreloadFiles }
|
||||
return { html, getPreloadFiles: this.getPreloadFiles.bind(this, { getPreloadFiles }) }
|
||||
}
|
||||
|
||||
let APP
|
||||
@ -322,7 +341,7 @@ export default class VueRenderer {
|
||||
return {
|
||||
html,
|
||||
cspScriptSrcHashSet,
|
||||
getPreloadFiles: context.getPreloadFiles,
|
||||
getPreloadFiles: this.getPreloadFiles.bind(this, context),
|
||||
error: context.nuxt.error,
|
||||
redirected: context.redirected
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ export default class SPAMetaRenderer {
|
||||
// Emulate getPreloadFiles from vue-server-renderer (works for JS chunks only)
|
||||
meta.getPreloadFiles = () =>
|
||||
clientManifest.initial
|
||||
.filter(file => shouldPreload(file))
|
||||
.map(SPAMetaRenderer.normalizeFile)
|
||||
.filter(({ fileWithoutQuery, asType }) => shouldPreload(fileWithoutQuery, asType))
|
||||
|
||||
// Set meta tags inside cache
|
||||
this.cache.set(url, meta)
|
||||
|
5
test/fixtures/modern/nuxt.config.js
vendored
5
test/fixtures/modern/nuxt.config.js
vendored
@ -9,5 +9,10 @@ export default {
|
||||
return `${isModern ? 'modern-' : ''}[name].js`
|
||||
}
|
||||
}
|
||||
},
|
||||
render: {
|
||||
http2: {
|
||||
push: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { loadFixture, getPort, Nuxt, rp } from '../utils'
|
||||
import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
|
||||
|
||||
let nuxt, port
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
@ -29,6 +29,16 @@ describe('modern client mode', () => {
|
||||
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-commons.app.js" as="script">')
|
||||
})
|
||||
|
||||
test('should contain module http2 pushed resources', async () => {
|
||||
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
||||
expect(link).toEqual([
|
||||
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
||||
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
||||
'</_nuxt/modern-app.js>; rel=preload; as=script',
|
||||
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; as=script`
|
||||
].join(', '))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
afterAll(async () => {
|
||||
await nuxt.close()
|
||||
|
@ -2,6 +2,7 @@ import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
|
||||
|
||||
let nuxt, port
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
const modernUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
|
||||
|
||||
describe('modern server mode', () => {
|
||||
beforeAll(async () => {
|
||||
@ -18,11 +19,7 @@ describe('modern server mode', () => {
|
||||
})
|
||||
|
||||
test('should use modern resources for modern resources', async () => {
|
||||
const response = await rp(url('/'), {
|
||||
headers: {
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
|
||||
}
|
||||
})
|
||||
const response = await rp(url('/'), { headers: { 'user-agent': modernUA } })
|
||||
expect(response).toContain('/_nuxt/modern-app.js')
|
||||
expect(response).toContain('/_nuxt/modern-commons.app.js')
|
||||
})
|
||||
@ -37,6 +34,31 @@ describe('modern server mode', () => {
|
||||
expect(response).toContain('arrow:function(){return"build test"}')
|
||||
})
|
||||
|
||||
test('should contain legacy http2 pushed resources', async () => {
|
||||
const { headers: { link } } = await rp(url('/'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
expect(link).toEqual([
|
||||
'</_nuxt/runtime.js>; rel=preload; as=script',
|
||||
'</_nuxt/commons.app.js>; rel=preload; as=script',
|
||||
'</_nuxt/app.js>; rel=preload; as=script',
|
||||
`</_nuxt/${wChunk('pages/index.js')}>; rel=preload; as=script`
|
||||
].join(', '))
|
||||
})
|
||||
|
||||
test('should contain module http2 pushed resources', async () => {
|
||||
const { headers: { link } } = await rp(url('/'), {
|
||||
headers: { 'user-agent': modernUA },
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
expect(link).toEqual([
|
||||
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
||||
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
||||
'</_nuxt/modern-app.js>; rel=preload; as=script',
|
||||
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; as=script`
|
||||
].join(', '))
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
afterAll(async () => {
|
||||
await nuxt.close()
|
||||
|
Loading…
Reference in New Issue
Block a user