summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-09-28 18:12:22 -0400
committerGravatar GitHub <noreply@github.com> 2022-09-28 18:12:22 -0400
commit01c1aaa00397c7fdc7a3ef7fb0212eb43aad6238 (patch)
tree1a14d4e85149112859643127e5aa475ead22ce49
parent55a1b5bb58a07cbf6d86818c28c199751bde03b5 (diff)
downloadastro-01c1aaa00397c7fdc7a3ef7fb0212eb43aad6238.tar.gz
astro-01c1aaa00397c7fdc7a3ef7fb0212eb43aad6238.tar.zst
astro-01c1aaa00397c7fdc7a3ef7fb0212eb43aad6238.zip
Fix CSS ordering between imported and Astro styles (#4907)
* Fix CSS ordering between imported and Astro styles * Fix linting errors * Add changeset and upgrade compiler version * Update test to reflect shared styles placed before page styles
-rw-r--r--.changeset/small-bugs-prove.md34
-rw-r--r--packages/astro/package.json2
-rw-r--r--packages/astro/test/css-order-import.test.js114
-rw-r--r--packages/astro/test/css-order.test.js5
-rw-r--r--packages/astro/test/fixtures/css-order-import/package.json6
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/components/One.astro4
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/components/Two.astro5
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/pages/component.astro19
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/pages/index.astro16
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/styles/One.css3
-rw-r--r--packages/astro/test/fixtures/css-order-import/src/styles/base.css3
-rw-r--r--pnpm-lock.yaml14
12 files changed, 218 insertions, 7 deletions
diff --git a/.changeset/small-bugs-prove.md b/.changeset/small-bugs-prove.md
new file mode 100644
index 000000000..16a89271d
--- /dev/null
+++ b/.changeset/small-bugs-prove.md
@@ -0,0 +1,34 @@
+---
+'astro': minor
+---
+
+Order Astro styles last, to override imported styles
+
+This fixes CSS ordering so that imported styles are placed *higher* than page/component level styles. This means that if you do:
+
+```astro
+---
+import '../styles/global.css';
+---
+<style>
+ body {
+ background: limegreen;
+ }
+</style>
+```
+
+The `<style>` defined in this component will be placed *below* the imported CSS. When compiled for production this will result in something like this:
+
+```css
+/* /src/styles/global.css */
+body {
+ background: blue;
+}
+
+/* /src/pages/index.astro */
+body:where(.astro-12345) {
+ background: limegreen;
+}
+```
+
+Given Astro's 0-specificity hashing, this change effectively makes it so that Astro styles "win" when they have the same specificity as global styles.
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 0a39c75e1..de6483e9d 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -95,7 +95,7 @@
"test:e2e:match": "playwright test -g"
},
"dependencies": {
- "@astrojs/compiler": "^0.24.0",
+ "@astrojs/compiler": "^0.25.0",
"@astrojs/language-server": "^0.26.2",
"@astrojs/markdown-remark": "^1.1.2",
"@astrojs/telemetry": "^1.0.0",
diff --git a/packages/astro/test/css-order-import.test.js b/packages/astro/test/css-order-import.test.js
new file mode 100644
index 000000000..91cecadab
--- /dev/null
+++ b/packages/astro/test/css-order-import.test.js
@@ -0,0 +1,114 @@
+import { expect } from 'chai';
+import * as cheerio from 'cheerio';
+import { loadFixture } from './test-utils.js';
+
+describe('CSS ordering - import order', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/css-order-import/',
+ });
+ });
+
+ /**
+ *
+ * @param {string} html
+ * @returns {string[]}
+ */
+ function getLinks(html) {
+ let $ = cheerio.load(html);
+ let out = [];
+ $('link[rel=stylesheet]').each((i, el) => {
+ out.push($(el).attr('href'));
+ });
+ return out;
+ }
+
+ function getStyles(html) {
+ let $ = cheerio.load(html);
+ let out = [];
+ $('style').each((i, el) => {
+ out.push($(el).text());
+ });
+ return out;
+ }
+
+ /**
+ *
+ * @param {string} href
+ * @returns {Promise<{ href: string; css: string; }>}
+ */
+ async function getLinkContent(href) {
+ const css = await fixture.readFile(href);
+ return { href, css };
+ }
+
+ describe('Development', () => {
+ /** @type {import('./test-utils').DevServer} */
+ let devServer;
+
+ before(async () => {
+ devServer = await fixture.startDevServer();
+ });
+
+ after(async () => {
+ await devServer.stop();
+ });
+
+ it('Page level CSS is defined lower in the page', async () => {
+ let res = await fixture.fetch('/');
+ let html = await res.text();
+ let [style1, style2] = getStyles(html);
+
+ expect(style1).to.include('green');
+ expect(style2).to.include('salmon');
+ });
+
+ it('import order is depth-first', async () => {
+ let res = await fixture.fetch('/component/');
+ let html = await res.text();
+ let [style1, style2, style3] = getStyles(html);
+
+ expect(style1).to.include('burlywood');
+ expect(style2).to.include('aliceblue');
+ expect(style3).to.include('whitesmoke');
+ });
+ });
+
+ describe('Production', () => {
+ before(async () => {
+ await fixture.build();
+ });
+
+ it('Page level CSS is defined lower in the page', async () => {
+ let html = await fixture.readFile('/index.html');
+
+ const content = await Promise.all(
+ getLinks(html).map((href) => getLinkContent(href))
+ );
+
+ const [{ css }] = content;
+ let idx1 = css.indexOf('salmon');
+ let idx2 = css.indexOf('green');
+
+ expect(idx1).to.be.greaterThan(idx2, 'Page level CSS should be placed after imported CSS');
+ });
+
+ it('import order is depth-first', async () => {
+ let html = await fixture.readFile('/component/index.html');
+
+ const content = await Promise.all(
+ getLinks(html).map((href) => getLinkContent(href))
+ );
+
+ const [{ css }] = content;
+ let idx1 = css.indexOf('whitesmoke');
+ let idx2 = css.indexOf('aliceblue');
+ let idx3 = css.indexOf('burlywood');
+
+ expect(idx1).to.be.greaterThan(idx2);
+ expect(idx2).to.be.greaterThan(idx3);
+ });
+ });
+});
diff --git a/packages/astro/test/css-order.test.js b/packages/astro/test/css-order.test.js
index fbcd580dd..e3333b875 100644
--- a/packages/astro/test/css-order.test.js
+++ b/packages/astro/test/css-order.test.js
@@ -87,9 +87,10 @@ describe('CSS production ordering', () => {
);
expect(content).to.have.a.lengthOf(3, 'there are 3 stylesheets');
- const [, found] = content;
+ const [, sharedStyles, pageStyles] = content;
- expect(found.css).to.match(/#00f/);
+ expect(sharedStyles.css).to.match(/red/);
+ expect(pageStyles.css).to.match(/#00f/);
});
it('CSS injected by injectScript comes first because of import order', async () => {
diff --git a/packages/astro/test/fixtures/css-order-import/package.json b/packages/astro/test/fixtures/css-order-import/package.json
new file mode 100644
index 000000000..2901a838f
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@test/css-order-import",
+ "dependencies": {
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/test/fixtures/css-order-import/src/components/One.astro b/packages/astro/test/fixtures/css-order-import/src/components/One.astro
new file mode 100644
index 000000000..54b1039b1
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/components/One.astro
@@ -0,0 +1,4 @@
+---
+import '../styles/One.css';
+---
+<link>
diff --git a/packages/astro/test/fixtures/css-order-import/src/components/Two.astro b/packages/astro/test/fixtures/css-order-import/src/components/Two.astro
new file mode 100644
index 000000000..1afb0ef87
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/components/Two.astro
@@ -0,0 +1,5 @@
+<style>
+ body {
+ background: aliceblue;
+ }
+</style>
diff --git a/packages/astro/test/fixtures/css-order-import/src/pages/component.astro b/packages/astro/test/fixtures/css-order-import/src/pages/component.astro
new file mode 100644
index 000000000..018ab1866
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/pages/component.astro
@@ -0,0 +1,19 @@
+---
+import One from '../components/One.astro';
+import Two from '../components/Two.astro';
+---
+<html>
+<head>
+ <title>Test</title>
+ <One />
+ <Two />
+ <style>
+ body {
+ background: whitesmoke;
+ }
+ </style>
+</head>
+<body>
+ <h1>Test</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/css-order-import/src/pages/index.astro b/packages/astro/test/fixtures/css-order-import/src/pages/index.astro
new file mode 100644
index 000000000..0843250c0
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/pages/index.astro
@@ -0,0 +1,16 @@
+---
+import '../styles/base.css';
+---
+<html>
+<head>
+ <title>Test</title>
+ <style>
+ body {
+ background: salmon;
+ }
+ </style>
+</head>
+<body>
+ <h1>Test</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/css-order-import/src/styles/One.css b/packages/astro/test/fixtures/css-order-import/src/styles/One.css
new file mode 100644
index 000000000..66d2bb71b
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/styles/One.css
@@ -0,0 +1,3 @@
+body {
+ background: burlywood;
+}
diff --git a/packages/astro/test/fixtures/css-order-import/src/styles/base.css b/packages/astro/test/fixtures/css-order-import/src/styles/base.css
new file mode 100644
index 000000000..828bff206
--- /dev/null
+++ b/packages/astro/test/fixtures/css-order-import/src/styles/base.css
@@ -0,0 +1,3 @@
+body {
+ background: green;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index aaeec592c..67b08ecc1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -349,7 +349,7 @@ importers:
packages/astro:
specifiers:
- '@astrojs/compiler': ^0.24.0
+ '@astrojs/compiler': ^0.25.0
'@astrojs/language-server': ^0.26.2
'@astrojs/markdown-remark': ^1.1.2
'@astrojs/telemetry': ^1.0.0
@@ -443,7 +443,7 @@ importers:
yargs-parser: ^21.0.1
zod: ^3.17.3
dependencies:
- '@astrojs/compiler': 0.24.0
+ '@astrojs/compiler': 0.25.0
'@astrojs/language-server': 0.26.2
'@astrojs/markdown-remark': link:../markdown/remark
'@astrojs/telemetry': link:../telemetry
@@ -1584,6 +1584,12 @@ importers:
dependencies:
astro: link:../../..
+ packages/astro/test/fixtures/css-order-import:
+ specifiers:
+ astro: workspace:*
+ dependencies:
+ astro: link:../../..
+
packages/astro/test/fixtures/custom-404:
specifiers:
astro: workspace:*
@@ -3639,8 +3645,8 @@ packages:
resolution: {integrity: sha512-vBMPy9ok4iLapSyCCT1qsZ9dK7LkVFl9mObtLEmWiec9myGHS9h2kQY2xzPeFNJiWXUf9O6tSyQpQTy5As/p3g==}
dev: false
- /@astrojs/compiler/0.24.0:
- resolution: {integrity: sha512-xZ81C/oMfExdF18I1Tyd2BKKzBqO+qYYctSy4iCwH4UWSo/4Y8A8MAzV1hG67uuE7hFRourSl6H5KUbhyChv/A==}
+ /@astrojs/compiler/0.25.0:
+ resolution: {integrity: sha512-thJdIFuKT7f6uzxUs5d7qjh3g/L4kmlSfddAcbC62QEMy4H9N9fig3+FBwg9exUvXYcqOjZ/nC2PsGsVIqmZYA==}
dev: false
/@astrojs/language-server/0.26.2: