Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(css): ensure order of extracted CSS #16588

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

susnux
Copy link
Contributor

@susnux susnux commented May 3, 2024

Description

Without this the order of the extracted CSS rules is defined by the order renderChunk of the css plugin is called. So with this the order of CSS rules is always in alphabetical order of the output chunks.

Previously on my project every time I ran the build the output style.css was different by rule order, which caused unnecessary conflicts.

Copy link

stackblitz bot commented May 3, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Comment on lines 915 to 917
// sorted chunk names to guarantee output order (deterministic output)
const chunkNames = [...chunkCSSMap.keys()].sort()
for (const chunkName of chunkNames)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot sort chunk names alphabetically because the order of the chunks are meaningful. The issue with chunkCSSMap being non-deterministic is because it's being populated via renderChunk that runs non-deterministically among chunks.

I think a better solution here is instead of iterating chunkCSSMap here, we can iterate prelimaryNameToChunkMap instead which is deterministic as it's derived from the `bundle..

Copy link
Contributor Author

@susnux susnux May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prelimaryNameToChunkMap is also not deterministic, entry points are in deterministic order, but the dynamic chunks are randomly sorted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share more how you got that? Chunks in Rollup (regardless if entry, non-entry, dynamic entry) should be consistent, otherwise it'll break many usecases and assumptions in Vite currently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm testing manually I can also see that bundle isn't deterministic. However, renderChunk's chunks are and chunkCSSMap should be following that order and should be deterministic. Unless there's an additional Vite plugin that uses async renderChunk() and changes the order, which is a bug I found today.

But we still can't sort alphabetically like this change now. It will break, for example, if you import two CSS files and expect them to render in order.

To fix this, it might be worth making chunkCSSMap deterministic directly, but it should be fixed since we added this line though. (Unless you use plugins that with the bug I mentioned above)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked my custom plugins but they do not seem to change the order.

``` plugins: [ 'vite:build-metadata', 'vite:watch-package-data', 'vite:pre-alias', 'alias', 'vite:modulepreload-polyfill', 'vite:resolve', 'vite:html-inline-proxy', 'vite:css', 'vite:esbuild', 'vite:json', 'vite:wasm-helper', 'vite:worker', 'vite:asset', 'vite:vue2', 'vite-plugin-node-polyfills', 'esbuild-minify', undefined, 'vite:wasm-fallback', 'vite:define', 'vite:css-post', 'vite:build-html', 'vite:worker-import-meta-url', 'vite:asset-import-meta-url', 'vite:force-systemjs-wrap-complete', 'commonjs', 'vite:data-uri', 'inject', 'vite:dynamic-import-vars', 'vite:import-glob', 'remove-ensure-watch-plugin', 'rollup-plugin-license', 'vite:build-import-analysis', 'vite:esbuild-transpile', 'vite:terser', 'vite:reporter', 'vite:load-fallback'] ```

I changed the approach a bit by not sorting but extracting from entries and then use their imports.
This seems to be deterministic as the entry order seems to be stable.

Without this the order of the extracted CSS rules is defined by the order `renderChunk` of the css plugin is called.
So with this the order of CSS rules is always in order of the output chunks of the bundle.

Signed-off-by: Ferdinand Thiessen <[email protected]>
@susnux susnux requested a review from bluwy May 15, 2024 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants