Skip to content

Conversation

@xiaoxiaojx
Copy link
Member

@xiaoxiaojx xiaoxiaojx commented Jul 11, 2025

What kind of change does this PR introduce?

Fixes #18961

Thanks to @jantimon for the detailed analysis of this issue. Instead of adopting the approach in #19012, I chose to fix the dependency order directly at the point where module updates are triggered, without relying on the internal implementation details of the graph.

Did you add tests for your changes?
Yes, The test cases come from

  1. reproduction-webpack-css-order - For this case, the issue can be resolved just by adding compareSelect in lib/NormalModule.js
  2. webpack-side-effects-optimization-keep-connections-order - For this case, we can reorder the dependencies after updateModule to ensure the subsequent dependency graph traversal produces the expected order. This change also covers the previous case.

Does this PR introduce a breaking change?
No

What needs to be documented once your changes are merged?
No

@Netail
Copy link

Netail commented Jul 11, 2025

There's also #19012, but not much activity there anymore :(

@codspeed-hq
Copy link

codspeed-hq bot commented Jul 11, 2025

CodSpeed Performance Report

Merging #19686 will degrade performances by 95.45%

Comparing fix/css_order (a99df5a) with main (ad1e3b4)

Summary

⚡ 2 improvements
❌ 5 regressions
✅ 126 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
benchmark "cache-filesystem", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 10.7 ms 234.9 ms -95.45%
benchmark "devtool-eval-source-map", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 42.8 ms 11.9 ms ×3.6
benchmark "devtool-source-map", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 11.8 ms 63.3 ms -81.31%
benchmark "future-defaults", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 11.7 ms 40.2 ms -71.03%
benchmark "many-chunks-commonjs", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 12 ms 61.4 ms -80.47%
benchmark "many-chunks-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 61.6 ms 11.8 ms ×5.2
benchmark "many-modules-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 11.2 ms 50.4 ms -77.83%
@xiaoxiaojx xiaoxiaojx force-pushed the fix/css_order branch 13 times, most recently from 94b6215 to 3a68feb Compare July 12, 2025 07:20
@xiaoxiaojx xiaoxiaojx changed the title fix: keep consistent css order fix: keep consistent CSS order for direct dependencies Jul 12, 2025
@xiaoxiaojx xiaoxiaojx force-pushed the fix/css_order branch 2 times, most recently from aa6643b to 0b1fe37 Compare July 12, 2025 19:23
@xiaoxiaojx xiaoxiaojx changed the title fix: keep consistent CSS order for direct dependencies fix: keep consistent CSS order Jul 12, 2025
@xiaoxiaojx xiaoxiaojx force-pushed the fix/css_order branch 2 times, most recently from f52f19d to 2bb2bc1 Compare July 13, 2025 06:14
@xiaoxiaojx xiaoxiaojx changed the title fix: keep consistent CSS order fix: keep the module graph traversal order consistent Jul 13, 2025
@xiaoxiaojx
Copy link
Member Author

xiaoxiaojx commented Jul 14, 2025

Hi @ahabhgk, may I ask if that Rspack issue has been resolved? I'd appreciate it if you could take a look at this code as well. cc @alexander-akait @hai-x @jantimon

@jantimon
Copy link
Contributor

jantimon commented Jul 14, 2025

I chose to fix the dependency order directly at the point where module updates are triggered

I believe this is the key to success 👍 - My first idea was to solve the order only inside lib/optimize/SideEffectsFlagPlugin.js. However that failed for several reasons and that's why I believe your approach is better.

In my solution the following example caused a lot of headaches:

import {Foo} from "./foo-barrel"; import {Bar} from "./bar-barrel"; console.log(Bar); console.log(Foo);

and

import {Foo} from "./barrel"; import {Bar} from "./barrel"; console.log(Bar); console.log(Foo);

The problem here is that Bar is used before Foo and therefore the css of Bar would be loaded first although Foo was imported first.

Could you please double check that this not a problem in your solution anymore?

@xiaoxiaojx
Copy link
Member Author

xiaoxiaojx commented Jul 14, 2025

Hi @jantimon, big thanks for your earlier work. I’ve confirmed that the case you mentioned shouldn’t be an issue. The core of my fix is to sort HarmonyImportSpecifierDependency by import order, so downstream logic like module graph traversal behaves as expected.

In webpack, HarmonyImportSideEffectDependency keeps the original import order, but others like HarmonyImportSpecifierDependency are sorted by usage. This mismatch can cause ordering issues, once tree-shaking removes the HarmonyImportSideEffectDependency, loading CSS solely via HarmonyImportSpecifierDependency causes it to follow usage order instead of import order.

To fix this, I propose sorting HarmonyImportSpecifierDependency by import order as well, aligning with how native JS engines handle modules without bundlers.

@ahabhgk
Copy link
Contributor

ahabhgk commented Jul 14, 2025

No, Rspack haven't resolve this, actually most css order inconsistent problem we are facing is caused by splitChunks, we are working on that before and introduced a experimental plugin which is inspired by next.js, to at least let users can resolve it by their own. And since not many libraries will publish CSS Modules directly so we put this on a low priority.

The code looks good to me, I would probably write it in a similar way if let me work on it 😃

@alexander-akait alexander-akait merged commit 0a98446 into main Jul 14, 2025
43 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

6 participants