(opts, bundle)
| 990 | : {}), |
| 991 | |
| 992 | async generateBundle(opts, bundle) { |
| 993 | // to avoid emitting duplicate assets for modern build and legacy build |
| 994 | if (this.environment.config.isOutputOptionsForLegacyChunks?.(opts)) { |
| 995 | return |
| 996 | } |
| 997 | |
| 998 | // vite:asset cleans up earlier assets of 'renderChunk', |
| 999 | // but with cssCodeSplit=false we may still emit CSS here. |
| 1000 | // So is our responsibility to respect emitAssets |
| 1001 | const canEmitAssets = |
| 1002 | config.command !== 'build' || this.environment.config.build.emitAssets |
| 1003 | |
| 1004 | // extract as single css bundle if no codesplit |
| 1005 | if ( |
| 1006 | canEmitAssets && |
| 1007 | !this.environment.config.build.cssCodeSplit && |
| 1008 | !hasEmitted |
| 1009 | ) { |
| 1010 | let extractedCss = '' |
| 1011 | const collected = new Set<OutputChunk>() |
| 1012 | // will be populated in order they are used by entry points |
| 1013 | const dynamicImports = new Set<string>() |
| 1014 | |
| 1015 | function collect(chunk: OutputChunk | OutputAsset | undefined) { |
| 1016 | if (!chunk || chunk.type !== 'chunk' || collected.has(chunk)) return |
| 1017 | collected.add(chunk) |
| 1018 | |
| 1019 | // First collect all styles from the synchronous imports (lowest priority) |
| 1020 | chunk.imports.forEach((importName) => collect(bundle[importName])) |
| 1021 | // Save dynamic imports in deterministic order to add the styles later (to have the highest priority) |
| 1022 | chunk.dynamicImports.forEach((importName) => |
| 1023 | dynamicImports.add(importName), |
| 1024 | ) |
| 1025 | // Then collect the styles of the current chunk (might overwrite some styles from previous imports) |
| 1026 | extractedCss += chunkCSSMap.get(chunk.preliminaryFileName) ?? '' |
| 1027 | } |
| 1028 | |
| 1029 | // The bundle is guaranteed to be deterministic, if not then we have a bug in rollup. |
| 1030 | // So we use it to ensure a deterministic order of styles |
| 1031 | for (const chunk of Object.values(bundle)) { |
| 1032 | if (chunk.type === 'chunk' && chunk.isEntry) { |
| 1033 | collect(chunk) |
| 1034 | } |
| 1035 | } |
| 1036 | // Now collect the dynamic chunks, this is done last to have the styles overwrite the previous ones |
| 1037 | for (const chunkName of dynamicImports) { |
| 1038 | collect(bundle[chunkName]) |
| 1039 | } |
| 1040 | |
| 1041 | // Finally, if there's any extracted CSS, we emit the asset |
| 1042 | if (extractedCss) { |
| 1043 | hasEmitted = true |
| 1044 | extractedCss = await finalizeCss(extractedCss, config) |
| 1045 | this.emitFile({ |
| 1046 | name: getCssBundleName(), |
| 1047 | type: 'asset', |
| 1048 | source: extractedCss, |
| 1049 | // this file is an implicit entry point, use defaultCssBundleName as the original file name |
nothing calls this directly
no test coverage detected