diff --git a/docs/guide/features.md b/docs/guide/features.md index dfd8c57f715ded..59d3883fe19b85 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -657,7 +657,15 @@ const worker = new Worker(new URL('./worker.js', import.meta.url), { }) ``` -The worker detection will only work if the `new URL()` constructor is used directly inside the `new Worker()` declaration. Additionally, all options parameters must be static values (i.e. string literals). +The worker detection will only work if the `new URL()` constructor is used directly inside the `new Worker()` declaration. Additionally, all options parameters must be static values (i.e. string literals), or a variable that is defined before the `new Worker()`, as follows: + +```ts +const workerOptions = { type: 'module' } +const worker = new Worker( + new URL('./worker.js', import.meta.url), + workerOptions, +) +``` ### Import with Query Suffixes diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index 8d8d316a4ec214..016f61696b08f7 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -34,7 +34,7 @@ function parseWorkerOptions( opts = evalValue(rawOpts) } catch { throw err( - 'Vite is unable to parse the worker options as the value is not static.' + + 'Vite is unable to parse the worker options as the value is neither static or variable.' + 'To ignore this error, please use /* @vite-ignore */ in the worker options.', optsStartIndex, ) @@ -54,6 +54,37 @@ function parseWorkerOptions( return opts } +function findVarDefinition( + raw: string, + clean: string, + endIndex: number, + varName: string, +): [string, number] { + const workerOptionsVarRE = new RegExp( + `(?:var|let|const)\\s*${varName}\\s*=\\s*`, + 'g', + ) + + let optsStartIndex: number | null = null + while (workerOptionsVarRE.exec(clean)) { + if (workerOptionsVarRE.lastIndex >= endIndex) break + optsStartIndex = workerOptionsVarRE.lastIndex + } + + if (!optsStartIndex) { + throw err( + 'Vite is unable to parse the worker options as the value is neither static or variable. ' + + 'To ignore this error, please use /* @vite-ignore */ in the worker options.', + optsStartIndex, + ) + } + + const optsEndIndex = clean.indexOf('}', optsStartIndex) + const workerOptString = raw.substring(optsStartIndex, optsEndIndex + 1) + + return [workerOptString, optsStartIndex] +} + function getWorkerType(raw: string, clean: string, i: number): WorkerType { const commaIndex = clean.indexOf(',', i) if (commaIndex === -1) { @@ -82,7 +113,22 @@ function getWorkerType(raw: string, clean: string, i: number): WorkerType { return 'classic' } - const workerOpts = parseWorkerOptions(workerOptString, commaIndex + 1) + let workerOpts: WorkerOptions + + // if worker options is a variable, try to find its closest definition + const varMatch = cleanWorkerOptString.match(/^\s*(\w+)\s*(?:,\s*)?$/) + if (varMatch) { + const [workerOptString, workerOptIndex] = findVarDefinition( + raw, + clean, + i, + varMatch[1], + ) + workerOpts = parseWorkerOptions(workerOptString, workerOptIndex) + } else { + workerOpts = parseWorkerOptions(workerOptString, commaIndex + 1) + } + if ( workerOpts.type && (workerOpts.type === 'module' || workerOpts.type === 'classic') diff --git a/playground/worker/index.html b/playground/worker/index.html index d6b3806b3293ae..9e2594bc96cfe6 100644 --- a/playground/worker/index.html +++ b/playground/worker/index.html @@ -99,6 +99,13 @@

format iife:

+

+ var workerOptions = { type: 'module' } new Worker(new URL('./url-worker.js', + import.meta.url), workerOptions) + .worker-import-meta-url-via-variable +

+ +

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 a59bc903800b12..590b915a83ecee 100644 --- a/playground/worker/worker/main-module.js +++ b/playground/worker/worker/main-module.js @@ -135,6 +135,17 @@ wWithoutExt.addEventListener('message', (ev) => text('.worker-import-meta-url-without-extension', JSON.stringify(ev.data)), ) +const myWorkerOptions = { type: 'module' } + +// url import worker via variable +const wViaVariable = new Worker( + new URL('../url-worker', import.meta.url), + myWorkerOptions, +) +wViaVariable.addEventListener('message', (ev) => + text('.worker-import-meta-url-via-variable', JSON.stringify(ev.data)), +) + const genWorkerName = () => 'module' const w2 = new SharedWorker( new URL('../url-shared-worker.js', import.meta.url),