Skip to content

Commit a52ed1d

Browse files
authored
fix(css): ensure order of extracted CSS (#16588)
1 parent 04af3a0 commit a52ed1d

File tree

1 file changed

+22
-10
lines changed
  • packages/vite/src/node/plugins

1 file changed

+22
-10
lines changed

packages/vite/src/node/plugins/css.ts

+22-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import postcssrc from 'postcss-load-config'
77
import type {
88
ExistingRawSourceMap,
99
ModuleFormat,
10+
OutputAsset,
1011
OutputChunk,
1112
RenderedChunk,
1213
RollupError,
@@ -844,23 +845,34 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
844845
function extractCss() {
845846
let css = ''
846847
const collected = new Set<OutputChunk>()
847-
const prelimaryNameToChunkMap = new Map(
848-
Object.values(bundle)
849-
.filter((chunk): chunk is OutputChunk => chunk.type === 'chunk')
850-
.map((chunk) => [chunk.preliminaryFileName, chunk]),
851-
)
848+
// will be populated in order they are used by entry points
849+
const dynamicImports = new Set<string>()
852850

853-
function collect(fileName: string) {
854-
const chunk = bundle[fileName]
851+
function collect(chunk: OutputChunk | OutputAsset) {
855852
if (!chunk || chunk.type !== 'chunk' || collected.has(chunk)) return
856853
collected.add(chunk)
857854

858-
chunk.imports.forEach(collect)
855+
// First collect all styles from the synchronous imports (lowest priority)
856+
chunk.imports.forEach((importName) => collect(bundle[importName]))
857+
// Save dynamic imports in deterministic order to add the styles later (to have the highest priority)
858+
chunk.dynamicImports.forEach((importName) =>
859+
dynamicImports.add(importName),
860+
)
861+
// Then collect the styles of the current chunk (might overwrite some styles from previous imports)
859862
css += chunkCSSMap.get(chunk.preliminaryFileName) ?? ''
860863
}
861864

862-
for (const chunkName of chunkCSSMap.keys())
863-
collect(prelimaryNameToChunkMap.get(chunkName)?.fileName ?? '')
865+
// The bundle is guaranteed to be deterministic, if not then we have a bug in rollup.
866+
// So we use it to ensure a deterministic order of styles
867+
for (const chunk of Object.values(bundle)) {
868+
if (chunk.type === 'chunk' && chunk.isEntry) {
869+
collect(chunk)
870+
}
871+
}
872+
// Now collect the dynamic chunks, this is done last to have the styles overwrite the previous ones
873+
for (const chunkName of dynamicImports) {
874+
collect(bundle[chunkName])
875+
}
864876

865877
return css
866878
}

0 commit comments

Comments
 (0)