diff --git a/.changeset/poor-frogs-melt.md b/.changeset/poor-frogs-melt.md new file mode 100644 index 000000000..a07930d29 --- /dev/null +++ b/.changeset/poor-frogs-melt.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix CSS styles on Windows diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts index 5d82a684f..133fc9edd 100644 --- a/packages/astro/src/content/vite-plugin-content-assets.ts +++ b/packages/astro/src/content/vite-plugin-content-assets.ts @@ -64,7 +64,7 @@ export function astroContentAssetPropagationPlugin({ if (!devModuleLoader.getModuleById(basePath)?.ssrModule) { await devModuleLoader.import(basePath); } - const { stylesMap, urls } = await getStylesForURL( + const { styles, urls } = await getStylesForURL( pathToFileURL(basePath), devModuleLoader, 'development' @@ -77,7 +77,7 @@ export function astroContentAssetPropagationPlugin({ ); stringifiedLinks = JSON.stringify([...urls]); - stringifiedStyles = JSON.stringify([...stylesMap.values()]); + stringifiedStyles = JSON.stringify(styles.map((s) => s.content)); stringifiedScripts = JSON.stringify([...hoistedScripts]); } else { // Otherwise, use placeholders to inject styles and scripts diff --git a/packages/astro/src/vite-plugin-astro-server/css.ts b/packages/astro/src/vite-plugin-astro-server/css.ts index d256f48c7..0da51db1e 100644 --- a/packages/astro/src/vite-plugin-astro-server/css.ts +++ b/packages/astro/src/vite-plugin-astro-server/css.ts @@ -4,14 +4,21 @@ import { viteID } from '../core/util.js'; import { isBuildableCSSRequest } from './util.js'; import { crawlGraph } from './vite.js'; +interface ImportedStyle { + id: string; + url: string; + content: string; +} + /** Given a filePath URL, crawl Vite’s module graph to find all style imports. */ export async function getStylesForURL( filePath: URL, loader: ModuleLoader, mode: RuntimeMode -): Promise<{ urls: Set; stylesMap: Map }> { +): Promise<{ urls: Set; styles: ImportedStyle[] }> { const importedCssUrls = new Set(); - const importedStylesMap = new Map(); + // Map of url to injected style object. Use a `url` key to deduplicate styles + const importedStylesMap = new Map(); for await (const importedModule of crawlGraph(loader, viteID(filePath), true)) { if (isBuildableCSSRequest(importedModule.url)) { @@ -28,7 +35,11 @@ export async function getStylesForURL( mode === 'development' && // only inline in development typeof ssrModule?.default === 'string' // ignore JS module styles ) { - importedStylesMap.set(importedModule.id ?? importedModule.url, ssrModule.default); + importedStylesMap.set(importedModule.url, { + id: importedModule.id ?? importedModule.url, + url: importedModule.url, + content: ssrModule.default, + }); } else { // NOTE: We use the `url` property here. `id` would break Windows. importedCssUrls.add(importedModule.url); @@ -38,6 +49,6 @@ export async function getStylesForURL( return { urls: importedCssUrls, - stylesMap: importedStylesMap, + styles: [...importedStylesMap.values()], }; } diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 34ab119da..069c2ffe8 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -293,7 +293,11 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa } // Pass framework CSS in as style tags to be appended to the page. - const { urls: styleUrls, stylesMap } = await getStylesForURL(filePath, moduleLoader, mode); + const { urls: styleUrls, styles: importedStyles } = await getStylesForURL( + filePath, + moduleLoader, + mode + ); let links = new Set(); [...styleUrls].forEach((href) => { links.add({ @@ -306,7 +310,7 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa }); let styles = new Set(); - [...stylesMap].forEach(([url, content]) => { + importedStyles.forEach(({ id, url, content }) => { // Vite handles HMR for styles injected as scripts scripts.add({ props: { @@ -319,7 +323,7 @@ async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesPa // should emulate what Vite injects so further HMR works as expected. styles.add({ props: { - 'data-vite-dev-id': url, + 'data-vite-dev-id': id, }, children: content, });