mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 23:52:06 +00:00
refactor: spa renderer (#4316)
This commit is contained in:
parent
d590858ff5
commit
70f0dc3825
@ -2,7 +2,8 @@
|
||||
|
||||
export default () => ({
|
||||
bundleRenderer: {
|
||||
shouldPrefetch: () => false
|
||||
shouldPrefetch: () => false,
|
||||
shouldPreload: (fileWithoutQuery, asType) => ['script', 'style'].includes(asType)
|
||||
},
|
||||
resourceHints: true,
|
||||
ssr: undefined,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { extname } from 'path'
|
||||
import Vue from 'vue'
|
||||
import VueMeta from 'vue-meta'
|
||||
import { createRenderer } from 'vue-server-renderer'
|
||||
@ -70,8 +71,8 @@ export default class SPAMetaRenderer {
|
||||
|
||||
const clientManifest = this.renderer.context.resources.clientManifest
|
||||
|
||||
const shouldPreload = this.options.render.bundleRenderer.shouldPreload || (() => true)
|
||||
const shouldPrefetch = this.options.render.bundleRenderer.shouldPrefetch || (() => true)
|
||||
const shouldPreload = this.options.render.bundleRenderer.shouldPreload
|
||||
const shouldPrefetch = this.options.render.bundleRenderer.shouldPrefetch
|
||||
|
||||
if (this.options.render.resourceHints && clientManifest) {
|
||||
const publicPath = clientManifest.publicPath || '/_nuxt/'
|
||||
@ -79,18 +80,25 @@ export default class SPAMetaRenderer {
|
||||
// Preload initial resources
|
||||
if (Array.isArray(clientManifest.initial)) {
|
||||
meta.resourceHints += clientManifest.initial
|
||||
.filter(file => shouldPreload(file))
|
||||
.map(
|
||||
r => `<link rel="preload" href="${publicPath}${r}" as="script" />`
|
||||
)
|
||||
.map(SPAMetaRenderer.normalizeFile)
|
||||
.filter(({ fileWithoutQuery, asType }) => shouldPreload(fileWithoutQuery, asType))
|
||||
.map(({ file, extension, fileWithoutQuery, asType }) => {
|
||||
let extra = ''
|
||||
if (asType === 'font') {
|
||||
extra = ` type="font/${extension}" crossorigin`
|
||||
}
|
||||
return `<link rel="preload" href="${publicPath}${file}"${
|
||||
asType !== '' ? ` as="${asType}"` : ''}${extra}>`
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
// Prefetch async resources
|
||||
if (Array.isArray(clientManifest.async)) {
|
||||
meta.resourceHints += clientManifest.async
|
||||
.filter(file => shouldPrefetch(file))
|
||||
.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`)
|
||||
.map(SPAMetaRenderer.normalizeFile)
|
||||
.filter(({ fileWithoutQuery, asType }) => shouldPrefetch(fileWithoutQuery, asType))
|
||||
.map(({ file }) => `<link rel="prefetch" href="${publicPath}${file}">`)
|
||||
.join('')
|
||||
}
|
||||
|
||||
@ -104,16 +112,36 @@ export default class SPAMetaRenderer {
|
||||
meta.getPreloadFiles = () =>
|
||||
clientManifest.initial
|
||||
.filter(file => shouldPreload(file))
|
||||
.map(r => ({
|
||||
file: r,
|
||||
fileWithoutQuery: r,
|
||||
asType: 'script',
|
||||
extension: 'js'
|
||||
}))
|
||||
.map(SPAMetaRenderer.normalizeFile)
|
||||
|
||||
// Set meta tags inside cache
|
||||
this.cache.set(url, meta)
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
static normalizeFile(file) {
|
||||
const withoutQuery = file.replace(/\?.*/, '')
|
||||
const extension = extname(withoutQuery).slice(1)
|
||||
return {
|
||||
file,
|
||||
extension,
|
||||
fileWithoutQuery: withoutQuery,
|
||||
asType: SPAMetaRenderer.getPreloadType(extension)
|
||||
}
|
||||
}
|
||||
|
||||
static getPreloadType(ext) {
|
||||
if (ext === 'js') {
|
||||
return 'script'
|
||||
} else if (ext === 'css') {
|
||||
return 'style'
|
||||
} else if (/jpe?g|png|svg|gif|webp|ico/.test(ext)) {
|
||||
return 'image'
|
||||
} else if (/woff2?|ttf|otf|eot/.test(ext)) {
|
||||
return 'font'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
test/fixtures/spa/nuxt.config.js
vendored
9
test/fixtures/spa/nuxt.config.js
vendored
@ -4,6 +4,15 @@ export default {
|
||||
render: {
|
||||
http2: {
|
||||
push: true
|
||||
},
|
||||
bundleRenderer: {
|
||||
shouldPrefetch: () => true
|
||||
}
|
||||
},
|
||||
build: {
|
||||
filenames: {
|
||||
app: '[name].js',
|
||||
chunk: '[name].js'
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
|
@ -1,5 +1,5 @@
|
||||
import consola from 'consola'
|
||||
import { loadFixture, getPort, Nuxt } from '../utils'
|
||||
import { loadFixture, getPort, Nuxt, wChunk } from '../utils'
|
||||
|
||||
let nuxt, port
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
@ -27,6 +27,21 @@ describe('spa', () => {
|
||||
consola.log.mockClear()
|
||||
})
|
||||
|
||||
test('/ (include preload and prefetch resources)', async () => {
|
||||
const { head } = await renderRoute('/')
|
||||
expect(head).toMatch(`<link rel="preload" href="/_nuxt/runtime.js" as="script">`)
|
||||
expect(head).toMatch(`<link rel="preload" href="/_nuxt/commons.app.js" as="script">`)
|
||||
expect(head).toMatch(`<link rel="preload" href="/_nuxt/app.js" as="script">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/custom.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/error-handler-async.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/error-handler-object.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/error-handler-string.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/error-handler.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/index.js')}">`)
|
||||
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/mounted.js')}">`)
|
||||
consola.log.mockClear()
|
||||
})
|
||||
|
||||
test('/custom (custom layout)', async () => {
|
||||
const { html } = await renderRoute('/custom')
|
||||
expect(html).toMatch('Custom layout')
|
||||
|
Loading…
Reference in New Issue
Block a user