mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 09:25:54 +00:00
feat(nuxi): bundle analyzer (#701)
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
694e95b2b4
commit
f0b9474b40
@ -15,9 +15,7 @@ export default {
|
||||
/**
|
||||
* Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them.
|
||||
*
|
||||
* This option is normally enabled by the CLI argument `--analyze`.
|
||||
*
|
||||
* Set to `true` to enable bundle analysis, or pass [an object with options](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin).
|
||||
* Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options).
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
@ -25,7 +23,6 @@ export default {
|
||||
* analyzerMode: 'static'
|
||||
* }
|
||||
* ```
|
||||
* @version 2
|
||||
*/
|
||||
analyze: false,
|
||||
|
||||
|
@ -58,8 +58,8 @@
|
||||
"pathe": "^0.2.0",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"rollup": "^2.58.0",
|
||||
"rollup-plugin-analyzer": "^4.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-visualizer": "^5.5.2",
|
||||
"serve-placeholder": "^1.2.4",
|
||||
"serve-static": "^1.14.1",
|
||||
"std-env": "^2.3.1",
|
||||
|
@ -4,6 +4,7 @@ import defu from 'defu'
|
||||
import { createHooks, Hookable, NestedHooks } from 'hookable'
|
||||
import type { Preset } from 'unenv'
|
||||
import type { NuxtHooks, NuxtOptions } from '@nuxt/kit'
|
||||
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'
|
||||
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
|
||||
import * as PRESETS from './presets'
|
||||
import type { NodeExternalsOptions } from './rollup/plugins/externals'
|
||||
@ -28,7 +29,7 @@ export interface NitroContext {
|
||||
minify: boolean
|
||||
sourceMap: boolean
|
||||
externals: boolean | NodeExternalsOptions
|
||||
analyze: boolean
|
||||
analyze: false | PluginVisualizerOptions
|
||||
entry: string
|
||||
node: boolean
|
||||
preset: string
|
||||
@ -94,7 +95,7 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
||||
minify: undefined,
|
||||
sourceMap: undefined,
|
||||
externals: undefined,
|
||||
analyze: undefined,
|
||||
analyze: nuxtOptions.build.analyze as any,
|
||||
entry: undefined,
|
||||
node: undefined,
|
||||
preset: undefined,
|
||||
|
@ -12,7 +12,7 @@ import replace from '@rollup/plugin-replace'
|
||||
import virtual from '@rollup/plugin-virtual'
|
||||
import wasmPlugin from '@rollup/plugin-wasm'
|
||||
import inject from '@rollup/plugin-inject'
|
||||
import analyze from 'rollup-plugin-analyzer'
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
import * as unenv from 'unenv'
|
||||
|
||||
import type { Preset } from 'unenv'
|
||||
@ -309,11 +309,6 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
||||
// https://github.com/rollup/plugins/tree/master/packages/inject
|
||||
rollupConfig.plugins.push(inject(env.inject))
|
||||
|
||||
if (nitroContext.analyze) {
|
||||
// https://github.com/doesdev/rollup-plugin-analyzer
|
||||
rollupConfig.plugins.push(analyze())
|
||||
}
|
||||
|
||||
// https://github.com/TrySound/rollup-plugin-terser
|
||||
// https://github.com/terser/terser#minify-nitroContext
|
||||
if (nitroContext.minify) {
|
||||
@ -328,5 +323,14 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
||||
}))
|
||||
}
|
||||
|
||||
if (nitroContext.analyze) {
|
||||
// https://github.com/btd/rollup-plugin-visualizer
|
||||
rollupConfig.plugins.push(visualizer({
|
||||
...nitroContext.analyze,
|
||||
filename: nitroContext.analyze.filename.replace('{name}', 'nitro'),
|
||||
title: 'Nitro Server bundle stats'
|
||||
}))
|
||||
}
|
||||
|
||||
return rollupConfig
|
||||
}
|
||||
|
77
packages/nuxi/src/commands/analyze.ts
Normal file
77
packages/nuxi/src/commands/analyze.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import { promises as fsp } from 'fs'
|
||||
import { join, resolve } from 'pathe'
|
||||
import { createApp, lazyHandle } from 'h3'
|
||||
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'
|
||||
import { createServer } from '../utils/server'
|
||||
import { writeTypes } from '../utils/prepare'
|
||||
import { loadKit } from '../utils/kit'
|
||||
import { clearDir } from '../utils/fs'
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
export default defineNuxtCommand({
|
||||
meta: {
|
||||
name: 'analyze',
|
||||
usage: 'npx nuxi analyze [rootDir]',
|
||||
description: 'Build nuxt and analyze production bundle (experimental)'
|
||||
},
|
||||
async invoke (args) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
|
||||
|
||||
const rootDir = resolve(args._[0] || '.')
|
||||
const statsDir = join(rootDir, '.nuxt/stats')
|
||||
|
||||
const { loadNuxt, buildNuxt } = await loadKit(rootDir)
|
||||
|
||||
const analyzeOptions: PluginVisualizerOptions = {
|
||||
template: 'treemap',
|
||||
projectRoot: rootDir,
|
||||
filename: join(statsDir, '{name}.html')
|
||||
}
|
||||
|
||||
const nuxt = await loadNuxt({
|
||||
rootDir,
|
||||
config: {
|
||||
build: {
|
||||
// @ts-ignore
|
||||
analyze: analyzeOptions
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await clearDir(nuxt.options.buildDir)
|
||||
await writeTypes(nuxt)
|
||||
await buildNuxt(nuxt)
|
||||
|
||||
const app = createApp()
|
||||
const server = createServer(app)
|
||||
|
||||
const serveFile = (filePath: string) => lazyHandle(async () => {
|
||||
const contents = await fsp.readFile(filePath, 'utf-8')
|
||||
return (_req, res) => { res.end(contents) }
|
||||
})
|
||||
|
||||
console.warn('Do not deploy analyze results! Use `nuxi build` before deployng.')
|
||||
|
||||
console.info('Starting stats server...')
|
||||
|
||||
app.use('/client', serveFile(join(statsDir, 'client.html')))
|
||||
app.use('/nitro', serveFile(join(statsDir, 'nitro.html')))
|
||||
app.use(() => `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><meta charset="utf-8">Nuxt Bundle Stats (experimental)</title>
|
||||
</head>
|
||||
<h1>Nuxt Bundle Stats (experimental)</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/nitro">Nitro server bundle stats</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/client">Client bundle stats</a>
|
||||
</li>
|
||||
</ul>
|
||||
</html>`)
|
||||
|
||||
await server.listen()
|
||||
}
|
||||
})
|
@ -5,6 +5,7 @@ const _rDefault = r => r.default || r
|
||||
export const commands = {
|
||||
dev: () => import('./dev').then(_rDefault),
|
||||
build: () => import('./build').then(_rDefault),
|
||||
analyze: () => import('./analyze').then(_rDefault),
|
||||
generate: () => import('./generate').then(_rDefault),
|
||||
prepare: () => import('./prepare').then(_rDefault),
|
||||
usage: () => import('./usage').then(_rDefault),
|
||||
|
@ -2,10 +2,10 @@ import type { RequestListener } from 'http'
|
||||
import type { ListenOptions } from 'listhen'
|
||||
import { loading } from '@nuxt/design'
|
||||
|
||||
export function createServer () {
|
||||
const listener = createDynamicFunction(createLoadingHandler('Loading...'))
|
||||
export function createServer (defaultApp?) {
|
||||
const listener = createDynamicFunction(defaultApp || createLoadingHandler('Loading...'))
|
||||
|
||||
async function listen (opts: Partial<ListenOptions>) {
|
||||
async function listen (opts?: Partial<ListenOptions>) {
|
||||
const { listen } = await import('listhen')
|
||||
return listen(listener.call, opts)
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-import-resolver": "^2.0.0",
|
||||
"postcss-url": "^10.1.3",
|
||||
"rollup-plugin-visualizer": "^5.5.2",
|
||||
"ufo": "^0.7.9",
|
||||
"vite": "^2.6.10"
|
||||
},
|
||||
|
@ -5,6 +5,8 @@ import vitePlugin from '@vitejs/plugin-vue'
|
||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||
import type { Connect } from 'vite'
|
||||
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
import { transform } from 'esbuild'
|
||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||
import { replace } from './plugins/replace'
|
||||
import { wpfs } from './utils/wpfs'
|
||||
@ -45,6 +47,33 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
}
|
||||
} as ViteOptions)
|
||||
|
||||
// Add analyze plugin if needed
|
||||
if (ctx.nuxt.options.build.analyze) {
|
||||
clientConfig.plugins.push({
|
||||
name: 'nuxt-analyze-minify',
|
||||
async generateBundle (_opts, outputBundle) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for (const [_bundleId, bundle] of Object.entries(outputBundle)) {
|
||||
if (bundle.type !== 'chunk') { continue }
|
||||
const originalEntries = Object.entries(bundle.modules)
|
||||
const minifiedEntries = await Promise.all(originalEntries.map(async ([moduleId, module]) => {
|
||||
const { code } = await transform(module.code || '', { minify: true })
|
||||
return [moduleId, { ...module, code }]
|
||||
}))
|
||||
bundle.modules = Object.fromEntries(minifiedEntries)
|
||||
}
|
||||
return null
|
||||
}
|
||||
})
|
||||
clientConfig.plugins.push(visualizer({
|
||||
...ctx.nuxt.options.build.analyze as any,
|
||||
// @ts-ignore
|
||||
filename: ctx.nuxt.options.build.analyze.filename.replace('{name}', 'client'),
|
||||
title: 'Client bundle stats',
|
||||
gzipSize: true
|
||||
}))
|
||||
}
|
||||
|
||||
await ctx.nuxt.callHook('vite:extendConfig', clientConfig, { isClient: true, isServer: false })
|
||||
|
||||
const viteServer = await vite.createServer(clientConfig)
|
||||
|
@ -80,7 +80,7 @@ function clientPlugins (ctx: WebpackConfigContext) {
|
||||
|
||||
// Webpack Bundle Analyzer
|
||||
// https://github.com/webpack-contrib/webpack-bundle-analyzer
|
||||
if (!ctx.isDev && options.build.analyze) {
|
||||
if (!ctx.isDev && ctx.name === 'client' && options.build.analyze) {
|
||||
const statsDir = resolve(options.buildDir, 'stats')
|
||||
|
||||
// @ts-ignore
|
||||
|
38
yarn.lock
38
yarn.lock
@ -2673,8 +2673,8 @@ __metadata:
|
||||
pathe: ^0.2.0
|
||||
pretty-bytes: ^5.6.0
|
||||
rollup: ^2.58.0
|
||||
rollup-plugin-analyzer: ^4.0.0
|
||||
rollup-plugin-terser: ^7.0.2
|
||||
rollup-plugin-visualizer: ^5.5.2
|
||||
serve-placeholder: ^1.2.4
|
||||
serve-static: ^1.14.1
|
||||
std-env: ^2.3.1
|
||||
@ -2815,6 +2815,7 @@ __metadata:
|
||||
postcss-import: ^14.0.2
|
||||
postcss-import-resolver: ^2.0.0
|
||||
postcss-url: ^10.1.3
|
||||
rollup-plugin-visualizer: ^5.5.2
|
||||
ufo: ^0.7.9
|
||||
unbuild: latest
|
||||
vite: ^2.6.10
|
||||
@ -13158,7 +13159,7 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:^3.1.23, nanoid@npm:^3.1.30":
|
||||
"nanoid@npm:^3.1.22, nanoid@npm:^3.1.23, nanoid@npm:^3.1.30":
|
||||
version: 3.1.30
|
||||
resolution: "nanoid@npm:3.1.30"
|
||||
bin:
|
||||
@ -14027,6 +14028,16 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"open@npm:^7.4.2":
|
||||
version: 7.4.2
|
||||
resolution: "open@npm:7.4.2"
|
||||
dependencies:
|
||||
is-docker: ^2.0.0
|
||||
is-wsl: ^2.1.1
|
||||
checksum: 3333900ec0e420d64c23b831bc3467e57031461d843c801f569b2204a1acc3cd7b3ec3c7897afc9dde86491dfa289708eb92bba164093d8bd88fb2c231843c91
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"open@npm:^8.0.5":
|
||||
version: 8.3.0
|
||||
resolution: "open@npm:8.3.0"
|
||||
@ -16906,13 +16917,6 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rollup-plugin-analyzer@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "rollup-plugin-analyzer@npm:4.0.0"
|
||||
checksum: 72f794f79efe4f620674a48949be9f64dc3cbf601c52ff90ae7cbeaacb604b86bb34321695d0f8f320e5c0b47880022849d92c51d231e1b32c6757a2c627be5e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rollup-plugin-dts@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "rollup-plugin-dts@npm:4.0.0"
|
||||
@ -16957,6 +16961,22 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rollup-plugin-visualizer@npm:^5.5.2":
|
||||
version: 5.5.2
|
||||
resolution: "rollup-plugin-visualizer@npm:5.5.2"
|
||||
dependencies:
|
||||
nanoid: ^3.1.22
|
||||
open: ^7.4.2
|
||||
source-map: ^0.7.3
|
||||
yargs: ^16.2.0
|
||||
peerDependencies:
|
||||
rollup: ^2.0.0
|
||||
bin:
|
||||
rollup-plugin-visualizer: dist/bin/cli.js
|
||||
checksum: b8a252c25efcf3dbd17557517768acc43208005dc9e3b805c3411dc226dd6765fc9779bf5c91577e909801a83b5f0bc2f6338e5b715f8ca8b4ecc924b12e8f25
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rollup-pluginutils@npm:^2.8.2":
|
||||
version: 2.8.2
|
||||
resolution: "rollup-pluginutils@npm:2.8.2"
|
||||
|
Loading…
Reference in New Issue
Block a user