Skip to content

Commit 4abe3be

Browse files
authored
fix(plugin-vue): ensure HMR updates styles when SFC is treated as a type dependency (#541)
1 parent 59946d3 commit 4abe3be

File tree

6 files changed

+60
-4
lines changed

6 files changed

+60
-4
lines changed

packages/plugin-vue/src/handleHotUpdate.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export async function handleHotUpdate(
3131
{ file, modules, read }: HmrContext,
3232
options: ResolvedOptions,
3333
customElement: boolean,
34+
typeDepModules?: ModuleNode[],
3435
): Promise<ModuleNode[] | void> {
3536
const prevDescriptor = getDescriptor(file, options, false, true)
3637
if (!prevDescriptor) {
@@ -172,7 +173,9 @@ export async function handleHotUpdate(
172173
}
173174
debug(`[vue:update(${updateType.join('&')})] ${file}`)
174175
}
175-
return [...affectedModules].filter(Boolean) as ModuleNode[]
176+
return [...affectedModules, ...(typeDepModules || [])].filter(
177+
Boolean,
178+
) as ModuleNode[]
176179
}
177180

178181
export function isEqualBlock(a: SFCBlock | null, b: SFCBlock | null): boolean {

packages/plugin-vue/src/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import fs from 'node:fs'
2-
import type { Plugin, ViteDevServer } from 'vite'
2+
import type { ModuleNode, Plugin, ViteDevServer } from 'vite'
33
import { createFilter, normalizePath } from 'vite'
44
import type {
55
SFCBlock,
@@ -224,14 +224,22 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
224224
if (options.value.compiler.invalidateTypeCache) {
225225
options.value.compiler.invalidateTypeCache(ctx.file)
226226
}
227+
228+
let typeDepModules: ModuleNode[] | undefined
229+
const matchesFilter = filter.value(ctx.file)
227230
if (typeDepToSFCMap.has(ctx.file)) {
228-
return handleTypeDepChange(typeDepToSFCMap.get(ctx.file)!, ctx)
231+
typeDepModules = handleTypeDepChange(
232+
typeDepToSFCMap.get(ctx.file)!,
233+
ctx,
234+
)
235+
if (!matchesFilter) return typeDepModules
229236
}
230-
if (filter.value(ctx.file)) {
237+
if (matchesFilter) {
231238
return handleHotUpdate(
232239
ctx,
233240
options.value,
234241
customElementFilter.value(ctx.file),
242+
typeDepModules,
235243
)
236244
}
237245
},

playground/vue/ExportTypeProps1.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<div class="export-type-props1">{{ props }}</div>
3+
</template>
4+
5+
<script lang="ts">
6+
export interface FooProps {
7+
msg: string
8+
}
9+
</script>
10+
11+
<script setup lang="ts">
12+
const props = defineProps<FooProps>()
13+
</script>
14+
15+
<style>
16+
.export-type-props1 {
17+
color: red;
18+
}
19+
</style>

playground/vue/ExportTypeProps2.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<template>
2+
<div class="export-type-props2">{{ props }}</div>
3+
</template>
4+
5+
<script setup lang="ts">
6+
import type { FooProps } from './ExportTypeProps1.vue'
7+
const props = defineProps<FooProps>()
8+
</script>

playground/vue/Main.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
<PreCompiledExternalScoped />
3737
<PreCompiledExternalCssModules />
3838
<ParserOptions />
39+
<ExportTypeProps1 msg="msg" />
40+
<ExportTypeProps2 msg="msg" />
3941
</template>
4042

4143
<script setup lang="ts">
@@ -66,6 +68,8 @@ import PreCompiledExternalScoped from './pre-compiled/external-scoped.vue'
6668
import PreCompiledExternalCssModules from './pre-compiled/external-cssmodules.vue'
6769
import ParserOptions from './ParserOptions.vue'
6870
import HmrCircularReference from './HmrCircularReference.vue'
71+
import ExportTypeProps1 from './ExportTypeProps1.vue'
72+
import ExportTypeProps2 from './ExportTypeProps2.vue'
6973
7074
const TsGeneric = defineAsyncComponent(() => import('./TsGeneric.vue'))
7175

playground/vue/__tests__/vue.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,20 @@ describe('macro imported types', () => {
409409
),
410410
)
411411
})
412+
413+
test('should hmr when SFC is treated as a type dependency', async () => {
414+
const cls1 = '.export-type-props1'
415+
expect(await getColor(cls1)).toBe('red')
416+
editFile('ExportTypeProps1.vue', (code) => code.replace('red', 'blue'))
417+
await untilUpdated(() => getColor(cls1), 'blue')
418+
419+
const cls2 = '.export-type-props2'
420+
editFile('ExportTypeProps1.vue', (code) => code.replace('msg: string', ''))
421+
await untilUpdated(
422+
() => page.textContent(cls2),
423+
JSON.stringify({}, null, 2),
424+
)
425+
})
412426
})
413427

414428
test('TS with generics', async () => {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy