summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/forty-goats-warn.md5
-rw-r--r--packages/astro/src/core/build/internal.ts49
-rw-r--r--packages/astro/src/core/build/static-build.ts10
-rw-r--r--packages/astro/src/vite-plugin-build-css/index.ts8
-rw-r--r--packages/astro/test/astro-client-only.test.js10
-rw-r--r--packages/astro/test/fixtures/astro-client-only/astro.config.mjs3
-rw-r--r--packages/astro/test/fixtures/astro-client-only/package.json1
-rw-r--r--packages/astro/test/fixtures/astro-client-only/src/components/JSXComponent.jsx6
-rw-r--r--packages/astro/test/fixtures/astro-client-only/src/components/PersistentCounter.svelte6
-rw-r--r--packages/astro/test/fixtures/astro-client-only/src/components/global.css3
-rw-r--r--packages/astro/test/fixtures/astro-client-only/src/pages/index.astro2
-rw-r--r--pnpm-lock.yaml2
12 files changed, 97 insertions, 8 deletions
diff --git a/.changeset/forty-goats-warn.md b/.changeset/forty-goats-warn.md
new file mode 100644
index 000000000..6f0d863e6
--- /dev/null
+++ b/.changeset/forty-goats-warn.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes client:only CSS
diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts
index d74722b1a..d9a21a7de 100644
--- a/packages/astro/src/core/build/internal.ts
+++ b/packages/astro/src/core/build/internal.ts
@@ -1,7 +1,8 @@
-import type { RouteData } from '../../@types/astro';
+import type { AstroConfig, RouteData } from '../../@types/astro';
import type { RenderedChunk } from 'rollup';
import type { PageBuildData, ViteID } from './types';
+import { fileURLToPath } from 'url';
import { viteID } from '../util.js';
export interface BuildInternals {
@@ -26,6 +27,11 @@ export interface BuildInternals {
pagesByViteID: Map<ViteID, PageBuildData>;
/**
+ * A map for page-specific information by a client:only component
+ */
+ pagesByClientOnly: Map<string, Set<PageBuildData>>;
+
+ /**
* chunkToReferenceIdMap maps them to a hash id used to find the final file.
* @deprecated This Map is only used for the legacy build.
*/
@@ -73,6 +79,7 @@ export function createBuildInternals(): BuildInternals {
pagesByComponent: new Map(),
pagesByViteID: new Map(),
+ pagesByClientOnly: new Map(),
};
}
@@ -88,6 +95,30 @@ export function trackPageData(
internals.pagesByViteID.set(viteID(componentURL), pageData);
}
+/**
+ * Tracks client-only components to the pages they are associated with.
+ */
+export function trackClientOnlyPageDatas(
+ internals: BuildInternals,
+ pageData: PageBuildData,
+ clientOnlys: string[],
+ astroConfig: AstroConfig,
+) {
+ for(const clientOnlyComponent of clientOnlys) {
+ const coPath = viteID(new URL('.' + clientOnlyComponent, astroConfig.root));
+ let pageDataSet: Set<PageBuildData>;
+ if(internals.pagesByClientOnly.has(coPath)) {
+ pageDataSet = internals.pagesByClientOnly.get(coPath)!;
+ } else {
+ pageDataSet = new Set<PageBuildData>();
+ internals.pagesByClientOnly.set(coPath, pageDataSet);
+ }
+ pageDataSet.add(pageData);
+ }
+}
+
+
+
export function* getPageDatasByChunk(
internals: BuildInternals,
chunk: RenderedChunk
@@ -100,6 +131,22 @@ export function* getPageDatasByChunk(
}
}
+export function* getPageDatasByClientOnlyChunk(
+ internals: BuildInternals,
+ chunk: RenderedChunk
+): Generator<PageBuildData, void, unknown> {
+ const pagesByClientOnly = internals.pagesByClientOnly;
+ if(pagesByClientOnly.size) {
+ for (const [modulePath] of Object.entries(chunk.modules)) {
+ if (pagesByClientOnly.has(modulePath)) {
+ for(const pageData of pagesByClientOnly.get(modulePath)!) {
+ yield pageData;
+ }
+ }
+ }
+ }
+}
+
export function getPageDataByComponent(
internals: BuildInternals,
component: string
diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts
index 40107844d..6be7ee4e2 100644
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
@@ -1,5 +1,5 @@
import type { RollupOutput } from 'rollup';
-import type { BuildInternals } from '../../core/build/internal.js';
+import { BuildInternals, trackClientOnlyPageDatas } from '../../core/build/internal.js';
import type { ViteConfigWithSSR } from '../create-vite';
import type { PageBuildData, StaticBuildOptions } from './types';
import glob from 'fast-glob';
@@ -54,13 +54,17 @@ export async function staticBuild(opts: StaticBuildOptions) {
const [renderers, mod] = pageData.preload;
const metadata = mod.$$metadata;
+ // Track client:only usage so we can map their CSS back to the Page they are used in.
+ const clientOnlys = Array.from(metadata.clientOnlyComponentPaths());
+ trackClientOnlyPageDatas(internals, pageData, clientOnlys, astroConfig);
+
const topLevelImports = new Set([
// Any component that gets hydrated
// 'components/Counter.jsx'
// { 'components/Counter.jsx': 'counter.hash.js' }
...metadata.hydratedComponentPaths(),
// Client-only components
- ...metadata.clientOnlyComponentPaths(),
+ ...clientOnlys,
// Any hydration directive like astro/client/idle.js
...metadata.hydrationDirectiveSpecifiers(),
// The client path for each renderer
@@ -148,6 +152,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
rollupPluginAstroBuildCSS({
internals,
legacy: false,
+ target: 'server'
}),
...(viteConfig.plugins || []),
// SSR needs to be last
@@ -218,6 +223,7 @@ async function clientBuild(
rollupPluginAstroBuildCSS({
internals,
legacy: false,
+ target: 'client'
}),
...(viteConfig.plugins || []),
],
diff --git a/packages/astro/src/vite-plugin-build-css/index.ts b/packages/astro/src/vite-plugin-build-css/index.ts
index 150cd7451..de62a9933 100644
--- a/packages/astro/src/vite-plugin-build-css/index.ts
+++ b/packages/astro/src/vite-plugin-build-css/index.ts
@@ -9,6 +9,7 @@ import {
getPageDatasByChunk,
getPageDataByViteID,
hasPageDataByViteID,
+ getPageDatasByClientOnlyChunk,
} from '../core/build/internal.js';
const PLUGIN_NAME = '@astrojs/rollup-plugin-build-css';
@@ -54,6 +55,7 @@ function isRawOrUrlModule(id: string) {
interface PluginOptions {
internals: BuildInternals;
legacy: boolean;
+ target: 'client' | 'server';
}
export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
@@ -172,7 +174,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
},
async renderChunk(_code, chunk) {
- if (!legacy) return null;
+ if (options.target === 'server') return null;
let chunkCSS = '';
let isPureCSS = true;
@@ -207,6 +209,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
for (const pageData of getPageDatasByChunk(internals, chunk)) {
pageData.css.add(fileName);
}
+ // Adds this CSS for client:only components to the appropriate page
+ for (const pageData of getPageDatasByClientOnlyChunk(internals, chunk)) {
+ pageData.css.add(fileName);
+ }
}
return null;
diff --git a/packages/astro/test/astro-client-only.test.js b/packages/astro/test/astro-client-only.test.js
index 812b7229b..dcd7faf17 100644
--- a/packages/astro/test/astro-client-only.test.js
+++ b/packages/astro/test/astro-client-only.test.js
@@ -1,5 +1,5 @@
import { expect } from 'chai';
-import cheerio from 'cheerio';
+import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('Client only components', () => {
@@ -14,7 +14,7 @@ describe('Client only components', () => {
it('Loads pages using client:only hydrator', async () => {
const html = await fixture.readFile('/index.html');
- const $ = cheerio.load(html);
+ const $ = cheerioLoad(html);
// test 1: <astro-root> is empty
expect($('astro-root').html()).to.equal('');
@@ -24,4 +24,10 @@ describe('Client only components', () => {
// test 2: svelte renderer is on the page
expect(/import\(".\/entry.*/g.test(script)).to.be.ok;
});
+
+ it('Adds the CSS to the page', async () => {
+ const html = await fixture.readFile('/index.html');
+ const $ = cheerioLoad(html);
+ expect($('link[rel=stylesheet]')).to.have.lengthOf(2);
+ })
});
diff --git a/packages/astro/test/fixtures/astro-client-only/astro.config.mjs b/packages/astro/test/fixtures/astro-client-only/astro.config.mjs
index 77fdcd1b9..1c8866ea7 100644
--- a/packages/astro/test/fixtures/astro-client-only/astro.config.mjs
+++ b/packages/astro/test/fixtures/astro-client-only/astro.config.mjs
@@ -1,7 +1,8 @@
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
+import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
- integrations: [svelte()],
+ integrations: [svelte(), react()],
});
diff --git a/packages/astro/test/fixtures/astro-client-only/package.json b/packages/astro/test/fixtures/astro-client-only/package.json
index 038e6f99d..96f83eac2 100644
--- a/packages/astro/test/fixtures/astro-client-only/package.json
+++ b/packages/astro/test/fixtures/astro-client-only/package.json
@@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@astrojs/svelte": "workspace:*",
+ "@astrojs/react": "workspace:*",
"astro": "workspace:*"
}
}
diff --git a/packages/astro/test/fixtures/astro-client-only/src/components/JSXComponent.jsx b/packages/astro/test/fixtures/astro-client-only/src/components/JSXComponent.jsx
new file mode 100644
index 000000000..e9d2411d1
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-client-only/src/components/JSXComponent.jsx
@@ -0,0 +1,6 @@
+import React from 'react';
+import './global.css';
+
+export default function() {
+ return <div>i am react</div>
+}
diff --git a/packages/astro/test/fixtures/astro-client-only/src/components/PersistentCounter.svelte b/packages/astro/test/fixtures/astro-client-only/src/components/PersistentCounter.svelte
index 92d005415..855be29ea 100644
--- a/packages/astro/test/fixtures/astro-client-only/src/components/PersistentCounter.svelte
+++ b/packages/astro/test/fixtures/astro-client-only/src/components/PersistentCounter.svelte
@@ -12,7 +12,11 @@
count -= 1;
}
</script>
-
+<style>
+ button {
+ background: yellowgreen;
+ }
+</style>
<div class="counter">
<button on:click={subtract}>-</button>
<pre>{ count }</pre>
diff --git a/packages/astro/test/fixtures/astro-client-only/src/components/global.css b/packages/astro/test/fixtures/astro-client-only/src/components/global.css
new file mode 100644
index 000000000..e495b6de9
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-client-only/src/components/global.css
@@ -0,0 +1,3 @@
+body {
+ font-family: 'Courier New', Courier, monospace;
+}
diff --git a/packages/astro/test/fixtures/astro-client-only/src/pages/index.astro b/packages/astro/test/fixtures/astro-client-only/src/pages/index.astro
index cb277d194..bf239197f 100644
--- a/packages/astro/test/fixtures/astro-client-only/src/pages/index.astro
+++ b/packages/astro/test/fixtures/astro-client-only/src/pages/index.astro
@@ -1,9 +1,11 @@
---
import PersistentCounter from '../components/PersistentCounter.svelte';
+import ReactComponent from '../components/JSXComponent.jsx';
---
<html>
<head><title>Client only pages</title></head>
<body>
<PersistentCounter client:only />
+ <ReactComponent client:only="react" />
</body>
</html>
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 445165259..2c8331563 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -684,9 +684,11 @@ importers:
packages/astro/test/fixtures/astro-client-only:
specifiers:
+ '@astrojs/react': workspace:*
'@astrojs/svelte': workspace:*
astro: workspace:*
dependencies:
+ '@astrojs/react': link:../../../../integrations/react
'@astrojs/svelte': link:../../../../integrations/svelte
astro: link:../../..