Skip to content

Commit 62b17f3

Browse files
authored
fix(hmr): should reload if relies file changed after re-render (#471)
1 parent de2f6b3 commit 62b17f3

File tree

5 files changed

+36
-2
lines changed

5 files changed

+36
-2
lines changed

packages/plugin-vue/src/index.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'node:fs'
22
import type { Plugin, ViteDevServer } from 'vite'
3-
import { createFilter } from 'vite'
3+
import { createFilter, normalizePath } from 'vite'
44
/* eslint-disable import/no-duplicates */
55
import type {
66
SFCBlock,
@@ -200,6 +200,12 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
200200
},
201201

202202
handleHotUpdate(ctx) {
203+
ctx.server.ws.send({
204+
type: 'custom',
205+
event: 'file-changed',
206+
data: { file: normalizePath(ctx.file) },
207+
})
208+
203209
if (options.value.compiler.invalidateTypeCache) {
204210
options.value.compiler.invalidateTypeCache(ctx.file)
205211
}

packages/plugin-vue/src/main.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,20 @@ export async function transformMain(
148148
`typeof __VUE_HMR_RUNTIME__ !== 'undefined' && ` +
149149
`__VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main)`,
150150
)
151+
output.push(
152+
`import.meta.hot.on('file-changed', ({ file }) => {`,
153+
` __VUE_HMR_RUNTIME__.CHANGED_FILE = file`,
154+
`})`,
155+
)
151156
// check if the template is the only thing that changed
152157
if (prevDescriptor && isOnlyTemplateChanged(prevDescriptor, descriptor)) {
153-
output.push(`export const _rerender_only = true`)
158+
// #7 only consider re-render if the HMR is triggered by the current component,
159+
// otherwise reload. Due to vite will cache the transform result. If the HMR
160+
// is triggered by other files that the current component relies on, a reload
161+
// is required.
162+
output.push(
163+
`export const _rerender_only = __VUE_HMR_RUNTIME__.CHANGED_FILE === ${JSON.stringify(normalizePath(filename))}`,
164+
)
154165
}
155166
output.push(
156167
`import.meta.hot.accept(mod => {`,

playground/vue/Hmr.vue

+3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
<h2 class="hmr">HMR</h2>
33
<p>Click the button then edit this message. The count should be preserved.</p>
44
<button class="hmr-inc" @click="count++">count is {{ count }}</button>
5+
<span class="hmr-number">{{ number }}</span>
56
</template>
67

78
<script setup lang="ts">
89
import { ref } from 'vue'
910
import Node from './Node.vue'
11+
import { test } from './lib.js'
12+
const number = test()
1013
1114
let foo: number = 0
1215

playground/vue/__tests__/vue.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,17 @@ describe('hmr', () => {
206206
await untilUpdated(() => page.textContent('.hmr-inc'), 'count is 100')
207207
})
208208

209+
test('should reload when relies file changed', async () => {
210+
// rerender
211+
editFile('Hmr.vue', (code) => code.replace('HMR', 'HMR updated'))
212+
await untilUpdated(() => page.textContent('h2.hmr'), 'HMR updated')
213+
await untilUpdated(() => page.textContent('.hmr-number'), '100')
214+
215+
// reload
216+
editFile('lib.js', (code) => code.replace('100', '200'))
217+
await untilUpdated(() => page.textContent('.hmr-number'), '200')
218+
})
219+
209220
test('global hmr for some scenarios', async () => {
210221
editFile('Hmr.vue', (code) =>
211222
code.replace('</template>', ' <Node/>\n' + '</template>'),

playground/vue/lib.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function test() {
2+
return 100
3+
}

0 commit comments

Comments
 (0)