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:
parent
ba49d3efc2
commit
fca6407318
3 changed files with 35 additions and 6 deletions
5
.changeset/lovely-lies-dress.md
Normal file
5
.changeset/lovely-lies-dress.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix astro scoping of "@import" inside of style tags
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue