css: implement handle_composes to build CssModuleReference entries
What
CssModule::handle_composes in src/css/css_modules.rs was a validation-only stub: it checked that composes: appears under a single class selector but never built the composed references. CssModuleReference::{Local, Global} were never constructed anywhere (flagged by the dead-code sweep in #36184) and CssModuleExport.composes was always empty in the ToCssResult.exports map.
Fix
For each single-class selector and each name in the composes: list, construct the appropriate reference and append it to the selector's export entry (creating the entry on first use), de-duplicating by value:
composes: … | reference |
|---|---|
alpha | Local { name: pattern.write_to_string(.., "alpha") } |
x from global | Global { name: "x" } |
x from "./other.css" | Dependency { name: "x", specifier: record.path.text } |
This matches the lightningcss handle_composes behavior. Note that Bun's Specifier has no SourceIndex variant, so that lightningcss arm does not apply here.
The bundler's composes: support is a separate parser-level path (ast.composes consumed by generateCodeForLazyExport / scanImportsAndExports) and is unchanged; handle_composes populates the printer-side ToCssResult.exports map.
Testing
Added cssInternals.cssModulesTest(source) (internal-for-testing only) which parses with css_modules: Some(Config::default()), wires the parsed symbol list into to_css, and returns { code, exports } where each export carries its composes array. New tests in test/js/bun/css/css-modules-composes.test.ts cover the local / global / dependency / multi-name-dedupe cases plus the existing invalid-selector error.
bun bd test test/js/bun/css/css-modules-composes.test.ts
5 pass, 0 fail
Existing test/bundler/css/css-modules.test.ts (6 pass) and test/bundler/esbuild/css.test.ts (56 pass) are unchanged.
[review] gate passed · iteration 1 · 5 files touched
fails on main (without fix)
ASAN without fix: 5 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/js/bun/css/css-modules-composes.test.ts
bun test v1.4.0 (7f7c0f69e)
test/js/bun/css/css-modules-composes.test.ts:
3 |
4 | const { cssModulesTest } = cssInternals as any;
5 |
6 | describe("css_modules handle_composes", () => {
7 | test("local composes builds a Local reference", () => {
8 | const result = cssModulesTest(
^
TypeError: cssModulesTest is not a function. (In 'cssModulesTest(`.alpha { color: red; }
.beta { composes: alpha; color: blue; }`)', 'cssModulesTest' is undefined)
at <anonymous> (/workspace/bun/test/js/bun/css/css-modules-composes.test.ts:8:20)
(fail) css_modules handle_composes > local composes builds a Local reference [11.01ms]
16 | const hash = result.exports.beta.name.slice("beta_".length);
17 | expect(result.exports.beta.composes[0].name).toBe(`alpha_${hash}`);
18 | });
19 |
20 | test("global composes builds a Global reference", () => {
21 | const result = cssModulesTest(`.alpha { composes: globalName from global; color: red; }`);
... (truncated)
release without fix: all passed
bun test v1.4.0-canary.1 (2de563454)
test/js/bun/css/css-modules-composes.test.ts:
(pass) css_modules handle_composes > local composes builds a Local reference [10.69ms]
(pass) css_modules handle_composes > global composes builds a Global reference [0.11ms]
(pass) css_modules handle_composes > composes from file builds a Dependency reference [0.06ms]
(pass) css_modules handle_composes > multiple names and dedupe [0.07ms]
(pass) css_modules handle_composes > invalid selector still errors [1.93ms]
5 pass
0 fail
6 expect() calls
Ran 5 tests across 1 file. [179.00ms]
__F:0:S:0
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/js/bun/css/css-modules-composes.test.ts
bun test v1.4.0 (7f7c0f69e)
test/js/bun/css/css-modules-composes.test.ts:
(pass) css_modules handle_composes > local composes builds a Local reference [19.03ms]
(pass) css_modules handle_composes > global composes builds a Global reference [3.71ms]
(pass) css_modules handle_composes > composes from file builds a Dependency reference [3.02ms]
(pass) css_modules handle_composes > multiple names and dedupe [4.28ms]
(pass) css_modules handle_composes > invalid selector still errors [5.25ms]
5 pass
0 fail
6 expect() calls
Ran 5 tests across 1 file. [2.09s]
__F:0:S:0
release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 708ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[0/1] reconfigure
[1/28] install /workspace/bun
bun install v1.4.0-canary.1 (2de563454)
Checked 124 installs across 170 packages (no changes) [4.00ms]
[2/28] esbuild runtime.out.js
build/release/codegen/runtime.out.js 5.3kb
⚡ Done in 5ms
[3/28] esbuild fallback-decoder.js
build/release/codegen/fallback-decoder.js 8.8kb
⚡ Done in 8ms
[4/28] esbuild bun-error
../../build/release/codegen/bun-error/index.js 42.9kb
../../build/release/codegen/bun-error/bun-error.css 12.8kb
⚡ Done in 18ms
[5/28] gen cpp.rs (cppbind)
[6/28] gen generated_host_exports.rs
generated_host_exports.rs: 94 exports (host=3, lazy=10, generic=81, rust=0); 240 extern-C blocks audited
[7/28] gen JS modules (bundle-modules)
Preprocess modules (9232ms)
Bundle modules (56ms)
Postprocesss modules (210ms)
Bundle Functions (739ms)
Generate Code (37ms)
[10.29s] Bundled "src/js" for production
2570 kb
193 internal modules
13 native modules
90 internal functions across 19 files
[7/14] cargo bun_bin → libbun_ru
... (truncated)
diff hotspot
src/css/css_modules.rs | 69 ++++++++++++---
src/css_jsc/css_internals.rs | 121 +++++++++++++++++++++++++++
src/js/internal-for-testing.ts | 1 +
src/runtime/dispatch_js2native.rs | 5 +-
test/js/bun/css/css-modules-composes.test.ts | 47 +++++++++++
5 files changed, 230 insertions(+), 13 deletions(-)
gate history · 2 passed · 0 rejected · iteration 1
evidence per changed file
file reads edits tests
src/css/css_modules.rs 1 1 0
src/css_jsc/css_internals.rs 2 2 0
src/js/internal-for-testing.ts 1 1 0
src/runtime/dispatch_js2native.rs 1 1 0
test/js/bun/css/css-modules-composes.test.ts 0 3 0