]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf: improve regexp performance with non-capturing groups (#13567)
author山吹色御守 <85992002+KazariEX@users.noreply.github.com>
Tue, 2 Sep 2025 09:30:02 +0000 (17:30 +0800)
committerGitHub <noreply@github.com>
Tue, 2 Sep 2025 09:30:02 +0000 (17:30 +0800)
14 files changed:
packages/compiler-core/src/transforms/vIf.ts
packages/compiler-core/src/transforms/vSlot.ts
packages/compiler-core/src/utils.ts
packages/compiler-dom/src/transforms/stringifyStatic.ts
packages/compiler-sfc/src/style/pluginScoped.ts
packages/compiler-sfc/src/template/templateUtils.ts
packages/compiler-ssr/src/transforms/ssrVIf.ts
packages/runtime-core/src/compat/global.ts
packages/runtime-core/src/component.ts
packages/runtime-dom/src/components/Transition.ts
packages/runtime-dom/src/components/TransitionGroup.ts
packages/runtime-dom/src/index.ts
packages/runtime-dom/src/modules/style.ts
packages/shared/src/general.ts

index 8bf5c6a32ff0a127465e9595b7205489a52ec7d6..74575322d46b6fca6e705d94afa399759b9b2412 100644 (file)
@@ -36,7 +36,7 @@ import { findDir, findProp, getMemoedVNodeCall, injectProp } from '../utils'
 import { PatchFlags } from '@vue/shared'
 
 export const transformIf: NodeTransform = createStructuralDirectiveTransform(
-  /^(if|else|else-if)$/,
+  /^(?:if|else|else-if)$/,
   (node, dir, context) => {
     return processIf(node, dir, context, (ifNode, branch, isRoot) => {
       // #1587: We need to dynamically increment the key based on the current
index 4681791f8d577cf0e5a4f5ca4afe606b7d2644f8..3493934e39bff10716abd254c84a23be0188b4b1 100644 (file)
@@ -223,7 +223,7 @@ export function buildSlots(
         ),
       )
     } else if (
-      (vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))
+      (vElse = findDir(slotElement, /^else(?:-if)?$/, true /* allowEmpty */))
     ) {
       // find adjacent v-if
       let j = i
@@ -234,7 +234,7 @@ export function buildSlots(
           break
         }
       }
-      if (prev && isTemplateNode(prev) && findDir(prev, /^(else-)?if$/)) {
+      if (prev && isTemplateNode(prev) && findDir(prev, /^(?:else-)?if$/)) {
         __TEST__ && assert(dynamicSlots.length > 0)
         // attach this slot to previous conditional
         let conditional = dynamicSlots[
index ab851ed6f69ae405d24a9ef3a151c7bb4f66972c..32b8e076cc2daa1e8236ebb30bf7d469f0f2df5d 100644 (file)
@@ -189,7 +189,7 @@ export const isMemberExpression: (
 ) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
 
 const fnExpRE =
-  /^\s*(async\s*)?(\([^)]*?\)|[\w$_]+)\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/
+  /^\s*(?:async\s*)?(?:\([^)]*?\)|[\w$_]+)\s*(?::[^=]+)?=>|^\s*(?:async\s+)?function(?:\s+[\w$]+)?\s*\(/
 
 export const isFnExpressionBrowser: (exp: ExpressionNode) => boolean = exp =>
   fnExpRE.test(getExpSource(exp))
index cd8f1a9d1844f6003f9dec7cea922f69e71375eb..0cda6f35ba4abcbbbb3ce01076602972caea2a2b 100644 (file)
@@ -184,7 +184,7 @@ const getCachedNode = (
   }
 }
 
-const dataAriaRE = /^(data|aria)-/
+const dataAriaRE = /^(?:data|aria)-/
 const isStringifiableAttr = (name: string, ns: Namespaces) => {
   return (
     (ns === Namespaces.HTML
index 071b3a36b12a6ee23a1da7669ce73dce8a488e17..81c735a6c3fe3b0f5ff1821aea5ea3361088957b 100644 (file)
@@ -8,8 +8,8 @@ import {
 import selectorParser from 'postcss-selector-parser'
 import { warn } from '../warn'
 
-const animationNameRE = /^(-\w+-)?animation-name$/
-const animationRE = /^(-\w+-)?animation$/
+const animationNameRE = /^(?:-\w+-)?animation-name$/
+const animationRE = /^(?:-\w+-)?animation$/
 const keyframesRE = /^(?:-\w+-)?keyframes$/
 
 const scopedPlugin: PluginCreator<string> = (id = '') => {
index c1414d1ecbdb3dc992943044d1d92fdfeee5eaab..98941386e5cebfe9118ee11270e9537ac6b889c0 100644 (file)
@@ -6,7 +6,7 @@ export function isRelativeUrl(url: string): boolean {
   return firstChar === '.' || firstChar === '~' || firstChar === '@'
 }
 
-const externalRE = /^(https?:)?\/\//
+const externalRE = /^(?:https?:)?\/\//
 export function isExternalUrl(url: string): boolean {
   return externalRE.test(url)
 }
index 0e3880247a16e29b5ecb2b187be71d2ae0478e26..79a4e20015de21e22d7917a22cef64b41ca80b9c 100644 (file)
@@ -17,7 +17,7 @@ import {
 
 // Plugin for the first transform pass, which simply constructs the AST node
 export const ssrTransformIf: NodeTransform = createStructuralDirectiveTransform(
-  /^(if|else|else-if)$/,
+  /^(?:if|else|else-if)$/,
   processIf,
 )
 
index edc57436a56a8071d3b0faa277dee1bcb68d3f49..e19b3fc38f3b14443dbf92a601fc0e0324c44879 100644 (file)
@@ -536,7 +536,7 @@ function installCompatMount(
         if (__DEV__) {
           for (let i = 0; i < container.attributes.length; i++) {
             const attr = container.attributes[i]
-            if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
+            if (attr.name !== 'v-cloak' && /^(?:v-|:|@)/.test(attr.name)) {
               warnDeprecation(DeprecationTypes.GLOBAL_MOUNT_CONTAINER, null)
               break
             }
index 60552d736d50aa9537c1cc250d09a95671e2cb3f..9eb9193da070312d285d343b079cc6edc65bf351 100644 (file)
@@ -1203,7 +1203,7 @@ export function getComponentPublicInstance(
   }
 }
 
-const classifyRE = /(?:^|[-_])(\w)/g
+const classifyRE = /(?:^|[-_])\w/g
 const classify = (str: string): string =>
   str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')
 
index 6c6344bfcacbc8dc84961131dbca8d49f813634f..ebd16a12a3e454ef94d9c8fa22cfae354ff3f576 100644 (file)
@@ -447,7 +447,7 @@ export function getTransitionInfo(
   }
   const hasTransform =
     type === TRANSITION &&
-    /\b(transform|all)(,|$)/.test(
+    /\b(?:transform|all)(?:,|$)/.test(
       getStyleProperties(`${TRANSITION}Property`).toString(),
     )
   return {
index 7bb5ce0c6b13e6657928db879a455c897e30d116..33a1533c72576bf2eb84543c9adebdb5e32d91ce 100644 (file)
@@ -103,7 +103,7 @@ const TransitionGroupImpl: ComponentOptions = /*@__PURE__*/ decorate({
           if (e && e.target !== el) {
             return
           }
-          if (!e || /transform$/.test(e.propertyName)) {
+          if (!e || e.propertyName.endsWith('transform')) {
             el.removeEventListener('transitionend', cb)
             ;(el as any)[moveCbKey] = null
             removeTransitionClass(el, moveClass)
index c69375983d81ee1cbbf0f1f023bf05cfbd25f052..6abfbb52e5dab745ebf3e88557313d2b5efc7462 100644 (file)
@@ -119,7 +119,7 @@ export const createApp = ((...args) => {
       if (__COMPAT__ && __DEV__ && container.nodeType === 1) {
         for (let i = 0; i < (container as Element).attributes.length; i++) {
           const attr = (container as Element).attributes[i]
-          if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
+          if (attr.name !== 'v-cloak' && /^(?:v-|:|@)/.test(attr.name)) {
             compatUtils.warnDeprecation(
               DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
               null,
index 383628a6ad0492d926d536fe9006a14dc9d9e717..679064bd7090eb166a8fd0d4c3213c681bc7c35b 100644 (file)
@@ -9,7 +9,7 @@ import { CSS_VAR_TEXT } from '../helpers/useCssVars'
 
 type Style = string | Record<string, string | string[]> | null
 
-const displayRE = /(^|;)\s*display\s*:/
+const displayRE = /(?:^|;)\s*display\s*:/
 
 export function patchStyle(el: Element, prev: Style, next: Style): void {
   const style = (el as HTMLElement).style
index 9c6a23132404d8c6bd54dacc8b073a2b18e837a7..8f190b62a1433ffc3f72a190c5c4d28c3ab92ca2 100644 (file)
@@ -101,13 +101,13 @@ const cacheStringFunction = <T extends (str: string) => string>(fn: T): T => {
   }) as T
 }
 
-const camelizeRE = /-(\w)/g
+const camelizeRE = /-\w/g
 /**
  * @private
  */
 export const camelize: (str: string) => string = cacheStringFunction(
   (str: string): string => {
-    return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
+    return str.replace(camelizeRE, c => c.slice(1).toUpperCase())
   },
 )