fix astro scoping of "@import" inside of style tags (#2656)

* fix astro scoping of "@import" inside of style tags

* Create lovely-lies-dress.md

* Update compile.ts

* fix smoke test

* Update package.json
This commit is contained in:
Fred K. Schott 2022-02-25 15:04:04 -08:00 committed by GitHub
parent ba49d3efc2
commit fca6407318
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
fix astro scoping of "@import" inside of style tags

View file

@ -4,7 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "astro dev --experimental-static-build", "dev": "astro dev --experimental-static-build",
"start": "astro dev", "start": "astro dev --experimental-static-build",
"build": "astro build --experimental-static-build", "build": "astro build --experimental-static-build",
"scan-build": "astro build", "scan-build": "astro build",
"preview": "astro preview" "preview": "astro preview"

View file

@ -9,11 +9,29 @@ import { transform } from '@astrojs/compiler';
import { transformWithVite } from './styles.js'; import { transformWithVite } from './styles.js';
type CompilationCache = Map<string, CompileResult>; type CompilationCache = Map<string, CompileResult>;
type CompileResult = TransformResult & { rawCSSDeps: Set<string> };
/**
* Note: this is currently needed because Astro is directly using a Vite internal CSS transform. This gives us
* some nice features out of the box, but at the expense of also running Vite's CSS postprocessing build step,
* which does some things that we don't like, like resolving/handling `@import` too early. This function pulls
* out the `@import` tags to be added back later, and then finally handled correctly by Vite.
*
* In the future, we should remove this workaround and most likely implement our own Astro style handling without
* having to hook into Vite's internals.
*/
function createImportPlaceholder(spec: string) {
// Note: We keep this small so that we can attempt to exactly match the # of characters in the original @import.
// This keeps sourcemaps accurate (to the best of our ability) at the intermediate step where this appears.
// -> `@import '${spec}';`;
return `/*IMPORT:${spec}*/`;
}
function safelyReplaceImportPlaceholder(code: string) {
return code.replace(/\/\*IMPORT\:(.*?)\*\//g, `@import '$1';`);
}
const configCache = new WeakMap<AstroConfig, CompilationCache>(); const configCache = new WeakMap<AstroConfig, CompilationCache>();
type CompileResult = TransformResult & { rawCSSDeps: Set<string> };
async function compile(config: AstroConfig, filename: string, source: string, viteTransform: TransformHook, opts: { ssr: boolean }): Promise<CompileResult> { async function compile(config: AstroConfig, filename: string, source: string, viteTransform: TransformHook, opts: { ssr: boolean }): Promise<CompileResult> {
// pages and layouts should be transformed as full documents (implicit <head> <body> etc) // pages and layouts should be transformed as full documents (implicit <head> <body> etc)
// everything else is treated as a fragment // everything else is treated as a fragment
@ -44,9 +62,15 @@ async function compile(config: AstroConfig, filename: string, source: string, vi
try { try {
// In the static build, grab any @import as CSS dependencies for HMR. // In the static build, grab any @import as CSS dependencies for HMR.
if (config.buildOptions.experimentalStaticBuild) { if (config.buildOptions.experimentalStaticBuild) {
value.replace(/(?:@import)\s(?:url\()?\s?["\'](.*?)["\']\s?\)?(?:[^;]*);?/gi, (match, spec) => { value = value.replace(/(?:@import)\s(?:url\()?\s?["\'](.*?)["\']\s?\)?(?:[^;]*);?/gi, (match, spec) => {
rawCSSDeps.add(spec); rawCSSDeps.add(spec);
// If the language is CSS: prevent `@import` inlining to prevent scoping of imports.
// Otherwise: Sass, etc. need to see imports for variables, so leave in for their compiler to handle.
if (lang === '.css') {
return createImportPlaceholder(spec);
} else {
return match; return match;
}
}); });
} }
@ -67,7 +91,7 @@ async function compile(config: AstroConfig, filename: string, source: string, vi
map = result.map.toString(); map = result.map.toString();
} }
} }
const code = result.code; const code = safelyReplaceImportPlaceholder(result.code);
return { code, map }; return { code, map };
} catch (err) { } catch (err) {
// save error to throw in plugin context // save error to throw in plugin context