From b15a5d0070bf97ac2eec482ad5fcfd40d3b28562 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 19 Apr 2023 10:54:55 +0200 Subject: [PATCH 1/8] feat(nuxi): add `--no-serve` flag for `nuxi analyze` --- packages/nuxi/src/commands/analyze.ts | 61 ++++++++++++++------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index f450897a79da..215896128abc 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -11,7 +11,7 @@ import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { name: 'analyze', - usage: 'npx nuxi analyze [--log-level] [rootDir]', + usage: 'npx nuxi analyze [--log-level] [--no-serve] [rootDir]', description: 'Build nuxt and analyze production bundle (experimental)' }, async invoke (args) { @@ -34,39 +34,42 @@ export default defineNuxtCommand({ await writeTypes(nuxt) await buildNuxt(nuxt) - const app = createApp() + console.info('Analyze results are available at: ' + statsDir) + console.warn('Do not deploy analyze results! Use `nuxi build` before deploying.') - const serveFile = (filePath: string) => lazyEventHandler(async () => { - const contents = await fsp.readFile(filePath, 'utf-8') - return eventHandler((event) => { event.node.res.end(contents) }) - }) + if (args.serve !== false) { + const app = createApp() - console.warn('Do not deploy analyze results! Use `nuxi build` before deploying.') + const serveFile = (filePath: string) => lazyEventHandler(async () => { + const contents = await fsp.readFile(filePath, 'utf-8') + return eventHandler((event) => { event.node.res.end(contents) }) + }) - console.info('Starting stats server...') + console.info('Starting stats server...') - app.use('/client', serveFile(join(statsDir, 'client.html'))) - app.use('/nitro', serveFile(join(statsDir, 'nitro.html'))) - app.use(eventHandler(() => ` - - - - Nuxt Bundle Stats (experimental) - -

Nuxt Bundle Stats (experimental)

- - - `)) + app.use('/client', serveFile(join(statsDir, 'client.html'))) + app.use('/nitro', serveFile(join(statsDir, 'nitro.html'))) + app.use(eventHandler(() => ` + + + + Nuxt Bundle Stats (experimental) + +

Nuxt Bundle Stats (experimental)

+ + + `)) - await listen(toNodeListener(app)) + await listen(toNodeListener(app)) - return 'wait' as const + return 'wait' as const + } } }) From 232646c7e2b146ba6576e197b56fb346a2959a07 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 19 Apr 2023 14:36:04 +0200 Subject: [PATCH 2/8] feat: update --- packages/nuxi/src/commands/analyze.ts | 50 ++++++++++++++++++++++----- packages/nuxt/src/core/nitro.ts | 2 +- packages/schema/src/config/build.ts | 3 +- packages/schema/src/config/common.ts | 37 ++++++++++++-------- packages/schema/src/config/vite.ts | 8 +++++ packages/schema/src/config/webpack.ts | 3 +- packages/schema/src/types/hooks.ts | 16 +++++++++ 7 files changed, 94 insertions(+), 25 deletions(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index 215896128abc..a1ea7ab529d4 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -2,6 +2,7 @@ import { promises as fsp } from 'node:fs' import { join, resolve } from 'pathe' import { createApp, eventHandler, lazyEventHandler, toNodeListener } from 'h3' import { listen } from 'listhen' +import type { NuxtAnalyzeMeta } from '@nuxt/schema' import { writeTypes } from '../utils/prepare' import { loadKit } from '../utils/kit' import { clearDir } from '../utils/fs' @@ -11,33 +12,66 @@ import { defineNuxtCommand } from './index' export default defineNuxtCommand({ meta: { name: 'analyze', - usage: 'npx nuxi analyze [--log-level] [--no-serve] [rootDir]', + usage: 'npx nuxi analyze [--log-level] [--name] [--no-serve] [rootDir]', description: 'Build nuxt and analyze production bundle (experimental)' }, async invoke (args) { overrideEnv('production') + const name = args.name || 'default' const rootDir = resolve(args._[0] || '.') - const statsDir = join(rootDir, '.nuxt/stats') + + let analyzeDir = join(rootDir, '.nuxt/analyze', name) + let buildDir = join(analyzeDir, '.nuxt') + let outDir = join(analyzeDir, '.output') + + const startTime = Date.now() const { loadNuxt, buildNuxt } = await loadKit(rootDir) const nuxt = await loadNuxt({ rootDir, overrides: { - build: { analyze: true }, + build: { + analyze: true + }, + analyzeDir, + buildDir, + nitro: { + output: { + dir: outDir + } + }, logLevel: args['log-level'] } }) - await clearDir(nuxt.options.buildDir) + analyzeDir = nuxt.options.analyzeDir + buildDir = nuxt.options.buildDir + outDir = nuxt.options.nitro.output?.dir || outDir + + await clearDir(analyzeDir) await writeTypes(nuxt) await buildNuxt(nuxt) - console.info('Analyze results are available at: ' + statsDir) + const endTime = Date.now() + + const meta: NuxtAnalyzeMeta = { + name, + 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) { + if (args.serve !== false && !process.env.CI) { const app = createApp() const serveFile = (filePath: string) => lazyEventHandler(async () => { @@ -47,8 +81,8 @@ export default defineNuxtCommand({ console.info('Starting stats server...') - app.use('/client', serveFile(join(statsDir, 'client.html'))) - app.use('/nitro', serveFile(join(statsDir, 'nitro.html'))) + app.use('/client', serveFile(join(analyzeDir, 'client.html'))) + app.use('/nitro', serveFile(join(analyzeDir, 'nitro.html'))) app.use(eventHandler(() => ` diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 964263b6ddb7..d552074bb39b 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -65,7 +65,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { analyze: nuxt.options.build.analyze && { template: 'treemap', 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), renderer: resolve(distDir, 'core/runtime/nitro/renderer'), diff --git a/packages/schema/src/config/build.ts b/packages/schema/src/config/build.ts index c905fae4ce81..cccdd038fa27 100644 --- a/packages/schema/src/config/build.ts +++ b/packages/schema/src/config/build.ts @@ -119,10 +119,11 @@ export default defineUntypedSchema({ return val ?? false } const rootDir = await get('rootDir') + const analyzeDir = await get('analyzeDir') return { template: 'treemap', projectRoot: rootDir, - filename: join(rootDir, '.nuxt/stats', '{name}.html') + filename: join(analyzeDir, '{name}.html') } } }, diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index bce40ea5adf0..c1032b94fd7d 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -117,20 +117,20 @@ export default defineUntypedSchema({ }, /** - * Used to set the modules directories for path resolving (for example, webpack's - * `resolveLoading`, `nodeExternals` and `postcss`). - * - * The configuration path is relative to `options.rootDir` (default is current working directory). - * - * Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. - * - * @example - * ```js - * export default { - * modulesDir: ['../../node_modules'] - * } - * ``` - */ + * Used to set the modules directories for path resolving (for example, webpack's + * `resolveLoading`, `nodeExternals` and `postcss`). + * + * The configuration path is relative to `options.rootDir` (default is current working directory). + * + * Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. + * + * @example + * ```js + * export default { + * modulesDir: ['../../node_modules'] + * } + * ``` + */ modulesDir: { $default: ['node_modules'], $resolve: async (val, get) => [ @@ -139,6 +139,15 @@ 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) => resolve(await get('rootDir'), val || '.nuxt/analyze') + }, + /** * Whether Nuxt is running in development mode. * diff --git a/packages/schema/src/config/vite.ts b/packages/schema/src/config/vite.ts index f4ace56354bf..ccbf687c37af 100644 --- a/packages/schema/src/config/vite.ts +++ b/packages/schema/src/config/vite.ts @@ -70,6 +70,14 @@ export default defineUntypedSchema({ emptyOutDir: false }, server: { + watch: { + ignored: { + $resolve: async (val, get) => [ + await get('analyzeDir'), + ...val ?? [] + ] + } + }, fs: { allow: { $resolve: async (val, get) => [ diff --git a/packages/schema/src/config/webpack.ts b/packages/schema/src/config/webpack.ts index edd3cf468949..6675d44a5675 100644 --- a/packages/schema/src/config/webpack.ts +++ b/packages/schema/src/config/webpack.ts @@ -22,10 +22,11 @@ export default defineUntypedSchema({ return val ?? false } const rootDir = await get('rootDir') + const analyzeDir = await get('analyzeDir') return { template: 'treemap', projectRoot: rootDir, - filename: join(rootDir, '.nuxt/stats', '{name}.html') + filename: join(analyzeDir, '{name}.html') } } }, diff --git a/packages/schema/src/types/hooks.ts b/packages/schema/src/types/hooks.ts index eaa1c0a91d6e..2983b29b13e3 100644 --- a/packages/schema/src/types/hooks.ts +++ b/packages/schema/src/types/hooks.ts @@ -47,6 +47,15 @@ export interface GenerateAppOptions { filter?: (template: ResolvedNuxtTemplate) => boolean } +export interface NuxtAnalyzeMeta { + name: string + startTime: number + endTime: number + analyzeDir: string + buildDir: string + outDir: string +} + /** * The listeners to Nuxt build time events */ @@ -131,6 +140,13 @@ export interface NuxtHooks { */ '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. * @param options GenerateAppOptions object From 6ae90f49664174a6f866e96f8f326c56d09ae97b Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 19 Apr 2023 14:41:42 +0200 Subject: [PATCH 3/8] chore: do not write types --- packages/nuxi/src/commands/analyze.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index a1ea7ab529d4..7ab0f28207b6 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -3,7 +3,6 @@ import { join, resolve } from 'pathe' import { createApp, eventHandler, lazyEventHandler, toNodeListener } from 'h3' import { listen } from 'listhen' import type { NuxtAnalyzeMeta } from '@nuxt/schema' -import { writeTypes } from '../utils/prepare' import { loadKit } from '../utils/kit' import { clearDir } from '../utils/fs' import { overrideEnv } from '../utils/env' @@ -51,7 +50,6 @@ export default defineNuxtCommand({ outDir = nuxt.options.nitro.output?.dir || outDir await clearDir(analyzeDir) - await writeTypes(nuxt) await buildNuxt(nuxt) const endTime = Date.now() From c6a881f361b44e4ea94c3ce779d8d112e0d9b4ea Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 19 Apr 2023 22:09:48 +0200 Subject: [PATCH 4/8] chore: update --- packages/nuxi/src/commands/analyze.ts | 2 +- packages/schema/src/config/common.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index 7ab0f28207b6..7eff118d743e 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -20,7 +20,7 @@ export default defineNuxtCommand({ const name = args.name || 'default' const rootDir = resolve(args._[0] || '.') - let analyzeDir = join(rootDir, '.nuxt/analyze', name) + let analyzeDir = join(rootDir, '.nuxt-analyze', name) let buildDir = join(analyzeDir, '.nuxt') let outDir = join(analyzeDir, '.output') diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index c1032b94fd7d..ad35e7c5c220 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -145,7 +145,7 @@ export default defineUntypedSchema({ * If a relative path is specified, it will be relative to your `rootDir`. */ analyzeDir: { - $resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt/analyze') + $resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt-analyze') }, /** From 609109732dc1e30aab62822de98a82103b57c975 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 21 Apr 2023 11:18:15 +0200 Subject: [PATCH 5/8] fix: improve --- packages/nuxi/src/commands/analyze.ts | 2 +- packages/schema/src/config/common.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index 7eff118d743e..a55bf9a39edf 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -20,7 +20,7 @@ export default defineNuxtCommand({ const name = args.name || 'default' const rootDir = resolve(args._[0] || '.') - let analyzeDir = join(rootDir, '.nuxt-analyze', name) + let analyzeDir = join(rootDir, '.nuxt-analyze', name.trim().replace(/[^a-z0-9_-]/gi, '_')) let buildDir = join(analyzeDir, '.nuxt') let outDir = join(analyzeDir, '.output') diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index ad35e7c5c220..5f3061086a92 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -354,6 +354,7 @@ export default defineUntypedSchema({ '**/*.{spec,test}.{js,ts,jsx,tsx}', // ignore tests '**/*.d.ts', // ignore type declarations '.output', + await get('analyzeDir'), await get('ignorePrefix') && `**/${await get('ignorePrefix')}*.*` ].concat(val).filter(Boolean) }, From 80a1446809393f2874486748967ed5972fdde9b9 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 21 Apr 2023 13:57:56 +0200 Subject: [PATCH 6/8] fix: change dir to `.nuxt/analyze` --- packages/nuxi/src/commands/analyze.ts | 4 +++- packages/nuxi/src/commands/build.ts | 4 ++-- packages/nuxi/src/commands/prepare.ts | 4 ++-- packages/nuxi/src/utils/fs.ts | 21 +++++++++++++++++---- packages/schema/src/config/common.ts | 4 +++- packages/schema/src/types/hooks.ts | 1 + 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/nuxi/src/commands/analyze.ts b/packages/nuxi/src/commands/analyze.ts index a55bf9a39edf..09987c5324da 100644 --- a/packages/nuxi/src/commands/analyze.ts +++ b/packages/nuxi/src/commands/analyze.ts @@ -18,9 +18,10 @@ export default defineNuxtCommand({ overrideEnv('production') const name = args.name || 'default' + const slug = name.trim().replace(/[^a-z0-9_-]/gi, '_') const rootDir = resolve(args._[0] || '.') - let analyzeDir = join(rootDir, '.nuxt-analyze', name.trim().replace(/[^a-z0-9_-]/gi, '_')) + let analyzeDir = join(rootDir, '.nuxt/analyze', slug) let buildDir = join(analyzeDir, '.nuxt') let outDir = join(analyzeDir, '.output') @@ -56,6 +57,7 @@ export default defineNuxtCommand({ const meta: NuxtAnalyzeMeta = { name, + slug, startTime, endTime, analyzeDir, diff --git a/packages/nuxi/src/commands/build.ts b/packages/nuxi/src/commands/build.ts index dc2c2ab545ac..a582d1209d7c 100644 --- a/packages/nuxi/src/commands/build.ts +++ b/packages/nuxi/src/commands/build.ts @@ -2,7 +2,7 @@ import { relative, resolve } from 'pathe' import { consola } from 'consola' import { writeTypes } from '../utils/prepare' import { loadKit } from '../utils/kit' -import { clearDir } from '../utils/fs' +import { clearBuildDir } from '../utils/fs' import { overrideEnv } from '../utils/env' import { showVersions } from '../utils/banner' import { defineNuxtCommand } from './index' @@ -36,7 +36,7 @@ export default defineNuxtCommand({ // Use ? for backward compatibility for Nuxt <= RC.10 const nitro = useNitro?.() - await clearDir(nuxt.options.buildDir) + await clearBuildDir(nuxt.options.buildDir) await writeTypes(nuxt) diff --git a/packages/nuxi/src/commands/prepare.ts b/packages/nuxi/src/commands/prepare.ts index 121dad7873a7..cd6b77a643c8 100644 --- a/packages/nuxi/src/commands/prepare.ts +++ b/packages/nuxi/src/commands/prepare.ts @@ -1,7 +1,7 @@ import { buildNuxt } from '@nuxt/kit' import { relative, resolve } from 'pathe' import { consola } from 'consola' -import { clearDir } from '../utils/fs' +import { clearBuildDir } from '../utils/fs' import { loadKit } from '../utils/kit' import { writeTypes } from '../utils/prepare' import { defineNuxtCommand } from './index' @@ -24,7 +24,7 @@ export default defineNuxtCommand({ logLevel: args['log-level'] } }) - await clearDir(nuxt.options.buildDir) + await clearBuildDir(nuxt.options.buildDir) await buildNuxt(nuxt) await writeTypes(nuxt) diff --git a/packages/nuxi/src/utils/fs.ts b/packages/nuxi/src/utils/fs.ts index 857cb47f2d9c..7f8640eb4fa3 100644 --- a/packages/nuxi/src/utils/fs.ts +++ b/packages/nuxi/src/utils/fs.ts @@ -1,5 +1,5 @@ -import { promises as fsp } from 'node:fs' -import { dirname } from 'pathe' +import { existsSync, promises as fsp } from 'node:fs' +import { dirname, join } from 'pathe' import { consola } from 'consola' // Check if a file exists @@ -12,11 +12,24 @@ export async function exists (path: string) { } } -export async function clearDir (path: string) { - await fsp.rm(path, { recursive: true, force: true }) +export async function clearDir (path: string, exclude?: string[]) { + if (!exclude) { + 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 }) } +export function clearBuildDir (path: string) { + return clearDir(path, ['cache', 'analyze']) +} + export async function rmRecursive (paths: string[]) { await Promise.all(paths.filter(p => typeof p === 'string').map(async (path) => { consola.debug('Removing recursive path', path) diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index 5f3061086a92..28bd6ce868d5 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -145,7 +145,9 @@ export default defineUntypedSchema({ * If a relative path is specified, it will be relative to your `rootDir`. */ analyzeDir: { - $resolve: async (val, get) => resolve(await get('rootDir'), val || '.nuxt-analyze') + $resolve: async (val, get) => val + ? resolve(await get('rootDir'), val) + : resolve(await get('buildDir'), 'analyze') }, /** diff --git a/packages/schema/src/types/hooks.ts b/packages/schema/src/types/hooks.ts index 2983b29b13e3..06dc5f2f4672 100644 --- a/packages/schema/src/types/hooks.ts +++ b/packages/schema/src/types/hooks.ts @@ -49,6 +49,7 @@ export interface GenerateAppOptions { export interface NuxtAnalyzeMeta { name: string + slug: string startTime: number endTime: number analyzeDir: string From 3f2819cd8f52b3e199ec44e5790b3b846cf40328 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 21 Apr 2023 16:03:38 +0200 Subject: [PATCH 7/8] fix: clean up --- packages/nuxi/src/commands/dev.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nuxi/src/commands/dev.ts b/packages/nuxi/src/commands/dev.ts index 8cbd6f850578..bb3e3c7c735a 100644 --- a/packages/nuxi/src/commands/dev.ts +++ b/packages/nuxi/src/commands/dev.ts @@ -12,7 +12,8 @@ import { writeTypes } from '../utils/prepare' import { loadKit } from '../utils/kit' import { importModule } from '../utils/esm' 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' export default defineNuxtCommand({ @@ -110,7 +111,7 @@ export default defineNuxtCommand({ const previousManifest = await loadNuxtManifest(currentNuxt.options.buildDir) const newManifest = await writeNuxtManifest(currentNuxt) if (previousManifest && newManifest && previousManifest._hash !== newManifest._hash) { - await cleanupNuxtDirs(currentNuxt.options.rootDir) + await clearBuildDir(currentNuxt.options.buildDir) } } From b8486fb986c9f356e70f3d4013ee7bf66a7c975e Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Tue, 2 May 2023 13:54:08 +0200 Subject: [PATCH 8/8] Update packages/schema/src/config/vite.ts Co-authored-by: Daniel Roe --- packages/schema/src/config/vite.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/schema/src/config/vite.ts b/packages/schema/src/config/vite.ts index ccbf687c37af..f4ace56354bf 100644 --- a/packages/schema/src/config/vite.ts +++ b/packages/schema/src/config/vite.ts @@ -70,14 +70,6 @@ export default defineUntypedSchema({ emptyOutDir: false }, server: { - watch: { - ignored: { - $resolve: async (val, get) => [ - await get('analyzeDir'), - ...val ?? [] - ] - } - }, fs: { allow: { $resolve: async (val, get) => [