Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion packages/vite/src/node/__tests__/plugins/worker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
import { resolve } from 'node:path'
import { expect, test } from 'vitest'
import { describe, expect, test } from 'vitest'
import type { OutputChunk, RolldownOutput } from 'rolldown'
import { build } from '../../build'
import { splitWorkerRequest } from '../../plugins/worker'

const fixturesDir = resolve(import.meta.dirname, 'fixtures')

describe('splitWorkerRequest', () => {
for (const [id, postfix] of [
['/worker.js', ''],
['/worker.js#hash', ''],
['/worker.js?worker', ''],
['/worker.js?sharedworker', ''],
['/worker.js?inline', ''],
['/worker.js?url', ''],
['/worker.js?worker&url', ''],
['/worker.js?worker&inline', ''],
['/worker.js?worker&foo&url&bar', '?foo&bar'],
['/worker.js?worker&foo&inline', '?foo'],
['/worker.js?foo&bar', '?foo&bar'],
['/worker.js?foo=foo&worker&bar=bar', '?foo=foo&bar=bar'],
['/worker.js?foo&bar&worker', '?foo&bar'],
]) {
test(`splits ${id}`, () => {
expect(splitWorkerRequest(id)).toEqual({ file: '/worker.js', postfix })
})
}
})

test('?worker&url should produce the same hash in client and SSR builds', async () => {
const root = resolve(fixturesDir, 'worker-url')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,14 @@ new Worker(
)"
`)
})

test('preserves custom search params in worker URL', async () => {
expect(
await transform(
'new Worker(new URL("./worker.js?foo=bar&baz=qux", import.meta.url), { type: "module" })',
),
).toMatchInlineSnapshot(
'"new Worker(new URL(/* @vite-ignore */ "/worker.js?worker_file&type=module&foo=bar&baz=qux", \'\' + import.meta.url), { type: "module" })"',
)
})
})
29 changes: 26 additions & 3 deletions packages/vite/src/node/plugins/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
injectQuery,
normalizePath,
prettifyUrl,
trailingSeparatorRE,
urlRE,
} from '../utils'
import {
Expand All @@ -29,7 +30,7 @@ import {
onRollupLog,
toOutputFilePathInJS,
} from '../build'
import { cleanUrl } from '../../shared/utils'
import { cleanUrl, splitFileAndPostfix } from '../../shared/utils'
import type { Logger } from '../logger'
import { fileToUrl, toOutputFilePathInJSForBundledDev } from './asset'

Expand Down Expand Up @@ -238,6 +239,24 @@ export const workerOrSharedWorkerRE: RegExp =
/(?:\?|&)(worker|sharedworker)(?:&|$)/
const workerFileRE = /(?:\?|&)worker_file&type=(\w+)(?:&|$)/
const inlineRE = /[?&]inline\b/
const workerQueriesRE =
/(\?|&)(?:(?:worker|sharedworker|inline|url)=?(?:&|$))+/g

export function splitWorkerRequest(id: string): {
file: string
postfix: string
} {
const { file, postfix } = splitFileAndPostfix(id)
if (!postfix || postfix[0] !== '?') {
return { file, postfix: '' }
}
return {
file,
postfix: postfix
.replace(workerQueriesRE, '$1')
.replace(trailingSeparatorRE, ''),
}
}

export const WORKER_FILE_ID = 'worker_file'
const workerOutputCaches = new WeakMap<ResolvedConfig, WorkerOutputCache>()
Expand Down Expand Up @@ -631,8 +650,12 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
}
}
} else {
let url = await fileToUrl(this, cleanUrl(id))
url = injectQuery(url, `${WORKER_FILE_ID}&type=${workerType}`)
const { file, postfix } = splitWorkerRequest(id)
let url = await fileToUrl(this, file)
url = injectQuery(
`${url}${postfix}`,
`${WORKER_FILE_ID}&type=${workerType}`,
)
urlCode = JSON.stringify(url)
}

Expand Down
18 changes: 10 additions & 8 deletions packages/vite/src/node/plugins/workerImportMetaUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { Plugin } from '../plugin'
import { evalValue, injectQuery, transformStableResult } from '../utils'
import { createBackCompatIdResolver } from '../idResolver'
import type { ResolveIdFn } from '../idResolver'
import { cleanUrl, slash } from '../../shared/utils'
import { cleanUrl, slash, splitFileAndPostfix } from '../../shared/utils'
import type { WorkerType } from './worker'
import {
WORKER_FILE_ID,
Expand Down Expand Up @@ -234,21 +234,23 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
s ||= new MagicString(code)
const workerType = await getWorkerType(code, cleanString, endIndex)
const url = rawUrl.slice(1, -1)
const { file: urlWithoutPostfix, postfix } = splitFileAndPostfix(url)
const queryPostfix = postfix[0] === '?' ? postfix : ''
let file: string | undefined
if (url[0] === '.') {
file = path.resolve(path.dirname(id), url)
if (urlWithoutPostfix[0] === '.') {
file = path.resolve(path.dirname(id), urlWithoutPostfix)
file = slash(tryFsResolve(file, fsResolveOptions) ?? file)
} else {
workerResolver ??= createBackCompatIdResolver(config, {
extensions: [],
tryIndex: false,
preferRelative: true,
})
file = await workerResolver(this.environment, url, id)
file = await workerResolver(this.environment, urlWithoutPostfix, id)
file ??=
url[0] === '/'
? slash(path.join(config.publicDir, url))
: slash(path.resolve(path.dirname(id), url))
urlWithoutPostfix[0] === '/'
? slash(path.join(config.publicDir, urlWithoutPostfix))
: slash(path.resolve(path.dirname(id), urlWithoutPostfix))
}

if (
Expand Down Expand Up @@ -282,7 +284,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
} else {
builtUrl = await fileToUrl(this, cleanUrl(file))
builtUrl = injectQuery(
builtUrl,
`${builtUrl}${queryPostfix}`,
`${WORKER_FILE_ID}&type=${workerType}`,
)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ const internalPrefixes = [
ENV_PUBLIC_PATH,
]
const InternalPrefixRE = new RegExp(`^(?:${internalPrefixes.join('|')})`)
const trailingSeparatorRE = /[?&]$/
export const trailingSeparatorRE: RegExp = /[?&]$/
export const isImportRequest = (url: string): boolean => importQueryRE.test(url)
export const isInternalRequest = (url: string): boolean =>
InternalPrefixRE.test(url)
Expand Down