From 3db7e2e13d29557fe0ef8f407cba2320921d0991 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 7 Feb 2025 00:36:59 +0800 Subject: [PATCH] feat(nuxt): granular debug options (#30578) --- packages/kit/src/module/define.ts | 2 +- .../app/plugins/{debug.ts => debug-hooks.ts} | 2 +- packages/nuxt/src/core/app.ts | 2 +- packages/nuxt/src/core/builder.ts | 8 +++--- packages/nuxt/src/core/nitro.ts | 2 +- packages/nuxt/src/core/nuxt.ts | 16 +++++++++--- packages/nuxt/src/pages/module.ts | 2 +- packages/schema/src/config/common.ts | 26 ++++++++++++++++++- packages/schema/src/config/vite.ts | 6 +++-- packages/schema/src/index.ts | 1 + packages/schema/src/types/config.ts | 3 ++- packages/schema/src/types/debug.ts | 21 +++++++++++++++ packages/webpack/src/presets/vue.ts | 2 +- 13 files changed, 75 insertions(+), 18 deletions(-) rename packages/nuxt/src/app/plugins/{debug.ts => debug-hooks.ts} (88%) create mode 100644 packages/schema/src/types/debug.ts diff --git a/packages/kit/src/module/define.ts b/packages/kit/src/module/define.ts index 4624692527..5e99ef792c 100644 --- a/packages/kit/src/module/define.ts +++ b/packages/kit/src/module/define.ts @@ -120,7 +120,7 @@ function _defineNuxtModule< // Measure setup time if (setupTime > 5000 && uniqueKey !== '@nuxt/telemetry') { logger.warn(`Slow module \`${uniqueKey || ''}\` took \`${setupTime}ms\` to setup.`) - } else if (nuxt.options.debug) { + } else if (nuxt.options.debug && nuxt.options.debug.modules) { logger.info(`Module \`${uniqueKey || ''}\` took \`${setupTime}ms\` to setup.`) } diff --git a/packages/nuxt/src/app/plugins/debug.ts b/packages/nuxt/src/app/plugins/debug-hooks.ts similarity index 88% rename from packages/nuxt/src/app/plugins/debug.ts rename to packages/nuxt/src/app/plugins/debug-hooks.ts index ccb841672c..d56d99735e 100644 --- a/packages/nuxt/src/app/plugins/debug.ts +++ b/packages/nuxt/src/app/plugins/debug-hooks.ts @@ -2,7 +2,7 @@ import { createDebugger } from 'hookable' import { defineNuxtPlugin } from '../nuxt' export default defineNuxtPlugin({ - name: 'nuxt:debug', + name: 'nuxt:debug:hooks', enforce: 'pre', setup (nuxtApp) { createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' }) diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index 75248d9bfb..9e95f35fa3 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -88,7 +88,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?: const perf = performance.now() - start const setupTime = Math.round((perf * 100)) / 100 - if (nuxt.options.debug || setupTime > 500) { + if ((nuxt.options.debug && nuxt.options.debug.templates) || setupTime > 500) { logger.info(`Compiled \`${template.filename}\` in ${setupTime}ms`) } diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index 2980a694a3..29bb6f2645 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -133,7 +133,7 @@ function createGranularWatcher () { const nuxt = useNuxt() const isIgnored = createIsIgnored(nuxt) - if (nuxt.options.debug) { + if (nuxt.options.debug && nuxt.options.debug.watchers) { // eslint-disable-next-line no-console console.time('[nuxt] builder:chokidar:watch') } @@ -178,7 +178,7 @@ function createGranularWatcher () { }) watcher.on('ready', () => { pending-- - if (nuxt.options.debug && !pending) { + if (nuxt.options.debug && nuxt.options.debug.watchers && !pending) { // eslint-disable-next-line no-console console.timeEnd('[nuxt] builder:chokidar:watch') } @@ -189,7 +189,7 @@ function createGranularWatcher () { async function createParcelWatcher () { const nuxt = useNuxt() - if (nuxt.options.debug) { + if (nuxt.options.debug && nuxt.options.debug.watchers) { // eslint-disable-next-line no-console console.time('[nuxt] builder:parcel:watch') } @@ -215,7 +215,7 @@ async function createParcelWatcher () { ], }) watcher.then((subscription) => { - if (nuxt.options.debug) { + if (nuxt.options.debug && nuxt.options.debug.watchers) { // eslint-disable-next-line no-console console.timeEnd('[nuxt] builder:parcel:watch') } diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 085a2d8f80..291752fce6 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -52,7 +52,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4 const nitroConfig: NitroConfig = defu(nuxt.options.nitro, { - debug: nuxt.options.debug, + debug: nuxt.options.debug ? nuxt.options.debug.nitro : false, rootDir: nuxt.options.rootDir, workspaceDir: nuxt.options.workspaceDir, srcDir: nuxt.options.serverDir, diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 4109f9b032..a5f8b06ef7 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -555,9 +555,13 @@ async function initNuxt (nuxt: Nuxt) { addPlugin(resolve(nuxt.options.appDir, 'plugins/preload.server')) } - // Add nuxt app debugger - if (nuxt.options.debug) { - addPlugin(resolve(nuxt.options.appDir, 'plugins/debug')) + // Add nuxt app hooks debugger + if ( + nuxt.options.debug + && nuxt.options.debug.hooks + && (nuxt.options.debug.hooks === true || nuxt.options.debug.hooks.client) + ) { + addPlugin(resolve(nuxt.options.appDir, 'plugins/debug-hooks')) } // Add experimental Chrome devtools timings support @@ -820,7 +824,11 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { nuxt.hooks.addHooks(opts.overrides.hooks) } - if (nuxt.options.debug) { + if ( + nuxt.options.debug + && nuxt.options.debug.hooks + && (nuxt.options.debug.hooks === true || nuxt.options.debug.hooks.server) + ) { createDebugger(nuxt.hooks, { tag: 'nuxt' }) } diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index 21bb900d93..a767950dc6 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -174,7 +174,7 @@ export default defineNuxtModule({ const options: TypedRouterOptions = { routesFolder: [], dts: resolve(nuxt.options.buildDir, declarationFile), - logs: nuxt.options.debug, + logs: nuxt.options.debug && nuxt.options.debug.router, async beforeWriteFiles (rootPage) { rootPage.children.forEach(child => child.delete()) const pages = nuxt.apps.default?.pages || await resolvePagesRoutes(nuxt) diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index 1d306f1630..5ffcf0eb60 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -8,6 +8,7 @@ import { defu } from 'defu' import { findWorkspaceDir } from 'pkg-types' import type { RuntimeConfig } from '../types/config' +import type { NuxtDebugOptions } from '../types/debug' export default defineUntypedSchema({ /** @@ -264,9 +265,32 @@ export default defineUntypedSchema({ * At the moment, it prints out hook names and timings on the server, and * logs hook arguments as well in the browser. * + * You can also set this to an object to enable specific debug options. + * + * @type {boolean | (typeof import('../src/types/debug').NuxtDebugOptions) | undefined} */ debug: { - $resolve: val => val ?? isDebug, + $resolve: (val: boolean | NuxtDebugOptions | undefined) => { + val ??= isDebug + if (val === false) { + return val + } + if (val === true) { + return { + templates: true, + modules: true, + watchers: true, + hooks: { + client: true, + server: true, + }, + nitro: true, + router: true, + hydration: true, + } satisfies Required + } + return val + }, }, /** diff --git a/packages/schema/src/config/vite.ts b/packages/schema/src/config/vite.ts index df971eefef..9d49537a12 100644 --- a/packages/schema/src/config/vite.ts +++ b/packages/schema/src/config/vite.ts @@ -2,6 +2,7 @@ import { consola } from 'consola' import { resolve } from 'pathe' import { isTest } from 'std-env' import { defineUntypedSchema } from 'untyped' +import type { NuxtDebugOptions } from '../types/debug' export default defineUntypedSchema({ /** @@ -20,9 +21,10 @@ export default defineUntypedSchema({ }, define: { $resolve: async (val: Record | undefined, get) => { - const [isDev, isDebug] = await Promise.all([get('dev'), get('debug')]) as [boolean, boolean] + const [isDev, debug] = await Promise.all([get('dev'), get('debug')]) as [boolean, boolean | NuxtDebugOptions] + return { - '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': isDebug, + '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': Boolean(debug && (debug === true || debug.hydration)), 'process.dev': isDev, 'import.meta.dev': isDev, 'process.test': isTest, diff --git a/packages/schema/src/index.ts b/packages/schema/src/index.ts index a682bb2f61..8ecabf766a 100644 --- a/packages/schema/src/index.ts +++ b/packages/schema/src/index.ts @@ -8,6 +8,7 @@ export type { AppHeadMetaObject, MetaObject, MetaObjectRaw, HeadAugmentations } export type { ModuleDefinition, ModuleMeta, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, NuxtModule, ResolvedModuleOptions } from './types/module' export type { Nuxt, NuxtApp, NuxtPlugin, NuxtPluginTemplate, NuxtTemplate, NuxtTypeTemplate, NuxtServerTemplate, ResolvedNuxtTemplate } from './types/nuxt' export type { RouterConfig, RouterConfigSerializable, RouterOptions } from './types/router' +export type { NuxtDebugOptions } from './types/debug' // Schema export { default as NuxtConfigSchema } from './config/index' diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index 2d9c1222ef..b3e6c8e7fb 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -76,9 +76,10 @@ export interface NuxtBuilder { } // Normalized Nuxt options available as `nuxt.options.*` -export interface NuxtOptions extends Omit { +export interface NuxtOptions extends Omit { vue: Omit & { config?: Partial> } sourcemap: Required> + debug: Required> builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | '@nuxt/rspack-builder' | NuxtBuilder postcss: Omit & { order: Exclude } webpack: ConfigSchema['webpack'] & { diff --git a/packages/schema/src/types/debug.ts b/packages/schema/src/types/debug.ts new file mode 100644 index 0000000000..9ea76b7fc0 --- /dev/null +++ b/packages/schema/src/types/debug.ts @@ -0,0 +1,21 @@ +import type { NitroOptions } from 'nitro/types' + +export interface NuxtDebugOptions { + /** Debug for Nuxt templates */ + templates?: boolean + /** Debug for modules setup timings */ + modules?: boolean + /** Debug for file watchers */ + watchers?: boolean + /** Debug options for Nitro */ + nitro?: NitroOptions['debug'] + /** Debug for production hydration mismatch */ + hydration?: boolean + /** Debug for Vue Router */ + router?: boolean + /** Debug for hooks, can be set to `true` or an object with `server` and `client` keys */ + hooks?: boolean | { + server?: boolean + client?: boolean + } +} diff --git a/packages/webpack/src/presets/vue.ts b/packages/webpack/src/presets/vue.ts index e14632a4fd..915acc51ad 100644 --- a/packages/webpack/src/presets/vue.ts +++ b/packages/webpack/src/presets/vue.ts @@ -33,6 +33,6 @@ export function vue (ctx: WebpackConfigContext) { ctx.config.plugins!.push(new webpack.DefinePlugin({ '__VUE_OPTIONS_API__': 'true', '__VUE_PROD_DEVTOOLS__': 'false', - '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': ctx.nuxt.options.debug, + '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': ctx.nuxt.options.debug && ctx.nuxt.options.debug.hydration, })) }