perf(webpack): decrease iteration count and improve type safety (#27488)

Co-authored-by: Michael Brevard <yonshi29@gmail.com>
This commit is contained in:
Daniel Roe 2024-06-07 23:32:46 +01:00 committed by GitHub
parent 5d7f7dae48
commit 61c3a2a4cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 57 additions and 57 deletions

View File

@ -17,10 +17,6 @@ interface PluginOptions {
nuxt: Nuxt
}
function uniq<T> (items: T[]) {
return [...new Set(items)]
}
export default class VueSSRClientPlugin {
options: PluginOptions
@ -34,38 +30,45 @@ export default class VueSSRClientPlugin {
compiler.hooks.afterEmit.tap('VueSSRClientPlugin', async (compilation: Compilation) => {
const stats = compilation.getStats().toJson()
const allFiles = uniq(stats.assets!
.map(a => a.name))
.filter(file => !isHotUpdate(file))
const initialFiles = new Set<string>()
for (const name in stats.entrypoints!) {
const entryAssets = stats.entrypoints![name]!.assets!
for (const asset of entryAssets) {
const file = asset.name
if ((isJS(file) || isCSS(file)) && !isHotUpdate(file)) {
initialFiles.add(file)
}
}
}
const initialFiles = uniq(Object.keys(stats.entrypoints!)
.map(name => stats.entrypoints![name].assets!)
.reduce((files, entryAssets) => files.concat(entryAssets.map(entryAsset => entryAsset.name)), [] as string[])
.filter(file => isJS(file) || isCSS(file)))
.filter(file => !isHotUpdate(file))
const allFiles = new Set<string>()
const asyncFiles = new Set<string>()
const asyncFiles = allFiles
.filter(file => isJS(file) || isCSS(file))
.filter(file => !initialFiles.includes(file))
.filter(file => !isHotUpdate(file))
for (const asset of stats.assets!) {
const file = asset.name
if (!isHotUpdate(file)) {
allFiles.add(file)
if (initialFiles.has(file)) { continue }
if (isJS(file) || isCSS(file)) {
asyncFiles.add(file)
}
}
}
const assetsMapping: Record<string, string[]> = {}
stats.assets!
.filter(({ name }) => isJS(name))
.filter(({ name }) => !isHotUpdate(name))
.forEach(({ name, chunkNames = [] }) => {
for (const { name, chunkNames = [] } of stats.assets!) {
if (isJS(name) && !isHotUpdate(name)) {
const componentHash = hash(chunkNames.join('|'))
if (!assetsMapping[componentHash]) {
assetsMapping[componentHash] = []
}
assetsMapping[componentHash].push(name)
})
const map = assetsMapping[componentHash] ||= []
map.push(name)
}
}
const webpackManifest = {
publicPath: stats.publicPath,
all: allFiles,
initial: initialFiles,
async: asyncFiles,
all: [...allFiles],
initial: [...initialFiles],
async: [...asyncFiles],
modules: { /* [identifier: string]: Array<index: number> */ } as Record<string, number[]>,
assetsMapping,
}
@ -78,7 +81,7 @@ export default class VueSSRClientPlugin {
if (m.chunks!.length === 1) {
const [cid] = m.chunks!
const chunk = stats.chunks!.find(c => c.id === cid)
if (!chunk || !chunk.files) {
if (!chunk || !chunk.files || !cid) {
return
}
const id = m.identifier!.replace(/\s\w+$/, '') // remove appended hash

View File

@ -26,7 +26,7 @@ export default class VueSSRServerPlugin {
}, (assets: any, cb: any) => {
const stats = compilation.getStats().toJson()
const [entryName] = Object.keys(stats.entrypoints!)
const entryInfo = stats.entrypoints![entryName]
const entryInfo = stats.entrypoints![entryName!]
if (!entryInfo) {
// #5553

View File

@ -13,8 +13,7 @@ export const validate = (compiler: Compiler) => {
if (!compiler.options.externals) {
logger.info(
'It is recommended to externalize dependencies in the server build for ' +
'better build performance.',
'It is recommended to externalize dependencies in the server build for better build performance.',
)
}
}

View File

@ -16,10 +16,10 @@ export function esbuild (ctx: WebpackConfigContext) {
loader: 'esbuild-loader',
exclude: (file) => {
// Not exclude files outside node_modules
file = file.split('node_modules', 2)[1]
if (!file) { return false }
const lastSegment = file.split('node_modules', 2)[1]
if (!lastSegment) { return false }
return !ctx.transpile.some(module => module.test(file))
return !ctx.transpile.some(module => module.test(lastSegment))
},
resolve: {
fullySpecified: false,

View File

@ -21,14 +21,15 @@ function minimizer (ctx: WebpackConfigContext) {
}
function extractCSS (ctx: WebpackConfigContext) {
const config = ctx.userConfig.extractCSS
if (!config) { return }
// CSS extraction
if (ctx.userConfig.extractCSS) {
ctx.config.plugins!.push(new MiniCssExtractPlugin({
filename: fileName(ctx, 'css'),
chunkFilename: fileName(ctx, 'css'),
...ctx.userConfig.extractCSS === true ? {} : ctx.userConfig.extractCSS,
}))
}
const filename = fileName(ctx, 'css')
ctx.config.plugins!.push(new MiniCssExtractPlugin({
filename,
chunkFilename: filename,
...config === true ? {} : config,
}))
}
function loaders (ctx: WebpackConfigContext) {

View File

@ -6,21 +6,18 @@ import { defu } from 'defu'
const isPureObject = (obj: unknown): obj is Object => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
const ensureItemIsLast = (item: string) => (arr: string[]) => {
const index = arr.indexOf(item)
if (index !== -1) {
arr.splice(index, 1)
arr.push(item)
}
return arr
}
const orderPresets = {
cssnanoLast (names: string[]) {
const nanoIndex = names.indexOf('cssnano')
if (nanoIndex !== names.length - 1) {
names.push(names.splice(nanoIndex, 1)[0])
}
return names
},
autoprefixerLast (names: string[]) {
const nanoIndex = names.indexOf('autoprefixer')
if (nanoIndex !== names.length - 1) {
names.push(names.splice(nanoIndex, 1)[0])
}
return names
},
cssnanoLast: ensureItemIsLast('cssnano'),
autoprefixerLast: ensureItemIsLast('autoprefixer'),
autoprefixerAndCssnanoLast (names: string[]) {
return orderPresets.cssnanoLast(orderPresets.autoprefixerLast(names))
},

View File

@ -8,7 +8,7 @@ export function registerVirtualModules () {
const virtualModules = new VirtualModulesPlugin(nuxt.vfs)
const writeFiles = () => {
for (const filePath in nuxt.vfs) {
virtualModules.writeModule(filePath, nuxt.vfs[filePath])
virtualModules.writeModule(filePath, nuxt.vfs[filePath] || '')
}
}