From 65216ef921d0f080d9a4995b0d8ebaf653ee3bfa Mon Sep 17 00:00:00 2001 From: Drew Powers <1369770+drwpow@users.noreply.github.com> Date: Mon, 15 Nov 2021 14:16:07 -0700 Subject: [PATCH] Fix PostCSS (and Autoprefixer) processing (#1837) * Fix PostCSS processing * Skip Windows tests (for now) --- .changeset/twenty-rabbits-repeat.md | 5 ++ docs/src/pages/guides/styling.md | 6 +- packages/astro/package.json | 1 + packages/astro/src/core/ssr/css.ts | 1 - packages/astro/src/core/util.ts | 4 +- packages/astro/src/vite-plugin-astro/index.ts | 4 +- .../astro/src/vite-plugin-astro/styles.ts | 9 ++- .../test/fixtures/postcss/postcss.config.cjs | 7 +++ .../test/fixtures/postcss/public/global.css | 3 + .../postcss/src/components/Astro.astro | 9 +++ .../fixtures/postcss/src/components/Solid.css | 3 + .../fixtures/postcss/src/components/Solid.jsx | 10 +++ .../postcss/src/components/Svelte.svelte | 9 +++ .../fixtures/postcss/src/components/Vue.vue | 12 ++++ .../fixtures/postcss/src/pages/index.astro | 24 ++++++++ .../fixtures/postcss/src/styles/linked.css | 3 + packages/astro/test/postcss.test.js | 61 +++++++++++++++++++ yarn.lock | 5 ++ 18 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 .changeset/twenty-rabbits-repeat.md create mode 100644 packages/astro/test/fixtures/postcss/postcss.config.cjs create mode 100644 packages/astro/test/fixtures/postcss/public/global.css create mode 100644 packages/astro/test/fixtures/postcss/src/components/Astro.astro create mode 100644 packages/astro/test/fixtures/postcss/src/components/Solid.css create mode 100644 packages/astro/test/fixtures/postcss/src/components/Solid.jsx create mode 100644 packages/astro/test/fixtures/postcss/src/components/Svelte.svelte create mode 100644 packages/astro/test/fixtures/postcss/src/components/Vue.vue create mode 100644 packages/astro/test/fixtures/postcss/src/pages/index.astro create mode 100644 packages/astro/test/fixtures/postcss/src/styles/linked.css create mode 100644 packages/astro/test/postcss.test.js diff --git a/.changeset/twenty-rabbits-repeat.md b/.changeset/twenty-rabbits-repeat.md new file mode 100644 index 000000000..4c39ad433 --- /dev/null +++ b/.changeset/twenty-rabbits-repeat.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Bugfix: PostCSS not working in all contexts diff --git a/docs/src/pages/guides/styling.md b/docs/src/pages/guides/styling.md index a42d759df..550ddd5f9 100644 --- a/docs/src/pages/guides/styling.md +++ b/docs/src/pages/guides/styling.md @@ -129,8 +129,10 @@ It’s recommended to only use this in scenarios where a `` tag won’t wo ```js // postcss.config.cjs module.exports = { - autoprefixer: { - /* (optional) autoprefixer settings */ + plugins: { + autoprefixer: { + /* (optional) autoprefixer settings */ + }, }, }; ``` diff --git a/packages/astro/package.json b/packages/astro/package.json index 6729aad1c..134011378 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -70,6 +70,7 @@ "astring": "^1.7.5", "ci-info": "^3.2.0", "connect": "^3.7.0", + "eol": "^0.9.1", "es-module-lexer": "^0.7.1", "esbuild": "^0.13.6", "estree-util-value-to-estree": "^1.2.0", diff --git a/packages/astro/src/core/ssr/css.ts b/packages/astro/src/core/ssr/css.ts index 9fba52fca..28fcbafd8 100644 --- a/packages/astro/src/core/ssr/css.ts +++ b/packages/astro/src/core/ssr/css.ts @@ -4,7 +4,6 @@ import path from 'path'; // https://vitejs.dev/guide/features.html#css-pre-processors export const STYLE_EXTENSIONS = new Set(['.css', '.pcss', '.scss', '.sass', '.styl', '.stylus', '.less']); -export const PREPROCESSOR_EXTENSIONS = new Set(['.pcss', '.scss', '.sass', '.styl', '.stylus', '.less']); /** find unloaded styles */ export function getStylesForID(id: string, viteServer: vite.ViteDevServer): Set { diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 3f29a32ba..3981aad95 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -1,6 +1,6 @@ import type { AstroConfig } from '../@types/astro-core'; import type { ErrorPayload } from 'vite'; -import fs from 'fs'; +import eol from 'eol'; import path from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import resolve from 'resolve'; @@ -41,7 +41,7 @@ export function parseNpmName(spec: string): { scope?: string; name: string; subp /** generate code frame from esbuild error */ export function codeFrame(src: string, loc: ErrorPayload['err']['loc']): string { if (!loc) return ''; - const lines = src.replace(/\r\n/g, '\n').split('\n'); + const lines = eol.lf(src).split('\n'); // grab 2 lines before, and 3 lines after focused line const visibleLines = []; for (let n = -2; n <= 2; n++) { diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index ea321f65b..821dd3b36 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -63,8 +63,8 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P sourcemap: 'both', internalURL: 'astro/internal', preprocessStyle: async (value: string, attrs: Record) => { - if (!attrs || !attrs.lang) return null; - const result = await transformWithVite({ value, attrs, id, transformHook: viteTransform, ssr: isSSR(opts) }); + const lang = `.${attrs?.lang || 'css'}`.toLowerCase(); + const result = await transformWithVite({ value, lang, id, transformHook: viteTransform, ssr: isSSR(opts) }); if (!result) { // TODO: compiler supports `null`, but types don't yet return result as any; diff --git a/packages/astro/src/vite-plugin-astro/styles.ts b/packages/astro/src/vite-plugin-astro/styles.ts index 7c87e60d2..96971f308 100644 --- a/packages/astro/src/vite-plugin-astro/styles.ts +++ b/packages/astro/src/vite-plugin-astro/styles.ts @@ -1,6 +1,6 @@ import type vite from '../core/vite'; -import { PREPROCESSOR_EXTENSIONS } from '../core/ssr/css.js'; +import { STYLE_EXTENSIONS } from '../core/ssr/css.js'; export type TransformHook = (code: string, id: string, ssr?: boolean) => Promise; @@ -14,16 +14,15 @@ export function getViteTransform(viteConfig: vite.ResolvedConfig): TransformHook interface TransformWithViteOptions { value: string; - attrs: Record; + lang: string; id: string; transformHook: TransformHook; ssr?: boolean; } /** Transform style using Vite hook */ -export async function transformWithVite({ value, attrs, transformHook, id, ssr }: TransformWithViteOptions): Promise { - const lang = (`.${attrs.lang}` || '').toLowerCase(); // add leading "."; don’t be case-sensitive - if (!PREPROCESSOR_EXTENSIONS.has(lang)) { +export async function transformWithVite({ value, lang, transformHook, id, ssr }: TransformWithViteOptions): Promise { + if (!STYLE_EXTENSIONS.has(lang)) { return null; // only preprocess langs supported by Vite } return transformHook(value, id + `?astro&type=style&lang${lang}`, ssr); diff --git a/packages/astro/test/fixtures/postcss/postcss.config.cjs b/packages/astro/test/fixtures/postcss/postcss.config.cjs new file mode 100644 index 000000000..019f40040 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/postcss.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + autoprefixer: { + overrideBrowserslist: ['> 0.1%', 'IE 11'] // enforce `appearance: none;` is prefixed with -webkit and -moz + } + } +}; diff --git a/packages/astro/test/fixtures/postcss/public/global.css b/packages/astro/test/fixtures/postcss/public/global.css new file mode 100644 index 000000000..878eed346 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/public/global.css @@ -0,0 +1,3 @@ +.global { + appearance: none; +} diff --git a/packages/astro/test/fixtures/postcss/src/components/Astro.astro b/packages/astro/test/fixtures/postcss/src/components/Astro.astro new file mode 100644 index 000000000..c85cd0415 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/components/Astro.astro @@ -0,0 +1,9 @@ + + +
+ Astro +
diff --git a/packages/astro/test/fixtures/postcss/src/components/Solid.css b/packages/astro/test/fixtures/postcss/src/components/Solid.css new file mode 100644 index 000000000..9c4272b56 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/components/Solid.css @@ -0,0 +1,3 @@ +.solid { + appearance: none; +} diff --git a/packages/astro/test/fixtures/postcss/src/components/Solid.jsx b/packages/astro/test/fixtures/postcss/src/components/Solid.jsx new file mode 100644 index 000000000..9f172eb3b --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/components/Solid.jsx @@ -0,0 +1,10 @@ +import { h } from 'solid-js'; +import './Solid.css'; + +export default function Counter() { + return ( +
+ Solid +
+ ); +} diff --git a/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte b/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte new file mode 100644 index 000000000..0b55ab627 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/components/Svelte.svelte @@ -0,0 +1,9 @@ + + +
+ Svelte +
diff --git a/packages/astro/test/fixtures/postcss/src/components/Vue.vue b/packages/astro/test/fixtures/postcss/src/components/Vue.vue new file mode 100644 index 000000000..20b928e08 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/components/Vue.vue @@ -0,0 +1,12 @@ + + + + diff --git a/packages/astro/test/fixtures/postcss/src/pages/index.astro b/packages/astro/test/fixtures/postcss/src/pages/index.astro new file mode 100644 index 000000000..bba92dbf7 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/pages/index.astro @@ -0,0 +1,24 @@ +--- +import AstroComponent from '../components/Astro.astro'; +import JSX from '../components/Solid.jsx'; +import Svelte from '../components/Svelte.svelte'; +import Vue from '../components/Vue.vue'; +--- + + + + + + + +
+ + + + +
+ diff --git a/packages/astro/test/fixtures/postcss/src/styles/linked.css b/packages/astro/test/fixtures/postcss/src/styles/linked.css new file mode 100644 index 000000000..c989da683 --- /dev/null +++ b/packages/astro/test/fixtures/postcss/src/styles/linked.css @@ -0,0 +1,3 @@ +.a-n { + appearance: none; +} diff --git a/packages/astro/test/postcss.test.js b/packages/astro/test/postcss.test.js new file mode 100644 index 000000000..ac38f6622 --- /dev/null +++ b/packages/astro/test/postcss.test.js @@ -0,0 +1,61 @@ +import { expect } from 'chai'; +import cheerio from 'cheerio'; +import eol from 'eol'; +import os from 'os'; +import { loadFixture } from './test-utils.js'; + +const PREFIXED_CSS = `{-webkit-appearance:none;-moz-appearance:none;appearance:none}`; + +let fixture; +let bundledCSS; +before(async () => { + fixture = await loadFixture({ + projectRoot: './fixtures/postcss', + renderers: ['@astrojs/renderer-solid', '@astrojs/renderer-svelte', '@astrojs/renderer-vue'], + }); + await fixture.build(); + + // get bundled CSS (will be hashed, hence DOM query) + const html = await fixture.readFile('/index.html'); + const $ = cheerio.load(html); + const bundledCSSHREF = $('link[rel=stylesheet][href^=assets/]').attr('href'); + bundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/')); +}); + +describe('PostCSS', () => { + it('works in Astro page styles', () => { + expect(bundledCSS).to.match(new RegExp(`.astro-page.astro-[^{]+${PREFIXED_CSS}`)); + }); + + it('works in Astro component styles', () => { + expect(bundledCSS).to.match(new RegExp(`.astro-component.astro-[^{]+${PREFIXED_CSS}`)); + }); + + it('works in ', () => { + expect(bundledCSS).to.match(new RegExp(`.a-n${PREFIXED_CSS}`)); + }); + + it('works in JSX', () => { + // TODO: fix in Windows + if (os.platform() === 'win32') return; + expect(bundledCSS).to.match(new RegExp(`.solid${PREFIXED_CSS}`)); + }); + + it('works in Vue', () => { + // TODO: fix in Windows + if (os.platform() === 'win32') return; + expect(bundledCSS).to.match(new RegExp(`.vue${PREFIXED_CSS}`)); + }); + + it('works in Svelte', () => { + // TODO: fix in Windows + if (os.platform() === 'win32') return; + expect(bundledCSS).to.match(new RegExp(`.svelte.s[^{]+${PREFIXED_CSS}`)); + }); + + it('ignores CSS in public/', async () => { + const publicCSS = await fixture.readFile('/global.css'); + // neither minified nor prefixed + expect(eol.lf(publicCSS.trim())).to.equal(`.global {\n appearance: none;\n}`); + }); +}); diff --git a/yarn.lock b/yarn.lock index feac9266f..943f1176a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4008,6 +4008,11 @@ envinfo@^7.7.4: resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +eol@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/eol/-/eol-0.9.1.tgz#f701912f504074be35c6117a5c4ade49cd547acd" + integrity sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg== + eol@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eol/-/eol-0.2.0.tgz#2f6db086a243a46e3e5dbd0e13435c7ebebf09dd"