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/calm-caches-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes incremental builds repeatedly rendering unchanged pages when modules or compiled CSS reference bundled assets.
3 changes: 2 additions & 1 deletion packages/astro/src/core/build/plugins/plugin-incremental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface TransitiveGraphCache {
const ASSET_PLACEHOLDERS = [
{ token: '__ASTRO_ASSET_IMAGE__', pattern: /__ASTRO_ASSET_IMAGE__([\w$]+)__(?:_(.*?)__)?/g },
{ token: '__VITE_ASSET__', pattern: /__VITE_ASSET__([\w$]+)__(?:\$_(.*?)__)?/g },
{ token: 'import.meta.ROLLDOWN_FILE_URL_', pattern: /import\.meta\.ROLLDOWN_FILE_URL_([\w$]+)/g },
];

/**
Expand Down Expand Up @@ -112,7 +113,7 @@ function hashModules(
// did not see (e.g. virtual CSS modules).
const compiled = compiledCss.get(id);
if (compiled != null) {
hasher.update(compiled);
hasher.update(resolveAssetPlaceholders(graph, compiled));
} else {
try {
hasher.update(nodeFs.readFileSync(removeQueryString(id), 'utf-8'));
Expand Down
37 changes: 37 additions & 0 deletions packages/astro/test/units/build/plugin-incremental.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ function assetCode(handle: string) {
return `export default "__VITE_ASSET__${handle}__"`;
}

function rolldownAssetCode(handle: string) {
return `export default import.meta.ROLLDOWN_FILE_URL_${handle}`;
}

function pluginContext(
codeByModule: Record<string, string>,
fileNames: Record<string, string>,
Expand Down Expand Up @@ -110,6 +114,18 @@ describe('pluginIncremental', () => {
assert.equal(first, second);
});

it('is stable when Rolldown emits the same assets with different handles', () => {
const first = dependencyHash(
{ [RED]: rolldownAssetCode(HANDLE_ONE), [VIDEO]: rolldownAssetCode(HANDLE_TWO) },
{ [HANDLE_ONE]: '_astro/red.aaaa.png', [HANDLE_TWO]: '_astro/clip.cccc.mp4' },
);
const second = dependencyHash(
{ [RED]: rolldownAssetCode(HANDLE_TWO), [VIDEO]: rolldownAssetCode(HANDLE_ONE) },
{ [HANDLE_TWO]: '_astro/red.aaaa.png', [HANDLE_ONE]: '_astro/clip.cccc.mp4' },
);
assert.equal(first, second);
});

it('changes when an imported image resolves to a different file name', () => {
const code = { [RED]: imageCode(HANDLE_ONE), [BLUE]: imageCode(HANDLE_TWO) };
const first = dependencyHash(code, {
Expand Down Expand Up @@ -158,6 +174,27 @@ describe('pluginIncremental', () => {
});

describe('CSS preprocessor partials (#17974)', () => {
it('is stable when compiled CSS assets are emitted with different handles', () => {
const cssId = '/project/src/styles/global.css';
const first = dependencyHash(
{ [cssId]: '' },
{ [HANDLE_ONE]: '_astro/red.aaaa.png' },
[cssId],
{
transforms: { [cssId]: `body { background: url(__VITE_ASSET__${HANDLE_ONE}__); }` },
},
);
const second = dependencyHash(
{ [cssId]: '' },
{ [HANDLE_TWO]: '_astro/red.aaaa.png' },
[cssId],
{
transforms: { [cssId]: `body { background: url(__VITE_ASSET__${HANDLE_TWO}__); }` },
},
);
assert.equal(first, second);
});

it('changes when compiled CSS output changes even if entry file is unchanged', () => {
const scssId = '/project/src/styles/global.scss';
// The entry file stays the same between builds; only the
Expand Down
Loading