Skip to content

Commit

Permalink
fix(css): fix inline query injection for CSS inlining (#11917)
Browse files Browse the repository at this point in the history
  • Loading branch information
sapphi-red authored Sep 10, 2024
1 parent b9394fa commit 8329d17
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 18 deletions.
19 changes: 10 additions & 9 deletions packages/astro/src/vite-plugin-astro-server/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ interface ImportedStyle {
content: string;
}

const inlineQueryRE = /(?:\?|&)inline(?:$|&)/

/** Given a filePath URL, crawl Vite’s module graph to find all style imports. */
export async function getStylesForURL(
filePath: URL,
Expand All @@ -32,21 +34,20 @@ export async function getStylesForURL(
}
// Else try to load it
else {
const url = new URL(importedModule.url, 'http://localhost');
let modId = importedModule.url
// Mark url with ?inline so Vite will return the CSS as plain string, even for CSS modules
url.searchParams.set('inline', '');
const modId = `${decodeURI(url.pathname)}${url.search}`;

if (!inlineQueryRE.test(importedModule.url)) {
if (importedModule.url.includes('?')) {
modId = importedModule.url.replace('?', '?inline&');
} else {
modId += '?inline';
}
}
try {
// The SSR module is possibly not loaded. Load it if it's null.
const ssrModule = await loader.import(modId);
css = ssrModule.default;
} catch {
// Some CSS modules, e.g. from Vue files, may not work with the ?inline query.
// If so, we fallback to a url instead
if (modId.includes('.module.')) {
importedCssUrls.add(importedModule.url);
}
// The module may not be inline-able, e.g. SCSS partials. Skip it as it may already
// be inlined into other modules if it happens to be in the graph.
continue;
Expand Down
9 changes: 2 additions & 7 deletions packages/astro/test/0-css.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ describe('CSS', function () {
it('<style module>', async () => {
const el = $('#vue-modules');
const classes = el.attr('class').split(' ');
const moduleClass = classes.find((name) => /^_title_[\w-]+/.test(name));
const moduleClass = classes.find((name) => /^_vueModules_[\w-]+/.test(name));

// 1. check HTML
assert.equal(el.attr('class').includes(moduleClass), true);
Expand Down Expand Up @@ -405,18 +405,13 @@ describe('CSS', function () {
});

it('resolves CSS from Vue', async () => {
const styles = ['VueModules.vue?vue&type=style&index=0&lang.module.scss'];
for (const style of styles) {
const href = $(`link[href$="${style}"]`).attr('href');
assert.equal((await fixture.fetch(href)).status, 200, style);
}

const allInjectedStyles = $('style').text().replace(/\s*/g, '');

assert.equal(allInjectedStyles.includes('.vue-css{'), true);
assert.equal(allInjectedStyles.includes('.vue-sass{'), true);
assert.equal(allInjectedStyles.includes('.vue-scss{'), true);
assert.equal(allInjectedStyles.includes('.vue-scoped[data-v-'), true);
assert.equal(allInjectedStyles.includes('._vueModules_'), true);
});

it('remove unused styles from client:load components', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<style module lang="scss">
$type: cursive;
.title {
.vueModules {
font-family: $type;
}
</style>

<template>
<h1 id="vue-modules" :class="$style.title">Vue CSS Modules</h1>
<h1 id="vue-modules" :class="$style.vueModules">Vue CSS Modules</h1>
</template>

0 comments on commit 8329d17

Please sign in to comment.