mirror of
https://github.com/vitejs/vite.git
synced 2024-11-21 22:59:10 +00:00
fix(hmr): multiple updates happened when invalidate is called while multiple tabs open (#16307)
This commit is contained in:
parent
01af308dfd
commit
21cc10bfda
@ -533,6 +533,7 @@ export function handlePrunedModules(
|
||||
const t = Date.now()
|
||||
mods.forEach((mod) => {
|
||||
mod.lastHMRTimestamp = t
|
||||
mod.lastHMRInvalidationReceived = false
|
||||
debugHmr?.(`[dispose] ${colors.dim(mod.file)}`)
|
||||
})
|
||||
hot.send({
|
||||
|
@ -787,7 +787,13 @@ export async function _createServer(
|
||||
|
||||
hot.on('vite:invalidate', async ({ path, message }) => {
|
||||
const mod = moduleGraph.urlToModuleMap.get(path)
|
||||
if (mod && mod.isSelfAccepting && mod.lastHMRTimestamp > 0) {
|
||||
if (
|
||||
mod &&
|
||||
mod.isSelfAccepting &&
|
||||
mod.lastHMRTimestamp > 0 &&
|
||||
!mod.lastHMRInvalidationReceived
|
||||
) {
|
||||
mod.lastHMRInvalidationReceived = true
|
||||
config.logger.info(
|
||||
colors.yellow(`hmr invalidate `) +
|
||||
colors.dim(path) +
|
||||
|
@ -35,6 +35,13 @@ export class ModuleNode {
|
||||
ssrModule: Record<string, any> | null = null
|
||||
ssrError: Error | null = null
|
||||
lastHMRTimestamp = 0
|
||||
/**
|
||||
* `import.meta.hot.invalidate` is called by the client.
|
||||
* If there's multiple clients, multiple `invalidate` request is received.
|
||||
* This property is used to dedupe those request to avoid multiple updates happening.
|
||||
* @internal
|
||||
*/
|
||||
lastHMRInvalidationReceived = false
|
||||
lastInvalidationTimestamp = 0
|
||||
/**
|
||||
* If the module only needs to update its imports timestamp (e.g. within an HMR chain),
|
||||
@ -199,6 +206,7 @@ export class ModuleGraph {
|
||||
|
||||
if (isHmr) {
|
||||
mod.lastHMRTimestamp = timestamp
|
||||
mod.lastHMRInvalidationReceived = false
|
||||
} else {
|
||||
// Save the timestamp for this invalidation, so we can avoid caching the result of possible already started
|
||||
// processing being done for this module
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { beforeAll, describe, expect, it, test } from 'vitest'
|
||||
import type { Page } from 'playwright-chromium'
|
||||
import { hasWindowsUnicodeFsBug } from '../../hasWindowsUnicodeFsBug'
|
||||
import {
|
||||
addFile,
|
||||
browser,
|
||||
browserLogs,
|
||||
editFile,
|
||||
getBg,
|
||||
@ -175,6 +177,38 @@ if (!isBuild) {
|
||||
await untilUpdated(() => el.textContent(), 'child updated')
|
||||
})
|
||||
|
||||
test('invalidate works with multiple tabs', async () => {
|
||||
let page2: Page
|
||||
try {
|
||||
page2 = await browser.newPage()
|
||||
await page2.goto(viteTestUrl)
|
||||
|
||||
const el = await page.$('.invalidation')
|
||||
await untilBrowserLogAfter(
|
||||
() =>
|
||||
editFile('invalidation/child.js', (code) =>
|
||||
code.replace('child', 'child updated'),
|
||||
),
|
||||
[
|
||||
'>>> vite:beforeUpdate -- update',
|
||||
'>>> vite:invalidate -- /invalidation/child.js',
|
||||
'[vite] invalidate /invalidation/child.js',
|
||||
'[vite] hot updated: /invalidation/child.js',
|
||||
'>>> vite:afterUpdate -- update',
|
||||
// if invalidate dedupe doesn't work correctly, this beforeUpdate will be called twice
|
||||
'>>> vite:beforeUpdate -- update',
|
||||
'(invalidation) parent is executing',
|
||||
'[vite] hot updated: /invalidation/parent.js',
|
||||
'>>> vite:afterUpdate -- update',
|
||||
],
|
||||
true,
|
||||
)
|
||||
await untilUpdated(() => el.textContent(), 'child updated')
|
||||
} finally {
|
||||
await page2.close()
|
||||
}
|
||||
})
|
||||
|
||||
test('soft invalidate', async () => {
|
||||
const el = await page.$('.soft-invalidation')
|
||||
expect(await el.textContent()).toBe(
|
||||
|
Loading…
Reference in New Issue
Block a user