First-class Embroider + GJS/GTS Support#340
Merged
Conversation
Fix classNames runtime helper for undefined and unmapped classes
Add setup instructions for v2 apps and addons, document config options (pathMapping, runtimeModule), usage examples for static, dynamic, and mixed class names, and a brief explanation of how the compile-time transform works.
Add explanation of what the plugin does (with before/after example), setup instructions for v2 addon rollup configs, and documentation for all three config options (include, generateScopedName, getOutputFilename).
Replace the HTML comment hiding the full documentation with a <details> element so it's still visible but collapsed by default, given the package is in maintenance mode.
Describe compatibility at each stage: ember-css-modules works with classic builds and Embroider+Webpack but not Vite, so the build pipeline migration and CSS Modules swap can be done separately.
Break out steps that can be done incrementally while still on ember-css-modules: consolidate to colocated layout, rename to .module.css, remove legacy config options, migrate PostCSS config.
Break out steps that can be done while still a v1 addon: consolidate to colocated layout and rename to .module.css. Converting-to-v2 steps now account for whether prep was already done.
Cover the common case of apps using SCSS via PostCSS plugins with ember-css-modules, and how to migrate to Vite's native Sass support.
Co-authored-by: Dan Freeman <dfreeman@salsify.com>
Add migration guides and package READMEs
Also archive CHANGELOG.md to opt into generated release notes
mnoble01
approved these changes
Feb 24, 2026
mnoble01
left a comment
There was a problem hiding this comment.
Looks good to me! The guides are very helpful and clear. I have one comment about some potential additional test coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎺
ember-css-modulesis dead; long live Ember CSS Modules.Background
This PR is the culmination of work that began back with embroider-build/embroider#1142 and ultimately produced the long-lived
standalone-template-transformbranch in this repo.The tl;dr is that what was once
ember-css-modulesis no longer needed: its two jobs were to:local-classsyntactic sugar in templatesThe first bullet is no longer needed in the modern ecosystem, as CSS Modules can be handled directly by the bundler (Vite in a v2 app, and Webpack in a v1 app with Embroider or
ember-auto-import).The second bullet is less needed in a world with FCCTs (
.gjs/.gtsfiles), as importing and referencing the classname mapping doesn't require creating a backing class to intermediate any longer. However, for ease of migration (or for those who just like the sugar), the end result here provides lighter-weight options to keeplocal-classaround.The Packages
This PR breaks the repository into four published packages. Details of each package is in the corresponding READMEs and the excellent migration guides that @deanmarano kindly put together.
ember-css-modulesA v3 version of
ember-css-modulesis included here as a stepping stone for migration. It keeps thebroccoli-css-modules-based processing of CSS in the classic Broccoli pipeline, but delegateslocal-classhandling to theglimmer-local-class-transformpackage described below.Notable breaking changes:
This version of
ember-css-modulesis now fully compatible with@embroider/webpackin terms of playing nicely with the variousstaticflags, though if you're at that point you likely want to consider moving toember-local-class(or on to Vite andglimmer-local-class-transform) instead. See compatibility listings below.glimmer-local-class-transformThis is a
@glimmer/syntaxAST transform that convertslocal-classsyntax to a reference to an import from the corresponding styles module. V2 apps and addons can use this transform directly by setting it up as part of the template processing in their Babel configuration.ember-local-classThis is a very lightweight v1 addon that just sets up
glimmer-local-class-transformon behalf of its parent. This is necessary for v1 apps, as they aren't able to add template transforms directly in their own config. (An in-repo addon is an option, but at that point you've essentially just vendoredember-local-classinto your repo.)ember-local-classhas a few notable differences toember-css-modules:.module.cssas the module extension rather than.cssrollup-plugin-preprocess-css-modulesThis is a Rollup plugin that enables v2 addons (or other component libraries) to preprocess CSS Modules into standards-compliant JS + CSS. This ensures that their use of CSS Modules is just an implementation detail and avoids imposing any requirements on host applications' bundlers processing CSS Modules on their behalf.
The notable difference between this package and using e.g.
rollup-plugin-postcssto process CSS Modules is thatrollup-plugin-preprocess-css-modulesleaves the resulting CSS as standalone.cssfiles that are referenced as needed by ESimportstatements. This adheres to the Embroider v2 package format RFC's expectations for CSS distribution and ensures that the host application can bundle styles in the most effective way.Usage Patterns
The packages here have varying levels of compatibility with v1/v2 addons/apps. Each of the setups described below has a corresponding test case in
/test-packages.V1 App
Choose one of the following combinations:
ember-css-modules(classic build or@embroider/webpack)ember-local-class+ember-auto-importwithallowAppImportsandmodules: { auto: true }ember-local-class+@embroider/webpackwithmodules: { auto: true }V1 Addon
Use
ember-css-modulesindependencies.ember-css-modulesis still the only solution available to v1 addons for CSS Modules, as they have no equivalent ofallowAppImportsconfig to opt certain subpaths into being handled directly by the host bundler.V2 App
Use
glimmer-local-class-transformand Vite's built-in CSS Modules support. Addglimmer-local-class-transformto thetransformsarray forbabel-plugin-ember-template-compilationin yourbabel.config.cjs.V2 Addon
Use
glimmer-local-class-transformandrollup-plugin-preprocess-css-modules.glimmer-local-class-transformto thetransformsarray forbabel-plugin-ember-template-compilationin yourbabel.publish.config.cjs.rollup.config.mjs:.hbsto theextensionsarray you pass to@rollup/plugin-babelrollup-plugin-preprocess-css-modulesabove the call toaddon.keepAssetsCloses #318, closes #285