Skip to content
Open
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
6 changes: 3 additions & 3 deletions packages/angular/build/src/tools/angular/angular-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export type AngularCompilerHost = ng.CompilerHost;

export interface AngularHostOptions {
fileReplacements?: Record<string, string>;
sourceFileCache?: Map<string, ts.SourceFile>;
modifiedFiles?: Set<string>;
externalStylesheets?: Map<string, string>;
transformStylesheet(
Expand Down Expand Up @@ -165,6 +164,7 @@ export function createAngularCompilerHost(
compilerOptions: AngularCompilerOptions,
hostOptions: AngularHostOptions,
packageJsonCache: ts.PackageJsonInfoCache | undefined,
sourceFileCache?: Map<string, ts.SourceFile>,
): AngularCompilerHost {
// Create TypeScript compiler host
const host: AngularCompilerHost = typescript.createIncrementalCompilerHost(compilerOptions);
Expand Down Expand Up @@ -254,8 +254,8 @@ export function createAngularCompilerHost(
}

// Augment TypeScript Host with source file caching if provided
if (hostOptions.sourceFileCache) {
augmentHostWithCaching(host, hostOptions.sourceFileCache);
if (sourceFileCache) {
augmentHostWithCaching(host, sourceFileCache);
}

return host;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import assert from 'node:assert';
import { relative } from 'node:path';
import ts from 'typescript';
import { useTypeChecking } from '../../../utils/environment-options';
import { toPosixPath } from '../../../utils/path';
import { profileAsync, profileSync } from '../../esbuild/profiling';
import {
AngularHostOptions,
Expand Down Expand Up @@ -55,6 +56,7 @@ class AngularCompilationState {

export class AotCompilation extends AngularCompilation {
#state?: AngularCompilationState;
readonly #sourceFiles = new Map<string, ts.SourceFile>();

constructor(private readonly browserOnlyBuild: boolean) {
super();
Expand Down Expand Up @@ -97,27 +99,37 @@ export class AotCompilation extends AngularCompilation {

let staleSourceFiles;
let clearPackageJsonCache = false;
if (hostOptions.modifiedFiles && this.#state) {
if (hostOptions.modifiedFiles) {
for (const modifiedFile of hostOptions.modifiedFiles) {
// Clear package.json cache if a node modules file was modified
if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) {
clearPackageJsonCache = true;
packageJsonCache?.clear();
}
this.#sourceFiles.delete(toPosixPath(modifiedFile));

// Collect stale source files for HMR analysis of inline component resources
if (useHmr) {
const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
if (sourceFile) {
staleSourceFiles ??= new Map<string, ts.SourceFile>();
staleSourceFiles.set(modifiedFile, sourceFile);
if (this.#state) {
// Clear package.json cache if a node modules file was modified
if (!clearPackageJsonCache && modifiedFile.includes('node_modules')) {
clearPackageJsonCache = true;
packageJsonCache?.clear();
}

// Collect stale source files for HMR analysis of inline component resources
if (useHmr) {
const sourceFile = this.#state.typeScriptProgram.getSourceFile(modifiedFile);
if (sourceFile) {
staleSourceFiles ??= new Map<string, ts.SourceFile>();
staleSourceFiles.set(modifiedFile, sourceFile);
}
}
}
}
}

// Create Angular compiler host
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, packageJsonCache);
const host = createAngularCompilerHost(
ts,
compilerOptions,
hostOptions,
packageJsonCache,
this.#sourceFiles,
);

// Create the Angular specific program that contains the Angular compiler
const angularProgram = profileSync(
Expand Down Expand Up @@ -451,6 +463,12 @@ export class AotCompilation extends AngularCompilation {

return emittedFiles.values();
}

override async update(files: Set<string>): Promise<void> {
for (const file of files) {
this.#sourceFiles.delete(toPosixPath(file));
}
}
}

function findAffectedFiles(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import type * as ng from '@angular/compiler-cli';
import assert from 'node:assert';
import ts from 'typescript';
import { toPosixPath } from '../../../utils/path';
import { profileSync } from '../../esbuild/profiling';
import { AngularHostOptions, createAngularCompilerHost } from '../angular-host';
import { createJitResourceTransformer } from '../transformers/jit-resource-transformer';
Expand All @@ -33,6 +34,7 @@ class JitCompilationState {

export class JitCompilation extends AngularCompilation {
#state?: JitCompilationState;
readonly #sourceFiles = new Map<string, ts.SourceFile>();

constructor(private readonly browserOnlyBuild: boolean) {
super();
Expand All @@ -56,8 +58,20 @@ export class JitCompilation extends AngularCompilation {
const compilerOptions =
compilerOptionsTransformer?.(originalCompilerOptions) ?? originalCompilerOptions;

if (hostOptions.modifiedFiles) {
for (const modifiedFile of hostOptions.modifiedFiles) {
this.#sourceFiles.delete(toPosixPath(modifiedFile));
}
}

// Create Angular compiler host
const host = createAngularCompilerHost(ts, compilerOptions, hostOptions, undefined);
const host = createAngularCompilerHost(
ts,
compilerOptions,
hostOptions,
undefined,
this.#sourceFiles,
);

// Create the TypeScript Program
const typeScriptProgram = profileSync('TS_CREATE_PROGRAM', () =>
Expand All @@ -70,10 +84,6 @@ export class JitCompilation extends AngularCompilation {
),
);

const affectedFiles = profileSync('TS_FIND_AFFECTED', () =>
findAffectedFiles(typeScriptProgram),
);

this.#state = new JitCompilationState(
host,
typeScriptProgram,
Expand Down Expand Up @@ -157,17 +167,10 @@ export class JitCompilation extends AngularCompilation {

return emittedFiles;
}
}

function findAffectedFiles(
builder: ts.EmitAndSemanticDiagnosticsBuilderProgram,
): Set<ts.SourceFile> {
const affectedFiles = new Set<ts.SourceFile>();

let result;
while ((result = builder.getSemanticDiagnosticsOfNextAffectedFile())) {
affectedFiles.add(result.affected as ts.SourceFile);
override async update(files: Set<string>): Promise<void> {
for (const file of files) {
this.#sourceFiles.delete(toPosixPath(file));
}
}

return affectedFiles;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import assert from 'node:assert';
import { randomUUID } from 'node:crypto';
import { type MessagePort, receiveMessageOnPort } from 'node:worker_threads';
import { initializeHash } from '../../../utils/hash';
import { SourceFileCache } from '../../esbuild/angular/source-file-cache';
import { getAndClearCumulativeDurations } from '../../esbuild/profiling';
import type {
AngularCompilation,
Expand All @@ -35,9 +34,12 @@ export interface InitRequest {

let compilation: AngularCompilation | undefined;

const sourceFileCache = new SourceFileCache();
const modifiedFiles = new Set<string>();

export async function initialize(request: InitRequest): Promise<AngularCompilationResult> {
const currentModifiedFiles = new Set(modifiedFiles);
modifiedFiles.clear();

await initializeHash();
Comment thread
clydin marked this conversation as resolved.
compilation ??= request.jit
? new JitCompilation(request.browserOnlyBuild)
Expand All @@ -62,8 +64,7 @@ export async function initialize(request: InitRequest): Promise<AngularCompilati
request.tsconfig,
{
fileReplacements: request.fileReplacements,
sourceFileCache,
modifiedFiles: sourceFileCache.modifiedFiles,
modifiedFiles: currentModifiedFiles,
transformStylesheet(data, containingFile, stylesheetFile, order, className) {
const requestId = randomUUID();
const resultPromise = new Promise<string>((resolve, reject) =>
Expand Down Expand Up @@ -151,6 +152,9 @@ export async function emit() {
return [...files];
}

export function update(files: Set<string>): void {
sourceFileCache.invalidate(files);
export async function update(files: Set<string>): Promise<void> {
for (const file of files) {
modifiedFiles.add(file);
}
await compilation?.update?.(files);
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ export function createCompilerPlugin(
const hostOptions: AngularHostOptions = {
fileReplacements: pluginOptions.fileReplacements,
modifiedFiles,
sourceFileCache: pluginOptions.sourceFileCache,
async transformStylesheet(data, containingFile, stylesheetFile, order, className) {
let stylesheetResult;
let resultSource = stylesheetFile ?? containingFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,24 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { platform } from 'node:os';
import * as path from 'node:path';
import type ts from 'typescript';
import { MemoryLoadResultCache } from '../load-result-cache';

const USING_WINDOWS = platform() === 'win32';
const WINDOWS_SEP_REGEXP = new RegExp(`\\${path.win32.sep}`, 'g');

export class SourceFileCache extends Map<string, ts.SourceFile> {
export class SourceFileCache {
readonly modifiedFiles = new Set<string>();
readonly typeScriptFileCache = new Map<string, string | Uint8Array>();
readonly loadResultCache = new MemoryLoadResultCache();

referencedFiles?: readonly string[];

constructor(readonly persistentCachePath?: string) {
super();
}
constructor(readonly persistentCachePath?: string) {}

/**
* Releases all cached content. The cached data is only needed for incremental
* rebuilds and can include the emitted contents of every TypeScript file in the
* program. The cache is repopulated if a build is performed after this is called.
*/
override clear(): void {
super.clear();
clear(): void {
this.modifiedFiles.clear();
this.typeScriptFileCache.clear();
this.loadResultCache.clear();
Expand All @@ -50,13 +42,6 @@ export class SourceFileCache extends Map<string, ts.SourceFile> {
file = path.normalize(file);
invalid = this.loadResultCache.invalidate(file) || invalid;
invalid = extraWatchFiles.has(file) || invalid;

// Normalize separators to allow matching TypeScript Host paths
if (USING_WINDOWS) {
file = file.replace(WINDOWS_SEP_REGEXP, path.posix.sep);
}

invalid = this.delete(file) || invalid;
this.modifiedFiles.add(file);
}

Expand Down