Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/full-dingos-stand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes CSS imported from an `injectScript('page')` script being dropped during build
10 changes: 7 additions & 3 deletions packages/astro/src/core/build/plugins/plugin-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,14 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
}

const wasInlined = toBeInlined && sheetAddedToPage;
// stylesheets already referenced as an asset by a chunk will not be inlined by
// this plugin, but should not be considered orphaned
// Stylesheets referenced by a chunk (via importedAssets for ?url imports,
// or importedCss for normal CSS imports) are delivered by Vite's preload
// helper at runtime and must not be treated as orphaned.
const wasAddedToChunk = Object.values(bundle).some(
(chunk) => chunk.type === 'chunk' && chunk.viteMetadata?.importedAssets?.has(id),
(chunk) =>
chunk.type === 'chunk' &&
(chunk.viteMetadata?.importedAssets?.has(id) ||
chunk.viteMetadata?.importedCss?.has(id)),
);
const isOrphaned = !sheetAddedToPage && !wasAddedToChunk;

Expand Down
14 changes: 14 additions & 0 deletions packages/astro/test/fixtures/injected-script-css/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig } from 'astro/config';

export default defineConfig({
integrations: [
{
name: 'injected-css-test',
hooks: {
'astro:config:setup': ({ injectScript }) => {
injectScript('page', `import '/integration/script.js';`);
},
},
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
document.querySelector('#injected').addEventListener('click', async () => {
const { mount } = await import('./widget.js');
mount('injected');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.injected-widget {
color: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import './widget.css';

export function mount(label) {
const el = document.createElement('p');
el.className = 'injected-widget';
el.textContent = `${label}: styled`;
document.body.append(el);
}
8 changes: 8 additions & 0 deletions packages/astro/test/fixtures/injected-script-css/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/injected-script-css",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>injected script CSS test</title>
</head>
<body>
<button id="injected">Load widget</button>
</body>
</html>
31 changes: 31 additions & 0 deletions packages/astro/test/injected-script-css.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
import { type Fixture, loadFixture } from './test-utils.ts';

describe('CSS imported from injectScript page scripts', () => {
let fixture: Fixture;

before(async () => {
fixture = await loadFixture({
root: './fixtures/injected-script-css/',
});
await fixture.build();
});

it('emits the CSS file to the build output', async () => {
const assets = await fixture.readdir('/_astro');
const cssFiles = assets.filter((f) => f.endsWith('.css'));
assert.ok(cssFiles.length > 0, 'Expected at least one CSS file in /_astro');

// Verify the CSS content includes the injected widget styles
let foundInjectedCss = false;
for (const cssFile of cssFiles) {
const content = await fixture.readFile(`/_astro/${cssFile}`);
if (content.includes('.injected-widget')) {
foundInjectedCss = true;
break;
}
}
assert.ok(foundInjectedCss, 'Expected .injected-widget styles in a CSS file');
});
});
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading