diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index c315d5b29dcba0..85e12b89d722fa 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -48,6 +48,11 @@ import { getImportMapFilename } from './html' // referenceId is base64url but replaces - with $ export const assetUrlRE: RegExp = /__VITE_ASSET__([\w$]+)__/g +const encodedHashPlaceholderRE = /!~%7B([\w$]{1,17})%7D~/g +function unescapeHashPlaceholders(uri: string): string { + return uri.replace(encodedHashPlaceholderRE, '!~{$1}~') +} + interface FileUrlMetadata { asFileUrl: boolean } @@ -329,7 +334,9 @@ export function assetPlugin(config: ResolvedConfig): Plugin { toRelativeRuntime, ) return typeof replacement === 'string' - ? JSON.stringify(encodeURIPath(replacement)) + ? JSON.stringify( + unescapeHashPlaceholders(encodeURIPath(replacement)), + ) : replacement.runtime }, diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 46e540d5c7a610..222ae0ba88cafe 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -218,6 +218,20 @@ describe('asset imports from js', () => { }) }) +describe.runIf(isBuild)('file URL emitted by an external plugin', () => { + test('replaces the preliminary hash', async () => { + expect(await page.textContent('.emitted-worker-url')).toMatch( + /^\/foo\/bar\/assets\/emitted-worker-[-\w]{8}\.js$/, + ) + }) + + test('loads the emitted chunk', async () => { + await expect + .poll(() => page.textContent('.emitted-worker-result')) + .toBe('worker loaded') + }) +}) + describe('css url() references', () => { test('fonts', async () => { expect( diff --git a/playground/assets/__tests__/encoded-base/assets-encoded-base.spec.ts b/playground/assets/__tests__/encoded-base/assets-encoded-base.spec.ts index 900fb34df2c9a8..c3adcf72cb4af6 100644 --- a/playground/assets/__tests__/encoded-base/assets-encoded-base.spec.ts +++ b/playground/assets/__tests__/encoded-base/assets-encoded-base.spec.ts @@ -73,6 +73,12 @@ describe('asset imports from js', () => { }) }) +test.runIf(isBuild)('loads the emitted worker', async () => { + await expect + .poll(() => page.textContent('.emitted-worker-result')) + .toBe('worker loaded') +}) + describe('css url() references', () => { test('fonts', async () => { expect( diff --git a/playground/assets/__tests__/relative-base/assets-relative-base.spec.ts b/playground/assets/__tests__/relative-base/assets-relative-base.spec.ts index 69b2b324119891..d786b3ff2b6288 100644 --- a/playground/assets/__tests__/relative-base/assets-relative-base.spec.ts +++ b/playground/assets/__tests__/relative-base/assets-relative-base.spec.ts @@ -77,6 +77,12 @@ describe('asset imports from js', () => { }) }) +test.runIf(isBuild)('loads the emitted worker', async () => { + await expect + .poll(() => page.textContent('.emitted-worker-result')) + .toBe('worker loaded') +}) + describe('css url() references', () => { test('fonts', async () => { expect( diff --git a/playground/assets/__tests__/runtime-base/assets-runtime-base.spec.ts b/playground/assets/__tests__/runtime-base/assets-runtime-base.spec.ts index 2b89521b8cabc5..39933d1836b766 100644 --- a/playground/assets/__tests__/runtime-base/assets-runtime-base.spec.ts +++ b/playground/assets/__tests__/runtime-base/assets-runtime-base.spec.ts @@ -70,6 +70,12 @@ describe('asset imports from js', () => { }) }) +test.runIf(isBuild)('loads the emitted worker', async () => { + await expect + .poll(() => page.textContent('.emitted-worker-result')) + .toBe('worker loaded') +}) + describe('css url() references', () => { test('fonts', async () => { expect( diff --git a/playground/assets/__tests__/url-base/assets-url-base.spec.ts b/playground/assets/__tests__/url-base/assets-url-base.spec.ts index 0e7b044d7e9be9..fd106883c57ed8 100644 --- a/playground/assets/__tests__/url-base/assets-url-base.spec.ts +++ b/playground/assets/__tests__/url-base/assets-url-base.spec.ts @@ -75,6 +75,12 @@ describe('asset imports from js', () => { }) }) +test.runIf(isBuild)('loads the emitted worker', async () => { + await expect + .poll(() => page.textContent('.emitted-worker-result')) + .toBe('worker loaded') +}) + describe('css url() references', () => { test('fonts', async () => { expect( diff --git a/playground/assets/asset/emitted-worker.js b/playground/assets/asset/emitted-worker.js new file mode 100644 index 00000000000000..ea9f1d6518605c --- /dev/null +++ b/playground/assets/asset/emitted-worker.js @@ -0,0 +1 @@ +self.postMessage('worker loaded') diff --git a/playground/assets/asset/main.js b/playground/assets/asset/main.js index e889874ff000d2..18bf777df83987 100644 --- a/playground/assets/asset/main.js +++ b/playground/assets/asset/main.js @@ -1,4 +1,14 @@ +import emittedWorkerUrl from 'virtual:emitted-worker-url' + function text(el, text) { document.querySelector(el).textContent = text } text('.relative-js', 'hello') + +if (emittedWorkerUrl) { + text('.emitted-worker-url', emittedWorkerUrl) + const worker = new Worker(emittedWorkerUrl, { type: 'module' }) + worker.addEventListener('message', ({ data }) => { + text('.emitted-worker-result', data) + }) +} diff --git a/playground/assets/index.html b/playground/assets/index.html index 6ba5233498bcd4..d9b395be1c12a1 100644 --- a/playground/assets/index.html +++ b/playground/assets/index.html @@ -54,6 +54,10 @@
pending
+pending
+