summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matt Kane <m@mk.gg> 2025-01-09 16:10:04 +0000
committerGravatar GitHub <noreply@github.com> 2025-01-09 16:10:04 +0000
commit3c2292f2f0accf1974b30dbe32f040c56413e731 (patch)
treecce9903fb8fc8466e97f51228c7946900dd4cd8b
parent0414f618a6eaa3778b5791e22bfd4567426c0214 (diff)
downloadastro-3c2292f2f0accf1974b30dbe32f040c56413e731.tar.gz
astro-3c2292f2f0accf1974b30dbe32f040c56413e731.tar.zst
astro-3c2292f2f0accf1974b30dbe32f040c56413e731.zip
fix: explicitly set dev mode for data store (#12947)
* fix: explicitly set dev mode for data store * Error handling * Add check for file before saving * rm unused import * Use explicit command * Ensure dir before writing
-rw-r--r--.changeset/purple-pillows-lay.md5
-rw-r--r--packages/astro/src/content/content-layer.ts6
-rw-r--r--packages/astro/src/content/mutable-data-store.ts35
-rw-r--r--packages/astro/src/core/build/index.ts4
-rw-r--r--packages/astro/src/core/dev/container.ts1
-rw-r--r--packages/astro/src/core/dev/dev.ts14
-rw-r--r--packages/astro/src/core/sync/index.ts21
-rw-r--r--packages/astro/test/astro-mode.test.js38
-rw-r--r--packages/astro/test/fixtures/content-layer/src/pages/missing.astro2
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 })
}