Skip to content

Commit 92da0d6

Browse files
committed
refactor(@angular/build): add NG_BUILD_CACHE_STORE environment variable support
This change introduces the `NG_BUILD_CACHE_STORE` environment variable to allow users and developers to customize the backing persistent cache storage mechanism. Usage: By default, the build system automatically uses the native LMDB cache store and falls back to the built-in SQLite cache store if LMDB fails to initialize. Users can now explicitly control this behavior by setting `NG_BUILD_CACHE_STORE` to one of the following values: - `sqlite`: Forces the use of the built-in SQLite cache store. No attempts to load the native LMDB store will be made. - `lmdb`: Forces the use of the native LMDB cache store. If the LMDB store fails to initialize, the build will fail. - `auto` / unset: Standard behavior (attempts LMDB first, falls back to SQLite). Example: $ NG_BUILD_CACHE_STORE=sqlite ng build
1 parent 131b4c9 commit 92da0d6

3 files changed

Lines changed: 111 additions & 0 deletions

File tree

packages/angular/build/src/tools/esbuild/cache.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Provides infrastructure for common caching functionality within the build system.
1212
*/
1313

14+
import { persistentCacheStoreSetting } from '../../utils/environment-options';
1415
import { assertIsError } from '../../utils/error';
1516

1617
/**
@@ -248,6 +249,36 @@ export class MemoryCache<V> extends Cache<V, Map<string, V>> {
248249
export async function createPersistentCacheStore(
249250
baseCachePath: string,
250251
): Promise<PersistentCacheStore> {
252+
if (persistentCacheStoreSetting === 'sqlite') {
253+
try {
254+
const { SqliteCacheStore } = await import('./sqlite-cache-store');
255+
256+
return new SqliteCacheStore(baseCachePath + '-sqlite.db');
257+
} catch (err) {
258+
assertIsError(err);
259+
260+
throw new Error(
261+
'Unable to initialize JavaScript cache storage.\n' + `SQLite error: ${err.message}`,
262+
{ cause: err },
263+
);
264+
}
265+
}
266+
267+
if (persistentCacheStoreSetting === 'lmdb') {
268+
try {
269+
const { LmdbCacheStore } = await import('./lmdb-cache-store');
270+
271+
return new LmdbCacheStore(baseCachePath + '.db');
272+
} catch (err) {
273+
assertIsError(err);
274+
275+
throw new Error(
276+
'Unable to initialize JavaScript cache storage.\n' + `LMDB error: ${err.message}`,
277+
{ cause: err },
278+
);
279+
}
280+
}
281+
251282
try {
252283
const { LmdbCacheStore } = await import('./lmdb-cache-store');
253284

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,68 @@ describe('SqliteCacheStore', () => {
111111
expect(checkStore.has('k1')).toBeFalse();
112112
checkStore.close();
113113
});
114+
115+
describe('NG_BUILD_CACHE_STORE env variable option', () => {
116+
it('should force SQLite when NG_BUILD_CACHE_STORE=sqlite', () => {
117+
const code = `
118+
(async () => {
119+
const { createPersistentCacheStore } = await import('./cache.js');
120+
const { SqliteCacheStore } = await import('./sqlite-cache-store.js');
121+
const store = await createPersistentCacheStore('dummy-sqlite-env');
122+
if (!(store instanceof SqliteCacheStore)) {
123+
console.error('Expected SqliteCacheStore, got:', store.constructor.name);
124+
process.exit(1);
125+
}
126+
})().catch(err => {
127+
console.error(err);
128+
process.exit(2);
129+
});
130+
`;
131+
const { execFileSync } = require('node:child_process');
132+
execFileSync(process.execPath, ['--input-type=module', '-e', code], {
133+
cwd: __dirname,
134+
env: {
135+
...process.env,
136+
NG_BUILD_CACHE_STORE: 'sqlite',
137+
},
138+
});
139+
});
140+
141+
it('should force LMDB when NG_BUILD_CACHE_STORE=lmdb', () => {
142+
const code = `
143+
(async () => {
144+
const { createPersistentCacheStore } = await import('./cache.js');
145+
const { LmdbCacheStore } = await import('./lmdb-cache-store.js');
146+
const store = await createPersistentCacheStore('dummy-lmdb-env');
147+
if (!(store instanceof LmdbCacheStore)) {
148+
console.error('Expected LmdbCacheStore, got:', store.constructor.name);
149+
process.exit(1);
150+
}
151+
})().catch(err => {
152+
console.error(err);
153+
process.exit(2);
154+
});
155+
`;
156+
const { execFileSync } = require('node:child_process');
157+
try {
158+
execFileSync(process.execPath, ['--input-type=module', '-e', code], {
159+
cwd: __dirname,
160+
env: {
161+
...process.env,
162+
NG_BUILD_CACHE_STORE: 'lmdb',
163+
},
164+
});
165+
} catch (e) {
166+
if (e && typeof e === 'object' && 'message' in e) {
167+
const error = e as { message: string; stderr?: Buffer };
168+
const output = error.stderr?.toString() || error.message;
169+
if (!output.includes('Unable to initialize JavaScript cache storage')) {
170+
throw e;
171+
}
172+
} else {
173+
throw e;
174+
}
175+
}
176+
});
177+
});
114178
});

packages/angular/build/src/utils/environment-options.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,19 @@ export const bazelEsbuildPluginPath =
201201
bazelBinDirectory && bazelExecRoot
202202
? process.env['NG_INTERNAL_ESBUILD_PLUGINS_DO_NOT_USE']
203203
: undefined;
204+
205+
/**
206+
* The persistent cache store configuration to use.
207+
* Managed by the `NG_BUILD_CACHE_STORE` environment variable.
208+
* - 'lmdb': Forces the use of LMDB.
209+
* - 'sqlite': Forces the use of SQLite.
210+
* - undefined / 'auto' / other: Automatically uses LMDB and falls back to SQLite.
211+
*/
212+
export const persistentCacheStoreSetting = (() => {
213+
const env = process.env['NG_BUILD_CACHE_STORE']?.trim().toLowerCase();
214+
if (env === 'lmdb' || env === 'sqlite') {
215+
return env;
216+
}
217+
218+
return undefined;
219+
})();

0 commit comments

Comments
 (0)