Skip to content

Commit bb18ffc

Browse files
committed
Fix CSS missing when building from a symlinked directory
1 parent 79a41e0 commit bb18ffc

8 files changed

Lines changed: 80 additions & 1 deletion

File tree

.changeset/quick-plums-argue.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes missing CSS when building from a symlinked or junction-linked directory

packages/astro/src/core/config/config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ export function resolveRoot(cwd?: string | URL): string {
2121
if (cwd instanceof URL) {
2222
cwd = fileURLToPath(cwd);
2323
}
24-
return cwd ? path.resolve(cwd) : process.cwd();
24+
const resolved = cwd ? path.resolve(cwd) : process.cwd();
25+
// Resolve symlinks so that the root path matches Vite's resolved module IDs.
26+
// Building from a symlinked directory otherwise causes path mismatches in the
27+
// CSS pipeline, where `pagesByViteID` keys no longer match Rollup module graph IDs.
28+
try {
29+
return fs.realpathSync(resolved);
30+
} catch {
31+
return resolved;
32+
}
2533
}
2634

2735
// Config paths to search for.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
symlink-css
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { defineConfig } from 'astro/config';
2+
export default defineConfig({});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
import '../styles/global.css';
3+
---
4+
<html>
5+
<head><meta charset="utf-8" /><title>Test</title></head>
6+
<body><slot /></body>
7+
</html>
8+
<style>
9+
body { margin: 0; padding: 2rem; }
10+
</style>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
import BaseLayout from '../layouts/BaseLayout.astro';
3+
---
4+
<BaseLayout>
5+
<h1>Hello World</h1>
6+
</BaseLayout>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
body {
2+
background-color: red;
3+
color: white;
4+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import assert from 'node:assert/strict';
2+
import { before, describe, it } from 'node:test';
3+
import * as cheerio from 'cheerio';
4+
import { loadFixture } from './test-utils.ts';
5+
6+
describe('Symlink CSS', () => {
7+
let realHtml: string;
8+
let linkedHtml: string;
9+
10+
before(
11+
async () => {
12+
// Build from real directory
13+
const realFixture = await loadFixture({
14+
root: './fixtures/symlink-css/',
15+
});
16+
await realFixture.build();
17+
realHtml = await realFixture.readFile('/index.html');
18+
19+
// Build from symlinked directory
20+
const linkedFixture = await loadFixture({
21+
root: './fixtures/symlink-css-linked/',
22+
});
23+
await linkedFixture.build();
24+
linkedHtml = await linkedFixture.readFile('/index.html');
25+
},
26+
{ timeout: 60000 },
27+
);
28+
29+
it('should include CSS when building from a symlinked directory', () => {
30+
const $linked = cheerio.load(linkedHtml);
31+
const cssLinks = $linked('link[rel=stylesheet]').length;
32+
const styles = $linked('style').length;
33+
assert.ok(cssLinks > 0 || styles > 0, 'Should have CSS in symlinked build');
34+
});
35+
36+
it('should have same CSS output as real directory build', () => {
37+
const $real = cheerio.load(realHtml);
38+
const $linked = cheerio.load(linkedHtml);
39+
const realCssCount = $real('link[rel=stylesheet]').length + $real('style').length;
40+
const linkedCssCount = $linked('link[rel=stylesheet]').length + $linked('style').length;
41+
assert.equal(linkedCssCount, realCssCount, 'Should have same number of CSS references');
42+
});
43+
});

0 commit comments

Comments
 (0)