diff --git a/packages/kit/src/ignore.ts b/packages/kit/src/ignore.ts index dc18508a06..8e52e59b94 100644 --- a/packages/kit/src/ignore.ts +++ b/packages/kit/src/ignore.ts @@ -3,12 +3,14 @@ import ignore from 'ignore' import { join, relative, resolve } from 'pathe' import { tryUseNuxt } from './context' +export function createIsIgnored (nuxt = tryUseNuxt()) { + return (pathname: string, stats?: unknown) => isIgnored(pathname, stats, nuxt) +} + /** * Return a filter function to filter an array of paths */ -export function isIgnored (pathname: string): boolean { - const nuxt = tryUseNuxt() - +export function isIgnored (pathname: string, _stats?: unknown, nuxt = tryUseNuxt()): boolean { // Happens with CLI reloads if (!nuxt) { return false diff --git a/packages/kit/src/index.ts b/packages/kit/src/index.ts index 04056b2784..f14fd8c81d 100644 --- a/packages/kit/src/index.ts +++ b/packages/kit/src/index.ts @@ -19,7 +19,7 @@ export { assertNuxtCompatibility, checkNuxtCompatibility, getNuxtVersion, hasNux export { addComponent, addComponentsDir } from './components' export type { AddComponentOptions } from './components' export { nuxtCtx, tryUseNuxt, useNuxt } from './context' -export { isIgnored, resolveIgnorePatterns } from './ignore' +export { createIsIgnored, isIgnored, resolveIgnorePatterns } from './ignore' export { addLayout } from './layout' export { addRouteMiddleware, extendPages, extendRouteRules } from './pages' export type { AddRouteMiddlewareOptions, ExtendRouteRulesOptions } from './pages' diff --git a/packages/nuxt/src/components/plugins/transform.ts b/packages/nuxt/src/components/plugins/transform.ts index ba819bbfa3..f7bf3586c6 100644 --- a/packages/nuxt/src/components/plugins/transform.ts +++ b/packages/nuxt/src/components/plugins/transform.ts @@ -58,7 +58,7 @@ export function TransformPlugin (nuxt: Nuxt, options: TransformPluginOptions) { enforce: 'post', transformInclude (id) { id = normalize(id) - return id.startsWith('virtual:') || id.startsWith('\0virtual:') || id.startsWith(nuxt.options.buildDir) || !isIgnored(id) + return id.startsWith('virtual:') || id.startsWith('\0virtual:') || id.startsWith(nuxt.options.buildDir) || !isIgnored(id, undefined, nuxt) }, async transform (code, id) { // Virtual component wrapper diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index cc420dc2bc..84e2c8e317 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -1,7 +1,7 @@ import type { EventType } from '@parcel/watcher' import type { FSWatcher } from 'chokidar' import { watch as chokidarWatch } from 'chokidar' -import { importModule, isIgnored, tryResolveModule, useNuxt } from '@nuxt/kit' +import { createIsIgnored, importModule, isIgnored, tryResolveModule, useNuxt } from '@nuxt/kit' import { debounce } from 'perfect-debounce' import { normalize, relative, resolve } from 'pathe' import type { Nuxt, NuxtBuilder } from 'nuxt/schema' @@ -100,14 +100,12 @@ async function watch (nuxt: Nuxt) { function createWatcher () { const nuxt = useNuxt() + const isIgnored = createIsIgnored(nuxt) const watcher = chokidarWatch(nuxt.options._layers.map(i => i.config.srcDir as string).filter(Boolean), { ...nuxt.options.watchers.chokidar, ignoreInitial: true, - ignored: [ - isIgnored, - 'node_modules', - ], + ignored: [isIgnored, /[\\/]node_modules[\\/]/], }) watcher.on('all', (event, path) => { @@ -121,6 +119,7 @@ function createWatcher () { function createGranularWatcher () { const nuxt = useNuxt() + const isIgnored = createIsIgnored(nuxt) if (nuxt.options.debug) { // eslint-disable-next-line no-console @@ -139,7 +138,7 @@ function createGranularWatcher () { } for (const dir of pathsToWatch) { pending++ - const watcher = chokidarWatch(dir, { ...nuxt.options.watchers.chokidar, ignoreInitial: false, depth: 0, ignored: [isIgnored, '**/node_modules'] }) + const watcher = chokidarWatch(dir, { ...nuxt.options.watchers.chokidar, ignoreInitial: false, depth: 0, ignored: [isIgnored, /[\\/]node_modules[\\/]/] }) const watchers: Record = {} watcher.on('all', (event, path) => { diff --git a/packages/nuxt/src/core/cache.ts b/packages/nuxt/src/core/cache.ts index 3096ecf554..5c24dab590 100644 --- a/packages/nuxt/src/core/cache.ts +++ b/packages/nuxt/src/core/cache.ts @@ -2,7 +2,7 @@ import { mkdir, open, readFile, stat, unlink, writeFile } from 'node:fs/promises import type { FileHandle } from 'node:fs/promises' import { resolve } from 'node:path' import { existsSync } from 'node:fs' -import { isIgnored } from '@nuxt/kit' +import { createIsIgnored } from '@nuxt/kit' import type { Nuxt, NuxtConfig, NuxtConfigLayer } from '@nuxt/schema' import { hash, murmurHash, objectHash } from 'ohash' import { glob } from 'tinyglobby' @@ -119,6 +119,7 @@ async function getHashes (nuxt: Nuxt, options: GetHashOptions): Promise data: murmurHash(f.data as any /* ArrayBuffer */), })) + const isIgnored = createIsIgnored(nuxt) const sourceFiles = await readFilesRecursive(options.cwd(layer), { shouldIgnore: isIgnored, // TODO: Validate if works with absolute paths cwd: nuxt.options.rootDir, diff --git a/packages/nuxt/src/core/schema.ts b/packages/nuxt/src/core/schema.ts index 4c7e8d7ada..0a81a15aa2 100644 --- a/packages/nuxt/src/core/schema.ts +++ b/packages/nuxt/src/core/schema.ts @@ -5,11 +5,8 @@ import { resolve } from 'pathe' import { watch } from 'chokidar' import { defu } from 'defu' import { debounce } from 'perfect-debounce' -import { createResolver, defineNuxtModule, importModule, tryResolveModule } from '@nuxt/kit' -import { - generateTypes, - resolveSchema as resolveUntypedSchema, -} from 'untyped' +import { createIsIgnored, createResolver, defineNuxtModule, importModule, tryResolveModule } from '@nuxt/kit' +import { generateTypes, resolveSchema as resolveUntypedSchema } from 'untyped' import type { Schema, SchemaDefinition } from 'untyped' import untypedPlugin from 'untyped/babel-plugin' import { createJiti } from 'jiti' @@ -71,11 +68,17 @@ export default defineNuxtModule({ logger.warn('Falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project.') } - const filesToWatch = await Promise.all(nuxt.options._layers.map(layer => - resolver.resolve(layer.config.rootDir, 'nuxt.schema.*'), - )) - const watcher = watch(filesToWatch, { + const isIgnored = createIsIgnored(nuxt) + const dirsToWatch = nuxt.options._layers.map(layer => resolver.resolve(layer.config.rootDir)) + const SCHEMA_RE = /(?:^|\/)nuxt.schema.\w+$/ + const watcher = watch(dirsToWatch, { ...nuxt.options.watchers.chokidar, + depth: 1, + ignored: [ + (path, stats) => (stats && !stats.isFile()) || !SCHEMA_RE.test(path), + isIgnored, + /[\\/]node_modules[\\/]/, + ], ignoreInitial: true, }) watcher.on('all', onChange) diff --git a/packages/nuxt/src/imports/module.ts b/packages/nuxt/src/imports/module.ts index 4854dc8677..1d669b2eaa 100644 --- a/packages/nuxt/src/imports/module.ts +++ b/packages/nuxt/src/imports/module.ts @@ -1,5 +1,5 @@ import { existsSync } from 'node:fs' -import { addBuildPlugin, addTemplate, addTypeTemplate, defineNuxtModule, isIgnored, resolveAlias, tryResolveModule, updateTemplates, useNuxt } from '@nuxt/kit' +import { addBuildPlugin, addTemplate, addTypeTemplate, createIsIgnored, defineNuxtModule, resolveAlias, tryResolveModule, updateTemplates, useNuxt } from '@nuxt/kit' import { isAbsolute, join, normalize, relative, resolve } from 'pathe' import type { Import, Unimport } from 'unimport' import { createUnimport, scanDirExports, toExports } from 'unimport' @@ -118,6 +118,7 @@ export default defineNuxtModule>({ return IMPORTS_TEMPLATE_RE.test(template.filename) } + const isIgnored = createIsIgnored(nuxt) const regenerateImports = async () => { await ctx.modifyDynamicImports(async (imports) => { // Clear old imports diff --git a/packages/schema/build.config.ts b/packages/schema/build.config.ts index ae065512f7..93548a912d 100644 --- a/packages/schema/build.config.ts +++ b/packages/schema/build.config.ts @@ -28,6 +28,7 @@ export default defineBuildConfig({ // Type imports '@unhead/schema', '@vitejs/plugin-vue', + 'chokidar', '@vitejs/plugin-vue-jsx', '@vue/language-core', 'autoprefixer', diff --git a/packages/schema/package.json b/packages/schema/package.json index 2d06404dea..88958c1069 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -44,6 +44,7 @@ "@vue/compiler-sfc": "3.5.13", "@vue/language-core": "2.2.0", "c12": "2.0.1", + "chokidar": "4.0.3", "compatx": "0.1.8", "esbuild-loader": "4.2.2", "file-loader": "6.2.0", diff --git a/packages/schema/src/config/common.ts b/packages/schema/src/config/common.ts index 59848e08dc..8fe1c3183b 100644 --- a/packages/schema/src/config/common.ts +++ b/packages/schema/src/config/common.ts @@ -519,9 +519,11 @@ export default defineUntypedSchema({ /** * Options to pass directly to `chokidar`. * @see [chokidar](https://github.com/paulmillr/chokidar#api) + * @type {typeof import('chokidar').ChokidarOptions} */ chokidar: { ignoreInitial: true, + ignorePermissionErrors: true, }, }, diff --git a/packages/vite/src/vite.ts b/packages/vite/src/vite.ts index d0a9325f8c..7471dbdfd8 100644 --- a/packages/vite/src/vite.ts +++ b/packages/vite/src/vite.ts @@ -2,7 +2,7 @@ import { existsSync } from 'node:fs' import * as vite from 'vite' import { dirname, join, normalize, resolve } from 'pathe' import type { Nuxt, NuxtBuilder, ViteConfig } from '@nuxt/schema' -import { addVitePlugin, isIgnored, logger, resolvePath, useNitro } from '@nuxt/kit' +import { addVitePlugin, createIsIgnored, logger, resolvePath, useNitro } from '@nuxt/kit' import replace from '@rollup/plugin-replace' import type { RollupReplaceOptions } from '@rollup/plugin-replace' import { sanitizeFilePath } from 'mlly' @@ -53,6 +53,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => { const { $client, $server, ...viteConfig } = nuxt.options.vite + const isIgnored = createIsIgnored(nuxt) const ctx: ViteBuildContext = { nuxt, entry, @@ -88,6 +89,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => { }, }, watch: { + chokidar: { ...nuxt.options.watchers.chokidar, ignored: [isIgnored, /[\\/]node_modules[\\/]/] }, exclude: nuxt.options.ignore, }, }, @@ -101,7 +103,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => { replace({ preventAssignment: true, ...globalThisReplacements }), ], server: { - watch: { ignored: isIgnored }, + watch: { ...nuxt.options.watchers.chokidar, ignored: [isIgnored, /[\\/]node_modules[\\/]/] }, fs: { allow: [...new Set(allowDirs)], }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cec3e07c94..cf7bc24fc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -690,6 +690,9 @@ importers: c12: specifier: 2.0.1 version: 2.0.1(magicast@0.3.5) + chokidar: + specifier: 4.0.3 + version: 4.0.3 compatx: specifier: 0.1.8 version: 0.1.8