From 78eec23dd53ccc4041f507a1172224422660ac77 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 18 Oct 2023 13:54:28 +0800 Subject: [PATCH] fix(assets): make timestamp invalidation lazy --- packages/vite/src/node/plugins/asset.ts | 23 +++++++++++++++---- playground/assets/__tests__/assets.spec.ts | 14 +++++------ .../relative-base-assets.spec.ts | 4 +--- .../runtime-base/runtime-base-assets.spec.ts | 4 +--- .../url-base/url-base-assets.spec.ts | 4 +--- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 89ff347c017244..eb4f65341a69a8 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -20,12 +20,14 @@ import type { ResolvedConfig } from '../config' import { cleanUrl, getHash, + injectQuery, joinUrlSegments, normalizePath, removeLeadingSlash, withTrailingSlash, } from '../utils' import { FS_PREFIX } from '../constants' +import type { ModuleGraph } from '../server/moduleGraph' // referenceId is base64url but replaces - with $ export const assetUrlRE = /__VITE_ASSET__([\w$]+)__(?:\$_(.*?)__)?/g @@ -144,6 +146,8 @@ const viteBuildPublicIdPrefix = '\0vite:asset:public' export function assetPlugin(config: ResolvedConfig): Plugin { registerCustomMime() + let moduleGraph: ModuleGraph | undefined + return { name: 'vite:asset', @@ -152,6 +156,10 @@ export function assetPlugin(config: ResolvedConfig): Plugin { generatedAssets.set(config, new Map()) }, + configureServer(server) { + moduleGraph = server.moduleGraph + }, + resolveId(id) { if (!config.assetsInclude(cleanUrl(id)) && !urlRE.test(id)) { return @@ -192,10 +200,17 @@ export function assetPlugin(config: ResolvedConfig): Plugin { } id = id.replace(urlRE, '$1').replace(unnededFinalQueryCharRE, '') - const url = await fileToUrl(id, config, this) - return `export default ${JSON.stringify( - config.command === 'serve' ? `${url}?t=${Date.now()}` : url, - )}` + let url = await fileToUrl(id, config, this) + + // Inherit HMR timestamp if this asset was invalidated + if (moduleGraph) { + const mod = moduleGraph.getModuleById(id) + if (mod && mod.lastHMRTimestamp > 0) { + url = injectQuery(url, `t=${mod.lastHMRTimestamp}`) + } + } + + return `export default ${JSON.stringify(url)}` }, renderChunk(code, chunk, opts) { diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index fec182a6e8048c..f2877146ea691b 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -293,9 +293,7 @@ describe('svg fragments', () => { test('from js import', async () => { const img = await page.$('.svg-frag-import') - expect(await img.getAttribute('src')).toMatch( - isBuild ? /svg#icon-heart-view$/ : /svg\?t=\d+#icon-heart-view$/, - ) + expect(await img.getAttribute('src')).toMatch(/svg#icon-heart-view$/) }) }) @@ -323,11 +321,11 @@ test('?url import', async () => { test('?url import on css', async () => { const src = readFile('css/icons.css') const txt = await page.textContent('.url-css') - isBuild - ? expect(txt).toEqual( - `data:text/css;base64,${Buffer.from(src).toString('base64')}`, - ) - : expect(txt).toMatch(/^\/foo\/bar\/css\/icons.css\?t=\d+$/) + expect(txt).toEqual( + isBuild + ? `data:text/css;base64,${Buffer.from(src).toString('base64')}` + : '/foo/bar/css/icons.css', + ) }) describe('unicode url', () => { diff --git a/playground/assets/__tests__/relative-base/relative-base-assets.spec.ts b/playground/assets/__tests__/relative-base/relative-base-assets.spec.ts index cdf272469021d4..40c353127e05de 100644 --- a/playground/assets/__tests__/relative-base/relative-base-assets.spec.ts +++ b/playground/assets/__tests__/relative-base/relative-base-assets.spec.ts @@ -179,9 +179,7 @@ describe('svg fragments', () => { test('from js import', async () => { const img = await page.$('.svg-frag-import') - expect(await img.getAttribute('src')).toMatch( - isBuild ? /svg#icon-heart-view$/ : /svg\?t=\d+#icon-heart-view$/, - ) + expect(await img.getAttribute('src')).toMatch(/svg#icon-heart-view$/) }) }) diff --git a/playground/assets/__tests__/runtime-base/runtime-base-assets.spec.ts b/playground/assets/__tests__/runtime-base/runtime-base-assets.spec.ts index fb11c678af2d28..b77a8bf6729678 100644 --- a/playground/assets/__tests__/runtime-base/runtime-base-assets.spec.ts +++ b/playground/assets/__tests__/runtime-base/runtime-base-assets.spec.ts @@ -179,9 +179,7 @@ describe('svg fragments', () => { test('from js import', async () => { const img = await page.$('.svg-frag-import') - expect(await img.getAttribute('src')).toMatch( - isBuild ? /svg#icon-heart-view$/ : /svg\?t=\d+#icon-heart-view$/, - ) + expect(await img.getAttribute('src')).toMatch(/svg#icon-heart-view$/) }) }) diff --git a/playground/assets/__tests__/url-base/url-base-assets.spec.ts b/playground/assets/__tests__/url-base/url-base-assets.spec.ts index 802cd9f4f96a4f..c12c2b80cce0db 100644 --- a/playground/assets/__tests__/url-base/url-base-assets.spec.ts +++ b/playground/assets/__tests__/url-base/url-base-assets.spec.ts @@ -173,9 +173,7 @@ describe('svg fragments', () => { test('from js import', async () => { const img = await page.$('.svg-frag-import') - expect(await img.getAttribute('src')).toMatch( - isBuild ? /svg#icon-heart-view$/ : /svg\?t=\d+#icon-heart-view$/, - ) + expect(await img.getAttribute('src')).toMatch(/svg#icon-heart-view$/) }) })