diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index d16b1ad7540b64..c20abbdc953406 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -14,6 +14,8 @@ import { import { CLIENT_ENTRY } from '../constants' import { fileToUrl } from './asset' import { preloadHelperId } from './importAnalysisBuild' +import type { InternalResolveOptions } from './resolve' +import { tryFsResolve } from './resolve' /** * Convert `new URL('./foo.png', import.meta.url)` to its resolved built URL @@ -29,6 +31,16 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { const normalizedPublicDir = normalizePath(config.publicDir) let assetResolver: ResolveFn + const fsResolveOptions: InternalResolveOptions = { + ...config.resolve, + root: config.root, + isProduction: config.isProduction, + isBuild: config.command === 'build', + packageCache: config.packageCache, + ssrConfig: config.ssr, + asSrc: true, + } + return { name: 'vite:asset-import-meta-url', async transform(code, id, options) { @@ -98,6 +110,7 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { let file: string | undefined if (url[0] === '.') { file = slash(path.resolve(path.dirname(id), url)) + file = tryFsResolve(file, fsResolveOptions) ?? file } else { assetResolver ??= config.createResolver({ extensions: [], diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index c5a0876a0963a4..4b28e810ab2c6e 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -498,7 +498,7 @@ function splitFileAndPostfix(path: string) { return { file, postfix: path.slice(file.length) } } -function tryFsResolve( +export function tryFsResolve( fsPath: string, options: InternalResolveOptions, tryIndex = true, diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index 2bda9ab737e273..5e186af64f8648 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -17,6 +17,8 @@ import type { ResolveFn } from '..' import type { WorkerType } from './worker' import { WORKER_FILE_ID, workerFileToUrl } from './worker' import { fileToUrl } from './asset' +import type { InternalResolveOptions } from './resolve' +import { tryFsResolve } from './resolve' const ignoreFlagRE = /\/\*\s*@vite-ignore\s*\*\// @@ -99,6 +101,16 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' let workerResolver: ResolveFn + const fsResolveOptions: InternalResolveOptions = { + ...config.resolve, + root: config.root, + isProduction: config.isProduction, + isBuild: config.command === 'build', + packageCache: config.packageCache, + ssrConfig: config.ssr, + asSrc: true, + } + return { name: 'vite:worker-import-meta-url', @@ -143,6 +155,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { let file: string | undefined if (url[0] === '.') { file = path.resolve(path.dirname(id), url) + file = tryFsResolve(file, fsResolveOptions) ?? file } else { workerResolver ??= config.createResolver({ extensions: [], diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 29d56820c6c4bf..d4a16dafde7404 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -312,6 +312,15 @@ test('new URL("/...", import.meta.url)', async () => { ) }) +test('new URL(..., import.meta.url) without extension', async () => { + expect(await page.textContent('.import-meta-url-without-extension')).toMatch( + isBuild ? 'data:application/javascript' : 'nested/test.js', + ) + expect( + await page.textContent('.import-meta-url-content-without-extension'), + ).toContain('export default class') +}) + test('new URL(`${dynamic}`, import.meta.url)', async () => { expect(await page.textContent('.dynamic-import-meta-url-1')).toMatch( isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png', diff --git a/playground/assets/index.html b/playground/assets/index.html index b9e857398b6c35..f8c1f5a515a140 100644 --- a/playground/assets/index.html +++ b/playground/assets/index.html @@ -190,6 +190,14 @@

new URL('/...', import.meta.url)

+

new URL('...', import.meta.url (without extension))

+

+ +

+

+ +

+

new URL('...', import.meta.url,) (with comma)

@@ -393,6 +401,13 @@

assets in noscript

text('.import-meta-url-base-path', metaUrlBasePath) document.querySelector('.import-meta-url-base-path-img').src = metaUrlBasePath + const metaUrlWithoutExtension = new URL('./nested/test', import.meta.url) + text('.import-meta-url-without-extension', metaUrlWithoutExtension) + ;(async () => { + const res = await fetch(metaUrlWithoutExtension) + text('.import-meta-url-content-without-extension', await res.text()) + })() + // prettier-ignore const metaUrlWithComma = new URL('./nested/asset.png', import.meta.url,) text('.import-meta-url-comma', metaUrlWithComma) diff --git a/playground/worker/__tests__/es/es-worker.spec.ts b/playground/worker/__tests__/es/es-worker.spec.ts index dfa2462f61a551..e20ecede337ff1 100644 --- a/playground/worker/__tests__/es/es-worker.spec.ts +++ b/playground/worker/__tests__/es/es-worker.spec.ts @@ -113,6 +113,11 @@ test('module worker', async () => { 'A string', true, ) + await untilUpdated( + () => page.textContent('.worker-import-meta-url-without-extension'), + 'A string', + true, + ) await untilUpdated( () => page.textContent('.shared-worker-import-meta-url'), 'A string', diff --git a/playground/worker/__tests__/iife/iife-worker.spec.ts b/playground/worker/__tests__/iife/iife-worker.spec.ts index f3e5f230a9b1ed..b3ec815b78ca22 100644 --- a/playground/worker/__tests__/iife/iife-worker.spec.ts +++ b/playground/worker/__tests__/iife/iife-worker.spec.ts @@ -98,6 +98,11 @@ test('module worker', async () => { /A\sstring.*\/iife\/.+url-worker\.js/, true, ) + await untilUpdated( + () => page.textContent('.worker-import-meta-url-without-extension'), + 'A string', + true, + ) await untilUpdated( () => page.textContent('.shared-worker-import-meta-url'), 'A string', diff --git a/playground/worker/index.html b/playground/worker/index.html index ff26fbcbba3206..20e4a99ca69876 100644 --- a/playground/worker/index.html +++ b/playground/worker/index.html @@ -56,6 +56,12 @@

format iife:

+

+ new Worker(new URL('./url-worker', import.meta.url), { type: 'module' }) + .worker-import-meta-url-without-extension +

+ +

new SharedWorker(new URL('./url-shared-worker.js', import.meta.url), { type: 'module' }) diff --git a/playground/worker/worker/main-module.js b/playground/worker/worker/main-module.js index e19f8f4ec3af3a..11180f4e63d379 100644 --- a/playground/worker/worker/main-module.js +++ b/playground/worker/worker/main-module.js @@ -90,6 +90,15 @@ wResolve.addEventListener('message', (ev) => text('.worker-import-meta-url-resolve', JSON.stringify(ev.data)), ) +// url import worker without extension +const wWithoutExt = new Worker( + new URL('../url-worker', import.meta.url), + /* @vite-ignore */ workerOptions, +) +wWithoutExt.addEventListener('message', (ev) => + text('.worker-import-meta-url-without-extension', JSON.stringify(ev.data)), +) + const genWorkerName = () => 'module' const w2 = new SharedWorker( new URL('../url-shared-worker.js', import.meta.url),