Skip to content

Commit 86bf776

Browse files
authored
fix(hmr): duplicated modules because of query params mismatch (fixes #2255) (#9773)
1 parent 091537c commit 86bf776

File tree

10 files changed

+66
-4
lines changed

10 files changed

+66
-4
lines changed

packages/vite/src/client/client.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,12 @@ export function removeStyle(id: string): void {
388388
}
389389
}
390390

391-
async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
391+
async function fetchUpdate({
392+
path,
393+
acceptedPath,
394+
timestamp,
395+
explicitImportRequired
396+
}: Update) {
392397
const mod = hotModulesMap.get(path)
393398
if (!mod) {
394399
// In a code-splitting project,
@@ -415,7 +420,9 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
415420
/* @vite-ignore */
416421
base +
417422
path.slice(1) +
418-
`?import&t=${timestamp}${query ? `&${query}` : ''}`
423+
`?${explicitImportRequired ? 'import&' : ''}t=${timestamp}${
424+
query ? `&${query}` : ''
425+
}`
419426
)
420427
moduleMap.set(dep, newMod)
421428
} catch (e) {

packages/vite/src/node/plugins/importAnalysis.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const canSkipImportAnalysis = (id: string): boolean =>
7676
const optimizedDepChunkRE = /\/chunk-[A-Z0-9]{8}\.js/
7777
const optimizedDepDynamicRE = /-[A-Z0-9]{8}\.js/
7878

79-
function isExplicitImportRequired(url: string) {
79+
export function isExplicitImportRequired(url: string): boolean {
8080
return !isJSRequest(cleanUrl(url)) && !isCSSRequest(url)
8181
}
8282

packages/vite/src/node/server/hmr.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { createDebugger, normalizePath, unique } from '../utils'
99
import type { ViteDevServer } from '..'
1010
import { isCSSRequest } from '../plugins/css'
1111
import { getAffectedGlobModules } from '../plugins/importMetaGlob'
12+
import { isExplicitImportRequired } from '../plugins/importAnalysis'
1213
import type { ModuleNode } from './moduleGraph'
1314

1415
export const debugHmr = createDebugger('vite:hmr')
@@ -151,9 +152,13 @@ export function updateModules(
151152

152153
updates.push(
153154
...[...boundaries].map(({ boundary, acceptedVia }) => ({
154-
type: `${boundary.type}-update` as Update['type'],
155+
type: `${boundary.type}-update` as const,
155156
timestamp,
156157
path: boundary.url,
158+
explicitImportRequired:
159+
boundary.type === 'js'
160+
? isExplicitImportRequired(acceptedVia.url)
161+
: undefined,
157162
acceptedPath: acceptedVia.url
158163
}))
159164
)

packages/vite/types/hmrPayload.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export interface Update {
2020
path: string
2121
acceptedPath: string
2222
timestamp: number
23+
/**
24+
* @internal
25+
*/
26+
explicitImportRequired: boolean | undefined
2327
}
2428

2529
export interface PrunePayload {

playground/hmr/__tests__/hmr.spec.ts

+26
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,32 @@ if (!isBuild) {
218218
expect(await btn.textContent()).toBe('Counter 1')
219219
})
220220

221+
// #2255
222+
test('importing reloaded', async () => {
223+
await page.goto(viteTestUrl)
224+
const outputEle = await page.$('.importing-reloaded')
225+
const getOutput = () => {
226+
return outputEle.innerHTML()
227+
}
228+
229+
await untilUpdated(getOutput, ['a.js: a0', 'b.js: b0,a0'].join('<br>'))
230+
231+
editFile('importing-updated/a.js', (code) => code.replace("'a0'", "'a1'"))
232+
await untilUpdated(
233+
getOutput,
234+
['a.js: a0', 'b.js: b0,a0', 'a.js: a1'].join('<br>')
235+
)
236+
237+
editFile('importing-updated/b.js', (code) =>
238+
code.replace('`b0,${a}`', '`b1,${a}`')
239+
)
240+
// note that "a.js: a1" should not happen twice after "b.js: b0,a0'"
241+
await untilUpdated(
242+
getOutput,
243+
['a.js: a0', 'b.js: b0,a0', 'a.js: a1', 'b.js: b1,a1'].join('<br>')
244+
)
245+
})
246+
221247
describe('acceptExports', () => {
222248
const HOT_UPDATED = /hot updated/
223249
const CONNECTED = /connected/

playground/hmr/hmr.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { foo as depFoo, nestedFoo } from './hmrDep'
2+
import './importing-updated'
23

34
export const foo = 1
45
text('.app', foo)

playground/hmr/importing-updated/a.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const val = 'a0'
2+
document.querySelector('.importing-reloaded').innerHTML += `a.js: ${val}<br>`
3+
4+
export default val
5+
6+
if (import.meta.hot) {
7+
import.meta.hot.accept()
8+
}

playground/hmr/importing-updated/b.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import a from './a.js'
2+
3+
const val = `b0,${a}`
4+
document.querySelector('.importing-reloaded').innerHTML += `b.js: ${val}<br>`
5+
6+
if (import.meta.hot) {
7+
import.meta.hot.accept()
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import './a'
2+
import './b'

playground/hmr/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
<div class="link-tag-added">no</div>
2626
<div class="link-tag-removed">no</div>
2727
<div class="import-image"></div>
28+
<div class="importing-reloaded"></div>

0 commit comments

Comments
 (0)