feat(nuxt): exclude page chunks from being prefetched (#6662)

This commit is contained in:
Daniel Roe 2022-08-16 12:19:39 +01:00 committed by GitHub
parent 3730ba88f5
commit 94214d6b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 14 deletions

View File

@ -1,6 +1,6 @@
import { existsSync } from 'node:fs'
import { defineNuxtModule, addTemplate, addPlugin, addVitePlugin, addWebpackPlugin, findPath } from '@nuxt/kit'
import { resolve } from 'pathe'
import { relative, resolve } from 'pathe'
import { genString, genImport, genObjectFromRawEntries } from 'knitwork'
import escapeRE from 'escape-string-regexp'
import type { NuxtApp, NuxtPage } from '@nuxt/schema'
@ -99,6 +99,24 @@ export default defineNuxtModule({
// Add router plugin
addPlugin(resolve(runtimeDir, 'router'))
const getSources = (pages: NuxtPage[]): string[] => pages.flatMap(p =>
[relative(nuxt.options.srcDir, p.file), ...getSources(p.children || [])]
)
// Do not prefetch page chunks
nuxt.hook('build:manifest', async (manifest) => {
const pages = await resolvePagesRoutes()
await nuxt.callHook('pages:extend', pages)
const sourceFiles = getSources(pages)
for (const key in manifest) {
if (manifest[key].isEntry) {
manifest[key].dynamicImports =
manifest[key].dynamicImports?.filter(i => !sourceFiles.includes(i))
}
}
})
// Add routes template
addTemplate({
filename: 'routes.mjs',

View File

@ -21,6 +21,7 @@ export default defineBuildConfig({
// Type imports
'vue-meta',
'vue-router',
'vue-bundle-renderer',
'vue',
'hookable',
'nitropack',

View File

@ -3,6 +3,7 @@ import type { Server as HttpsServer } from 'node:https'
import type { Compiler, Configuration, Stats } from 'webpack'
import type { TSConfig } from 'pkg-types'
import type { InlineConfig as ViteInlineConfig, ViteDevServer } from 'vite'
import type { Manifest } from 'vue-bundle-renderer'
import type { ModuleContainer } from './module'
import type { NuxtTemplate, Nuxt, NuxtApp } from './nuxt'
import type { Preset as ImportPreset, Import } from 'unimport'
@ -72,6 +73,7 @@ export interface NuxtHooks {
'app:templatesGenerated': (app: NuxtApp) => HookResult
'builder:generateApp': () => HookResult
'pages:extend': (pages: NuxtPage[]) => HookResult
'build:manifest': (manifest: Manifest) => HookResult
// Auto imports
'autoImports:sources': (presets: ImportPresetWithDeprecation[]) => HookResult

View File

@ -2,7 +2,8 @@ import fse from 'fs-extra'
import { resolve } from 'pathe'
import { withoutLeadingSlash, withTrailingSlash } from 'ufo'
import escapeRE from 'escape-string-regexp'
import { normalizeViteManifest, Manifest } from 'vue-bundle-renderer'
import { normalizeViteManifest } from 'vue-bundle-renderer'
import type { Manifest } from 'vue-bundle-renderer'
import type { ViteBuildContext } from './vite'
export async function writeManifest (ctx: ViteBuildContext, css: string[] = []) {
@ -45,7 +46,10 @@ export async function writeManifest (ctx: ViteBuildContext, css: string[] = [])
}
await fse.mkdirp(serverDist)
const manifest = normalizeViteManifest(clientManifest)
await ctx.nuxt.callHook('build:manifest', manifest)
await fse.writeFile(resolve(serverDist, 'client.manifest.json'), JSON.stringify(manifest, null, 2), 'utf8')
await fse.writeFile(resolve(serverDist, 'client.manifest.mjs'), 'export default ' + JSON.stringify(manifest, null, 2), 'utf8')
}

View File

@ -9,14 +9,18 @@ import hash from 'hash-sum'
import { uniq } from 'lodash-es'
import fse from 'fs-extra'
import type { Nuxt } from '@nuxt/schema'
import { isJS, isCSS, isHotUpdate } from './util'
export default class VueSSRClientPlugin {
options: {
filename: string
}
interface PluginOptions {
filename: string
nuxt: Nuxt
}
constructor (options = {}) {
export default class VueSSRClientPlugin {
options: PluginOptions
constructor (options: PluginOptions) {
this.options = Object.assign({
filename: null
}, options)
@ -53,7 +57,7 @@ export default class VueSSRClientPlugin {
assetsMapping[componentHash].push(name)
})
const manifest = {
const webpackManifest = {
publicPath: stats.publicPath,
all: allFiles,
initial: initialFiles,
@ -64,7 +68,7 @@ export default class VueSSRClientPlugin {
const { entrypoints, namedChunkGroups } = stats
const assetModules = stats.modules.filter(m => m.assets.length)
const fileToIndex = file => manifest.all.indexOf(file)
const fileToIndex = file => webpackManifest.all.indexOf(file)
stats.modules.forEach((m) => {
// Ignore modules duplicated in multiple chunks
if (m.chunks.length === 1) {
@ -88,15 +92,15 @@ export default class VueSSRClientPlugin {
}
const files = Array.from(filesSet)
manifest.modules[hash(id)] = files
webpackManifest.modules[hash(id)] = files
// In production mode, modules may be concatenated by scope hoisting
// Include ConcatenatedModule for not losing module-component mapping
if (Array.isArray(m.modules)) {
for (const concatenatedModule of m.modules) {
const id = hash(concatenatedModule.identifier.replace(/\s\w+$/, ''))
if (!manifest.modules[id]) {
manifest.modules[id] = files
if (!webpackManifest.modules[id]) {
webpackManifest.modules[id] = files
}
}
}
@ -110,7 +114,10 @@ export default class VueSSRClientPlugin {
}
})
const src = JSON.stringify(normalizeWebpackManifest(manifest), null, 2)
const manifest = normalizeWebpackManifest(webpackManifest)
await this.options.nuxt.callHook('build:manifest', manifest)
const src = JSON.stringify(manifest, null, 2)
await fse.mkdirp(dirname(this.options.filename))
await fse.writeFile(this.options.filename, src)

View File

@ -22,7 +22,8 @@ export function vue (ctx: WebpackConfigContext) {
if (ctx.isClient) {
config.plugins.push(new VueSSRClientPlugin({
filename: resolve(options.buildDir, 'dist/server', `${ctx.name}.manifest.json`)
filename: resolve(options.buildDir, 'dist/server', `${ctx.name}.manifest.json`),
nuxt: ctx.nuxt
}))
} else {
config.plugins.push(new VueSSRServerPlugin({