diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index f9e8fa879bb28a..001a21dab43530 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -356,7 +356,12 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { // its last updated timestamp to force the browser to fetch the most // up-to-date version of this module. try { - const depModule = await moduleGraph.ensureEntryFromUrl(url, ssr) + // delay setting `isSelfAccepting` until the file is actually used (#7870) + const depModule = await moduleGraph.ensureEntryFromUrl( + url, + ssr, + canSkipImportAnalysis(url) + ) if (depModule.lastHMRTimestamp > 0) { url = injectQuery(url, `t=${depModule.lastHMRTimestamp}`) } diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index e12f1a2effd244..f96e9353ce0450 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -169,18 +169,24 @@ export function updateModules( ws.send({ type: 'full-reload' }) - } else { - config.logger.info( - updates - .map(({ path }) => colors.green(`hmr update `) + colors.dim(path)) - .join('\n'), - { clear: true, timestamp: true } - ) - ws.send({ - type: 'update', - updates - }) + return } + + if (updates.length === 0) { + debugHmr(colors.yellow(`no update happened `) + colors.dim(file)) + return + } + + config.logger.info( + updates + .map(({ path }) => colors.green(`hmr update `) + colors.dim(path)) + .join('\n'), + { clear: true, timestamp: true } + ) + ws.send({ + type: 'update', + updates + }) } export async function handleFileAddUnlink( diff --git a/packages/vite/src/node/server/moduleGraph.ts b/packages/vite/src/node/server/moduleGraph.ts index e925ed85b06a22..45fea171ddcc1e 100644 --- a/packages/vite/src/node/server/moduleGraph.ts +++ b/packages/vite/src/node/server/moduleGraph.ts @@ -2,7 +2,6 @@ import { extname } from 'node:path' import { parse as parseUrl } from 'node:url' import type { ModuleInfo, PartialResolvedId } from 'rollup' import { isDirectCSSRequest } from '../plugins/css' -import { isHTMLRequest } from '../plugins/html' import { cleanUrl, normalizePath, @@ -10,7 +9,6 @@ import { removeTimestampQuery } from '../utils' import { FS_PREFIX } from '../constants' -import { canSkipImportAnalysis } from '../plugins/importAnalysis' import type { TransformResult } from './transformRequest' export class ModuleNode { @@ -39,13 +37,13 @@ export class ModuleNode { lastHMRTimestamp = 0 lastInvalidationTimestamp = 0 - constructor(url: string) { + /** + * @param setIsSelfAccepting - set `false` to set `isSelfAccepting` later. e.g. #7870 + */ + constructor(url: string, setIsSelfAccepting = true) { this.url = url this.type = isDirectCSSRequest(url) ? 'css' : 'js' - // #7870 - // The `isSelfAccepting` value is set by importAnalysis, but some - // assets don't go through importAnalysis. - if (isHTMLRequest(url) || canSkipImportAnalysis(url)) { + if (setIsSelfAccepting) { this.isSelfAccepting = false } } @@ -182,11 +180,15 @@ export class ModuleGraph { return noLongerImported } - async ensureEntryFromUrl(rawUrl: string, ssr?: boolean): Promise { + async ensureEntryFromUrl( + rawUrl: string, + ssr?: boolean, + setIsSelfAccepting = true + ): Promise { const [url, resolvedId, meta] = await this.resolveUrl(rawUrl, ssr) let mod = this.urlToModuleMap.get(url) if (!mod) { - mod = new ModuleNode(url) + mod = new ModuleNode(url, setIsSelfAccepting) if (meta) mod.meta = meta this.urlToModuleMap.set(url, mod) mod.id = resolvedId