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 @@
+
+
+
+
+
@@ -393,6 +401,13 @@
++ 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),