Skip to content

Commit 0dfec97

Browse files
committed
fix(@angular/build): ensure parent directory exists in SQLite cache store
Previously, initializing DatabaseSync directly with a path in a nonexistent directory failed with an unable to open database file error. Unlike other storage backends, node:sqlite does not recursively create parent directory structures. Parent directories for the cache database are now created recursively before opening the database file, preventing initialization errors when the cache directory does not yet exist.
1 parent 3b01482 commit 0dfec97

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

packages/angular/build/src/tools/esbuild/sqlite-cache-store.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import { mkdirSync } from 'node:fs';
10+
import { dirname } from 'node:path';
911
import { DatabaseSync, StatementSync } from 'node:sqlite';
1012
import { deserialize, serialize } from 'node:v8';
1113
import { Cache, PersistentCacheStore } from './cache';
@@ -35,7 +37,17 @@ export class SqliteCacheStore implements PersistentCacheStore<unknown> {
3537

3638
#ensureDb(): DatabaseSync {
3739
if (!this.#db) {
38-
this.#db = new DatabaseSync(this.cachePath);
40+
// Optimistically attempt to open the database file first to avoid directory creation
41+
// syscalls on warm builds where the parent directory already exists.
42+
try {
43+
this.#db = new DatabaseSync(this.cachePath);
44+
} catch {
45+
if (this.cachePath !== ':memory:') {
46+
mkdirSync(dirname(this.cachePath), { recursive: true });
47+
}
48+
this.#db = new DatabaseSync(this.cachePath);
49+
}
50+
3951
// Optimize SQLite for cache usage
4052
this.#db.exec('PRAGMA auto_vacuum = FULL;');
4153
this.#db.exec('PRAGMA journal_mode = WAL;');

packages/angular/build/src/tools/esbuild/sqlite-cache-store_spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,20 @@ describe('SqliteCacheStore', () => {
220220
}
221221
});
222222

223+
it('should create parent directories if they do not exist', async () => {
224+
const nestedDir = join(tempDir, 'nested', 'deeply', 'cache');
225+
const nestedCachePath = join(nestedDir, 'nested-cache.db');
226+
const nestedStore = new SqliteCacheStore(nestedCachePath);
227+
228+
try {
229+
await nestedStore.set('nested-key', 'nested-value');
230+
const result = await nestedStore.get('nested-key');
231+
expect(result).toBe('nested-value');
232+
} finally {
233+
nestedStore.close();
234+
}
235+
});
236+
223237
describe('NG_BUILD_CACHE_STORE env variable option', () => {
224238
it('should force SQLite when NG_BUILD_CACHE_STORE=sqlite', () => {
225239
const code = `

0 commit comments

Comments
 (0)