diff --git a/.changeset/bright-ravens-remain.md b/.changeset/bright-ravens-remain.md new file mode 100644 index 000000000..77afdfbdc --- /dev/null +++ b/.changeset/bright-ravens-remain.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Bugfix: improve CSS import order diff --git a/packages/astro/src/vite-plugin-build-css/index.ts b/packages/astro/src/vite-plugin-build-css/index.ts index 0aaf3d41f..d46f56d13 100644 --- a/packages/astro/src/vite-plugin-build-css/index.ts +++ b/packages/astro/src/vite-plugin-build-css/index.ts @@ -94,11 +94,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { async load(id) { if (isPageStyleVirtualModule(id)) { - const source = astroPageStyleMap.get(id)!; - return source; + return astroPageStyleMap.get(id) || null; } if (isStyleVirtualModule(id)) { - return astroStyleMap.get(id)!; + return astroStyleMap.get(id) || null; } return null; }, @@ -106,13 +105,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { async transform(value, id) { if (isStyleVirtualModule(id)) { styleSourceMap.set(id, value); - return null; } - if (isCSSRequest(id)) { styleSourceMap.set(id, value); } - return null; }, diff --git a/packages/astro/src/vite-plugin-build-html/index.ts b/packages/astro/src/vite-plugin-build-html/index.ts index 139cc4051..cabc5e0bd 100644 --- a/packages/astro/src/vite-plugin-build-html/index.ts +++ b/packages/astro/src/vite-plugin-build-html/index.ts @@ -256,11 +256,10 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin { // Create a mapping of chunks to dependent chunks, used to add the proper // link tags for CSS. for (const chunk of pureCSSChunks) { - const referenceId = chunkToReferenceIdMap.get(chunk.fileName)!; - const chunkReferenceIds = [referenceId]; - for (const imp of chunk.imports) { - if (chunkToReferenceIdMap.has(imp)) { - chunkReferenceIds.push(chunkToReferenceIdMap.get(imp)!); + const chunkReferenceIds: string[] = []; + for (const [specifier, chunkRefID] of chunkToReferenceIdMap.entries()) { + if (chunk.imports.includes(specifier) || specifier === chunk.fileName) { + chunkReferenceIds.push(chunkRefID); } } for (const [id] of Object.entries(chunk.modules)) { diff --git a/packages/astro/test/astro-css-bundling-import.test.js b/packages/astro/test/astro-css-bundling-import.test.js new file mode 100644 index 000000000..66ecc8119 --- /dev/null +++ b/packages/astro/test/astro-css-bundling-import.test.js @@ -0,0 +1,50 @@ +import { expect } from 'chai'; +import cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; + +describe('CSS Bundling (ESM import)', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ projectRoot: './fixtures/astro-css-bundling-import/' }); + await fixture.build(); + }); + + it('CSS output in import order', async () => { + // note: this test is a little confusing, but the main idea is that + // page-2.astro contains all of page-1.astro, plus some unique styles. + // we only test page-2 to ensure the proper order is observed. + const html = await fixture.readFile('/page-2/index.html'); + const $ = cheerio.load(html); + + let css = ''; + + for (const style of $('link[rel=stylesheet]')) { + const href = style.attribs.href.replace(/^\.\./, ''); + if (!href) continue; + css += await fixture.readFile(href); + } + + // test 1: insure green comes after red (site.css) + expect(css.indexOf('p{color:green}')).to.be.greaterThan(css.indexOf('p{color:red}')); + + // test 2: insure green comes after blue (page-1.css) + expect(css.indexOf('p{color:green}')).to.be.greaterThan(css.indexOf('p{color:red}')); + }); + + // TODO: need more investigation to fix this + it.skip('no empty CSS files', async () => { + for (const page of ['/page-1/index.html', '/page-2/index.html']) { + const html = await fixture.readFile(page); + const $ = cheerio.load(html); + + for (const style of $('link[rel=stylesheet]')) { + const href = style.attribs.href.replace(/^\.\./, ''); + if (!href) continue; + const css = await fixture.readFile(href); + + expect(css).to.be.ok; + } + } + }); +}); diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/BaseLayout.astro b/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/BaseLayout.astro new file mode 100644 index 000000000..bcede331f --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/BaseLayout.astro @@ -0,0 +1,27 @@ +--- +import "../styles/site.css" + +const {title} = Astro.props; +--- + + + +
+ + + +Nothing to see here. Check Page 2
+This text should be green, because we want page-2.css
to override site.css
This works in the dev-server. However in the prod build, the text is blue. Execute npm run build
and then execute npx http-server dist/
.
We can view the built html at https://github-qoihup--8080.local.webcontainer.io/page-2/. The color there is blue.
+ +If it helps debug the issue, rename the page-1.astro
file to page-1.astro.bak
. Build the prod site and view it. This time the color is green.