diff options
-rw-r--r-- | .changeset/purple-pillows-lay.md | 5 | ||||
-rw-r--r-- | packages/astro/src/content/content-layer.ts | 6 | ||||
-rw-r--r-- | packages/astro/src/content/mutable-data-store.ts | 35 | ||||
-rw-r--r-- | packages/astro/src/core/build/index.ts | 4 | ||||
-rw-r--r-- | packages/astro/src/core/dev/container.ts | 1 | ||||
-rw-r--r-- | packages/astro/src/core/dev/dev.ts | 14 | ||||
-rw-r--r-- | packages/astro/src/core/sync/index.ts | 21 | ||||
-rw-r--r-- | packages/astro/test/astro-mode.test.js | 38 | ||||
-rw-r--r-- | packages/astro/test/fixtures/content-layer/src/pages/missing.astro | 2 |
9 files changed, 91 insertions, 35 deletions
diff --git a/.changeset/purple-pillows-lay.md b/.changeset/purple-pillows-lay.md new file mode 100644 index 000000000..c372a1068 --- /dev/null +++ b/.changeset/purple-pillows-lay.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a bug that caused empty content collections when running dev with NODE_ENV set diff --git a/packages/astro/src/content/content-layer.ts b/packages/astro/src/content/content-layer.ts index a544d5304..865da268c 100644 --- a/packages/astro/src/content/content-layer.ts +++ b/packages/astro/src/content/content-layer.ts @@ -278,8 +278,7 @@ export class ContentLayer { ); await fs.mkdir(this.#settings.config.cacheDir, { recursive: true }); await fs.mkdir(this.#settings.dotAstroDir, { recursive: true }); - const cacheFile = getDataStoreFile(this.#settings); - await this.#store.writeToDisk(cacheFile); + await this.#store.writeToDisk(); const assetImportsFile = new URL(ASSET_IMPORTS_FILE, this.#settings.dotAstroDir); await this.#store.writeAssetImports(assetImportsFile); const modulesImportsFile = new URL(MODULES_IMPORTS_FILE, this.#settings.dotAstroDir); @@ -379,8 +378,7 @@ export async function simpleLoader<TData extends { id: string }>( * During development, this is in the `.astro` directory so that the Vite watcher can see it. * In production, it's in the cache directory so that it's preserved between builds. */ -export function getDataStoreFile(settings: AstroSettings, isDev?: boolean) { - isDev ??= process?.env.NODE_ENV === 'development'; +export function getDataStoreFile(settings: AstroSettings, isDev: boolean) { return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir); } diff --git a/packages/astro/src/content/mutable-data-store.ts b/packages/astro/src/content/mutable-data-store.ts index 7f125ed4b..c033584d6 100644 --- a/packages/astro/src/content/mutable-data-store.ts +++ b/packages/astro/src/content/mutable-data-store.ts @@ -180,16 +180,15 @@ export default new Map([\n${lines.join(',\n')}]); #saveToDiskDebounced() { this.#dirty = true; - // Only save to disk if it has already been saved once - if (this.#file) { - if (this.#saveTimeout) { - clearTimeout(this.#saveTimeout); - } - this.#saveTimeout = setTimeout(() => { - this.#saveTimeout = undefined; - this.writeToDisk(this.#file!); - }, SAVE_DEBOUNCE_MS); + if (this.#saveTimeout) { + clearTimeout(this.#saveTimeout); } + this.#saveTimeout = setTimeout(() => { + this.#saveTimeout = undefined; + if (this.#file) { + this.writeToDisk(); + } + }, SAVE_DEBOUNCE_MS); } #writing = new Set<string>(); @@ -331,13 +330,15 @@ export default new Map([\n${lines.join(',\n')}]); return devalue.stringify(this._collections); } - async writeToDisk(filePath: PathLike) { + async writeToDisk() { if (!this.#dirty) { return; } + if (!this.#file) { + throw new AstroError(AstroErrorData.UnknownFilesystemError); + } try { - await this.#writeFileAtomic(filePath, this.toString()); - this.#file = filePath; + await this.#writeFileAtomic(this.#file, this.toString()); this.#dirty = false; } catch (err) { throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err }); @@ -373,10 +374,16 @@ export default new Map([\n${lines.join(',\n')}]); try { if (existsSync(filePath)) { const data = await fs.readFile(filePath, 'utf-8'); - return MutableDataStore.fromString(data); + const store = await MutableDataStore.fromString(data); + store.#file = filePath; + return store; + } else { + await fs.mkdir(new URL('./', filePath), { recursive: true }); } } catch {} - return new MutableDataStore(); + const store = new MutableDataStore(); + store.#file = filePath; + return store; } } diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 1fcbd6f03..e39280018 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -68,7 +68,8 @@ export default async function build( const settings = await createSettings(astroConfig, fileURLToPath(astroConfig.root)); if (inlineConfig.force) { - await clearContentLayerCache({ settings, logger, fs }); + // isDev is always false, because it's interested in the build command, not the output type + await clearContentLayerCache({ settings, logger, fs, isDev: false }); } const builder = new AstroBuilder(settings, { @@ -154,6 +155,7 @@ class AstroBuilder { logger, fs, manifest: this.manifest, + command: 'build', }); return { viteConfig }; diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 3484227af..e82f65a0b 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -119,6 +119,7 @@ export async function createContainer({ }, force: inlineConfig?.force, manifest, + command: 'dev', }); const viteServer = await vite.createServer(viteConfig); diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts index 31b677ef8..b54074c8e 100644 --- a/packages/astro/src/core/dev/dev.ts +++ b/packages/astro/src/core/dev/dev.ts @@ -1,4 +1,4 @@ -import fs, { existsSync } from 'node:fs'; +import fs from 'node:fs'; import type http from 'node:http'; import type { AddressInfo } from 'node:net'; import { performance } from 'node:perf_hooks'; @@ -87,22 +87,22 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevS let store: MutableDataStore | undefined; try { const dataStoreFile = getDataStoreFile(restart.container.settings, true); - if (existsSync(dataStoreFile)) { - store = await MutableDataStore.fromFile(dataStoreFile); - } + store = await MutableDataStore.fromFile(dataStoreFile); } catch (err: any) { logger.error('content', err.message); } - if (!store) { - store = new MutableDataStore(); + + if(!store) { + logger.error('content', 'Failed to create data store'); } + await attachContentServerListeners(restart.container); const config = globalContentConfigObserver.get(); if (config.status === 'error') { logger.error('content', config.error.message); } - if (config.status === 'loaded') { + if (config.status === 'loaded' && store) { const contentLayer = globalContentLayer.init({ settings: restart.container.settings, logger, diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index ff408e323..6f796c171 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -1,4 +1,4 @@ -import fsMod, { existsSync } from 'node:fs'; +import fsMod from 'node:fs'; import { dirname, relative } from 'node:path'; import { performance } from 'node:perf_hooks'; import { fileURLToPath } from 'node:url'; @@ -49,6 +49,7 @@ export type SyncOptions = { cleanup?: boolean; }; manifest: ManifestData; + command: "build" | "dev" | "sync"; }; export default async function sync( @@ -78,6 +79,7 @@ export default async function sync( fs, force: inlineConfig.force, manifest, + command: 'sync', }); } @@ -88,12 +90,14 @@ export async function clearContentLayerCache({ settings, logger, fs = fsMod, + isDev, }: { settings: AstroSettings; logger: Logger; fs?: typeof fsMod; + isDev: boolean; }) { - const dataStore = getDataStoreFile(settings); + const dataStore = getDataStoreFile(settings, isDev); if (fs.existsSync(dataStore)) { logger.debug('content', 'clearing data store'); await fs.promises.rm(dataStore, { force: true }); @@ -115,9 +119,11 @@ export async function syncInternal({ skip, force, manifest, + command, }: SyncOptions): Promise<void> { + const isDev = command === 'dev'; if (force) { - await clearContentLayerCache({ settings, logger, fs }); + await clearContentLayerCache({ settings, logger, fs, isDev }); } const timerStart = performance.now(); @@ -127,15 +133,14 @@ export async function syncInternal({ settings.timer.start('Sync content layer'); let store: MutableDataStore | undefined; try { - const dataStoreFile = getDataStoreFile(settings); - if (existsSync(dataStoreFile)) { - store = await MutableDataStore.fromFile(dataStoreFile); - } + const dataStoreFile = getDataStoreFile(settings, isDev); + store = await MutableDataStore.fromFile(dataStoreFile); } catch (err: any) { logger.error('content', err.message); } if (!store) { - store = new MutableDataStore(); + logger.error('content', 'Failed to load content store'); + return; } const contentLayer = globalContentLayer.init({ settings, diff --git a/packages/astro/test/astro-mode.test.js b/packages/astro/test/astro-mode.test.js index 09585831a..cffacce6e 100644 --- a/packages/astro/test/astro-mode.test.js +++ b/packages/astro/test/astro-mode.test.js @@ -2,15 +2,25 @@ import assert from 'node:assert/strict'; import { after, afterEach, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import { loadFixture } from './test-utils.js'; +import { existsSync, promises as fs } from 'node:fs'; describe('--mode', () => { /** @type {import('./test-utils.js').Fixture} */ let fixture; + let devDataStoreFile; + let prodDataStoreFile; + + async function deleteDataStoreFiles() { + await fs.unlink(devDataStoreFile).catch(() => {}); + await fs.unlink(prodDataStoreFile).catch(() => {}); + } before(async () => { fixture = await loadFixture({ root: './fixtures/astro-mode/', }); + devDataStoreFile = new URL('./.astro/data-store.json', fixture.config.root); + prodDataStoreFile = new URL('./node_modules/.astro/data-store.json', fixture.config.root); }); afterEach(() => { @@ -25,6 +35,7 @@ describe('--mode', () => { describe('build', () => { before(async () => { + await deleteDataStoreFiles(); await fixture.build(); }); @@ -37,10 +48,15 @@ describe('--mode', () => { assert.equal($('#env-title').text(), 'production'); assert.equal($('#env-astro-title').text(), 'production'); }); + + it('writes data store file in the correct location', async () => { + assert.ok(existsSync(prodDataStoreFile)); + }) }); describe('build --mode testing --devOutput', () => { before(async () => { + await deleteDataStoreFiles(); await fixture.build({ mode: 'testing' }, { devOutput: true }); }); @@ -52,11 +68,17 @@ describe('--mode', () => { assert.equal($('#env-prod').text(), 'false'); assert.equal($('#env-title').text(), ''); assert.equal($('#env-astro-title').text(), 'unset'); + assert.ok }); + + it('writes data store file in the correct location', async () => { + assert.ok(existsSync(prodDataStoreFile)); + }) }); describe('build --mode staging', () => { before(async () => { + await deleteDataStoreFiles(); await fixture.build({ mode: 'staging' }); }); @@ -69,12 +91,18 @@ describe('--mode', () => { assert.equal($('#env-title').text(), 'staging'); assert.equal($('#env-astro-title').text(), 'staging'); }); + + it('writes data store file in the correct location', async () => { + assert.ok(existsSync(prodDataStoreFile)); + }) + }); describe('dev', () => { /** @type {import('./test-utils.js').DevServer} */ let devServer; before(async () => { + await deleteDataStoreFiles(); devServer = await fixture.startDevServer(); }); after(async () => { @@ -92,12 +120,17 @@ describe('--mode', () => { assert.equal($('#env-title').text(), 'development'); assert.equal($('#env-astro-title').text(), 'development'); }); + + it('writes data store file in the correct location', async () => { + assert.ok(existsSync(devDataStoreFile)); + }) }); describe('dev --mode develop', () => { /** @type {import('./test-utils.js').DevServer} */ let devServer; before(async () => { + await deleteDataStoreFiles(); devServer = await fixture.startDevServer({ mode: 'develop' }); }); after(async () => { @@ -115,5 +148,10 @@ describe('--mode', () => { assert.equal($('#env-title').text(), ''); assert.equal($('#env-astro-title').text(), 'unset'); }); + + it('writes data store file in the correct location', async () => { + assert.ok(existsSync(devDataStoreFile)); + }) + }); }); diff --git a/packages/astro/test/fixtures/content-layer/src/pages/missing.astro b/packages/astro/test/fixtures/content-layer/src/pages/missing.astro index 6fee7db07..f0e65d1bc 100644 --- a/packages/astro/test/fixtures/content-layer/src/pages/missing.astro +++ b/packages/astro/test/fixtures/content-layer/src/pages/missing.astro @@ -1,7 +1,7 @@ --- import { getEntry, render } from "astro:content" // Skipping the broken page in production so the build doesn't fail -if(import.meta.env.PROD) { +if(import.meta.env.PROD || import.meta.env.MODE === "production") { return new Response(null, { status: 404 }) } |