Skip to content

Commit

Permalink
fix(css): ensure order of extracted CSS (#16588)
Browse files Browse the repository at this point in the history
  • Loading branch information
susnux authored Jun 10, 2024
1 parent 04af3a0 commit a52ed1d
Showing 1 changed file with 22 additions and 10 deletions.
32 changes: 22 additions & 10 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import postcssrc from 'postcss-load-config'
import type {
ExistingRawSourceMap,
ModuleFormat,
OutputAsset,
OutputChunk,
RenderedChunk,
RollupError,
Expand Down Expand Up @@ -844,23 +845,34 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
function extractCss() {
let css = ''
const collected = new Set<OutputChunk>()
const prelimaryNameToChunkMap = new Map(
Object.values(bundle)
.filter((chunk): chunk is OutputChunk => chunk.type === 'chunk')
.map((chunk) => [chunk.preliminaryFileName, chunk]),
)
// will be populated in order they are used by entry points
const dynamicImports = new Set<string>()

function collect(fileName: string) {
const chunk = bundle[fileName]
function collect(chunk: OutputChunk | OutputAsset) {
if (!chunk || chunk.type !== 'chunk' || collected.has(chunk)) return
collected.add(chunk)

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

for (const chunkName of chunkCSSMap.keys())
collect(prelimaryNameToChunkMap.get(chunkName)?.fileName ?? '')
// The bundle is guaranteed to be deterministic, if not then we have a bug in rollup.
// So we use it to ensure a deterministic order of styles
for (const chunk of Object.values(bundle)) {
if (chunk.type === 'chunk' && chunk.isEntry) {
collect(chunk)
}
}
// Now collect the dynamic chunks, this is done last to have the styles overwrite the previous ones
for (const chunkName of dynamicImports) {
collect(bundle[chunkName])
}

return css
}
Expand Down

0 comments on commit a52ed1d

Please sign in to comment.