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; +--- + + + + + + + + {title} + + + + + + + + + diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/PageLayout.astro b/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/PageLayout.astro new file mode 100644 index 000000000..b1b4514ca --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/layouts/PageLayout.astro @@ -0,0 +1,12 @@ +--- +import BaseLayout from "./BaseLayout.astro" +import "../styles/page-one.css" + +const {title} = Astro.props; +--- + + +
+ +
+
diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-1.astro b/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-1.astro new file mode 100644 index 000000000..cd20c6b36 --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-1.astro @@ -0,0 +1,8 @@ +--- +import PageLayout from "../layouts/PageLayout.astro" +--- + + +

Page 1

+

Nothing to see here. Check Page 2

+
diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-2.astro b/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-2.astro new file mode 100644 index 000000000..1df7e4353 --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/pages/page-2.astro @@ -0,0 +1,13 @@ +--- +import PageLayout from "../layouts/PageLayout.astro" +import "../styles/page-two.css" +--- + + +

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.

+
diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-one.css b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-one.css new file mode 100644 index 000000000..ce7da0463 --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-one.css @@ -0,0 +1,3 @@ +p { + color: blue; +} diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-two.css b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-two.css new file mode 100644 index 000000000..87002430a --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/page-two.css @@ -0,0 +1,3 @@ +p { + color: green; +} diff --git a/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/site.css b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/site.css new file mode 100644 index 000000000..47a8192ee --- /dev/null +++ b/packages/astro/test/fixtures/astro-css-bundling-import/src/styles/site.css @@ -0,0 +1,7 @@ +p { + color: red; +} + +h1 { + outline: 1px solid red; +}