Visitar URL original
perf: check globToRegExp output without building a RegExp by alexander-akait · Pull Request #372 · webpack/watchpack · GitHub
Skip to content

perf: check globToRegExp output without building a RegExp - #372

Merged
alexander-akait merged 1 commit into
mainfrom
perf/glob-to-regexp-no-check-regexp
Nov 7, 2026
Merged

alexander-akait merged 1 commit into
mainfrom
perf/glob-to-regexp-no-check-regexp

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

Summary

util.globToRegExp built a RegExp from its output only to find out whether it compiles. It then returned the string, and every caller compiles it again: webpack's sideEffects globs, and watchpack's own ignored option. So each glob was compiled twice.

The check is now a single pass over the source: brackets, parentheses, escapes and class ranges, the only constructs translate can emit. It reads ranges as a non-unicode RegExp does. That covers \d/\s/\w sets, \b, control escapes, legacy octal, \x, \u and a lone \c. When the check fails, the same literal fallback is used as before.

Before After
RegExp objects built per call 1 0
1.6M calls over 8 common and invalid globs 3.1–3.5 s 0.49–0.69 s

The output is byte-identical to main for every glob checked: about 9.4 million globs over four alphabets. These are every glob of up to 5–6 characters from each alphabet, plus random longer ones. The alphabets cover brackets, braces, escapes, octal, \x, \u, \c, ranges and non-ASCII.

Tests

New case in test/globToRegExp.test.js, "should read escapes and ranges in a class as a regexp does". Each escape kind and range rule appears once valid, matched through the class, and once invalid, matched literally. npm run lint passes, as does test/globToRegExp.test.js.

Use of AI

Claude Code wrote the change and tests. The requester reviewed and directed the changes.


Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of glob patterns containing character classes and escape sequences, including hexadecimal, Unicode, control, octal, and shorthand escapes.
    • Malformed patterns, such as reversed ranges or unclosed character classes, are handled as literal text.
  • Performance
    • Pattern validation is approximately five times faster.

The source was compiled only to find out whether it compiles, and every
caller compiles it again. A linear check of the brackets, parentheses,
escapes and class ranges translate can emit gives the same answer.
@changeset-bot

changeset-bot Bot commented Nov 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 05feae1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
watchpack Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 7, 2026

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The change replaces RegExp construction as the validity check with a source validator that handles escapes, parentheses, and character classes. Invalid translated sources use literal-mode translation. Tests cover character-class escapes and ranges, including malformed cases. The changeset describes the change as about five times faster.

Merge Risk: Minimal · up to 05fea

No actionable merge-blocking issue was established. The change is ready for normal checks.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly describes the main change: checking globToRegExp output without constructing a RegExp.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

test/globToRegExp.test.js

Oops! Something went wrong! :(

ESLint: 9.39.5

Error: Error while loading rule 'jest/no-deprecated-functions': Unable to detect Jest version - please ensure jest package is installed, or otherwise set version explicitly
Occurred while linting /test/globToRegExp.test.js
at detectJestVersion (/.eslint-tmp/node_modules/eslint-plugin-jest/lib/rules/utils/detectJestVersion.js:22:9)
at create (/.eslint-tmp/node_modules/eslint-plugin-jest/lib/rules/no-deprecated-functions.js:31:107)
at Object.create (/.eslint-tmp/node_modules/@typescript-eslint/utils/dist/eslint-utils/RuleCreator.js:39:20)
at createRuleListeners (/.eslint-tmp/node_modules/eslint/lib/linter/linter.js:1019:15)
at /.eslint-tmp/node_modules/eslint/lib/linter/linter.js:1151:7
at Array.forEach ()
at runRules (/.eslint-tmp/node_modules/eslint/lib/linter/linter.js:1085:31)
at #flatVerifyWithoutProcessors (/.eslint-tmp/node_modules/eslint/lib/linter/linter.js:2115:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/.eslint-tmp/node_modules/eslint/lib/linter/linter.js:2203:43)
at Linter._verifyWithFlatConfigArray (/.eslint-tmp/node_modules/eslint/lib/linter/linter.js:2306:15)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 875fbfa5-303d-4d2c-ba94-6662a42a109d
Commits

Reviewing files that changed from the base of the PR and between be223cc and 05feae1.

Files selected for processing: 3

  • .changeset/glob-to-regexp-no-check-regexp.md
  • lib/util/globToRegExp.js
  • test/globToRegExp.test.js

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

@codspeed

codspeed Bot commented Nov 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ 1 benchmark is dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 36 untouched benchmarks


Comparing perf/glob-to-regexp-no-check-regexp (05feae1) with main (be223cc)

Open in CodSpeed

@codecov

codecov Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.66%. Comparing base (be223cc) to head (05feae1).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #372      +/-   ##
==========================================
+ Coverage   95.38%   95.66%   +0.28%     
==========================================
  Files           8        8              
  Lines        1429     1522      +93     
  Branches      434      483      +49     
==========================================
+ Hits         1363     1456      +93     
  Misses         61       61              
  Partials        5        5              
Flag Coverage Δ
integration 95.66% <100.00%> (+0.28%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait
alexander-akait merged commit 9f64c79 into main Nov 7, 2026
51 checks passed
@alexander-akait
alexander-akait deleted the perf/glob-to-regexp-no-check-regexp branch November 7, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant