Skip to content

Commit a26a854

Browse files
committed
fix: fix style block hmr for vitepress md files
close vuejs/vitepress#3129
1 parent e6417f6 commit a26a854

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

packages/plugin-vue/src/handleHotUpdate.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { HmrContext, ModuleNode } from 'vite'
44
import { isCSSRequest } from 'vite'
55

66
import {
7+
cache,
78
createDescriptor,
89
getDescriptor,
910
invalidateDescriptor,
@@ -148,9 +149,20 @@ export async function handleHotUpdate(
148149
updateType.push(`style`)
149150
}
150151
if (updateType.length) {
151-
// invalidate the descriptor cache so that the next transform will
152-
// re-analyze the file and pick up the changes.
153-
invalidateDescriptor(file)
152+
if (file.endsWith('.vue')) {
153+
// invalidate the descriptor cache so that the next transform will
154+
// re-analyze the file and pick up the changes.
155+
invalidateDescriptor(file)
156+
} else {
157+
// https://github.com/vuejs/vitepress/issues/3129
158+
// For non-vue files, e.g. .md files in VitePress, invalidating the
159+
// descriptor will cause the main `load()` hook to attempt to read and
160+
// parse a descriptor from a non-vue source file, leading to errors.
161+
// To fix that we need to provide the descriptor we parsed here in the
162+
// main cache. This assumes no other plugin is applying pre-transform to
163+
// the file type - not impossible, but should be extremely unlikely.
164+
cache.set(file, descriptor)
165+
}
154166
debug(`[vue:update(${updateType.join('&')})] ${file}`)
155167
}
156168
return [...affectedModules].filter(Boolean) as ModuleNode[]

packages/plugin-vue/src/main.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,22 @@ export async function transformMain(
4040
const prevDescriptor = getPrevDescriptor(filename)
4141
const { descriptor, errors } = createDescriptor(filename, code, options)
4242

43-
if (fs.existsSync(filename))
44-
// set descriptor for HMR if it's not set yet
45-
getDescriptor(filename, options, true, true)
43+
if (fs.existsSync(filename)) {
44+
// populate descriptor cache for HMR if it's not set yet
45+
getDescriptor(
46+
filename,
47+
options,
48+
true,
49+
true,
50+
// for vue files, create descriptor from fs read to be consistent with
51+
// logic in handleHotUpdate()
52+
// for non vue files, e.g. md files in vitepress, we assume
53+
// `hmrContext.read` is overwriten so handleHotUpdate() is dealing with
54+
// post-transform code, so we populate the descriptor with post-transform
55+
// code here as well.
56+
filename.endsWith('.vue') ? undefined : code,
57+
)
58+
}
4659

4760
if (errors.length) {
4861
errors.forEach((error) =>

packages/plugin-vue/src/utils/descriptorCache.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export interface SFCParseResult {
1212
}
1313

1414
export const cache = new Map<string, SFCDescriptor>()
15+
// we use a separate descriptor cache for HMR purposes.
16+
// The main cached descriptors are parsed from SFCs that may have been
17+
// transformed by other plugins, e.g. vue-macros;
18+
// The HMR cached descriptors are based on the raw, pre-transform SFCs.
1519
export const hmrCache = new Map<string, SFCDescriptor>()
1620
const prevCache = new Map<string, SFCDescriptor | undefined>()
1721

@@ -52,6 +56,7 @@ export function getDescriptor(
5256
options: ResolvedOptions,
5357
createIfNotFound = true,
5458
hmr = false,
59+
code?: string,
5560
): SFCDescriptor | undefined {
5661
const _cache = hmr ? hmrCache : cache
5762
if (_cache.has(filename)) {
@@ -60,7 +65,7 @@ export function getDescriptor(
6065
if (createIfNotFound) {
6166
const { descriptor, errors } = createDescriptor(
6267
filename,
63-
fs.readFileSync(filename, 'utf-8'),
68+
code ?? fs.readFileSync(filename, 'utf-8'),
6469
options,
6570
hmr,
6671
)

0 commit comments

Comments
 (0)