Skip to content

Commit a161d7f

Browse files
committed
fix: distinguish HMR and transform descriptor
vitejs/vite-plugin-vue@9119d4d vitejs/vite-plugin-vue@b7b1383
1 parent edc2db9 commit a161d7f

File tree

3 files changed

+31
-19
lines changed

3 files changed

+31
-19
lines changed

src/core/handleHotUpdate.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { type SFCBlock, type SFCDescriptor } from 'vue/compiler-sfc'
44
import {
55
createDescriptor,
66
getDescriptor,
7-
setPrevDescriptor,
7+
invalidateDescriptor,
88
} from './utils/descriptorCache'
99
import {
1010
getResolvedScript,
@@ -25,16 +25,14 @@ export async function handleHotUpdate(
2525
{ file, modules, read }: HmrContext,
2626
options: ResolvedOptions
2727
): Promise<ModuleNode[] | undefined> {
28-
const prevDescriptor = getDescriptor(file, options, false)
28+
const prevDescriptor = getDescriptor(file, options, false, true)
2929
if (!prevDescriptor) {
3030
// file hasn't been requested yet (e.g. async component)
3131
return
3232
}
3333

34-
setPrevDescriptor(file, prevDescriptor)
35-
3634
const content = await read()
37-
const { descriptor } = createDescriptor(file, content, options)
35+
const { descriptor } = createDescriptor(file, content, options, true)
3836

3937
let needRerender = false
4038
const affectedModules = new Set<ModuleNode | undefined>()
@@ -147,6 +145,9 @@ export async function handleHotUpdate(
147145
updateType.push(`style`)
148146
}
149147
if (updateType.length > 0) {
148+
// invalidate the descriptor cache so that the next transform will
149+
// re-analyze the file and pick up the changes.
150+
invalidateDescriptor(file)
150151
debug(`[vue:update(${updateType.join('&')})] ${file}`)
151152
}
152153
return [...affectedModules].filter(Boolean) as ModuleNode[]

src/core/main.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'node:path'
2+
import fs from 'node:fs'
23
import { normalizePath, transformWithEsbuild } from 'vite'
34
import { type RawSourceMap } from 'source-map'
45
import {
@@ -16,6 +17,7 @@ import { type PluginContext } from 'rollup'
1617
import { type SFCBlock, type SFCDescriptor } from 'vue/compiler-sfc'
1718
import {
1819
createDescriptor,
20+
getDescriptor,
1921
getPrevDescriptor,
2022
setSrcDescriptor,
2123
} from './utils/descriptorCache'
@@ -41,10 +43,13 @@ export async function transformMain(
4143
) {
4244
const { devServer, isProduction, devToolsEnabled } = options
4345

44-
// prev descriptor is only set and used for hmr
4546
const prevDescriptor = getPrevDescriptor(filename)
4647
const { descriptor, errors } = createDescriptor(filename, code, options)
4748

49+
if (fs.existsSync(filename))
50+
// set descriptor for HMR if it's not set yet
51+
getDescriptor(filename, options, true, true)
52+
4853
if (errors.length > 0) {
4954
errors.forEach((error) =>
5055
pluginContext.error(createRollupError(filename, error))

src/core/utils/descriptorCache.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ export interface SFCParseResult {
1212
}
1313

1414
export const cache = new Map<string, SFCDescriptor>()
15+
export const hmrCache = new Map<string, SFCDescriptor>()
1516
const prevCache = new Map<string, SFCDescriptor | undefined>()
1617

1718
export function createDescriptor(
1819
filename: string,
1920
source: string,
20-
{ root, isProduction, sourceMap, compiler }: ResolvedOptions
21+
{ root, isProduction, sourceMap, compiler }: ResolvedOptions,
22+
hmr = false
2123
): SFCParseResult {
2224
const { descriptor, errors } = compiler.parse(source, {
2325
filename,
@@ -28,37 +30,41 @@ export function createDescriptor(
2830
// project (relative to root) and on different systems.
2931
const normalizedPath = slash(path.normalize(path.relative(root, filename)))
3032
descriptor.id = getHash(normalizedPath + (isProduction ? source : ''))
31-
32-
cache.set(filename, descriptor)
33+
;(hmr ? hmrCache : cache).set(filename, descriptor)
3334
return { descriptor, errors }
3435
}
3536

3637
export function getPrevDescriptor(filename: string): SFCDescriptor | undefined {
3738
return prevCache.get(filename)
3839
}
3940

40-
export function setPrevDescriptor(
41-
filename: string,
42-
entry: SFCDescriptor
43-
): void {
44-
prevCache.set(filename, entry)
41+
export function invalidateDescriptor(filename: string, hmr = false): void {
42+
const _cache = hmr ? hmrCache : cache
43+
const prev = _cache.get(filename)
44+
_cache.delete(filename)
45+
if (prev) {
46+
prevCache.set(filename, prev)
47+
}
4548
}
4649

4750
export function getDescriptor(
4851
filename: string,
4952
options: ResolvedOptions,
50-
createIfNotFound = true
53+
createIfNotFound = true,
54+
hmr = false
5155
): SFCDescriptor | undefined {
52-
if (cache.has(filename)) {
53-
return cache.get(filename)!
56+
const _cache = hmr ? hmrCache : cache
57+
if (_cache.has(filename)) {
58+
return _cache.get(filename)!
5459
}
5560
if (createIfNotFound) {
5661
const { descriptor, errors } = createDescriptor(
5762
filename,
5863
fs.readFileSync(filename, 'utf-8'),
59-
options
64+
options,
65+
hmr
6066
)
61-
if (errors.length > 0) {
67+
if (errors.length > 0 && !hmr) {
6268
throw errors[0]
6369
}
6470
return descriptor

0 commit comments

Comments
 (0)