Skip to content

Commit 952bae3

Browse files
authored
perf: improve regex performance (#17789)
1 parent 796eef3 commit 952bae3

19 files changed

+64
-34
lines changed

eslint.config.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ const require = createRequire(import.meta.url)
1111
const pkg = require('./package.json')
1212
const pkgVite = require('./packages/vite/package.json')
1313

14+
// Some rules work better with typechecking enabled, but as enabling it is slow,
15+
// we only do so when linting in IDEs for now. If you want to lint with typechecking
16+
// explicitly, set this to `true` manually.
17+
const shouldTypeCheck = typeof process.env.VSCODE_PID === 'string'
18+
1419
export default tseslint.config(
1520
{
1621
ignores: [
@@ -34,6 +39,12 @@ export default tseslint.config(
3439
parserOptions: {
3540
sourceType: 'module',
3641
ecmaVersion: 2022,
42+
project: shouldTypeCheck
43+
? [
44+
'./packages/*/tsconfig.json',
45+
'./packages/vite/src/*/tsconfig.json',
46+
]
47+
: undefined,
3748
},
3849
globals: {
3950
...globals.es2021,
@@ -294,4 +305,25 @@ export default tseslint.config(
294305
'@typescript-eslint/ban-ts-comment': 'off',
295306
},
296307
},
308+
{
309+
name: 'disables/typechecking',
310+
files: [
311+
'**/*.js',
312+
'**/*.mjs',
313+
'**/*.cjs',
314+
'**/*.d.ts',
315+
'**/*.d.cts',
316+
'**/__tests__/**',
317+
'docs/**',
318+
'playground/**',
319+
'scripts/**',
320+
'vitest.config.ts',
321+
'vitest.config.e2e.ts',
322+
],
323+
languageOptions: {
324+
parserOptions: {
325+
project: false,
326+
},
327+
},
328+
},
297329
)

packages/plugin-legacy/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ const legacyEnvVarMarker = `__VITE_IS_LEGACY__`
120120
const _require = createRequire(import.meta.url)
121121

122122
const nonLeadingHashInFileNameRE = /[^/]+\[hash(?::\d+)?\]/
123-
const prefixedHashInFileNameRE = /\W?\[hash(:\d+)?\]/
123+
const prefixedHashInFileNameRE = /\W?\[hash(?::\d+)?\]/
124124

125125
function viteLegacyPlugin(options: Options = {}): Plugin[] {
126126
let config: ResolvedConfig

packages/plugin-legacy/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"include": ["src"],
2+
"include": ["build.config.ts", "src"],
33
"exclude": ["**/*.spec.ts"],
44
"compilerOptions": {
55
"outDir": "dist",

packages/vite/rollup.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ const __require = require;
275275
name: 'cjs-chunk-patch',
276276
renderChunk(code, chunk) {
277277
if (!chunk.fileName.includes('chunks/dep-')) return
278-
const match = code.match(/^(?:import[\s\S]*?;\s*)+/)
278+
const match = /^(?:import[\s\S]*?;\s*)+/.exec(code)
279279
const index = match ? match.index! + match[0].length : 0
280280
const s = new MagicString(code)
281281
// inject after the last `import`

packages/vite/rollupLicensePlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default function licensePlugin(
6868
'\n' +
6969
licenseText
7070
.trim()
71-
.replace(/(\r\n|\r)/g, '\n')
71+
.replace(/\r\n|\r/g, '\n')
7272
.split('\n')
7373
.map((line) => `> ${line}`)
7474
.join('\n') +

packages/vite/src/node/optimizer/resolve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export function expandGlobIds(id: string, config: ResolvedConfig): string[] {
109109
// `filePath`: "./dist/glob/foo-browser/foo.js"
110110
// we need to revert the file path back to the export key by
111111
// matching value regex and replacing the capture groups to the key
112-
const matched = slash(filePath).match(exportsValueGlobRe)
112+
const matched = exportsValueGlobRe.exec(slash(filePath))
113113
// `matched`: [..., 'foo', 'foo']
114114
if (matched) {
115115
let allGlobSame = matched.length === 2

packages/vite/src/node/optimizer/scan.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,10 @@ function esbuildScanPlugin(
413413
let scriptId = 0
414414
const matches = raw.matchAll(scriptRE)
415415
for (const [, openTag, content] of matches) {
416-
const typeMatch = openTag.match(typeRE)
416+
const typeMatch = typeRE.exec(openTag)
417417
const type =
418418
typeMatch && (typeMatch[1] || typeMatch[2] || typeMatch[3])
419-
const langMatch = openTag.match(langRE)
419+
const langMatch = langRE.exec(openTag)
420420
const lang =
421421
langMatch && (langMatch[1] || langMatch[2] || langMatch[3])
422422
// skip non type module script
@@ -440,7 +440,7 @@ function esbuildScanPlugin(
440440
} else if (p.endsWith('.astro')) {
441441
loader = 'ts'
442442
}
443-
const srcMatch = openTag.match(srcRE)
443+
const srcMatch = srcRE.exec(openTag)
444444
if (srcMatch) {
445445
const src = srcMatch[1] || srcMatch[2] || srcMatch[3]
446446
js += `import ${JSON.stringify(src)}\n`
@@ -480,7 +480,7 @@ function esbuildScanPlugin(
480480

481481
const virtualModulePath = JSON.stringify(virtualModulePrefix + key)
482482

483-
const contextMatch = openTag.match(contextRE)
483+
const contextMatch = contextRE.exec(openTag)
484484
const context =
485485
contextMatch &&
486486
(contextMatch[1] || contextMatch[2] || contextMatch[3])

packages/vite/src/node/plugins/css.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ const inlineCSSRE = /[?&]inline-css\b/
195195
const styleAttrRE = /[?&]style-attr\b/
196196
const functionCallRE = /^[A-Z_][\w-]*\(/i
197197
const transformOnlyRE = /[?&]transform-only\b/
198-
const nonEscapedDoubleQuoteRe = /(?<!\\)(")/g
198+
const nonEscapedDoubleQuoteRe = /(?<!\\)"/g
199199

200200
const cssBundleName = 'style.css'
201201

@@ -1223,7 +1223,7 @@ async function compileCSS(
12231223
// crawl them in order to register watch dependencies.
12241224
const needInlineImport = code.includes('@import')
12251225
const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code)
1226-
const lang = id.match(CSS_LANGS_RE)?.[1] as CssLang | undefined
1226+
const lang = CSS_LANGS_RE.exec(id)?.[1] as CssLang | undefined
12271227
const postcssConfig = await resolvePostcssConfig(config)
12281228

12291229
// 1. plain css that needs no processing
@@ -1295,7 +1295,7 @@ async function compileCSS(
12951295
},
12961296
async load(id) {
12971297
const code = await fs.promises.readFile(id, 'utf-8')
1298-
const lang = id.match(CSS_LANGS_RE)?.[1] as CssLang | undefined
1298+
const lang = CSS_LANGS_RE.exec(id)?.[1] as CssLang | undefined
12991299
if (isPreProcessor(lang)) {
13001300
const result = await compileCSSPreprocessors(
13011301
id,
@@ -2892,7 +2892,7 @@ export const convertTargets = (
28922892
const targets: LightningCSSOptions['targets'] = {}
28932893

28942894
const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => {
2895-
const match = e.match(esRE)
2895+
const match = esRE.exec(e)
28962896
if (!match) return e
28972897
const year = Number(match[1])
28982898
if (!esMap[year]) throw new Error(`Unsupported target "${e}"`)

packages/vite/src/node/plugins/dataUri.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function dataURIPlugin(): Plugin {
3131
return
3232
}
3333

34-
const match = uri.pathname.match(dataUriRE)
34+
const match = dataUriRE.exec(uri.pathname)
3535
if (!match) {
3636
return
3737
}

packages/vite/src/node/plugins/esbuild.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const debug = createDebugger('vite:esbuild')
2828
// IIFE content looks like `var MyLib = function() {`.
2929
// Spaces are removed and parameters are mangled when minified
3030
const IIFE_BEGIN_RE =
31-
/(const|var)\s+\S+\s*=\s*function\([^()]*\)\s*\{\s*"use strict";/
31+
/(?:const|var)\s+\S+\s*=\s*function\([^()]*\)\s*\{\s*"use strict";/
3232

3333
const validExtensionRE = /\.\w+$/
3434
const jsxExtensionsRE = /\.(?:j|t)sx\b/

packages/vite/src/node/plugins/html.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ interface ScriptAssetsUrl {
4747
}
4848

4949
const htmlProxyRE =
50-
/\?html-proxy=?(?:&inline-css)?(?:&style-attr)?&index=(\d+)\.(js|css)$/
50+
/\?html-proxy=?(?:&inline-css)?(?:&style-attr)?&index=(\d+)\.(?:js|css)$/
5151
const isHtmlProxyRE = /\?html-proxy\b/
5252

5353
const inlineCSSRE = /__VITE_INLINE_CSS__([a-z\d]{8}_\d+)__/g
@@ -99,7 +99,7 @@ export function htmlInlineProxyPlugin(config: ResolvedConfig): Plugin {
9999
},
100100

101101
load(id) {
102-
const proxyMatch = id.match(htmlProxyRE)
102+
const proxyMatch = htmlProxyRE.exec(id)
103103
if (proxyMatch) {
104104
const index = Number(proxyMatch[1])
105105
const file = cleanUrl(id)
@@ -237,7 +237,7 @@ export function overwriteAttrValue(
237237
sourceCodeLocation.startOffset,
238238
sourceCodeLocation.endOffset,
239239
)
240-
const valueStart = srcString.match(attrValueStartRE)
240+
const valueStart = attrValueStartRE.exec(srcString)
241241
if (!valueStart) {
242242
// overwrite attr value can only be called for a well-defined value
243243
throw new Error(
@@ -1354,7 +1354,7 @@ export async function applyHtmlTransforms(
13541354
return html
13551355
}
13561356

1357-
const importRE = /\bimport\s*("[^"]*[^\\]"|'[^']*[^\\]');*/g
1357+
const importRE = /\bimport\s*(?:"[^"]*[^\\]"|'[^']*[^\\]');*/g
13581358
const commentRE = /\/\*[\s\S]*?\*\/|\/\/.*$/gm
13591359
function isEntirelyImport(code: string) {
13601360
// only consider "side-effect" imports, which match <script type=module> semantics exactly

packages/vite/src/node/plugins/importAnalysis.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
384384
// (e.g. vue blocks), inherit importer's version query
385385
// do not do this for unknown type imports, otherwise the appended
386386
// query can break 3rd party plugin's extension checks.
387-
const versionMatch = importer.match(DEP_VERSION_RE)
387+
const versionMatch = DEP_VERSION_RE.exec(importer)
388388
if (versionMatch) {
389389
url = injectQuery(url, versionMatch[1])
390390
}

packages/vite/src/node/plugins/importAnalysisBuild.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
272272
* ^
273273
*/
274274
if (match[3]) {
275-
let names = match[4].match(/\.([^.?]+)/)?.[1] || ''
275+
let names = /\.([^.?]+)/.exec(match[4])?.[1] || ''
276276
// avoid `default` keyword error
277277
if (names === 'default') {
278278
names = 'default: __vite_default__'

packages/vite/src/node/plugins/optimizedDeps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function optimizedDepsPlugin(config: ResolvedConfig): Plugin {
3535
if (depsOptimizer?.isOptimizedDepFile(id)) {
3636
const metadata = depsOptimizer.metadata
3737
const file = cleanUrl(id)
38-
const versionMatch = id.match(DEP_VERSION_RE)
38+
const versionMatch = DEP_VERSION_RE.exec(file)
3939
const browserHash = versionMatch
4040
? versionMatch[1].split('=')[1]
4141
: undefined

packages/vite/src/node/plugins/resolve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ export function tryNodeResolve(
717717
const { root, dedupe, isBuild, preserveSymlinks, packageCache } = options
718718

719719
// check for deep import, e.g. "my-lib/foo"
720-
const deepMatch = id.match(deepImportRE)
720+
const deepMatch = deepImportRE.exec(id)
721721
// package name doesn't include postfixes
722722
// trim them to support importing package with queries (e.g. `import css from 'normalize.css?inline'`)
723723
const pkgId = deepMatch ? deepMatch[1] || deepMatch[2] : cleanUrl(id)

packages/vite/src/node/server/middlewares/error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function buildErrorMessage(
3737

3838
function cleanStack(stack: string) {
3939
return stack
40-
.split(/\n/g)
40+
.split(/\n/)
4141
.filter((l) => /^\s*at/.test(l))
4242
.join('\n')
4343
}

packages/vite/src/node/ssr/ssrTransform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async function ssrTransformScript(
9292
const declaredConst = new Set<string>()
9393

9494
// hoist at the start of the file, after the hashbang
95-
const hoistIndex = code.match(hashbangRE)?.[0].length ?? 0
95+
const hoistIndex = hashbangRE.exec(code)?.[0].length ?? 0
9696

9797
function defineImport(
9898
index: number,

packages/vite/src/node/utils.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const createFilter = _createFilter as (
5757

5858
const replaceSlashOrColonRE = /[/:]/g
5959
const replaceDotRE = /\./g
60-
const replaceNestedIdRE = /(\s*>\s*)/g
60+
const replaceNestedIdRE = /\s*>\s*/g
6161
const replaceHashRE = /#/g
6262
export const flattenId = (id: string): string => {
6363
const flatId = limitFlattenIdLength(
@@ -558,7 +558,7 @@ export function emptyDir(dir: string, skip?: string[]): void {
558558
if (skip?.length) {
559559
for (const file of skip) {
560560
if (path.dirname(file) !== '.') {
561-
const matched = file.match(splitFirstDirRE)
561+
const matched = splitFirstDirRE.exec(file)
562562
if (matched) {
563563
nested ??= new Map()
564564
const [, nestedDir, skipPath] = matched
@@ -656,7 +656,7 @@ function windowsMappedRealpathSync(path: string) {
656656
}
657657
return realPath
658658
}
659-
const parseNetUseRE = /^(\w+)? +(\w:) +([^ ]+)\s/
659+
const parseNetUseRE = /^\w* +(\w:) +([^ ]+)\s/
660660
let firstSafeRealPathSyncRun = false
661661

662662
function windowsSafeRealPathSync(path: string): string {
@@ -691,8 +691,8 @@ function optimizeSafeRealPathSync() {
691691
// OK Y: \\NETWORKA\Foo Microsoft Windows Network
692692
// OK Z: \\NETWORKA\Bar Microsoft Windows Network
693693
for (const line of lines) {
694-
const m = line.match(parseNetUseRE)
695-
if (m) windowsNetworkMap.set(m[3], m[2])
694+
const m = parseNetUseRE.exec(line)
695+
if (m) windowsNetworkMap.set(m[2], m[1])
696696
}
697697
if (windowsNetworkMap.size === 0) {
698698
safeRealpathSync = fs.realpathSync.native
@@ -724,7 +724,7 @@ interface ImageCandidate {
724724
url: string
725725
descriptor: string
726726
}
727-
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
727+
const escapedSpaceCharacters = /(?: |\\t|\\n|\\f|\\r)+/g
728728
const imageSetUrlRE = /^(?:[\w\-]+\(.*?\)|'.*?'|".*?"|\S*)/
729729
function joinSrcset(ret: ImageCandidate[]) {
730730
return ret

packages/vite/src/runtime/moduleCache.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,7 @@ export class ModuleCacheMap extends Map<string, ModuleCache> {
156156
const mod = this.get(moduleId)
157157
if (mod.map) return mod.map
158158
if (!mod.meta || !('code' in mod.meta)) return null
159-
const mapString = mod.meta.code.match(
160-
VITE_RUNTIME_SOURCEMAPPING_REGEXP,
161-
)?.[1]
159+
const mapString = VITE_RUNTIME_SOURCEMAPPING_REGEXP.exec(mod.meta.code)?.[1]
162160
if (!mapString) return null
163161
const baseFile = mod.meta.file || moduleId.split('?')[0]
164162
mod.map = new DecodedMap(JSON.parse(decodeBase64(mapString)), baseFile)

0 commit comments

Comments
 (0)