Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/angular/build/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ ts_project(
":node_modules/jsonc-parser",
":node_modules/less",
":node_modules/listr2",
":node_modules/lmdb",
":node_modules/magic-string",
":node_modules/mrmime",
":node_modules/ng-packagr",
Expand Down
3 changes: 0 additions & 3 deletions packages/angular/build/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@
"vite": "7.3.1",
"watchpack": "2.5.1"
},
"optionalDependencies": {
"lmdb": "3.5.1"
},
"devDependencies": {
"@angular-devkit/core": "workspace:*",
"@angular/ssr": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ export function createCompilerPlugin(

// Initialize a worker pool for JavaScript transformations.
// Webcontainers currently do not support this persistent cache store.
let cacheStore: import('../lmdb-cache-store').LmdbCacheStore | undefined;
let cacheStore: import('../sqlite-cache-store').SqliteCacheStore | undefined;
if (pluginOptions.sourceFileCache?.persistentCachePath && !process.versions.webcontainer) {
try {
const { LmdbCacheStore } = await import('../lmdb-cache-store');
cacheStore = new LmdbCacheStore(
const { SqliteCacheStore } = await import('../sqlite-cache-store');
cacheStore = new SqliteCacheStore(
path.join(pluginOptions.sourceFileCache.persistentCachePath, 'angular-compiler.db'),
);
} catch (e) {
setupWarnings.push({
text: 'Unable to initialize JavaScript cache storage.',
location: null,
notes: [
// Only show first line of lmdb load error which has platform support listed
// Only show first line of sqlite load error
{ text: (e as Error)?.message.split('\n')[0] ?? `${e}` },
{
text: 'This will not affect the build output content but may result in slower builds.',
Expand Down
8 changes: 4 additions & 4 deletions packages/angular/build/src/tools/esbuild/i18n-inliner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { createHash } from 'node:crypto';
import { extname, join } from 'node:path';
import { WorkerPool } from '../../utils/worker-pool';
import { BuildOutputFile, BuildOutputFileType } from './bundler-context';
import type { LmdbCacheStore } from './lmdb-cache-store';
import type { SqliteCacheStore } from './sqlite-cache-store';
import { createOutputFile } from './utils';

/**
Expand Down Expand Up @@ -39,7 +39,7 @@ export interface I18nInlinerOptions {
export class I18nInliner {
#cacheInitFailed = false;
#workerPool: WorkerPool;
#cache: LmdbCacheStore | undefined;
#cache: SqliteCacheStore | undefined;
readonly #localizeFiles: ReadonlyMap<string, BuildOutputFile>;
readonly #unmodifiedFiles: Array<BuildOutputFile>;

Expand Down Expand Up @@ -274,9 +274,9 @@ export class I18nInliner {

// Initialize a persistent cache for i18n transformations.
try {
const { LmdbCacheStore } = await import('./lmdb-cache-store');
const { SqliteCacheStore } = await import('./sqlite-cache-store');

this.#cache = new LmdbCacheStore(join(persistentCachePath, 'angular-i18n.db'));
this.#cache = new SqliteCacheStore(join(persistentCachePath, 'angular-i18n.db'));
} catch {
this.#cacheInitFailed = true;

Expand Down
59 changes: 0 additions & 59 deletions packages/angular/build/src/tools/esbuild/lmdb-cache-store.ts

This file was deleted.

89 changes: 89 additions & 0 deletions packages/angular/build/src/tools/esbuild/sqlite-cache-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import assert from 'node:assert';
import { DatabaseSync, StatementSync } from 'node:sqlite';
import { deserialize, serialize } from 'node:v8';
import { Cache, type CacheStore } from './cache';

export class SqliteCacheStore implements CacheStore<unknown> {
#db: DatabaseSync | undefined;
#getStatement: StatementSync | undefined;
#hasStatement: StatementSync | undefined;
#setStatement: StatementSync | undefined;

constructor(readonly cachePath: string) {}

#ensureDb(): void {
if (this.#db) {
return;
}

const db = new DatabaseSync(this.cachePath);
db.exec(`
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
CREATE TABLE IF NOT EXISTS cache (
key TEXT PRIMARY KEY,
value BLOB
);
`);

this.#getStatement = db.prepare('SELECT value FROM cache WHERE key = ?');
this.#hasStatement = db.prepare('SELECT 1 FROM cache WHERE key = ?');
this.#setStatement = db.prepare('INSERT OR REPLACE INTO cache (key, value) VALUES (?, ?)');

this.#db = db;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async get(key: string): Promise<any> {
this.#ensureDb();

assert(this.#getStatement, 'getStatement should be initialized by ensureDb');

const result = this.#getStatement.get(key) as { value: Uint8Array } | undefined;
if (result) {
return deserialize(result.value);
}

return undefined;
}

has(key: string): boolean {
this.#ensureDb();

assert(this.#hasStatement, 'hasStatement should be initialized by ensureDb');

const result = this.#hasStatement.get(key);

return result !== undefined;
}

async set(key: string, value: unknown): Promise<this> {
this.#ensureDb();

assert(this.#setStatement, 'setStatement should be initialized by ensureDb');

this.#setStatement.run(key, serialize(value));

return this;
}

createCache<V = unknown>(namespace: string): Cache<V> {
return new Cache(this, namespace);
}

async close() {
try {
this.#db?.close();
} catch {
// Failure to close should not be fatal
}
}
}
Loading
Loading