fix hmr for shared transitive deps on data loaders

pull/4525/head
Divyansh Singh 7 months ago
parent 21f9ed53c0
commit 7356890cd8

@ -134,9 +134,7 @@ export const dynamicRoutesPlugin = async (
// params are injected with special markers and extracted as part of // params are injected with special markers and extracted as part of
// __pageData in ../markdownToVue.ts // __pageData in ../markdownToVue.ts
return `__VP_PARAMS_START${JSON.stringify( return `__VP_PARAMS_START${JSON.stringify(params)}__VP_PARAMS_END__${baseContent}`
params
)}__VP_PARAMS_END__${baseContent}`
} }
}, },

@ -1,4 +1,4 @@
import path, { dirname, resolve } from 'node:path' import path from 'node:path'
import { isMatch } from 'picomatch' import { isMatch } from 'picomatch'
import { glob } from 'tinyglobby' import { glob } from 'tinyglobby'
import { import {
@ -25,10 +25,12 @@ export function defineLoader(loader: LoaderModule) {
return loader return loader
} }
// Map from loader module id to its module info
const idToLoaderModulesMap: Record<string, LoaderModule | undefined> = const idToLoaderModulesMap: Record<string, LoaderModule | undefined> =
Object.create(null) Object.create(null)
const depToLoaderModuleIdMap: Record<string, string> = Object.create(null) // Map from dependency file to a set of loader module ids
const depToLoaderModuleIdsMap: Record<string, Set<string>> = Object.create(null)
// During build, the load hook will be called on the same file twice // 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 // 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 watch: LoaderModule['watch']
let load: LoaderModule['load'] let load: LoaderModule['load']
@ -77,7 +79,11 @@ export const staticDataPlugin: Plugin = {
// record deps for hmr // record deps for hmr
if (server && res) { if (server && res) {
for (const dep of res.dependencies) { 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) { if (watch) {
watch = watch.map((p) => { watch = watch.map((p) => {
return p.startsWith('.') return p.startsWith('.')
? normalizePath(resolve(base, p)) ? normalizePath(path.resolve(base, p))
: normalizePath(p) : normalizePath(p)
}) })
} }
@ -97,9 +103,8 @@ export const staticDataPlugin: Plugin = {
} }
// load the data // load the data
let watchedFiles let watchedFiles: string[] = []
if (watch) { if (watch) {
if (typeof watch === 'string') watch = [watch]
watchedFiles = ( watchedFiles = (
await glob(watch, { await glob(watch, {
ignore: ['**/node_modules/**', '**/dist/**'], ignore: ['**/node_modules/**', '**/dist/**'],
@ -107,7 +112,7 @@ export const staticDataPlugin: Plugin = {
}) })
).sort() ).sort()
} }
const data = await load(watchedFiles || []) const data = await load(watchedFiles)
// record loader module for HMR // record loader module for HMR
if (server) { if (server) {
@ -125,19 +130,29 @@ export const staticDataPlugin: Plugin = {
if (this.environment.name !== 'client') return if (this.environment.name !== 'client') return
const modules: EnvironmentModuleNode[] = [] const modules: EnvironmentModuleNode[] = []
const normalizedFile = normalizePath(file)
// dependency of data loader changed
// (note the dep array includes the loader file itself) // Trigger update if a dependency (including transitive ones) changed.
if (file in depToLoaderModuleIdMap) { if (normalizedFile in depToLoaderModuleIdsMap) {
const id = depToLoaderModuleIdMap[file]! for (const id of Array.from(
delete idToLoaderModulesMap[id] depToLoaderModuleIdsMap[normalizedFile] || []
modules.push(this.environment.moduleGraph.getModuleById(id)!) )) {
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) { for (const id in idToLoaderModulesMap) {
const { watch } = idToLoaderModulesMap[id]! const loader = idToLoaderModulesMap[id]
if (watch && isMatch(file, watch)) { if (loader && loader.watch && isMatch(normalizedFile, loader.watch)) {
modules.push(this.environment.moduleGraph.getModuleById(id)!) const mod = this.environment.moduleGraph.getModuleById(id)
if (mod && !modules.includes(mod)) {
modules.push(mod)
}
} }
} }

Loading…
Cancel
Save