Fix PostCSS (and Autoprefixer) processing (#1837)

* Fix PostCSS processing

* Skip Windows tests

(for now)
This commit is contained in:
Drew Powers 2021-11-15 14:16:07 -07:00 committed by GitHub
parent 64cc9ed9c1
commit 65216ef921
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 164 additions and 12 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Bugfix: PostCSS not working in all contexts

View file

@ -129,8 +129,10 @@ Its recommended to only use this in scenarios where a `<link>` tag wont wo
```js
// postcss.config.cjs
module.exports = {
autoprefixer: {
/* (optional) autoprefixer settings */
plugins: {
autoprefixer: {
/* (optional) autoprefixer settings */
},
},
};
```

View file

@ -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",

View file

@ -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<string> {

View file

@ -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++) {

View file

@ -63,8 +63,8 @@ export default function astro({ config, devServer }: AstroPluginOptions): vite.P
sourcemap: 'both',
internalURL: 'astro/internal',
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
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;

View file

@ -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<vite.TransformResult>;
@ -14,16 +14,15 @@ export function getViteTransform(viteConfig: vite.ResolvedConfig): TransformHook
interface TransformWithViteOptions {
value: string;
attrs: Record<string, string>;
lang: string;
id: string;
transformHook: TransformHook;
ssr?: boolean;
}
/** Transform style using Vite hook */
export async function transformWithVite({ value, attrs, transformHook, id, ssr }: TransformWithViteOptions): Promise<vite.TransformResult | null> {
const lang = (`.${attrs.lang}` || '').toLowerCase(); // add leading "."; dont be case-sensitive
if (!PREPROCESSOR_EXTENSIONS.has(lang)) {
export async function transformWithVite({ value, lang, transformHook, id, ssr }: TransformWithViteOptions): Promise<vite.TransformResult | null> {
if (!STYLE_EXTENSIONS.has(lang)) {
return null; // only preprocess langs supported by Vite
}
return transformHook(value, id + `?astro&type=style&lang${lang}`, ssr);

View file

@ -0,0 +1,7 @@
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ['> 0.1%', 'IE 11'] // enforce `appearance: none;` is prefixed with -webkit and -moz
}
}
};

View file

@ -0,0 +1,3 @@
.global {
appearance: none;
}

View file

@ -0,0 +1,9 @@
<style>
.astro-component {
appearance: none;
}
</style>
<div class="astro-component">
Astro
</div>

View file

@ -0,0 +1,3 @@
.solid {
appearance: none;
}

View file

@ -0,0 +1,10 @@
import { h } from 'solid-js';
import './Solid.css';
export default function Counter() {
return (
<div class="solid">
Solid
</div>
);
}

View file

@ -0,0 +1,9 @@
<style>
.svelte {
appearance: none;
}
</style>
<div class="svelte">
Svelte
</div>

View file

@ -0,0 +1,12 @@
<style>
.vue {
appearance: none;
}
</style>
<template>
<div class="vue">
Vue
</div>
</template>

View file

@ -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';
---
<head>
<link rel="stylesheet" type="text/css" href="/global.css">
<link rel="stylesheet" type="text/css" href={Astro.resolve('../styles/linked.css')}>
<style>
.astro-page {
appearance: none;
}
</style>
</head>
<body>
<div class="astro-page">
<AstroComponent />
<JSX />
<Svelte />
<Vue />
</div>
</body>

View file

@ -0,0 +1,3 @@
.a-n {
appearance: none;
}

View file

@ -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 <link>', () => {
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}`);
});
});

View file

@ -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"