From 0348137a2315fc288f0e915169c36947f69bba63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sun, 3 Dec 2023 21:37:17 +0900 Subject: [PATCH] refactor: use dedicated regex methods (#15228) --- .../src/node/__tests__/plugins/css.spec.ts | 2 +- packages/vite/src/node/__tests__/scan.spec.ts | 1 + packages/vite/src/node/build.ts | 2 +- packages/vite/src/node/optimizer/index.ts | 2 +- .../src/node/plugins/assetImportMetaUrl.ts | 18 +++++++-------- packages/vite/src/node/plugins/css.ts | 22 ++++++++++--------- packages/vite/src/node/plugins/esbuild.ts | 2 +- packages/vite/src/node/plugins/html.ts | 18 +++++++-------- .../vite/src/node/plugins/importAnalysis.ts | 6 ++--- .../src/node/plugins/importAnalysisBuild.ts | 16 +++++--------- packages/vite/src/node/plugins/resolve.ts | 4 ++-- packages/vite/src/node/plugins/worker.ts | 3 ++- .../src/node/plugins/workerImportMetaUrl.ts | 21 +++++++----------- packages/vite/src/node/utils.ts | 2 +- packages/vite/src/shared/hmr.ts | 2 +- playground/hmr/__tests__/hmr.spec.ts | 2 +- playground/hmr/hmr.ts | 2 +- playground/vitestGlobalSetup.ts | 2 +- 18 files changed, 60 insertions(+), 67 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index f77fc44f16d03c..cfd7dc6e6d4e47 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -325,7 +325,7 @@ require("other-module");` `"require("some-module"),/* empty css */require("other-module");"`, ) // So there should be no pure css chunk anymore - expect(newCode.match(/pure_css_chunk\.js/)).toBeNull() + expect(newCode).not.toContain('pure_css_chunk.js') }) test('replaces require call in minified code that uses comma operator followed by assignment', () => { diff --git a/packages/vite/src/node/__tests__/scan.spec.ts b/packages/vite/src/node/__tests__/scan.spec.ts index b461f447e609d7..6fa9f76d1ceac4 100644 --- a/packages/vite/src/node/__tests__/scan.spec.ts +++ b/packages/vite/src/node/__tests__/scan.spec.ts @@ -106,6 +106,7 @@ describe('optimizer-scan:script-test', () => { `import type Bar from 'foo'`, ] shouldFailArray.forEach((str) => { + importsRE.lastIndex = 0 expect(importsRE.test(str)).toBe(false) }) }) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 402eed8b7c8399..9525809419114d 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -910,7 +910,7 @@ export function onRollupWarning( const id = warning.id const exporter = warning.exporter // throw unless it's commonjs external... - if (!id || !/\?commonjs-external$/.test(id)) { + if (!id || !id.endsWith('?commonjs-external')) { throw new Error( `[vite]: Rollup failed to resolve import "${exporter}" from "${id}".\n` + `This is most likely unintended because it can break your application at runtime.\n` + diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 12e40fef5ff14f..6beed48d27aa06 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -642,7 +642,7 @@ export function runOptimizeDeps( } for (const o of Object.keys(meta.outputs)) { - if (!o.match(jsMapExtensionRE)) { + if (!jsMapExtensionRE.test(o)) { const id = path .relative(processingCacheDirOutputPath, o) .replace(jsExtensionRE, '') diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index f57db10321befb..bccb5497a90f84 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -53,15 +53,13 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { ) { let s: MagicString | undefined const assetImportMetaUrlRE = - /\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*(?:,\s*)?\)/g + // eslint-disable-next-line regexp/no-unused-capturing-group -- https://github.com/ota-meshi/eslint-plugin-regexp/issues/675 + /\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*(?:,\s*)?\)/dg const cleanString = stripLiteral(code) let match: RegExpExecArray | null while ((match = assetImportMetaUrlRE.exec(cleanString))) { - const { 0: exp, 1: emptyUrl, index } = match - - const urlStart = cleanString.indexOf(emptyUrl, index) - const urlEnd = urlStart + emptyUrl.length + const [[startIndex, endIndex], [urlStart, urlEnd]] = match.indices! const rawUrl = code.slice(urlStart, urlEnd) if (!s) s = new MagicString(code) @@ -93,8 +91,8 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { query: injectQuery(queryString, 'url'), } s.update( - index, - index + exp.length, + startIndex, + endIndex, `new URL((import.meta.glob(${JSON.stringify( pattern, )}, ${JSON.stringify( @@ -141,15 +139,15 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { } } if (!builtUrl) { - const rawExp = code.slice(index, index + exp.length) + const rawExp = code.slice(startIndex, endIndex) config.logger.warnOnce( `\n${rawExp} doesn't exist at build time, it will remain unchanged to be resolved at runtime`, ) builtUrl = url } s.update( - index, - index + exp.length, + startIndex, + endIndex, `new URL(${JSON.stringify(builtUrl)}, import.meta.url)`, ) } diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 9707273c1ad6dc..905f0b4025cb91 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1288,8 +1288,6 @@ export async function preprocessCSS( return await compileCSS(filename, code, config) } -const postcssReturnsVirtualFilesRE = /^<.+>$/ - export async function formatPostcssSourceMap( rawMap: ExistingRawSourceMap, file: string, @@ -1299,7 +1297,8 @@ export async function formatPostcssSourceMap( const sources = rawMap.sources.map((source) => { const cleanSource = cleanUrl(decodeURIComponent(source)) - if (postcssReturnsVirtualFilesRE.test(cleanSource)) { + // postcss virtual files + if (cleanSource[0] === '<' && cleanSource[cleanSource.length - 1] === '>') { return `\0${cleanSource}` } @@ -1373,7 +1372,7 @@ async function resolvePostcssConfig( const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root result = postcssrc({}, searchPath).catch((e) => { - if (!/No PostCSS Config found/.test(e.message)) { + if (!e.message.includes('No PostCSS Config found')) { if (e instanceof Error) { const { name, message, stack } = e e.name = 'Failed to load PostCSS config' @@ -1654,6 +1653,11 @@ function resolveMinifyCssEsbuildOptions( } } +const atImportRE = + /@import(?:\s*(?:url\([^)]*\)|"(?:[^"]|(?<=\\)")*"|'(?:[^']|(?<=\\)')*').*?|[^;]*);/g +const atCharsetRE = + /@charset(?:\s*(?:"(?:[^"]|(?<=\\)")*"|'(?:[^']|(?<=\\)')*').*?|[^;]*);/g + export async function hoistAtRules(css: string): Promise { const s = new MagicString(css) const cleanCss = emptyCssComments(css) @@ -1663,8 +1667,7 @@ export async function hoistAtRules(css: string): Promise { // CSS @import can only appear at top of the file. We need to hoist all @import // to top when multiple files are concatenated. // match until semicolon that's not in quotes - const atImportRE = - /@import(?:\s*(?:url\([^)]*\)|"(?:[^"]|(?<=\\)")*"|'(?:[^']|(?<=\\)')*').*?|[^;]*);/g + atImportRE.lastIndex = 0 while ((match = atImportRE.exec(cleanCss))) { s.remove(match.index, match.index + match[0].length) // Use `appendLeft` instead of `prepend` to preserve original @import order @@ -1673,8 +1676,7 @@ export async function hoistAtRules(css: string): Promise { // #6333 // CSS @charset must be the top-first in the file, hoist the first to top - const atCharsetRE = - /@charset(?:\s*(?:"(?:[^"]|(?<=\\)")*"|'(?:[^']|(?<=\\)')*').*?|[^;]*);/g + atCharsetRE.lastIndex = 0 let foundCharset = false while ((match = atCharsetRE.exec(cleanCss))) { s.remove(match.index, match.index + match[0].length) @@ -2406,8 +2408,8 @@ export const convertTargets = ( for (const entry of entriesWithoutES) { if (entry === 'esnext') continue - const index = entry.match(versionRE)?.index - if (index) { + const index = entry.search(versionRE) + if (index >= 0) { const browser = map[entry.slice(0, index)] if (browser === false) continue // No mapping available if (browser) { diff --git a/packages/vite/src/node/plugins/esbuild.ts b/packages/vite/src/node/plugins/esbuild.ts index 6f37877e6b07aa..a62f041fcb38f4 100644 --- a/packages/vite/src/node/plugins/esbuild.ts +++ b/packages/vite/src/node/plugins/esbuild.ts @@ -320,7 +320,7 @@ export const buildEsbuildPlugin = (config: ResolvedConfig): Plugin => { const esbuildCode = res.code const contentIndex = opts.format === 'iife' - ? esbuildCode.match(IIFE_BEGIN_RE)?.index || 0 + ? Math.max(esbuildCode.search(IIFE_BEGIN_RE), 0) : opts.format === 'umd' ? esbuildCode.indexOf(`(function(`) // same for minified or not : 0 diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 3cb5ac20bfd3f4..ec7132425e1287 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -48,7 +48,8 @@ const htmlProxyRE = const inlineCSSRE = /__VITE_INLINE_CSS__([a-z\d]{8}_\d+)__/g // Do not allow preceding '.', but do allow preceding '...' for spread operations const inlineImportRE = - /(? { - const importMapIndex = html.match(importMapRE)?.index - if (importMapIndex === undefined) return + const importMapIndex = html.search(importMapRE) + if (importMapIndex < 0) return - const importMapAppendIndex = html.match(importMapAppendRE)?.index - if (importMapAppendIndex === undefined) return + const importMapAppendIndex = html.search(importMapAppendRE) + if (importMapAppendIndex < 0) return if (importMapAppendIndex < importMapIndex) { const relativeHtml = normalizePath( diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index e3ec1e1a4957f6..7a04387b7ca9c1 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -366,7 +366,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { if ( (isRelative || isSelfImport) && !hasImportInQueryParamsRE.test(url) && - !url.match(DEP_VERSION_RE) + !DEP_VERSION_RE.test(url) ) { const versionMatch = importer.match(DEP_VERSION_RE) if (versionMatch) { @@ -535,7 +535,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { let rewriteDone = false if ( depsOptimizer?.isOptimizedDepFile(resolvedId) && - !resolvedId.match(optimizedDepChunkRE) + !optimizedDepChunkRE.test(resolvedId) ) { // for optimized cjs deps, support named imports by rewriting named imports to const assignments. // internal optimized chunks don't need es interop and are excluded @@ -555,7 +555,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { // Non-entry dynamic imports from dependencies will reach here as there isn't // optimize info for them, but they don't need es interop. If the request isn't // a dynamic import, then it is an internal Vite error - if (!file.match(optimizedDepDynamicRE)) { + if (!optimizedDepDynamicRE.test(file)) { config.logger.error( colors.red( `Vite Error, ${url} optimized info should be defined`, diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts index c3278de7a66097..16e51e287db3a7 100644 --- a/packages/vite/src/node/plugins/importAnalysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts @@ -45,7 +45,7 @@ export const preloadMarker = `__VITE_PRELOAD__` export const preloadBaseMarker = `__VITE_PRELOAD_BASE__` export const preloadHelperId = '\0vite/preload-helper.js' -const preloadMarkerWithQuote = new RegExp(`['"]${preloadMarker}['"]`) +const preloadMarkerWithQuote = new RegExp(`['"]${preloadMarker}['"]`, 'g') const dynamicImportPrefixRE = /import\s*\(/ @@ -63,13 +63,9 @@ function indexOfMatchInSlice( reg: RegExp, pos: number = 0, ): number { - if (pos !== 0) { - str = str.slice(pos) - } - - const matcher = str.match(reg) - - return matcher?.index !== undefined ? matcher.index + pos : -1 + reg.lastIndex = pos + const result = reg.exec(str) + return result?.index ?? -1 } /** @@ -351,7 +347,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { if (url !== specifier) { if ( depsOptimizer.isOptimizedDepFile(resolvedId) && - !resolvedId.match(optimizedDepChunkRE) + !optimizedDepChunkRE.test(resolvedId) ) { const file = cleanUrl(resolvedId) // Remove ?v={hash} @@ -368,7 +364,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { // Non-entry dynamic imports from dependencies will reach here as there isn't // optimize info for them, but they don't need es interop. If the request isn't // a dynamic import, then it is an internal Vite error - if (!file.match(optimizedDepDynamicRE)) { + if (!optimizedDepDynamicRE.test(file)) { config.logger.error( colors.red( `Vite Error, ${url} optimized info should be defined`, diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 0c93628f6cfc5a..4131f08f2cb7de 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -263,7 +263,7 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { // Inject the current browserHash version if the path doesn't have one if ( !resolveOptions.isBuild && - !normalizedFsPath.match(DEP_VERSION_RE) + !DEP_VERSION_RE.test(normalizedFsPath) ) { const browserHash = optimizedDepInfoFromFile( depsOptimizer.metadata, @@ -501,7 +501,7 @@ function ensureVersionQuery( // file path after symlinks resolution const isNodeModule = isInNodeModules(id) || isInNodeModules(resolved) - if (isNodeModule && !resolved.match(DEP_VERSION_RE)) { + if (isNodeModule && !DEP_VERSION_RE.test(resolved)) { const versionHash = depsOptimizer.metadata.browserHash if (versionHash && isOptimizable(resolved, depsOptimizer.options)) { resolved = injectQuery(resolved, `v=${versionHash}`) diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index 0df6f9d843e99c..a656b6d07e6916 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -379,7 +379,8 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { } ) } - if (code.match(workerAssetUrlRE)) { + workerAssetUrlRE.lastIndex = 0 + if (workerAssetUrlRE.test(code)) { const toRelativeRuntime = createToImportMetaURLBasedRelativeRuntime( outputOptions.format, config.isWorker, diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index e88d1ac3362a43..6a6dd9f55a697c 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -137,31 +137,26 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { let s: MagicString | undefined const cleanString = stripLiteral(code) const workerImportMetaUrlRE = - /\bnew\s+(?:Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/g + // eslint-disable-next-line regexp/no-unused-capturing-group -- https://github.com/ota-meshi/eslint-plugin-regexp/issues/675 + /\bnew\s+(?:Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/dg let match: RegExpExecArray | null while ((match = workerImportMetaUrlRE.exec(cleanString))) { - const { 0: allExp, 1: exp, 2: emptyUrl, index } = match - const urlIndex = allExp.indexOf(exp) + index + const [[, endIndex], [expStart, expEnd], [urlStart, urlEnd]] = + match.indices! - const urlStart = cleanString.indexOf(emptyUrl, index) - const urlEnd = urlStart + emptyUrl.length const rawUrl = code.slice(urlStart, urlEnd) // potential dynamic template string if (rawUrl[0] === '`' && rawUrl.includes('${')) { this.error( `\`new URL(url, import.meta.url)\` is not supported in dynamic template string.`, - urlIndex, + expStart, ) } s ||= new MagicString(code) - const workerType = getWorkerType( - code, - cleanString, - index + allExp.length, - ) + const workerType = getWorkerType(code, cleanString, endIndex) const url = rawUrl.slice(1, -1) let file: string | undefined if (url[0] === '.') { @@ -190,8 +185,8 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { builtUrl = injectQuery(builtUrl, `type=${workerType}`) } s.update( - urlIndex, - urlIndex + exp.length, + expStart, + expEnd, // add `'' +` to skip vite:asset-import-meta-url plugin `new URL('' + ${JSON.stringify(builtUrl)}, import.meta.url)`, ) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 4e893968c44444..65264b14ccf4c4 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -235,7 +235,7 @@ export function fsPathFromId(id: string): string { const fsPath = normalizePath( id.startsWith(FS_PREFIX) ? id.slice(FS_PREFIX.length) : id, ) - return fsPath[0] === '/' || fsPath.match(VOLUME_RE) ? fsPath : `/${fsPath}` + return fsPath[0] === '/' || VOLUME_RE.test(fsPath) ? fsPath : `/${fsPath}` } export function fsPathFromUrl(url: string): string { diff --git a/packages/vite/src/shared/hmr.ts b/packages/vite/src/shared/hmr.ts index 60c26b50e49da5..9c0004793d30c3 100644 --- a/packages/vite/src/shared/hmr.ts +++ b/packages/vite/src/shared/hmr.ts @@ -200,7 +200,7 @@ export class HMRClient { } protected warnFailedUpdate(err: Error, path: string | string[]): void { - if (!err.message.match('fetch')) { + if (!err.message.includes('fetch')) { this.logger.error(err) } this.logger.error( diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts index 2ff737f85951f3..e4c7825c5a5d2e 100644 --- a/playground/hmr/__tests__/hmr.spec.ts +++ b/playground/hmr/__tests__/hmr.spec.ts @@ -23,7 +23,7 @@ test('should render', async () => { if (!isBuild) { test('should connect', async () => { expect(browserLogs.length).toBe(3) - expect(browserLogs.some((msg) => msg.match('connected'))).toBe(true) + expect(browserLogs.some((msg) => msg.includes('connected'))).toBe(true) browserLogs.length = 0 }) diff --git a/playground/hmr/hmr.ts b/playground/hmr/hmr.ts index 3861ba17f6ba17..5e572f83b703aa 100644 --- a/playground/hmr/hmr.ts +++ b/playground/hmr/hmr.ts @@ -66,7 +66,7 @@ if (import.meta.hot) { const cssUpdate = event.updates.find( (update) => - update.type === 'css-update' && update.path.match('global.css'), + update.type === 'css-update' && update.path.includes('global.css'), ) if (cssUpdate) { text( diff --git a/playground/vitestGlobalSetup.ts b/playground/vitestGlobalSetup.ts index ff1cb80e521093..d62edca8f23daf 100644 --- a/playground/vitestGlobalSetup.ts +++ b/playground/vitestGlobalSetup.ts @@ -35,7 +35,7 @@ export async function setup(): Promise { return !hasWindowsUnicodeFsBug } file = file.replace(/\\/g, '/') - return !file.includes('__tests__') && !file.match(/dist(\/|$)/) + return !file.includes('__tests__') && !/dist(?:\/|$)/.test(file) }, }) .catch(async (error) => {