diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index 6872de5249e014..d16b1ad7540b64 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -5,6 +5,7 @@ import type { Plugin } from '../plugin' import type { ResolvedConfig } from '../config' import type { ResolveFn } from '../' import { + injectQuery, isParentDirectory, normalizePath, slash, @@ -55,7 +56,12 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { // potential dynamic template string if (rawUrl[0] === '`' && rawUrl.includes('${')) { - const ast = this.parse(rawUrl) + let [pureUrl, queryString = ''] = rawUrl.split('?') + if (queryString) { + pureUrl += '`' + queryString = '?' + queryString.slice(0, -1) + } + const ast = this.parse(pureUrl) const templateLiteral = (ast as any).body[0].expression if (templateLiteral.expressions.length) { const pattern = buildGlobPattern(templateLiteral) @@ -65,6 +71,12 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { continue } + const globOptions = { + eager: true, + import: 'default', + // A hack to allow 'as' & 'query' exist at the same time + query: injectQuery(queryString, 'url'), + } // Note: native import.meta.url is not supported in the baseline // target so we use the global location here. It can be // window.location or self.location in case it is used in a Web Worker. @@ -74,7 +86,9 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { index + exp.length, `new URL((import.meta.glob(${JSON.stringify( pattern, - )}, { eager: true, import: 'default', as: 'url' }))[${rawUrl}], self.location)`, + )}, ${JSON.stringify( + globOptions, + )}))[${pureUrl}], self.location)`, ) continue } diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 3aa3a9ab3189dd..29d56820c6c4bf 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -324,6 +324,17 @@ test('new URL(`${dynamic}`, import.meta.url)', async () => { ) }) +test('new URL(`./${dynamic}?abc`, import.meta.url)', async () => { + expect(await page.textContent('.dynamic-import-meta-url-1-query')).toMatch( + isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png?abc', + ) + expect(await page.textContent('.dynamic-import-meta-url-2-query')).toMatch( + isBuild + ? /\/foo\/assets\/asset-\w{8}\.png\?abc/ + : '/foo/nested/asset.png?abc', + ) +}) + test('new URL(`non-existent`, import.meta.url)', async () => { expect(await page.textContent('.non-existent-import-meta-url')).toMatch( new URL('non-existent', page.url()).pathname, diff --git a/playground/assets/index.html b/playground/assets/index.html index 57caa90f4f552d..b9e857398b6c35 100644 --- a/playground/assets/index.html +++ b/playground/assets/index.html @@ -221,6 +221,16 @@

new URL(`./${dynamic}`, import.meta.url,) (with comma)

+

new URL(`./${dynamic}?abc`, import.meta.url)

+

+ + +

+

+ + +

+

new URL(`non-existent`, import.meta.url)

@@ -432,6 +442,17 @@

assets in noscript

testDynamicImportMetaUrlWithComma('icon', 1) testDynamicImportMetaUrlWithComma('asset', 2) + function testDynamicImportMetaUrlWithQuery(name, i) { + // prettier-ignore + const metaUrl = new URL(`./nested/${name}.png?abc`, import.meta.url,) + text(`.dynamic-import-meta-url-${i}-query`, metaUrl) + document.querySelector(`.dynamic-import-meta-url-img-${i}-query`).src = + metaUrl + } + + testDynamicImportMetaUrlWithQuery('icon', 1) + testDynamicImportMetaUrlWithQuery('asset', 2) + { const name = 'test' const js = new URL(`./nested/${name}.js`, import.meta.url).href