mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
perf(webpack): decrease iteration count and improve type safety (#27488)
Co-authored-by: Michael Brevard <yonshi29@gmail.com>
This commit is contained in:
parent
5d7f7dae48
commit
61c3a2a4cd
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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))
|
||||
},
|
||||
|
@ -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] || '')
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user