diff --git a/packages/astro/src/vite-plugin-build-css/index.ts b/packages/astro/src/vite-plugin-build-css/index.ts index 3cc4676810..a38ffc731e 100644 --- a/packages/astro/src/vite-plugin-build-css/index.ts +++ b/packages/astro/src/vite-plugin-build-css/index.ts @@ -72,123 +72,128 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] const CSS_PLUGIN_NAME = '@astrojs/rollup-plugin-build-css'; const CSS_MINIFY_PLUGIN_NAME = '@astrojs/rollup-plugin-build-css-minify'; - return [{ - name: CSS_PLUGIN_NAME, + return [ + { + name: CSS_PLUGIN_NAME, - configResolved(resolvedConfig) { - // Our plugin needs to run before `vite:css-post` because we have to modify - // The bundles before vite:css-post sees them. We can remove this code - // after this bug is fixed: https://github.com/vitejs/vite/issues/8330 - const plugins = resolvedConfig.plugins as VitePlugin[]; - const viteCSSPostIndex = resolvedConfig.plugins.findIndex((p) => p.name === 'vite:css-post'); - if (viteCSSPostIndex !== -1) { - // Move our plugin to be right before this one. - const ourIndex = plugins.findIndex((p) => p.name === CSS_PLUGIN_NAME); - const ourPlugin = plugins[ourIndex]; + configResolved(resolvedConfig) { + // Our plugin needs to run before `vite:css-post` because we have to modify + // The bundles before vite:css-post sees them. We can remove this code + // after this bug is fixed: https://github.com/vitejs/vite/issues/8330 + const plugins = resolvedConfig.plugins as VitePlugin[]; + const viteCSSPostIndex = resolvedConfig.plugins.findIndex( + (p) => p.name === 'vite:css-post' + ); + if (viteCSSPostIndex !== -1) { + // Move our plugin to be right before this one. + const ourIndex = plugins.findIndex((p) => p.name === CSS_PLUGIN_NAME); + const ourPlugin = plugins[ourIndex]; - // Remove us from where we are now and place us right before the viteCSSPost plugin - plugins.splice(ourIndex, 1); - plugins.splice(viteCSSPostIndex - 1, 0, ourPlugin); - } - }, - - outputOptions(outputOptions) { - const manualChunks = outputOptions.manualChunks || Function.prototype; - outputOptions.manualChunks = function (id, ...args) { - // Defer to user-provided `manualChunks`, if it was provided. - if (typeof manualChunks == 'object') { - if (id in manualChunks) { - return manualChunks[id]; - } - } else if (typeof manualChunks === 'function') { - const outid = manualChunks.call(this, id, ...args); - if (outid) { - return outid; - } + // Remove us from where we are now and place us right before the viteCSSPost plugin + plugins.splice(ourIndex, 1); + plugins.splice(viteCSSPostIndex - 1, 0, ourPlugin); } + }, - // For CSS, create a hash of all of the pages that use it. - // This causes CSS to be built into shared chunks when used by multiple pages. - if (isCSSRequest(id)) { - return createHashOfPageParents(id, args[0]); - } - }; - }, + outputOptions(outputOptions) { + const manualChunks = outputOptions.manualChunks || Function.prototype; + outputOptions.manualChunks = function (id, ...args) { + // Defer to user-provided `manualChunks`, if it was provided. + if (typeof manualChunks == 'object') { + if (id in manualChunks) { + return manualChunks[id]; + } + } else if (typeof manualChunks === 'function') { + const outid = manualChunks.call(this, id, ...args); + if (outid) { + return outid; + } + } - async generateBundle(_outputOptions, bundle) { - type ViteMetadata = { - importedAssets: Set; - importedCss: Set; - }; + // For CSS, create a hash of all of the pages that use it. + // This causes CSS to be built into shared chunks when used by multiple pages. + if (isCSSRequest(id)) { + return createHashOfPageParents(id, args[0]); + } + }; + }, - for (const [_, chunk] of Object.entries(bundle)) { - if (chunk.type === 'chunk') { - const c = chunk; - if ('viteMetadata' in chunk) { - const meta = chunk['viteMetadata'] as ViteMetadata; + async generateBundle(_outputOptions, bundle) { + type ViteMetadata = { + importedAssets: Set; + importedCss: Set; + }; - // Chunks that have the viteMetadata.importedCss are CSS chunks - if (meta.importedCss.size) { - // For the client build, client:only styles need to be mapped - // over to their page. For this chunk, determine if it's a child of a - // client:only component and if so, add its CSS to the page it belongs to. - if (options.target === 'client') { + for (const [_, chunk] of Object.entries(bundle)) { + if (chunk.type === 'chunk') { + const c = chunk; + if ('viteMetadata' in chunk) { + const meta = chunk['viteMetadata'] as ViteMetadata; + + // Chunks that have the viteMetadata.importedCss are CSS chunks + if (meta.importedCss.size) { + // For the client build, client:only styles need to be mapped + // over to their page. For this chunk, determine if it's a child of a + // client:only component and if so, add its CSS to the page it belongs to. + if (options.target === 'client') { + for (const [id] of Object.entries(c.modules)) { + for (const pageData of getParentClientOnlys(id, this)) { + for (const importedCssImport of meta.importedCss) { + pageData.css.add(importedCssImport); + } + } + } + } + + // For this CSS chunk, walk parents until you find a page. Add the CSS to that page. for (const [id] of Object.entries(c.modules)) { - for (const pageData of getParentClientOnlys(id, this)) { + for (const pageViteID of getTopLevelPages(id, this)) { + const pageData = getPageDataByViteID(internals, pageViteID); for (const importedCssImport of meta.importedCss) { - pageData.css.add(importedCssImport); + pageData?.css.add(importedCssImport); } } } } + } + } - // For this CSS chunk, walk parents until you find a page. Add the CSS to that page. - for (const [id] of Object.entries(c.modules)) { - for (const pageViteID of getTopLevelPages(id, this)) { - const pageData = getPageDataByViteID(internals, pageViteID); - for (const importedCssImport of meta.importedCss) { - pageData?.css.add(importedCssImport); - } - } + if (chunk.type === 'chunk') { + // This simply replaces single quotes with double quotes because the vite:css-post + // plugin only works with single for some reason. This code can be removed + // When the Vite bug is fixed: https://github.com/vitejs/vite/issues/8330 + const exp = new RegExp( + `(\\bimport\\s*)[']([^']*(?:[a-z]+\.[0-9a-z]+\.m?js))['](;\n?)`, + 'g' + ); + chunk.code = chunk.code.replace(exp, (_match, begin, chunkPath, end) => { + return begin + '"' + chunkPath + '"' + end; + }); + } + } + }, + }, + { + name: CSS_MINIFY_PLUGIN_NAME, + enforce: 'post', + async generateBundle(_outputOptions, bundle) { + // Minify CSS in each bundle ourselves, since server builds are not minified + // so that the JS is debuggable. Since you cannot configure vite:css-post to minify + // we need to do it ourselves. + if (options.target === 'server') { + for (const [, output] of Object.entries(bundle)) { + if (output.type === 'asset') { + if (output.name?.endsWith('.css') && typeof output.source === 'string') { + const { code: minifiedCSS } = await esbuild.transform(output.source, { + loader: 'css', + minify: true, + }); + output.source = minifiedCSS; } } } } - - if (chunk.type === 'chunk') { - // This simply replaces single quotes with double quotes because the vite:css-post - // plugin only works with single for some reason. This code can be removed - // When the Vite bug is fixed: https://github.com/vitejs/vite/issues/8330 - const exp = new RegExp( - `(\\bimport\\s*)[']([^']*(?:[a-z]+\.[0-9a-z]+\.m?js))['](;\n?)`, - 'g' - ); - chunk.code = chunk.code.replace(exp, (_match, begin, chunkPath, end) => { - return begin + '"' + chunkPath + '"' + end; - }); - } - } + }, }, - }, { - name: CSS_MINIFY_PLUGIN_NAME, - enforce: 'post', - async generateBundle(_outputOptions, bundle) { - // Minify CSS in each bundle ourselves, since server builds are not minified - // so that the JS is debuggable. Since you cannot configure vite:css-post to minify - // we need to do it ourselves. - if(options.target === 'server') { - for(const [, output] of Object.entries(bundle)) { - if(output.type === 'asset') { - if(output.name?.endsWith('.css') && typeof output.source === 'string') { - const { code: minifiedCSS } = await esbuild.transform(output.source, { - loader: 'css', - minify: true, - }); - output.source = minifiedCSS; - } - } - } - } - } - }]; + ]; }