Skip to content

Commit

Permalink
fix: clear the content layer cache when the Astro config changes (#12767
Browse files Browse the repository at this point in the history
)

* fix: clear the content layer cache when the Astro config changes

* Use deterministic-object-hash

* Switch back to safe-stringify

* Whitespace
  • Loading branch information
ascorbic authored Dec 18, 2024
1 parent a581c15 commit 36c1e06
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-dancers-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Clears the content layer cache when the Astro config is changed
26 changes: 23 additions & 3 deletions packages/astro/src/content/content-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getEntryConfigByExtMap,
getEntryDataAndImages,
globalContentConfigObserver,
safeStringify,
} from './utils.js';

export interface ContentLayerOptions {
Expand Down Expand Up @@ -87,7 +88,7 @@ export class ContentLayer {
// It uses wasm, so we need to load it asynchronously.
const { h64ToString } = await xxhash();

this.#generateDigest = (data: Record<string, unknown> | string) => {
this.#generateDigest = (data: unknown) => {
const dataString = typeof data === 'string' ? data : JSON.stringify(data);
return h64ToString(dataString);
};
Expand Down Expand Up @@ -143,12 +144,28 @@ export class ContentLayer {
}

logger.info('Syncing content');
const {
vite: _vite,
integrations: _integrations,
adapter: _adapter,
...hashableConfig
} = this.#settings.config;

const astroConfigDigest = safeStringify(hashableConfig);

const { digest: currentConfigDigest } = contentConfig.config;
this.#lastConfigDigest = currentConfigDigest;

let shouldClear = false;
const previousConfigDigest = await this.#store.metaStore().get('config-digest');
const previousConfigDigest = await this.#store.metaStore().get('content-config-digest');
const previousAstroConfigDigest = await this.#store.metaStore().get('astro-config-digest');
const previousAstroVersion = await this.#store.metaStore().get('astro-version');

if (previousAstroConfigDigest && previousAstroConfigDigest !== astroConfigDigest) {
logger.info('Astro config changed');
shouldClear = true;
}

if (currentConfigDigest && previousConfigDigest !== currentConfigDigest) {
logger.info('Content config changed');
shouldClear = true;
Expand All @@ -165,7 +182,10 @@ export class ContentLayer {
await this.#store.metaStore().set('astro-version', process.env.ASTRO_VERSION);
}
if (currentConfigDigest) {
await this.#store.metaStore().set('config-digest', currentConfigDigest);
await this.#store.metaStore().set('content-config-digest', currentConfigDigest);
}
if (astroConfigDigest) {
await this.#store.metaStore().set('astro-config-digest', astroConfigDigest);
}
await Promise.all(
Object.entries(contentConfig.config.collections).map(async ([name, collection]) => {
Expand Down
23 changes: 23 additions & 0 deletions packages/astro/src/content/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,3 +832,26 @@ export function contentModuleToId(fileName: string) {
params.set(CONTENT_MODULE_FLAG, 'true');
return `${DEFERRED_MODULE}?${params.toString()}`;
}

// Based on https://github.com/sindresorhus/safe-stringify
function safeStringifyReplacer(seen: WeakSet<object>) {
return function (_key: string, value: unknown) {
if (!(value !== null && typeof value === 'object')) {
return value;
}
if (seen.has(value)) {
return '[Circular]';
}
seen.add(value);
const newValue = Array.isArray(value) ? [] : {};
for (const [key2, value2] of Object.entries(value)) {
(newValue as Record<string, unknown>)[key2] = safeStringifyReplacer(seen)(key2, value2);
}
seen.delete(value);
return newValue;
};
}
export function safeStringify(value: unknown) {
const seen = new WeakSet();
return JSON.stringify(value, safeStringifyReplacer(seen));
}
14 changes: 13 additions & 1 deletion packages/astro/test/content-layer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ describe('Content Layer', () => {
assert.equal(newJson.entryWithReference.data.something?.content, 'transform me');
});

it('clears the store on new build if the config has changed', async () => {
it('clears the store on new build if the content config has changed', async () => {
let newJson = devalue.parse(await fixture.readFile('/collections.json'));
assert.equal(newJson.increment.data.lastValue, 1);
await fixture.editFile('src/content.config.ts', (prev) => {
Expand All @@ -299,6 +299,18 @@ describe('Content Layer', () => {
assert.equal(newJson.increment.data.lastValue, 1);
await fixture.resetAllFiles();
});

it('clears the store on new build if the Astro config has changed', async () => {
let newJson = devalue.parse(await fixture.readFile('/collections.json'));
assert.equal(newJson.increment.data.lastValue, 1);
await fixture.editFile('astro.config.mjs', (prev) => {
return prev.replace('Astro content layer', 'Astro more content layer');
});
await fixture.build();
newJson = devalue.parse(await fixture.readFile('/collections.json'));
assert.equal(newJson.increment.data.lastValue, 1);
await fixture.resetAllFiles();
});
});

describe('Dev', () => {
Expand Down
3 changes: 2 additions & 1 deletion packages/astro/test/fixtures/content-layer/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { defineConfig } from 'astro/config';
import { fileURLToPath } from 'node:url';

export default defineConfig({
integrations: [mdx(), {
name: 'Astro content layer',
integrations: [mdx(), {
name: '@astrojs/my-integration',
hooks: {
'astro:server:setup': async ({ server, refreshContent }) => {
Expand Down

0 comments on commit 36c1e06

Please sign in to comment.