diff --git a/src/node/plugins/dynamicRoutesPlugin.ts b/src/node/plugins/dynamicRoutesPlugin.ts index bef6fb00..79d8fc22 100644 --- a/src/node/plugins/dynamicRoutesPlugin.ts +++ b/src/node/plugins/dynamicRoutesPlugin.ts @@ -134,9 +134,7 @@ export const dynamicRoutesPlugin = async ( // params are injected with special markers and extracted as part of // __pageData in ../markdownToVue.ts - return `__VP_PARAMS_START${JSON.stringify( - params - )}__VP_PARAMS_END__${baseContent}` + return `__VP_PARAMS_START${JSON.stringify(params)}__VP_PARAMS_END__${baseContent}` } }, diff --git a/src/node/plugins/staticDataPlugin.ts b/src/node/plugins/staticDataPlugin.ts index f02da16b..1833c733 100644 --- a/src/node/plugins/staticDataPlugin.ts +++ b/src/node/plugins/staticDataPlugin.ts @@ -1,4 +1,4 @@ -import path, { dirname, resolve } from 'node:path' +import path from 'node:path' import { isMatch } from 'picomatch' import { glob } from 'tinyglobby' import { @@ -25,10 +25,12 @@ export function defineLoader(loader: LoaderModule) { return loader } +// Map from loader module id to its module info const idToLoaderModulesMap: Record = Object.create(null) -const depToLoaderModuleIdMap: Record = Object.create(null) +// Map from dependency file to a set of loader module ids +const depToLoaderModuleIdsMap: Record> = Object.create(null) // During build, the load hook will be called on the same file twice // once for client and once for server build. Not only is this wasteful, it @@ -62,7 +64,7 @@ export const staticDataPlugin: Plugin = { }) } - const base = dirname(id) + const base = path.dirname(id) let watch: LoaderModule['watch'] let load: LoaderModule['load'] @@ -77,7 +79,11 @@ export const staticDataPlugin: Plugin = { // record deps for hmr if (server && res) { for (const dep of res.dependencies) { - depToLoaderModuleIdMap[normalizePath(path.resolve(dep))] = id + const depPath = normalizePath(path.resolve(dep)) + if (!depToLoaderModuleIdsMap[depPath]) { + depToLoaderModuleIdsMap[depPath] = new Set() + } + depToLoaderModuleIdsMap[depPath].add(id) } } @@ -89,7 +95,7 @@ export const staticDataPlugin: Plugin = { if (watch) { watch = watch.map((p) => { return p.startsWith('.') - ? normalizePath(resolve(base, p)) + ? normalizePath(path.resolve(base, p)) : normalizePath(p) }) } @@ -97,9 +103,8 @@ export const staticDataPlugin: Plugin = { } // load the data - let watchedFiles + let watchedFiles: string[] = [] if (watch) { - if (typeof watch === 'string') watch = [watch] watchedFiles = ( await glob(watch, { ignore: ['**/node_modules/**', '**/dist/**'], @@ -107,7 +112,7 @@ export const staticDataPlugin: Plugin = { }) ).sort() } - const data = await load(watchedFiles || []) + const data = await load(watchedFiles) // record loader module for HMR if (server) { @@ -125,19 +130,29 @@ export const staticDataPlugin: Plugin = { if (this.environment.name !== 'client') return const modules: EnvironmentModuleNode[] = [] - - // dependency of data loader changed - // (note the dep array includes the loader file itself) - if (file in depToLoaderModuleIdMap) { - const id = depToLoaderModuleIdMap[file]! - delete idToLoaderModulesMap[id] - modules.push(this.environment.moduleGraph.getModuleById(id)!) + const normalizedFile = normalizePath(file) + + // Trigger update if a dependency (including transitive ones) changed. + if (normalizedFile in depToLoaderModuleIdsMap) { + for (const id of Array.from( + depToLoaderModuleIdsMap[normalizedFile] || [] + )) { + delete idToLoaderModulesMap[id] + const mod = this.environment.moduleGraph.getModuleById(id) + if (mod) { + modules.push(mod) + } + } } + // Also check if the file matches any custom watch patterns. for (const id in idToLoaderModulesMap) { - const { watch } = idToLoaderModulesMap[id]! - if (watch && isMatch(file, watch)) { - modules.push(this.environment.moduleGraph.getModuleById(id)!) + const loader = idToLoaderModulesMap[id] + if (loader && loader.watch && isMatch(normalizedFile, loader.watch)) { + const mod = this.environment.moduleGraph.getModuleById(id) + if (mod && !modules.includes(mod)) { + modules.push(mod) + } } }