Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
42 changes: 42 additions & 0 deletions packages/vite/src/node/__tests__/filterRegex.spec.ts
Comment thread
bluwy marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { describe, expect, test } from 'vitest'
import { assetImportMetaUrlFilterRE } from '../plugins/assetImportMetaUrl'
import { workerImportMetaUrlRE } from '../plugins/workerImportMetaUrl'

// These are the filter.code regexes used in the transform hooks.
// They must not cause catastrophic backtracking on large files.
// See https://github.com/vitejs/vite/issues/21696

describe('filter regexes do not cause catastrophic backtracking', () => {
// Large file where `new URL(...)` appears many times but `import.meta.url`
// is absent. With the old /s + .+ pattern, each `new URL` occurrence would
// cause the regex engine to consume the rest of the file before backtracking.
const largeCode =
`new URL('https://example.com');\n`.repeat(200) +
`var a = 1;\n`.repeat(200_000)

// These tests rely on the default test timeout (5s) to catch backtracking.
// The old regexes took >1s on this input; the new ones complete in ~3ms.
test('assetImportMetaUrlFilterRE completes without backtracking on large files', () => {
expect(assetImportMetaUrlFilterRE.test(largeCode)).toBe(false)
})

test('workerImportMetaUrlRE completes without backtracking on large files', () => {
expect(workerImportMetaUrlRE.test(largeCode)).toBe(false)
})

test('assetImportMetaUrlFilterRE still matches valid patterns', () => {
expect(
assetImportMetaUrlFilterRE.test(
`new URL('./asset.png', import.meta.url)`,
),
).toBe(true)
})

test('workerImportMetaUrlRE still matches valid patterns', () => {
expect(
workerImportMetaUrlRE.test(
`new Worker(new URL('./worker.js', import.meta.url))`,
),
).toBe(true)
})
})
3 changes: 2 additions & 1 deletion packages/vite/src/node/optimizer/rolldownDepPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { Environment } from '../environment'
import { createBackCompatIdResolver } from '../idResolver'
import { isWindows } from '../../shared/utils'
import { hasViteIgnoreRE } from '../plugins/importAnalysis'
import { assetImportMetaUrlFilterRE } from '../plugins/assetImportMetaUrl'

const externalWithConversionNamespace =
'vite:dep-pre-bundle:external-conversion'
Expand Down Expand Up @@ -313,7 +314,7 @@ export function rolldownDepPlugin(
},
transform: {
filter: {
code: /new\s+URL.+import\.meta\.url/s,
code: assetImportMetaUrlFilterRE,
},
async handler(code, id) {
let s: MagicString | undefined
Expand Down
5 changes: 4 additions & 1 deletion packages/vite/src/node/plugins/assetImportMetaUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ import { hasViteIgnoreRE } from './importAnalysis'
* import.meta.glob('./dir/**.png', { eager: true, import: 'default' })[`./dir/${name}.png`]
* ```
*/
export const assetImportMetaUrlFilterRE: RegExp =
/\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url/

export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const { publicDir } = config
let assetResolver: ResolveIdFn
Expand All @@ -56,7 +59,7 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
id: {
exclude: [exactRegex(preloadHelperId), exactRegex(CLIENT_ENTRY)],
},
code: /new\s+URL.+import\.meta\.url/s,
code: assetImportMetaUrlFilterRE,
},
async handler(code, id) {
let s: MagicString | undefined
Expand Down
4 changes: 2 additions & 2 deletions packages/vite/src/node/plugins/workerImportMetaUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ async function getWorkerType(
return 'classic'
}

const workerImportMetaUrlRE =
/new\s+(?:Worker|SharedWorker)\s*\(\s*new\s+URL.+?import\.meta\.url/s
export const workerImportMetaUrlRE: RegExp =
/\bnew\s+(?:Worker|SharedWorker)\s*\(\s*new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url/

export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const isBundled = config.isBundled
Expand Down