Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

import { BuilderContext } from '@angular-devkit/architect';
import { createAngularCompilation } from '../../tools/angular/compilation';
import { AngularCompilationContext } from '../../tools/esbuild/angular/compilation-state';
import {
AngularCompilationContext,
PrimaryCompilationContext,
} from '../../tools/esbuild/angular/compilation-state';
import { SourceFileCache } from '../../tools/esbuild/angular/source-file-cache';
import { generateBudgetStats } from '../../tools/esbuild/budget-stats';
import { BundleContextResult, BundlerContext } from '../../tools/esbuild/bundler-context';
Expand Down Expand Up @@ -125,7 +128,7 @@ export async function executeBuild(
!!options.jit,
!options.serverEntryPoint,
);
angularCompilationContext = new AngularCompilationContext(angularCompilation);
angularCompilationContext = new PrimaryCompilationContext(angularCompilation);
bundlerContexts = setupBundlerContexts(
options,
target,
Expand Down
5 changes: 3 additions & 2 deletions packages/angular/build/src/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
* their existence may change in any future version.
*/

import { NoopCompilation, createAngularCompilation } from './tools/angular/compilation';
import { createAngularCompilation } from './tools/angular/compilation';
import { SecondaryCompilationContext } from './tools/esbuild/angular/compilation-state';
import {
CompilerPluginOptions,
createCompilerPlugin as internalCreateCompilerPlugin,
Expand Down Expand Up @@ -52,7 +53,7 @@ export function createCompilerPlugin(
return internalCreateCompilerPlugin(
pluginOptions,
pluginOptions.noopTypeScriptCompilation
? new NoopCompilation()
? new SecondaryCompilationContext()
: () => createAngularCompilation(!!pluginOptions.jit, !!pluginOptions.browserOnlyBuild),
new ComponentStylesheetBundler(
styleOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
AngularCompilation,
AngularCompilationResult,
DiagnosticModes,
NoopCompilation,
createAngularCompilation,
} from './index';

Expand Down Expand Up @@ -59,44 +58,6 @@ describe('AngularCompilation', () => {
expect(diagnostics).toEqual({});
});

describe('NoopCompilation', () => {
it('initializes with empty referencedFiles and compiler options', async () => {
const compilation = new NoopCompilation();
const mockHostOptions = {} as AngularHostOptions;
const result = await compilation.initialize('tsconfig.json', mockHostOptions);

expect(result.referencedFiles).toEqual([]);
expect(result.compilerOptions).toBeDefined();
});

it('initializes with CompilerOptionOverrides object', async () => {
const compilation = new NoopCompilation();
const mockHostOptions = {} as AngularHostOptions;
const result = await compilation.initialize('tsconfig.json', mockHostOptions, {
sourcemap: true,
enableHmr: true,
});

expect(result.referencedFiles).toEqual([]);
expect(result.compilerOptions.inlineSources).toBe(true);
expect(result.compilerOptions.inlineSourceMap).toBe(true);
expect(result.compilerOptions['_enableHmr']).toBe(true);
});

it('throws when calling emitAffectedFiles', () => {
const compilation = new NoopCompilation();
expect(() => compilation.emitAffectedFiles()).toThrowError(
'Not available when using noop compilation.',
);
});

it('returns empty diagnostics from diagnoseFiles', async () => {
const compilation = new NoopCompilation();
const diagnostics = await compilation.diagnoseFiles();
expect(diagnostics).toEqual({});
});
});

describe('TypeScriptCompilation', () => {
class MockTypeScriptCompilation extends TypeScriptCompilation {
async initialize(): Promise<AngularCompilationResult> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ export {
} from './angular-compilation';
export type { CompilerOptionOverrides } from './compiler-options';
export { createAngularCompilation, type AngularCompilationMode } from './factory';
export { NoopCompilation } from './noop-compilation';

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,46 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { type AngularCompilation, NoopCompilation } from '../../angular/compilation';
import type { CompilerOptions } from '@angular/compiler-cli';
import type { AngularCompilation } from '../../angular/compilation';

export class AngularCompilationContext {
#compilation: AngularCompilation;
export abstract class AngularCompilationContext {
abstract readonly compilation?: AngularCompilation;
abstract isPrimary(): this is PrimaryCompilationContext;
abstract readonly waitUntilReady: Promise<boolean>;
abstract getCompilerOptions(): Promise<CompilerOptions>;
abstract dispose(): Promise<void>;

createSecondaryContext(): AngularCompilationContext {
return new SecondaryCompilationContext(this);
}
}

export class PrimaryCompilationContext extends AngularCompilationContext {
readonly #compilation: AngularCompilation;
#pendingCompilation = true;
#resolveCompilationReady: ((value: boolean) => void) | undefined;
#compilationReadyPromise: Promise<boolean> | undefined;
#hasErrors = true;

#compilerOptions: CompilerOptions | undefined;
#resolveCompilerOptions: ((options: CompilerOptions) => void) | undefined;
#compilerOptionsPromise: Promise<CompilerOptions> | undefined;

constructor(compilation: AngularCompilation) {
super();
this.#compilation = compilation;
}

get compilation(): AngularCompilation {
override isPrimary(): this is PrimaryCompilationContext {
return true;
}

override get compilation(): AngularCompilation {
return this.#compilation;
}

get waitUntilReady(): Promise<boolean> {
override get waitUntilReady(): Promise<boolean> {
if (!this.#pendingCompilation) {
return Promise.resolve(this.#hasErrors);
}
Expand All @@ -35,20 +57,51 @@ export class AngularCompilationContext {
return this.#compilationReadyPromise;
}

override getCompilerOptions(): Promise<CompilerOptions> {
if (this.#compilerOptions) {
return Promise.resolve(this.#compilerOptions);
}

if (!this.#pendingCompilation) {
return Promise.resolve({});
}

this.#compilerOptionsPromise ??= new Promise((resolve) => {
this.#resolveCompilerOptions = resolve;
});

return this.#compilerOptionsPromise;
}

setCompilerOptions(options: CompilerOptions): void {
this.#compilerOptions = options;
this.#resolveCompilerOptions?.(options);
this.#resolveCompilerOptions = undefined;
this.#compilerOptionsPromise = undefined;
}

markAsReady(hasErrors: boolean): void {
this.#hasErrors = hasErrors;
this.#resolveCompilationReady?.(hasErrors);
this.#resolveCompilationReady = undefined;
this.#compilationReadyPromise = undefined;
this.#pendingCompilation = false;
Comment thread
clydin marked this conversation as resolved.

if (this.#resolveCompilerOptions) {
this.#resolveCompilerOptions(this.#compilerOptions ?? {});
this.#resolveCompilerOptions = undefined;
this.#compilerOptionsPromise = undefined;
}
}

markAsInProgress(): void {
this.#pendingCompilation = true;
this.#compilerOptions = undefined;
}

#disposal: Promise<void> | undefined;

dispose(): Promise<void> {
override dispose(): Promise<void> {
// Reuse any in progress disposal to ensure all callers can await completion
return (this.#disposal ??= this.#close());
}
Expand All @@ -61,27 +114,27 @@ export class AngularCompilationContext {
// Suppress closure errors to avoid unhandled rejections during teardown.
}
}
}

createSecondaryContext(): AngularCompilationContext {
return new SecondaryCompilationContext(this);
export class SecondaryCompilationContext extends AngularCompilationContext {
constructor(private readonly primaryContext?: AngularCompilationContext) {
super();
}
}

class SecondaryCompilationContext extends AngularCompilationContext {
constructor(private primaryContext: AngularCompilationContext) {
super(new NoopCompilation());
override isPrimary(): this is PrimaryCompilationContext {
return false;
}

override get waitUntilReady(): Promise<boolean> {
return this.primaryContext.waitUntilReady;
override get compilation(): undefined {
return undefined;
}

override markAsReady(hasErrors: boolean): void {
// No-op: secondary contexts do not control compilation state
override get waitUntilReady(): Promise<boolean> {
return this.primaryContext?.waitUntilReady ?? Promise.resolve(false);
}

override markAsInProgress(): void {
// No-op: secondary contexts do not control compilation state
override getCompilerOptions(): Promise<CompilerOptions> {
return this.primaryContext?.getCompilerOptions() ?? Promise.resolve({});
}

override async dispose(): Promise<void> {
Expand Down
Loading