mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-11 11:18:06 +00:00
feat(nuxt): support tracking changes to nuxt options by modules (#30555)
This commit is contained in:
parent
5e7d4938cd
commit
090bc6d7da
@ -28,7 +28,9 @@ export async function installModule<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call module
|
// Call module
|
||||||
const res = await nuxtModule(inlineOptions || {}, nuxt) ?? {}
|
const res = nuxt.options.experimental?.debugModuleMutation && nuxt._asyncLocalStorageModule
|
||||||
|
? await nuxt._asyncLocalStorageModule.run(nuxtModule, () => nuxtModule(inlineOptions || {}, nuxt)) ?? {}
|
||||||
|
: await nuxtModule(inlineOptions || {}, nuxt) ?? {}
|
||||||
if (res === false /* setup aborted */) {
|
if (res === false /* setup aborted */) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -53,6 +55,7 @@ export async function installModule<
|
|||||||
|
|
||||||
nuxt.options._installedModules.push({
|
nuxt.options._installedModules.push({
|
||||||
meta: defu(await nuxtModule.getMeta?.(), buildTimeModuleMeta),
|
meta: defu(await nuxtModule.getMeta?.(), buildTimeModuleMeta),
|
||||||
|
module: nuxtModule,
|
||||||
timings: res.timings,
|
timings: res.timings,
|
||||||
entryPath,
|
entryPath,
|
||||||
})
|
})
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
"nypm": "^0.5.2",
|
"nypm": "^0.5.2",
|
||||||
"ofetch": "^1.4.1",
|
"ofetch": "^1.4.1",
|
||||||
"ohash": "^1.1.4",
|
"ohash": "^1.1.4",
|
||||||
|
"on-change": "^5.0.1",
|
||||||
"pathe": "^2.0.2",
|
"pathe": "^2.0.2",
|
||||||
"perfect-debounce": "^1.0.0",
|
"perfect-debounce": "^1.0.0",
|
||||||
"pkg-types": "^1.3.1",
|
"pkg-types": "^1.3.1",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { existsSync } from 'node:fs'
|
import { existsSync } from 'node:fs'
|
||||||
import { rm } from 'node:fs/promises'
|
import { rm } from 'node:fs/promises'
|
||||||
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
||||||
import { join, normalize, relative, resolve } from 'pathe'
|
import { join, normalize, relative, resolve } from 'pathe'
|
||||||
import { createDebugger, createHooks } from 'hookable'
|
import { createDebugger, createHooks } from 'hookable'
|
||||||
import ignore from 'ignore'
|
import ignore from 'ignore'
|
||||||
@ -10,6 +11,7 @@ import type { PackageJson } from 'pkg-types'
|
|||||||
import { readPackageJSON } from 'pkg-types'
|
import { readPackageJSON } from 'pkg-types'
|
||||||
import { hash } from 'ohash'
|
import { hash } from 'ohash'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import onChange from 'on-change'
|
||||||
import { colorize } from 'consola/utils'
|
import { colorize } from 'consola/utils'
|
||||||
import { updateConfig } from 'c12/update'
|
import { updateConfig } from 'c12/update'
|
||||||
import { formatDate, resolveCompatibilityDatesFromEnv } from 'compatx'
|
import { formatDate, resolveCompatibilityDatesFromEnv } from 'compatx'
|
||||||
@ -53,7 +55,7 @@ export function createNuxt (options: NuxtOptions): Nuxt {
|
|||||||
|
|
||||||
const nuxt: Nuxt = {
|
const nuxt: Nuxt = {
|
||||||
_version: version,
|
_version: version,
|
||||||
options,
|
_asyncLocalStorageModule: options.experimental.debugModuleMutation ? new AsyncLocalStorage() : undefined,
|
||||||
hooks,
|
hooks,
|
||||||
callHook: hooks.callHook,
|
callHook: hooks.callHook,
|
||||||
addHooks: hooks.addHooks,
|
addHooks: hooks.addHooks,
|
||||||
@ -62,6 +64,55 @@ export function createNuxt (options: NuxtOptions): Nuxt {
|
|||||||
close: () => hooks.callHook('close', nuxt),
|
close: () => hooks.callHook('close', nuxt),
|
||||||
vfs: {},
|
vfs: {},
|
||||||
apps: {},
|
apps: {},
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.experimental.debugModuleMutation) {
|
||||||
|
const proxiedOptions = new WeakMap<NuxtModule, NuxtOptions>()
|
||||||
|
|
||||||
|
Object.defineProperty(nuxt, 'options', {
|
||||||
|
get () {
|
||||||
|
const currentModule = nuxt._asyncLocalStorageModule!.getStore()
|
||||||
|
if (!currentModule) {
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxiedOptions.has(currentModule)) {
|
||||||
|
return proxiedOptions.get(currentModule)!
|
||||||
|
}
|
||||||
|
|
||||||
|
nuxt._debug ||= {}
|
||||||
|
nuxt._debug.moduleMutationRecords ||= []
|
||||||
|
|
||||||
|
const proxied = onChange(options, (keys, newValue, previousValue, applyData) => {
|
||||||
|
if (newValue === previousValue && !applyData) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let value = applyData?.args ?? newValue
|
||||||
|
// Make a shallow copy of the value
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value = [...value]
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
value = { ...(value as any) }
|
||||||
|
}
|
||||||
|
nuxt._debug!.moduleMutationRecords!.push({
|
||||||
|
module: currentModule,
|
||||||
|
keys,
|
||||||
|
target: 'nuxt.options',
|
||||||
|
value,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
method: applyData?.name,
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
ignoreUnderscores: true,
|
||||||
|
ignoreSymbols: true,
|
||||||
|
pathAsArray: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
proxiedOptions.set(currentModule, proxied)
|
||||||
|
return proxied
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hooks.hookOnce('close', () => { hooks.removeAllHooks() })
|
hooks.hookOnce('close', () => { hooks.removeAllHooks() })
|
||||||
|
@ -437,5 +437,14 @@ export default defineUntypedSchema({
|
|||||||
browserDevtoolsTiming: {
|
browserDevtoolsTiming: {
|
||||||
$resolve: async (val, get) => val ?? await get('dev'),
|
$resolve: async (val, get) => val ?? await get('dev'),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record mutations to `nuxt.options` in module context
|
||||||
|
*/
|
||||||
|
debugModuleMutation: {
|
||||||
|
$resolve: async (val, get) => {
|
||||||
|
return val ?? Boolean(await get('debug'))
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ export default defineUntypedSchema({
|
|||||||
appDir: '',
|
appDir: '',
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {Array<{ meta: ModuleMeta; timings?: Record<string, number | undefined>; entryPath?: string }>}
|
* @type {Array<{ meta: ModuleMeta; module: NuxtModule, timings?: Record<string, number | undefined>; entryPath?: string }>}
|
||||||
*/
|
*/
|
||||||
_installedModules: [],
|
_installedModules: [],
|
||||||
/** @private */
|
/** @private */
|
||||||
|
@ -8,7 +8,7 @@ export type { AppHeadMetaObject, MetaObject, MetaObjectRaw, HeadAugmentations }
|
|||||||
export type { ModuleDefinition, ModuleMeta, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, NuxtModule, ResolvedModuleOptions } from './types/module'
|
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 { Nuxt, NuxtApp, NuxtPlugin, NuxtPluginTemplate, NuxtTemplate, NuxtTypeTemplate, NuxtServerTemplate, ResolvedNuxtTemplate } from './types/nuxt'
|
||||||
export type { RouterConfig, RouterConfigSerializable, RouterOptions } from './types/router'
|
export type { RouterConfig, RouterConfigSerializable, RouterOptions } from './types/router'
|
||||||
export type { NuxtDebugOptions } from './types/debug'
|
export type { NuxtDebugContext, NuxtDebugModuleMutationRecord } from './types/debug'
|
||||||
|
|
||||||
// Schema
|
// Schema
|
||||||
export { default as NuxtConfigSchema } from './config/index'
|
export { default as NuxtConfigSchema } from './config/index'
|
||||||
|
@ -1,4 +1,21 @@
|
|||||||
import type { NitroOptions } from 'nitro/types'
|
import type { NitroOptions } from 'nitro/types'
|
||||||
|
import type { NuxtModule } from './module'
|
||||||
|
|
||||||
|
export interface NuxtDebugContext {
|
||||||
|
/**
|
||||||
|
* Module mutation records to the `nuxt` instance.
|
||||||
|
*/
|
||||||
|
moduleMutationRecords?: NuxtDebugModuleMutationRecord[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NuxtDebugModuleMutationRecord {
|
||||||
|
module: NuxtModule
|
||||||
|
keys: (string | symbol)[]
|
||||||
|
target: 'nuxt.options'
|
||||||
|
value: any
|
||||||
|
method?: string
|
||||||
|
timestamp: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface NuxtDebugOptions {
|
export interface NuxtDebugOptions {
|
||||||
/** Debug for Nuxt templates */
|
/** Debug for Nuxt templates */
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
import type { AsyncLocalStorage } from 'node:async_hooks'
|
||||||
import type { Hookable } from 'hookable'
|
import type { Hookable } from 'hookable'
|
||||||
import type { Ignore } from 'ignore'
|
import type { Ignore } from 'ignore'
|
||||||
|
import type { NuxtModule } from './module'
|
||||||
import type { NuxtHooks, NuxtLayout, NuxtMiddleware, NuxtPage } from './hooks'
|
import type { NuxtHooks, NuxtLayout, NuxtMiddleware, NuxtPage } from './hooks'
|
||||||
import type { Component } from './components'
|
import type { Component } from './components'
|
||||||
import type { NuxtOptions } from './config'
|
import type { NuxtOptions } from './config'
|
||||||
|
import type { NuxtDebugContext } from './debug'
|
||||||
|
|
||||||
export interface NuxtPlugin {
|
export interface NuxtPlugin {
|
||||||
/** @deprecated use mode */
|
/** @deprecated use mode */
|
||||||
@ -83,6 +86,9 @@ export interface Nuxt {
|
|||||||
_version: string
|
_version: string
|
||||||
_ignore?: Ignore
|
_ignore?: Ignore
|
||||||
_dependencies?: Set<string>
|
_dependencies?: Set<string>
|
||||||
|
_debug?: NuxtDebugContext
|
||||||
|
/** Async local storage for current running Nuxt module instance. */
|
||||||
|
_asyncLocalStorageModule?: AsyncLocalStorage<NuxtModule>
|
||||||
|
|
||||||
/** The resolved Nuxt configuration. */
|
/** The resolved Nuxt configuration. */
|
||||||
options: NuxtOptions
|
options: NuxtOptions
|
||||||
|
@ -444,6 +444,9 @@ importers:
|
|||||||
ohash:
|
ohash:
|
||||||
specifier: 1.1.4
|
specifier: 1.1.4
|
||||||
version: 1.1.4
|
version: 1.1.4
|
||||||
|
on-change:
|
||||||
|
specifier: ^5.0.1
|
||||||
|
version: 5.0.1
|
||||||
pathe:
|
pathe:
|
||||||
specifier: ^2.0.2
|
specifier: ^2.0.2
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
@ -6064,6 +6067,10 @@ packages:
|
|||||||
ohash@1.1.4:
|
ohash@1.1.4:
|
||||||
resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==}
|
resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==}
|
||||||
|
|
||||||
|
on-change@5.0.1:
|
||||||
|
resolution: {integrity: sha512-n7THCP7RkyReRSLkJb8kUWoNsxUIBxTkIp3JKno+sEz6o/9AJ3w3P9fzQkITEkMwyTKJjZciF3v/pVoouxZZMg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
on-finished@2.4.1:
|
on-finished@2.4.1:
|
||||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -14067,6 +14074,8 @@ snapshots:
|
|||||||
|
|
||||||
ohash@1.1.4: {}
|
ohash@1.1.4: {}
|
||||||
|
|
||||||
|
on-change@5.0.1: {}
|
||||||
|
|
||||||
on-finished@2.4.1:
|
on-finished@2.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ee-first: 1.1.1
|
ee-first: 1.1.1
|
||||||
|
Loading…
Reference in New Issue
Block a user