Skip to content

CSS: @value replacement in keyframes/animation produces broken output #22030

Open

Description

@Knagis

Have you used AI?

Yes

Which part of webpack is affected?

css

Bug Description

The animName replacement doesn't work correctly.

@value animName: pulseAnim;

.anim {
    animation: animName 2s linear;
}

@keyframes animName {
    from { opacity: 0; }
}

Link to Minimal Reproduction and steps to reproduce

https://github.com/Knagis/rspack-webpack-css-value-animation

Expected Behavior

Likely to keep consistency with how @value are used (not hashed) in selectors:

.css-modules-value-animation-src_index_css-anim {
    animation: pulseAnim 2s linear;
}

@keyframes pulseAnim {
    from { opacity: 0; }
}

Actual Behavior

.css-modules-value-animation-src_index_css-anim {
    animation: css-modules-value-animation-src_index_css-pulseAnim 2s linear;
}

@keyframes css-modules-value-animation-src_index_css-pulseAnimpulseAnim {
    from { opacity: 0; }
}

Environment

webpack 5.108.4

Is this a regression?

None

Last Working Version

No response

Additional Context

No response

Activity

  1. added theissue type on Sep 10, 2026
  2. Knagis commented on Sep 10, 2026

    @Knagis
    ContributorAuthor

    there is some discussion in the rspack issue about what exactly would be the expected output in this case...

  3. intellild commented on Sep 10, 2026

    @intellild
    Contributor

    Things are a little bit complicated.

    In this case, if we prefer animation first, the @value imported from can also be an animation in "values.module.css".

    @value imported from "./values.module.css";
    
    .before {
    	animation: imported 1s linear;
    	animation-name: imported;
    }
    
    @keyframes imported {
    	from { opacity: 0; }
    }
  4. alexander-akait commented on Sep 10, 2026

    @alexander-akait
    Member

    @Knagis i want to say the current behavior is right, firstly we resolve @value, then we apply interpolations, it was a bug in css modules plugins for postcss (I literally worked on them and I want confirm it is a bug)

  5. alexander-akait commented on Sep 10, 2026

    @alexander-akait
    Member

    @value is a build time replacement, after resolving all
    @value’s, we apply the standard logic for css modules, you can use global() to keep the name as is

  6. Knagis commented on Sep 10, 2026

    @Knagis
    ContributorAuthor

    But that isn't the case for selectors - there the value replaced ident isn't then hashed

  7. alexander-akait commented on Sep 10, 2026

    @alexander-akait
    Member

    @Knagis are sure? I remember we made it and had tests for this

  8. Knagis commented on Sep 10, 2026

    @Knagis
    ContributorAuthor

    Yes, pretty sure, see the repro page https://github.com/Knagis/rspack-webpack-css-value-animation#webpack-output-native-cssmodule

    I wouldn't mind it being hashed either, as long as the behavior is consistent and defined 🙂

  9. alexander-akait commented on Sep 10, 2026

    @alexander-akait
    Member

    @Knagis give me time to think about it, @value was always bad written in docs and spec, so we need to think how to we should behave

  10. alexander-akait commented on Sep 13, 2026

    @alexander-akait
    Member

    @Knagis implemented - #22036, please take a look, open to any discussions

  11. added a commit that references this issue on Sep 13, 2026
    da4ad13
  12. alexander-akait commented on Oct 3, 2026

    @alexander-akait
    Member

    @Knagis friendly ping, if it is good behavior for you we can close or continue the discussion

  13. Knagis commented on Oct 3, 2026

    @Knagis
    ContributorAuthor

    Sorry for not responding.

    It looks great imo. Though for me the most important part is simply that this is specified behavior now.

    BTW, what is the JS output for @value animName: pulseAnim; @keyframes animName {}? Do we get exports.animName = "pulseAnim" and then exports.pulseAnim = "value-at-rule-prelude-style_module_css-pulseAnim"?

  14. alexander-akait commented on Oct 5, 2026

    @alexander-akait
    Member

    @Knagis found some bugs with reexport and fixed them, and yes, it works like your describe, feel free to test and report about any bugs if you find them

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: cssCSS support (lib/css)

    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