feat(kit, schema): measure module setup timings (#18648)

This commit is contained in:
pooya parsa 2023-03-10 12:30:22 +01:00 committed by GitHub
parent c91e4d7933
commit 6bd9b9448e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 7 deletions

View File

@ -1,8 +1,9 @@
import { promises as fsp } from 'node:fs' import { promises as fsp } from 'node:fs'
import { performance } from 'node:perf_hooks'
import { defu } from 'defu' import { defu } from 'defu'
import { applyDefaults } from 'untyped' import { applyDefaults } from 'untyped'
import { dirname } from 'pathe' import { dirname } from 'pathe'
import type { Nuxt, NuxtModule, ModuleOptions, ModuleDefinition, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema' import type { Nuxt, NuxtModule, ModuleOptions, ModuleSetupReturn, ModuleDefinition, NuxtOptions, ResolvedNuxtTemplate } from '@nuxt/schema'
import { logger } from '../logger' import { logger } from '../logger'
import { useNuxt, nuxtCtx, tryUseNuxt } from '../context' import { useNuxt, nuxtCtx, tryUseNuxt } from '../context'
import { isNuxt2, checkNuxtCompatibility } from '../compatibility' import { isNuxt2, checkNuxtCompatibility } from '../compatibility'
@ -67,7 +68,27 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
} }
// Call setup // Call setup
await definition.setup?.call(null as any, _options, nuxt) const mark = performance.mark()
const res = await definition.setup?.call(null as any, _options, nuxt) ?? {}
const perf = performance.measure(`nuxt:module:${uniqueKey || (Math.round(Math.random() * 10000))}`, mark.name)
const setupTime = Math.round((perf.duration * 100)) / 100
// Measure setup time
if (setupTime > 5000) {
logger.warn(`Slow module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
} else if (nuxt.options.debug) {
logger.info(`Module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
}
// Check if module is ignored
if (res === false) { return false }
// Return module install result
return defu(res, <ModuleSetupReturn> {
timings: {
setup: setupTime
}
})
} }
// Define getters for options and meta // Define getters for options and meta

View File

@ -9,7 +9,7 @@ export async function installModule (moduleToInstall: string | NuxtModule, _inli
const { nuxtModule, inlineOptions } = await normalizeModule(moduleToInstall, _inlineOptions) const { nuxtModule, inlineOptions } = await normalizeModule(moduleToInstall, _inlineOptions)
// Call module // Call module
const res = await nuxtModule(inlineOptions, nuxt) const res = await nuxtModule(inlineOptions, nuxt) ?? {}
if (res === false /* setup aborted */) { if (res === false /* setup aborted */) {
return return
} }
@ -21,6 +21,7 @@ export async function installModule (moduleToInstall: string | NuxtModule, _inli
nuxt.options._installedModules = nuxt.options._installedModules || [] nuxt.options._installedModules = nuxt.options._installedModules || []
nuxt.options._installedModules.push({ nuxt.options._installedModules.push({
meta: await nuxtModule.getMeta?.(), meta: await nuxtModule.getMeta?.(),
timings: res.timings,
entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined
}) })
} }

View File

@ -26,19 +26,32 @@ export interface ModuleMeta {
/** The options received. */ /** The options received. */
export type ModuleOptions = Record<string, any> export type ModuleOptions = Record<string, any>
/** Optional result for nuxt modules */
export interface ModuleSetupReturn {
/**
* Timing information for the initial setup
*/
timings?: {
/** Total time took for module setup in ms */
setup?: number
[key: string]: number | undefined
}
}
type Awaitable<T> = T | Promise<T>
type _ModuleSetupReturn = Awaitable<void | false | ModuleSetupReturn>
/** Input module passed to defineNuxtModule. */ /** Input module passed to defineNuxtModule. */
export interface ModuleDefinition<T extends ModuleOptions = ModuleOptions> { export interface ModuleDefinition<T extends ModuleOptions = ModuleOptions> {
meta?: ModuleMeta meta?: ModuleMeta
defaults?: T | ((nuxt: Nuxt) => T) defaults?: T | ((nuxt: Nuxt) => T)
schema?: T schema?: T
hooks?: Partial<NuxtHooks> hooks?: Partial<NuxtHooks>
setup?: (this: void, resolvedOptions: T, nuxt: Nuxt) => void | Promise<void> setup?: (this: void, resolvedOptions: T, nuxt: Nuxt) => _ModuleSetupReturn
} }
/** Nuxt modules are always a simple function. */
type Awaitable<T> = T | Promise<T>
export interface NuxtModule<T extends ModuleOptions = ModuleOptions> { export interface NuxtModule<T extends ModuleOptions = ModuleOptions> {
(this: void, inlineOptions: T, nuxt: Nuxt): Awaitable<void | false> (this: void, inlineOptions: T, nuxt: Nuxt): _ModuleSetupReturn
getOptions?: (inlineOptions?: T, nuxt?: Nuxt) => Promise<T> getOptions?: (inlineOptions?: T, nuxt?: Nuxt) => Promise<T>
getMeta?: () => Promise<ModuleMeta> getMeta?: () => Promise<ModuleMeta>
} }