0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-30 22:03:56 -05:00

fix: clear the content layer cache when the Astro config changes (#12767)

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

* Use deterministic-object-hash

* Switch back to safe-stringify

* Whitespace
This commit is contained in:
Matt Kane 2024-12-18 14:01:56 +00:00 committed by GitHub
parent a581c152fc
commit 36c1e0697d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 66 additions and 5 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Clears the content layer cache when the Astro config is changed

View file

@ -19,6 +19,7 @@ import {
getEntryConfigByExtMap,
getEntryDataAndImages,
globalContentConfigObserver,
safeStringify,
} from './utils.js';
export interface ContentLayerOptions {
@ -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);
};
@ -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;
@ -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]) => {

View file

@ -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));
}

View file

@ -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) => {
@ -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', () => {

View file

@ -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 }) => {