mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-31 07:40:33 +00:00
feat(nuxi): allow greater control of nuxi analyze
from cli (#20387)
This commit is contained in:
parent
84559e84aa
commit
fb76b3931a
@ -2,7 +2,7 @@ import { promises as fsp } from 'node:fs'
|
|||||||
import { join, resolve } from 'pathe'
|
import { join, resolve } from 'pathe'
|
||||||
import { createApp, eventHandler, lazyEventHandler, toNodeListener } from 'h3'
|
import { createApp, eventHandler, lazyEventHandler, toNodeListener } from 'h3'
|
||||||
import { listen } from 'listhen'
|
import { listen } from 'listhen'
|
||||||
import { writeTypes } from '../utils/prepare'
|
import type { NuxtAnalyzeMeta } from '@nuxt/schema'
|
||||||
import { loadKit } from '../utils/kit'
|
import { loadKit } from '../utils/kit'
|
||||||
import { clearDir } from '../utils/fs'
|
import { clearDir } from '../utils/fs'
|
||||||
import { overrideEnv } from '../utils/env'
|
import { overrideEnv } from '../utils/env'
|
||||||
@ -11,29 +11,67 @@ import { defineNuxtCommand } from './index'
|
|||||||
export default defineNuxtCommand({
|
export default defineNuxtCommand({
|
||||||
meta: {
|
meta: {
|
||||||
name: 'analyze',
|
name: 'analyze',
|
||||||
usage: 'npx nuxi analyze [--log-level] [rootDir]',
|
usage: 'npx nuxi analyze [--log-level] [--name] [--no-serve] [rootDir]',
|
||||||
description: 'Build nuxt and analyze production bundle (experimental)'
|
description: 'Build nuxt and analyze production bundle (experimental)'
|
||||||
},
|
},
|
||||||
async invoke (args) {
|
async invoke (args) {
|
||||||
overrideEnv('production')
|
overrideEnv('production')
|
||||||
|
|
||||||
|
const name = args.name || 'default'
|
||||||
|
const slug = name.trim().replace(/[^a-z0-9_-]/gi, '_')
|
||||||
const rootDir = resolve(args._[0] || '.')
|
const rootDir = resolve(args._[0] || '.')
|
||||||
const statsDir = join(rootDir, '.nuxt/stats')
|
|
||||||
|
let analyzeDir = join(rootDir, '.nuxt/analyze', slug)
|
||||||
|
let buildDir = join(analyzeDir, '.nuxt')
|
||||||
|
let outDir = join(analyzeDir, '.output')
|
||||||
|
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
const { loadNuxt, buildNuxt } = await loadKit(rootDir)
|
const { loadNuxt, buildNuxt } = await loadKit(rootDir)
|
||||||
|
|
||||||
const nuxt = await loadNuxt({
|
const nuxt = await loadNuxt({
|
||||||
rootDir,
|
rootDir,
|
||||||
overrides: {
|
overrides: {
|
||||||
build: { analyze: true },
|
build: {
|
||||||
|
analyze: true
|
||||||
|
},
|
||||||
|
analyzeDir,
|
||||||
|
buildDir,
|
||||||
|
nitro: {
|
||||||
|
output: {
|
||||||
|
dir: outDir
|
||||||
|
}
|
||||||
|
},
|
||||||
logLevel: args['log-level']
|
logLevel: args['log-level']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await clearDir(nuxt.options.buildDir)
|
analyzeDir = nuxt.options.analyzeDir
|
||||||
await writeTypes(nuxt)
|
buildDir = nuxt.options.buildDir
|
||||||
|
outDir = nuxt.options.nitro.output?.dir || outDir
|
||||||
|
|
||||||
|
await clearDir(analyzeDir)
|
||||||
await buildNuxt(nuxt)
|
await buildNuxt(nuxt)
|
||||||
|
|
||||||
|
const endTime = Date.now()
|
||||||
|
|
||||||
|
const meta: NuxtAnalyzeMeta = {
|
||||||
|
name,
|
||||||
|
slug,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
analyzeDir,
|
||||||
|
buildDir,
|
||||||
|
outDir
|
||||||
|
}
|
||||||
|
|
||||||
|
await nuxt.callHook('build:analyze:done', meta)
|
||||||
|
await fsp.writeFile(join(analyzeDir, 'meta.json'), JSON.stringify(meta, null, 2), 'utf-8')
|
||||||
|
|
||||||
|
console.info('Analyze results are available at: `' + analyzeDir + '`')
|
||||||
|
console.warn('Do not deploy analyze results! Use `nuxi build` before deploying.')
|
||||||
|
|
||||||
|
if (args.serve !== false && !process.env.CI) {
|
||||||
const app = createApp()
|
const app = createApp()
|
||||||
|
|
||||||
const serveFile = (filePath: string) => lazyEventHandler(async () => {
|
const serveFile = (filePath: string) => lazyEventHandler(async () => {
|
||||||
@ -41,12 +79,10 @@ export default defineNuxtCommand({
|
|||||||
return eventHandler((event) => { event.node.res.end(contents) })
|
return eventHandler((event) => { event.node.res.end(contents) })
|
||||||
})
|
})
|
||||||
|
|
||||||
console.warn('Do not deploy analyze results! Use `nuxi build` before deploying.')
|
|
||||||
|
|
||||||
console.info('Starting stats server...')
|
console.info('Starting stats server...')
|
||||||
|
|
||||||
app.use('/client', serveFile(join(statsDir, 'client.html')))
|
app.use('/client', serveFile(join(analyzeDir, 'client.html')))
|
||||||
app.use('/nitro', serveFile(join(statsDir, 'nitro.html')))
|
app.use('/nitro', serveFile(join(analyzeDir, 'nitro.html')))
|
||||||
app.use(eventHandler(() => `<!DOCTYPE html>
|
app.use(eventHandler(() => `<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@ -69,4 +105,5 @@ export default defineNuxtCommand({
|
|||||||
|
|
||||||
return 'wait' as const
|
return 'wait' as const
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,7 @@ import { relative, resolve } from 'pathe'
|
|||||||
import { consola } from 'consola'
|
import { consola } from 'consola'
|
||||||
import { writeTypes } from '../utils/prepare'
|
import { writeTypes } from '../utils/prepare'
|
||||||
import { loadKit } from '../utils/kit'
|
import { loadKit } from '../utils/kit'
|
||||||
import { clearDir } from '../utils/fs'
|
import { clearBuildDir } from '../utils/fs'
|
||||||
import { overrideEnv } from '../utils/env'
|
import { overrideEnv } from '../utils/env'
|
||||||
import { showVersions } from '../utils/banner'
|
import { showVersions } from '../utils/banner'
|
||||||
import { defineNuxtCommand } from './index'
|
import { defineNuxtCommand } from './index'
|
||||||
@ -36,7 +36,7 @@ export default defineNuxtCommand({
|
|||||||
// Use ? for backward compatibility for Nuxt <= RC.10
|
// Use ? for backward compatibility for Nuxt <= RC.10
|
||||||
const nitro = useNitro?.()
|
const nitro = useNitro?.()
|
||||||
|
|
||||||
await clearDir(nuxt.options.buildDir)
|
await clearBuildDir(nuxt.options.buildDir)
|
||||||
|
|
||||||
await writeTypes(nuxt)
|
await writeTypes(nuxt)
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ import { writeTypes } from '../utils/prepare'
|
|||||||
import { loadKit } from '../utils/kit'
|
import { loadKit } from '../utils/kit'
|
||||||
import { importModule } from '../utils/esm'
|
import { importModule } from '../utils/esm'
|
||||||
import { overrideEnv } from '../utils/env'
|
import { overrideEnv } from '../utils/env'
|
||||||
import { cleanupNuxtDirs, loadNuxtManifest, writeNuxtManifest } from '../utils/nuxt'
|
import { loadNuxtManifest, writeNuxtManifest } from '../utils/nuxt'
|
||||||
|
import { clearBuildDir } from '../utils/fs'
|
||||||
import { defineNuxtCommand } from './index'
|
import { defineNuxtCommand } from './index'
|
||||||
|
|
||||||
export default defineNuxtCommand({
|
export default defineNuxtCommand({
|
||||||
@ -110,7 +111,7 @@ export default defineNuxtCommand({
|
|||||||
const previousManifest = await loadNuxtManifest(currentNuxt.options.buildDir)
|
const previousManifest = await loadNuxtManifest(currentNuxt.options.buildDir)
|
||||||
const newManifest = await writeNuxtManifest(currentNuxt)
|
const newManifest = await writeNuxtManifest(currentNuxt)
|
||||||
if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) {
|
if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) {
|
||||||
await cleanupNuxtDirs(currentNuxt.options.rootDir)
|
await clearBuildDir(currentNuxt.options.buildDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { relative, resolve } from 'pathe'
|
import { relative, resolve } from 'pathe'
|
||||||
import { consola } from 'consola'
|
import { consola } from 'consola'
|
||||||
import { clearDir } from '../utils/fs'
|
import { clearBuildDir } from '../utils/fs'
|
||||||
import { loadKit } from '../utils/kit'
|
import { loadKit } from '../utils/kit'
|
||||||
import { writeTypes } from '../utils/prepare'
|
import { writeTypes } from '../utils/prepare'
|
||||||
import { defineNuxtCommand } from './index'
|
import { defineNuxtCommand } from './index'
|
||||||
@ -23,7 +23,7 @@ export default defineNuxtCommand({
|
|||||||
logLevel: args['log-level']
|
logLevel: args['log-level']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await clearDir(nuxt.options.buildDir)
|
await clearBuildDir(nuxt.options.buildDir)
|
||||||
|
|
||||||
await buildNuxt(nuxt)
|
await buildNuxt(nuxt)
|
||||||
await writeTypes(nuxt)
|
await writeTypes(nuxt)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { promises as fsp } from 'node:fs'
|
import { existsSync, promises as fsp } from 'node:fs'
|
||||||
import { dirname } from 'pathe'
|
import { dirname, join } from 'pathe'
|
||||||
import { consola } from 'consola'
|
import { consola } from 'consola'
|
||||||
|
|
||||||
// Check if a file exists
|
// Check if a file exists
|
||||||
@ -12,11 +12,24 @@ export async function exists (path: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clearDir (path: string) {
|
export async function clearDir (path: string, exclude?: string[]) {
|
||||||
|
if (!exclude) {
|
||||||
await fsp.rm(path, { recursive: true, force: true })
|
await fsp.rm(path, { recursive: true, force: true })
|
||||||
|
} else if (existsSync(path)) {
|
||||||
|
const files = await fsp.readdir(path)
|
||||||
|
await Promise.all(files.map(async (name) => {
|
||||||
|
if (!exclude.includes(name)) {
|
||||||
|
await fsp.rm(join(path, name), { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
await fsp.mkdir(path, { recursive: true })
|
await fsp.mkdir(path, { recursive: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function clearBuildDir (path: string) {
|
||||||
|
return clearDir(path, ['cache', 'analyze'])
|
||||||
|
}
|
||||||
|
|
||||||
export async function rmRecursive (paths: string[]) {
|
export async function rmRecursive (paths: string[]) {
|
||||||
await Promise.all(paths.filter(p => typeof p === 'string').map(async (path) => {
|
await Promise.all(paths.filter(p => typeof p === 'string').map(async (path) => {
|
||||||
consola.debug('Removing recursive path', path)
|
consola.debug('Removing recursive path', path)
|
||||||
|
@ -65,7 +65,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
analyze: nuxt.options.build.analyze && {
|
analyze: nuxt.options.build.analyze && {
|
||||||
template: 'treemap',
|
template: 'treemap',
|
||||||
projectRoot: nuxt.options.rootDir,
|
projectRoot: nuxt.options.rootDir,
|
||||||
filename: join(nuxt.options.rootDir, '.nuxt/stats', '{name}.html')
|
filename: join(nuxt.options.analyzeDir, '{name}.html')
|
||||||
},
|
},
|
||||||
scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean),
|
scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean),
|
||||||
renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
|
renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
|
||||||
|
@ -119,10 +119,11 @@ export default defineUntypedSchema({
|
|||||||
return val ?? false
|
return val ?? false
|
||||||
}
|
}
|
||||||
const rootDir = await get('rootDir')
|
const rootDir = await get('rootDir')
|
||||||
|
const analyzeDir = await get('analyzeDir')
|
||||||
return {
|
return {
|
||||||
template: 'treemap',
|
template: 'treemap',
|
||||||
projectRoot: rootDir,
|
projectRoot: rootDir,
|
||||||
filename: join(rootDir, '.nuxt/stats', '{name}.html')
|
filename: join(analyzeDir, '{name}.html')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -139,6 +139,17 @@ export default defineUntypedSchema({
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory where Nuxt will store the generated files when running `nuxt analyze`.
|
||||||
|
*
|
||||||
|
* If a relative path is specified, it will be relative to your `rootDir`.
|
||||||
|
*/
|
||||||
|
analyzeDir: {
|
||||||
|
$resolve: async (val, get) => val
|
||||||
|
? resolve(await get('rootDir'), val)
|
||||||
|
: resolve(await get('buildDir'), 'analyze')
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether Nuxt is running in development mode.
|
* Whether Nuxt is running in development mode.
|
||||||
*
|
*
|
||||||
@ -346,6 +357,7 @@ export default defineUntypedSchema({
|
|||||||
'**/*.d.ts', // ignore type declarations
|
'**/*.d.ts', // ignore type declarations
|
||||||
'.output',
|
'.output',
|
||||||
'.git',
|
'.git',
|
||||||
|
await get('analyzeDir'),
|
||||||
await get('ignorePrefix') && `**/${await get('ignorePrefix')}*.*`
|
await get('ignorePrefix') && `**/${await get('ignorePrefix')}*.*`
|
||||||
].concat(val).filter(Boolean)
|
].concat(val).filter(Boolean)
|
||||||
},
|
},
|
||||||
|
@ -22,10 +22,11 @@ export default defineUntypedSchema({
|
|||||||
return val ?? false
|
return val ?? false
|
||||||
}
|
}
|
||||||
const rootDir = await get('rootDir')
|
const rootDir = await get('rootDir')
|
||||||
|
const analyzeDir = await get('analyzeDir')
|
||||||
return {
|
return {
|
||||||
template: 'treemap',
|
template: 'treemap',
|
||||||
projectRoot: rootDir,
|
projectRoot: rootDir,
|
||||||
filename: join(rootDir, '.nuxt/stats', '{name}.html')
|
filename: join(analyzeDir, '{name}.html')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -47,6 +47,16 @@ export interface GenerateAppOptions {
|
|||||||
filter?: (template: ResolvedNuxtTemplate<any>) => boolean
|
filter?: (template: ResolvedNuxtTemplate<any>) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NuxtAnalyzeMeta {
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
startTime: number
|
||||||
|
endTime: number
|
||||||
|
analyzeDir: string
|
||||||
|
buildDir: string
|
||||||
|
outDir: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The listeners to Nuxt build time events
|
* The listeners to Nuxt build time events
|
||||||
*/
|
*/
|
||||||
@ -131,6 +141,13 @@ export interface NuxtHooks {
|
|||||||
*/
|
*/
|
||||||
'build:manifest': (manifest: Manifest) => HookResult
|
'build:manifest': (manifest: Manifest) => HookResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when `nuxt analyze` is finished
|
||||||
|
* @param meta the analyze meta object, mutations will be saved to `meta.json`
|
||||||
|
* @returns Promise
|
||||||
|
*/
|
||||||
|
'build:analyze:done': (meta: NuxtAnalyzeMeta) => HookResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before generating the app.
|
* Called before generating the app.
|
||||||
* @param options GenerateAppOptions object
|
* @param options GenerateAppOptions object
|
||||||
|
Loading…
Reference in New Issue
Block a user