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: empty CSS file was output when only .css?url is used #15846

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
158 changes: 78 additions & 80 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,92 +718,90 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
}
}

if (!chunkCSS && !s) {
return null
}
Comment on lines -721 to -723
Copy link
Member Author

Choose a reason for hiding this comment

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

If a file contains __VITE_CSS_URL__ (!s === false) and doesn't have side effect CSS imports (e.g. import './foo.css') (!chunkCSS === true), the if-else block below should not run and if (s) block should run.


if (config.build.cssCodeSplit) {
if (opts.format === 'es' || opts.format === 'cjs') {
if (isPureCssChunk) {
// this is a shared CSS-only chunk that is empty.
pureCssChunks.add(chunk)
}
if (chunkCSS) {
if (config.build.cssCodeSplit) {
if (opts.format === 'es' || opts.format === 'cjs') {
if (isPureCssChunk) {
// this is a shared CSS-only chunk that is empty.
pureCssChunks.add(chunk)
}

const isEntry = chunk.isEntry && isPureCssChunk
const cssFullAssetName = ensureFileExt(chunk.name, '.css')
// if facadeModuleId doesn't exist or doesn't have a CSS extension,
// that means a JS entry file imports a CSS file.
// in this case, only use the filename for the CSS chunk name like JS chunks.
const cssAssetName =
chunk.isEntry &&
(!chunk.facadeModuleId || !isCSSRequest(chunk.facadeModuleId))
? path.basename(cssFullAssetName)
: cssFullAssetName
const originalFilename = getChunkOriginalFileName(
chunk,
config.root,
opts.format,
)
const isEntry = chunk.isEntry && isPureCssChunk
const cssFullAssetName = ensureFileExt(chunk.name, '.css')
// if facadeModuleId doesn't exist or doesn't have a CSS extension,
// that means a JS entry file imports a CSS file.
// in this case, only use the filename for the CSS chunk name like JS chunks.
const cssAssetName =
chunk.isEntry &&
(!chunk.facadeModuleId || !isCSSRequest(chunk.facadeModuleId))
? path.basename(cssFullAssetName)
: cssFullAssetName
const originalFilename = getChunkOriginalFileName(
chunk,
config.root,
opts.format,
)

chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssAssetName)
chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssAssetName)

// wait for previous tasks as well
chunkCSS = await codeSplitEmitQueue.run(async () => {
return finalizeCss(chunkCSS, true, config)
})
// wait for previous tasks as well
chunkCSS = await codeSplitEmitQueue.run(async () => {
return finalizeCss(chunkCSS, true, config)
})

// emit corresponding css file
const referenceId = this.emitFile({
name: cssAssetName,
type: 'asset',
source: chunkCSS,
})
generatedAssets
.get(config)!
.set(referenceId, { originalName: originalFilename, isEntry })
chunk.viteMetadata!.importedCss.add(this.getFileName(referenceId))
} else if (!config.build.ssr) {
// legacy build and inline css

// Entry chunk CSS will be collected into `chunk.viteMetadata.importedCss`
// and injected later by the `'vite:build-html'` plugin into the `index.html`
// so it will be duplicated. (https://github.com/vitejs/vite/issues/2062#issuecomment-782388010)
// But because entry chunk can be imported by dynamic import,
// we shouldn't remove the inlined CSS. (#10285)

chunkCSS = await finalizeCss(chunkCSS, true, config)
let cssString = JSON.stringify(chunkCSS)
cssString =
renderAssetUrlInJS(
this,
config,
chunk,
opts,
cssString,
)?.toString() || cssString
const style = `__vite_style__`
const injectCode =
`var ${style} = document.createElement('style');` +
`${style}.textContent = ${cssString};` +
`document.head.appendChild(${style});`
let injectionPoint
const wrapIdx = code.indexOf('System.register')
if (wrapIdx >= 0) {
const executeFnStart = code.indexOf('execute:', wrapIdx)
injectionPoint = code.indexOf('{', executeFnStart) + 1
} else {
const insertMark = "'use strict';"
injectionPoint = code.indexOf(insertMark) + insertMark.length
// emit corresponding css file
const referenceId = this.emitFile({
name: cssAssetName,
type: 'asset',
source: chunkCSS,
})
generatedAssets
.get(config)!
.set(referenceId, { originalName: originalFilename, isEntry })
chunk.viteMetadata!.importedCss.add(this.getFileName(referenceId))
} else if (!config.build.ssr) {
// legacy build and inline css

// Entry chunk CSS will be collected into `chunk.viteMetadata.importedCss`
// and injected later by the `'vite:build-html'` plugin into the `index.html`
// so it will be duplicated. (https://github.com/vitejs/vite/issues/2062#issuecomment-782388010)
// But because entry chunk can be imported by dynamic import,
// we shouldn't remove the inlined CSS. (#10285)

chunkCSS = await finalizeCss(chunkCSS, true, config)
let cssString = JSON.stringify(chunkCSS)
cssString =
renderAssetUrlInJS(
this,
config,
chunk,
opts,
cssString,
)?.toString() || cssString
const style = `__vite_style__`
const injectCode =
`var ${style} = document.createElement('style');` +
`${style}.textContent = ${cssString};` +
`document.head.appendChild(${style});`
let injectionPoint
const wrapIdx = code.indexOf('System.register')
if (wrapIdx >= 0) {
const executeFnStart = code.indexOf('execute:', wrapIdx)
injectionPoint = code.indexOf('{', executeFnStart) + 1
} else {
const insertMark = "'use strict';"
injectionPoint = code.indexOf(insertMark) + insertMark.length
}
s ||= new MagicString(code)
s.appendRight(injectionPoint, injectCode)
}
s ||= new MagicString(code)
s.appendRight(injectionPoint, injectCode)
}
} else {
// resolve public URL from CSS paths, we need to use absolute paths
chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssBundleName)
// finalizeCss is called for the aggregated chunk in generateBundle
} else {
// resolve public URL from CSS paths, we need to use absolute paths
chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssBundleName)
// finalizeCss is called for the aggregated chunk in generateBundle

chunkCSSMap.set(chunk.fileName, chunkCSS)
chunkCSSMap.set(chunk.fileName, chunkCSS)
}
}

if (s) {
Expand Down