From 9119d4df16cfe6a1b1df5a2ecc54b4d3d482bdf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Mon, 21 Aug 2023 15:54:44 +0800 Subject: [PATCH] fix(plugin-vue): distinguish HMR and transform descriptor (#232) --- packages/plugin-vue/src/handleHotUpdate.ts | 11 ++++---- packages/plugin-vue/src/main.ts | 5 +++- .../plugin-vue/src/utils/descriptorCache.ts | 26 ++++++++++++------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/plugin-vue/src/handleHotUpdate.ts b/packages/plugin-vue/src/handleHotUpdate.ts index 97ceefc5..f12ef54b 100644 --- a/packages/plugin-vue/src/handleHotUpdate.ts +++ b/packages/plugin-vue/src/handleHotUpdate.ts @@ -6,7 +6,7 @@ import { isCSSRequest } from 'vite' import { createDescriptor, getDescriptor, - setPrevDescriptor, + invalidateDescriptor, } from './utils/descriptorCache' import { getResolvedScript, @@ -26,16 +26,14 @@ export async function handleHotUpdate( { file, modules, read }: HmrContext, options: ResolvedOptions, ): Promise { - const prevDescriptor = getDescriptor(file, options, false) + const prevDescriptor = getDescriptor(file, options, false, true) if (!prevDescriptor) { // file hasn't been requested yet (e.g. async component) return } - setPrevDescriptor(file, prevDescriptor) - const content = await read() - const { descriptor } = createDescriptor(file, content, options) + const { descriptor } = createDescriptor(file, content, options, true) let needRerender = false const affectedModules = new Set() @@ -150,6 +148,9 @@ export async function handleHotUpdate( updateType.push(`style`) } if (updateType.length) { + // invalidate the descriptor cache so that the next transform will + // re-analyze the file and pick up the changes. + invalidateDescriptor(file) debug(`[vue:update(${updateType.join('&')})] ${file}`) } return [...affectedModules].filter(Boolean) as ModuleNode[] diff --git a/packages/plugin-vue/src/main.ts b/packages/plugin-vue/src/main.ts index be5b5610..6b426037 100644 --- a/packages/plugin-vue/src/main.ts +++ b/packages/plugin-vue/src/main.ts @@ -9,6 +9,7 @@ import { addMapping, fromMap, toEncodedMap } from '@jridgewell/gen-mapping' import { normalizePath, transformWithEsbuild } from 'vite' import { createDescriptor, + getDescriptor, getPrevDescriptor, setSrcDescriptor, } from './utils/descriptorCache' @@ -35,10 +36,12 @@ export async function transformMain( ) { const { devServer, isProduction, devToolsEnabled } = options - // prev descriptor is only set and used for hmr const prevDescriptor = getPrevDescriptor(filename) const { descriptor, errors } = createDescriptor(filename, code, options) + // set descriptor for HMR if it's not set yet + getDescriptor(filename, options, true, true) + if (errors.length) { errors.forEach((error) => pluginContext.error(createRollupError(filename, error)), diff --git a/packages/plugin-vue/src/utils/descriptorCache.ts b/packages/plugin-vue/src/utils/descriptorCache.ts index 2152cd21..e86cb7cd 100644 --- a/packages/plugin-vue/src/utils/descriptorCache.ts +++ b/packages/plugin-vue/src/utils/descriptorCache.ts @@ -12,12 +12,14 @@ export interface SFCParseResult { } export const cache = new Map() +export const hmrCache = new Map() const prevCache = new Map() export function createDescriptor( filename: string, source: string, { root, isProduction, sourceMap, compiler }: ResolvedOptions, + hmr = false, ): SFCParseResult { const { descriptor, errors } = compiler.parse(source, { filename, @@ -28,8 +30,7 @@ export function createDescriptor( // project (relative to root) and on different systems. const normalizedPath = slash(path.normalize(path.relative(root, filename))) descriptor.id = getHash(normalizedPath + (isProduction ? source : '')) - - cache.set(filename, descriptor) + ;(hmr ? hmrCache : cache).set(filename, descriptor) return { descriptor, errors } } @@ -37,28 +38,33 @@ export function getPrevDescriptor(filename: string): SFCDescriptor | undefined { return prevCache.get(filename) } -export function setPrevDescriptor( - filename: string, - entry: SFCDescriptor, -): void { - prevCache.set(filename, entry) +export function invalidateDescriptor(filename: string, hmr = false): void { + const _cache = hmr ? hmrCache : cache + const prev = _cache.get(filename) + _cache.delete(filename) + if (prev) { + prevCache.set(filename, prev) + } } export function getDescriptor( filename: string, options: ResolvedOptions, createIfNotFound = true, + hmr = false, ): SFCDescriptor | undefined { - if (cache.has(filename)) { - return cache.get(filename)! + const _cache = hmr ? hmrCache : cache + if (_cache.has(filename)) { + return _cache.get(filename)! } if (createIfNotFound) { const { descriptor, errors } = createDescriptor( filename, fs.readFileSync(filename, 'utf-8'), options, + hmr, ) - if (errors.length) { + if (errors.length && !hmr) { throw errors[0] } return descriptor