Skip to content

7.2.0 double-escapes class names from postcss-modules-scope (css-loader CSS modules) #362

Closed

Description

@denniskigen

Since 7.2.0, CSS modules built with css-loader produce selectors that match nothing. postcss-modules-scope passes className() a name css-loader has already escaped, and #349 now escapes it again:

const parser = require("postcss-selector-parser");

parser.className({ value: "a\\+b" }).toString();
// 7.1.8: .a\+b
// 7.2.0: .a\\\+b

I can see the release notes call this out, and raws.value is the right way to pass a pre-escaped name, so I'll open a PR on postcss-modules-scope to do that. Until that's released, though, anyone on css-loader with [hash:base64] names (or anything else that escapes) gets broken styles as soon as their install picks up 7.2.0. We hit it in OpenMRS, where all of our distro builds broke.

Would you consider releasing this change as a major, or reverting it in 7.2.x until postcss-modules-scope has the fix out? #360 would do the same to :local(#id) selectors, so it's probably worth holding that one too.

Activity

  1. denniskigen commented on Nov 9, 2026

    @denniskigen
    Author

    PR for postcss-modules-scope: css-modules/postcss-modules-scope#71

  2. MoOx commented on Nov 12, 2026

    @MoOx
    Collaborator

    Thanks for the precise report, and for opening the fix on postcss-modules-scope at the same time.

    You were right: 7.2.0 changed what the class constructor does with its input, and that belongs in a major. 7.2.1 reverts it, together with the matching change to the id setter from #326, so values are written as given again, as they were through 7.1.8. 7.2.1 is out as latest. Both changes are parked in #357 for a future major. I checked 7.2.1 against postcss-modules-scope 3.2.1 itself: the emitted selectors match 7.1.8 again.

    One correction for anyone who lands here later: plain [hash:base64] names were not affected, because css-loader strips the hash down to [A-Za-z0-9_] before escaping it. What broke is [local] with a class name that needs escaping, [path], [name] or [folder] with a character such as a space or a parenthesis, and custom getLocalIdent functions.

    #360 and #361 are held, as you suggested. Your postcss-modules-scope PR is still worth landing: passing the unescaped name as value and the escaped spelling as raws.value gives the same output on every 7.x release.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions