diff --git a/src/node/plugins/staticDataPlugin.ts b/src/node/plugins/staticDataPlugin.ts index b0a7752b..34ae1fe7 100644 --- a/src/node/plugins/staticDataPlugin.ts +++ b/src/node/plugins/staticDataPlugin.ts @@ -1,33 +1,41 @@ import path from 'node:path' -import { isMatch } from 'picomatch' -import { glob } from 'tinyglobby' +import pm from 'picomatch' import { + loadConfigFromFile, + normalizePath, type EnvironmentModuleNode, type Plugin, - type ViteDevServer, - loadConfigFromFile, - normalizePath + type ViteDevServer } from 'vite' +import type { Awaitable } from '../shared' +import { + getWatchedFiles, + normalizeWatchPatterns, + type GlobOptions +} from '../utils/glob' const loaderMatch = /\.data\.m?(j|t)s($|\?)/ let server: ViteDevServer -export interface LoaderModule { +export interface LoaderModule { watch?: string[] | string - load: (watchedFiles: string[]) => any + load: (watchedFiles: string[]) => Awaitable + options?: { globOptions?: GlobOptions } } /** * Helper for defining loaders with type inference */ -export function defineLoader(loader: LoaderModule) { +export function defineLoader(loader: LoaderModule): LoaderModule { return loader } // Map from loader module id to its module info -const idToLoaderModulesMap: Record = - Object.create(null) +const idToLoaderModulesMap: Record< + string, + (Required> & { watch: string[] }) | undefined +> = Object.create(null) // Map from dependency file to a set of loader module ids const depToLoaderModuleIdsMap: Record> = Object.create(null) @@ -56,9 +64,7 @@ export const staticDataPlugin: Plugin = { if (loaderMatch.test(id)) { let _resolve: ((res: any) => void) | undefined if (isBuild) { - if (idToPendingPromiseMap[id]) { - return idToPendingPromiseMap[id] - } + if (idToPendingPromiseMap[id]) return idToPendingPromiseMap[id] idToPendingPromiseMap[id] = new Promise((r) => { _resolve = r }) @@ -67,10 +73,11 @@ export const staticDataPlugin: Plugin = { const base = path.dirname(id) let watch: LoaderModule['watch'] let load: LoaderModule['load'] + let options: LoaderModule['options'] const existing = idToLoaderModulesMap[id] if (existing) { - ;({ watch, load } = existing) + ;({ watch, load, options } = existing) } else { // use vite's load config util as a way to load Node.js file with // TS & native ESM support @@ -88,36 +95,17 @@ export const staticDataPlugin: Plugin = { } const loaderModule = res?.config as LoaderModule - watch = - typeof loaderModule.watch === 'string' - ? [loaderModule.watch] - : loaderModule.watch - if (watch) { - watch = watch.map((p) => { - return p.startsWith('.') - ? normalizePath(path.resolve(base, p)) - : normalizePath(p) - }) - } + watch = normalizeWatchPatterns(loaderModule.watch, base) load = loaderModule.load + options = loaderModule.options || {} } // load the data - let watchedFiles: string[] = [] - if (watch) { - watchedFiles = ( - await glob(watch, { - ignore: ['**/node_modules/**', '**/dist/**'], - expandDirectories: false - }) - ).sort() - } + const watchedFiles = await getWatchedFiles(watch, options.globOptions) const data = await load(watchedFiles) // record loader module for HMR - if (server) { - idToLoaderModulesMap[id] = { watch, load } - } + if (server) idToLoaderModulesMap[id] = { watch, load, options } const result = `export const data = JSON.parse(${JSON.stringify(JSON.stringify(data))})` @@ -139,20 +127,19 @@ export const staticDataPlugin: Plugin = { )) { delete idToLoaderModulesMap[id] const mod = this.environment.moduleGraph.getModuleById(id) - if (mod) { - modules.push(mod) - } + if (mod) modules.push(mod) } } // Also check if the file matches any custom watch patterns. for (const id in idToLoaderModulesMap) { const loader = idToLoaderModulesMap[id] - if (loader && loader.watch && isMatch(normalizedFile, loader.watch)) { + if ( + loader?.watch?.length && + pm(loader.watch, loader.options.globOptions)(normalizedFile) + ) { const mod = this.environment.moduleGraph.getModuleById(id) - if (mod) { - modules.push(mod) - } + if (mod) modules.push(mod) } } diff --git a/src/node/utils/glob.ts b/src/node/utils/glob.ts new file mode 100644 index 00000000..79dc9f3a --- /dev/null +++ b/src/node/utils/glob.ts @@ -0,0 +1,35 @@ +import path from 'node:path' +import { glob } from 'tinyglobby' +import { normalizePath } from 'vite' + +export interface GlobOptions { + cwd?: string + ignore?: string | string[] + dot?: boolean + debug?: boolean +} + +export function normalizeWatchPatterns( + patterns: string[] | string | undefined, + base: string +): string[] { + if (!patterns) return [] + if (typeof patterns === 'string') patterns = [patterns] + return patterns.map((p) => + p.startsWith('.') ? normalizePath(path.resolve(base, p)) : normalizePath(p) + ) +} + +export async function getWatchedFiles( + patterns: string[] | undefined, + options?: GlobOptions +): Promise { + if (!patterns?.length) return [] + return ( + await glob(patterns, { + ignore: ['**/node_modules/**', '**/dist/**', ...(options?.ignore || [])], + expandDirectories: false, + ...options + }) + ).sort() +}