Skip to content

RuleSetCompiler.hasRuleForResource fails to detect path-scoped rules with grouped/alternate extensions (e.g. .(css|scss) or .(ts|tsx)) #21943

Closed

Description

@Abhirup0

Have you used AI?

No

Which part of webpack is affected?

config (options, defaults, validation), css, html

Bug Description

RuleSetCompiler.hasRuleForResource returns false when a rule uses a path-scoped RegExp with grouped or alternate extensions (e.g., test: /[\\/]src[\\/].*\.(css|scss)$/, test: /\/components\/.*\.(ts|tsx)$/, or test: /\/templates\/.*\.(html|htm)$/).

Because hasRuleForResource fails to detect that the user has configured loaders for .css, .html, or .ts, the experiments.css, experiments.html, and experiments.typescript defaults do not resolve to false. Instead, they stay "auto" (or resolve to true for experiments.typescript on Node >= 22.6), allowing built-in experimental processing (like native TypeScript type-stripping via stripTypeScriptTypes or CSS/HTML module handling) to activate alongside or conflict with the user's explicit loaders.

Link to Minimal Reproduction and steps to reproduce

const webpack = require("webpack");
const RuleSetCompiler = require("webpack/lib/rules/RuleSetCompiler");

// User configures a path-scoped rule with grouped extensions:
const rules = [
{
test: /[\/]src[\/].*.(css|scss)$/,
use: ["style-loader", "css-loader"]
}
];

// 1. Direct check on hasRuleForResource:
console.log("hasRuleForResource('/file.css'):", RuleSetCompiler.hasRuleForResource(rules, "/file.css"));
// Expected: true
// Actual: false

// 2. Options resolution check:
const compiler = webpack({
mode: "development",
entry: "./src/index.js",
module: { rules }
});

console.log("Resolved experiments.css:", compiler.options.experiments.css);
// Expected: false (disabled because user handles css)
// Actual: "auto"

Expected Behavior

RuleSetCompiler.hasRuleForResource(rules, "/file.css") should return true when a rule's test regexp targets .css files even if the regexp uses alternation groups (such as \.(css|scss) or \.(?:css|module\.css)).

Consequently, experiments.css should resolve to false in applyExperimentsDefaults when the user has provided loaders for these files.

Actual Behavior

RuleSetCompiler.hasRuleForResource(rules, "/file.css") returns false. experiments.css remains "auto".

Environment

System:
  OS: Windows 11 10.0.26200
  CPU: (20) x64 12th Gen Intel(R) Core(TM) i7-12700H
  Memory: 5.09 GB / 23.63 GB

Binaries:
  Node: 24.7.0
  npm: 11.5.1

Browsers:
  Chrome: 152.0.7977.65
  Edge: Chromium (152.0.4191.53)

Packages:
  webpack: 5.x (main)
  webpack-cli: 7.2.2
  css-loader: 7.1.4
  html-loader: 5.1.0
  ts-loader: 9.6.2

Is this a regression?

None

Last Working Version

No response

Additional Context

The issue is in lib/rules/RuleSetCompiler.js:

  1. For /file.css, extProbe is "\\.css".
  2. matchRuleSetCondition(condition, "/file.css") fails against /file.css because the dummy path lacks the path prefix (e.g. src/).
  3. conditionReferencesExtension performs condition.source.includes("\\.css"), which is a literal substring search. For regexes with grouped extensions like "/[\\\\/]src[\\\\/].*\\.(css|scss)$/" or "/src\\/.*\\.(?:ts|tsx)$/", condition.source contains (css|scss) rather than literal \\.css, returning false.

Activity

  1. added theissue type on Sep 3, 2026
  2. added
    area: configOptions, defaults, validation (lib/config, schemas/)
    area: cssCSS support (lib/css)
    area: htmlExperimental HTML support (lib/html)
    on Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: configOptions, defaults, validation (lib/config, schemas/)area: cssCSS support (lib/css)area: htmlExperimental HTML support (lib/html)

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions