diff --git a/.changeset/three-cooks-drive.md b/.changeset/three-cooks-drive.md new file mode 100644 index 000000000000..90d71321c792 --- /dev/null +++ b/.changeset/three-cooks-drive.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Replaces internal CSS chunking behavior for Astro components' scoped styles to use Vite's `cssScopeTo` feature. The feature is a port of Astro's implementation so this should not change the behavior. diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts index c39d4da6f08f..d985a6a5311a 100644 --- a/packages/astro/src/core/build/plugins/plugin-css.ts +++ b/packages/astro/src/core/build/plugins/plugin-css.ts @@ -1,12 +1,11 @@ import type { GetModuleInfo } from 'rollup'; -import type { BuildOptions, ResolvedConfig, Rollup, Plugin as VitePlugin } from 'vite'; +import type { BuildOptions, ResolvedConfig, Plugin as VitePlugin } from 'vite'; import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js'; import type { BuildInternals } from '../internal.js'; import type { AstroBuildPlugin, BuildTarget } from '../plugin.js'; import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types.js'; import { hasAssetPropagationFlag } from '../../../content/index.js'; -import type { AstroPluginCssMetadata } from '../../../vite-plugin-astro/index.js'; import * as assetName from '../css-asset-name.js'; import { getParentExtendedModuleInfos, @@ -156,32 +155,6 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] { }, }; - /** - * This plugin is a port of https://github.com/vitejs/vite/pull/16058. It enables removing unused - * scoped CSS from the bundle if the scoped target (e.g. Astro files) were not bundled. - * Once/If that PR is merged, we can refactor this away, renaming `meta.astroCss` to `meta.vite`. - */ - const cssScopeToPlugin: VitePlugin = { - name: 'astro:rollup-plugin-css-scope-to', - renderChunk(_, chunk, __, meta) { - for (const id in chunk.modules) { - // If this CSS is scoped to its importers exports, check if those importers exports - // are rendered in the chunks. If they are not, we can skip bundling this CSS. - const modMeta = this.getModuleInfo(id)?.meta as AstroPluginCssMetadata | undefined; - const cssScopeTo = modMeta?.astroCss?.cssScopeTo; - if (cssScopeTo && !isCssScopeToRendered(cssScopeTo, Object.values(meta.chunks))) { - // If this CSS is not used, delete it from the chunk modules so that Vite is unable - // to trace that it's used - delete chunk.modules[id]; - const moduleIdsIndex = chunk.moduleIds.indexOf(id); - if (moduleIdsIndex > -1) { - chunk.moduleIds.splice(moduleIdsIndex, 1); - } - } - } - }, - }; - const singleCssPlugin: VitePlugin = { name: 'astro:rollup-plugin-single-css', enforce: 'post', @@ -273,7 +246,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] { }, }; - return [cssBuildPlugin, cssScopeToPlugin, singleCssPlugin, inlineStylesheetsPlugin]; + return [cssBuildPlugin, singleCssPlugin, inlineStylesheetsPlugin]; } /***** UTILITY FUNCTIONS *****/ @@ -321,25 +294,3 @@ function appendCSSToPage( } } } - -/** - * `cssScopeTo` is a map of `importer`s to its `export`s. This function iterate each `cssScopeTo` entries - * and check if the `importer` and its `export`s exists in the final chunks. If at least one matches, - * `cssScopeTo` is considered "rendered" by Rollup and we return true. - */ -function isCssScopeToRendered( - cssScopeTo: Record, - chunks: Rollup.RenderedChunk[], -) { - for (const moduleId in cssScopeTo) { - const exports = cssScopeTo[moduleId]; - // Find the chunk that renders this `moduleId` and get the rendered module - const renderedModule = chunks.find((c) => c.moduleIds.includes(moduleId))?.modules[moduleId]; - // Return true if `renderedModule` exists and one of its exports is rendered - if (renderedModule?.renderedExports.some((e) => exports.includes(e))) { - return true; - } - } - - return false; -} diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index 21d9dcfb1486..8edbc98ae31c 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -2,11 +2,7 @@ import type { SourceDescription } from 'rollup'; import type * as vite from 'vite'; import type { Logger } from '../core/logger/core.js'; import type { AstroSettings } from '../types/astro.js'; -import type { - PluginCssMetadata as AstroPluginCssMetadata, - PluginMetadata as AstroPluginMetadata, - CompileMetadata, -} from './types.js'; +import type { PluginMetadata as AstroPluginMetadata, CompileMetadata } from './types.js'; import { defaultClientConditions, defaultServerConditions, normalizePath } from 'vite'; import type { AstroConfig } from '../types/public/config.js'; @@ -16,7 +12,7 @@ import { handleHotUpdate } from './hmr.js'; import { parseAstroRequest } from './query.js'; import { loadId } from './utils.js'; export { getAstroMetadata } from './metadata.js'; -export type { AstroPluginMetadata, AstroPluginCssMetadata }; +export type { AstroPluginMetadata }; interface AstroPluginOptions { settings: AstroSettings; @@ -138,17 +134,15 @@ export default function astro({ settings, logger }: AstroPluginOptions): vite.Pl return { code: result.code, - // This metadata is used by `cssScopeToPlugin` to remove this module from the bundle - // if the `filename` default export (the Astro component) is unused. + // `vite.cssScopeTo` is a Vite feature that allows this CSS to be treeshaken + // if the Astro component's default export is not used meta: result.isGlobal ? undefined - : ({ - astroCss: { - cssScopeTo: { - [filename]: ['default'], - }, + : { + vite: { + cssScopeTo: [filename, 'default'], }, - } satisfies AstroPluginCssMetadata), + }, }; } case 'script': { diff --git a/packages/astro/src/vite-plugin-astro/types.ts b/packages/astro/src/vite-plugin-astro/types.ts index 09d2e8b52e4b..0cb0c70c0799 100644 --- a/packages/astro/src/vite-plugin-astro/types.ts +++ b/packages/astro/src/vite-plugin-astro/types.ts @@ -18,27 +18,6 @@ export interface PluginMetadata { }; } -export interface PluginCssMetadata { - astroCss: { - /** - * For Astro CSS virtual modules, it can scope to the main Astro module's default export - * so that if those exports are treeshaken away, the CSS module will also be treeshaken. - * - * Example config if the CSS id is `/src/Foo.astro?astro&type=style&lang.css`: - * ```js - * cssScopeTo: { - * '/src/Foo.astro': ['default'] - * } - * ``` - * - * The above is the only config we use today, but we're exposing as a `Record` to follow the - * upstream Vite implementation: https://github.com/vitejs/vite/pull/16058. When/If that lands, - * we can also remove our custom implementation. - */ - cssScopeTo: Record; - }; -} - export interface CompileMetadata { /** Used for HMR to compare code changes */ originalCode: string;