mirror of
https://github.com/withastro/astro.git
synced 2025-02-17 22:44:24 -05:00
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
This commit is contained in:
parent
0414f618a6
commit
3c2292f2f0
9 changed files with 91 additions and 35 deletions
5
.changeset/purple-pillows-lay.md
Normal file
5
.changeset/purple-pillows-lay.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fixes a bug that caused empty content collections when running dev with NODE_ENV set
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -119,6 +119,7 @@ export async function createContainer({
|
|||
},
|
||||
force: inlineConfig?.force,
|
||||
manifest,
|
||||
command: 'dev',
|
||||
});
|
||||
|
||||
const viteServer = await vite.createServer(viteConfig);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
} catch (err: any) {
|
||||
logger.error('content', err.message);
|
||||
}
|
||||
|
||||
if(!store) {
|
||||
store = new MutableDataStore();
|
||||
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,
|
||||
|
|
|
@ -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)) {
|
||||
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,
|
||||
|
|
|
@ -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));
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue