0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-06 22:10:10 -05:00

Prevent ?inline and ?raw CSS from being bundled as CSS (#6161)

* Prevent ?inline and ?raw CSS from being bundled as CSS

* Add a changeset

* oopts

* Replace use of isCSSRequest
This commit is contained in:
Matthew Phillips 2023-02-07 10:49:13 -05:00 committed by GitHub
parent 460f9e7329
commit f6fc662c3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 123 additions and 26 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Prevent ?inline and ?raw CSS from being bundled as CSS

View file

@ -2,7 +2,7 @@ import * as crypto from 'node:crypto';
import * as npath from 'node:path';
import type { GetModuleInfo } from 'rollup';
import { Plugin as VitePlugin, ResolvedConfig, transformWithEsbuild } from 'vite';
import { isCSSRequest } from '../../render/util.js';
import { isBuildableCSSRequest } from '../../render/dev/util.js';
import type { BuildInternals } from '../internal';
import type { AstroBuildPlugin } from '../plugin';
import type { PageBuildData, StaticBuildOptions } from '../types';
@ -66,7 +66,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
after(id, meta) {
// For CSS, create a hash of all of the pages that use it.
// This causes CSS to be built into shared chunks when used by multiple pages.
if (isCSSRequest(id)) {
if (isBuildableCSSRequest(id)) {
for (const [pageInfo] of walkParentInfos(id, {
getModuleInfo: meta.getModuleInfo,
})) {

View file

@ -3,7 +3,7 @@ import type { ModuleLoader } from '../../module-loader/index';
import path from 'path';
import { RuntimeMode } from '../../../@types/astro.js';
import { viteID } from '../../util.js';
import { STYLE_EXTENSIONS } from '../util.js';
import { isCSSRequest } from './util.js';
import { crawlGraph } from './vite.js';
/** Given a filePath URL, crawl Vites module graph to find all style imports. */
@ -16,8 +16,7 @@ export async function getStylesForURL(
const importedStylesMap = new Map<string, string>();
for await (const importedModule of crawlGraph(loader, viteID(filePath), true)) {
const ext = path.extname(importedModule.url).toLowerCase();
if (STYLE_EXTENSIONS.has(ext)) {
if (isCSSRequest(importedModule.url)) {
let ssrModule: Record<string, any>;
try {
// The SSR module is possibly not loaded. Load it if it's null.

View file

@ -0,0 +1,9 @@
import { isCSSRequest } from 'vite';
const rawRE = /(?:\?|&)raw(?:&|$)/;
const inlineRE = /(?:\?|&)inline\b/;
export { isCSSRequest };
export const isBuildableCSSRequest = (request: string): boolean => isCSSRequest(request) &&
!rawRE.test(request) && !inlineRE.test(request);

View file

@ -4,7 +4,7 @@ import npath from 'path';
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
import { unwrapId } from '../../util.js';
import { STYLE_EXTENSIONS } from '../util.js';
import { isCSSRequest } from './util.js';
/**
* List of file extensions signalling we can (and should) SSR ahead-of-time
@ -43,7 +43,7 @@ export async function* crawlGraph(
}
if (id === entry.id) {
scanned.add(id);
const entryIsStyle = STYLE_EXTENSIONS.has(npath.extname(id));
const entryIsStyle = isCSSRequest(id);
for (const importedModule of entry.importedModules) {
// some dynamically imported modules are *not* server rendered in time
// to only SSR modules that we can safely transform, we check against
@ -57,7 +57,7 @@ export async function* crawlGraph(
// Tools like Tailwind might add HMR dependencies as `importedModules`
// but we should skip them--they aren't really imported. Without this,
// every hoisted script in the project is added to every page!
if (entryIsStyle && !STYLE_EXTENSIONS.has(npath.extname(importedModulePathname))) {
if (entryIsStyle && !isCSSRequest(importedModulePathname)) {
continue;
}
if (fileExtensionsToSSR.has(npath.extname(importedModulePathname))) {

View file

@ -1,18 +0,0 @@
// https://vitejs.dev/guide/features.html#css-pre-processors
export const STYLE_EXTENSIONS = new Set([
'.css',
'.pcss',
'.postcss',
'.scss',
'.sass',
'.styl',
'.stylus',
'.less',
]);
const cssRe = new RegExp(
`\\.(${Array.from(STYLE_EXTENSIONS)
.map((s) => s.slice(1))
.join('|')})($|\\?)`
);
export const isCSSRequest = (request: string): boolean => cssRe.test(request);

View file

@ -0,0 +1,28 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('Importing raw/inlined CSS', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/css-inline/',
});
await fixture.build();
});
it('?inline is imported as a string', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
expect($('#inline').text()).to.contain('tomato');
});
it('?raw is imported as a string', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
expect($('#raw').text()).to.contain('plum');
});
});

View file

@ -0,0 +1,8 @@
{
"name": "@test/css-inline",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,3 @@
body {
background: tomato;
}

View file

@ -0,0 +1,35 @@
---
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
<style is:global>
:root {
--accent: 124, 58, 237;
--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
}
html {
font-family: system-ui, sans-serif;
background-color: #F6F6F6;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
</style>

View file

@ -0,0 +1,19 @@
---
import Layout from '../layouts/Layout.astro';
import inline from '../inline.css?inline';
import raw from '../raw.css?raw';
---
<Layout title="Welcome to Astro.">
<main>
<h1>Welcome to Astro</h1>
<p>
This are some `?inline` styles to show as object:
</p>
<p id="inline">
{inline}
</p>
<p id="raw">
{raw}
</p>
</main>
</Layout>

View file

@ -0,0 +1,3 @@
main {
background: plum;
}

View file

@ -1690,6 +1690,12 @@ importers:
packages/astro/test/fixtures/css-assets/packages/font-awesome:
specifiers: {}
packages/astro/test/fixtures/css-inline:
specifiers:
astro: workspace:*
dependencies:
astro: link:../../..
packages/astro/test/fixtures/css-no-code-split:
specifiers:
astro: workspace:*