Skip to content
Closed
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
2 changes: 1 addition & 1 deletion packages/compiler-cli/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/program_driver",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/shims",
"//packages/compiler-cli/src/ngtsc/transform/jit",
"//packages/compiler-cli/src/ngtsc/translator",
"//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/typecheck/api",
"//packages/compiler-cli/src/ngtsc/util",
"//packages/compiler-cli/src/transformers/jit_transforms",
"@npm//@bazel/concatjs",
"@npm//@types/node",
"@npm//@types/yargs",
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {NodeJSFileSystem, setFileSystem} from './src/ngtsc/file_system';

export {VERSION} from './src/version';

export * from './src/transformers/jit_transforms';
export * from './src/ngtsc/transform/jit';
export * from './src/transformers/api';
export * from './src/transformers/entry_points';

Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-cli/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/perf",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/sourcemaps",
"//packages/compiler-cli/src/ngtsc/transform/jit",
"//packages/compiler-cli/src/ngtsc/typecheck/api",
"//packages/compiler-cli/src/transformers/jit_transforms",
"@npm//typescript",
],
)
2 changes: 1 addition & 1 deletion packages/compiler-cli/private/tooling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import ts from 'typescript';

import {angularJitApplicationTransform} from '../src/transformers/jit_transforms/index';
import {angularJitApplicationTransform} from '../src/ngtsc/transform/jit/index';

/**
* Known values for global variables in `@angular/core` that Terser should set using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from './src/references_registry';
export * from './src/schema';
export * from './src/util';
export * from './src/input_transforms';
export * from './src/jit_declaration_registry';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @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.io/license
*/

import {ClassDeclaration} from '../../../reflection';

/**
* Registry that keeps track of Angular declarations that are explicitly
* marked for JIT compilation and are skipping compilation by trait handlers.
*/
export class JitDeclarationRegistry {
jitDeclarations = new Set<ClassDeclaration>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ import {
validateAndFlattenComponentImports,
} from './util';
import {getTemplateDiagnostics} from '../../../typecheck';
import {JitDeclarationRegistry} from '../../common/src/jit_declaration_registry';

const EMPTY_ARRAY: any[] = [];

Expand Down Expand Up @@ -249,6 +250,7 @@ export class ComponentDecoratorHandler
private readonly enableBlockSyntax: boolean,
private readonly enableLetSyntax: boolean,
private readonly localCompilationExtraImportsTracker: LocalCompilationExtraImportsTracker | null,
private readonly jitDeclarationRegistry: JitDeclarationRegistry,
) {
this.extractTemplateOptions = {
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
Expand Down Expand Up @@ -410,10 +412,11 @@ export class ComponentDecoratorHandler
this.compilationMode,
this.elementSchemaRegistry.getDefaultComponentElementName(),
);
if (directiveResult === undefined) {
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this
// case, compilation of the decorator is skipped. Returning an empty object signifies
// that no analysis was produced.
// `extractDirectiveMetadata` returns `jitForced = true` when the `@Component` has
// set `jit: true`. In this case, compilation of the decorator is skipped. Returning
// an empty object signifies that no analysis was produced.
if (directiveResult.jitForced) {
this.jitDeclarationRegistry.jitDeclarations.add(node);
return {};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {getDeclaration, makeProgram} from '../../../testing';
import {CompilationMode} from '../../../transform';
import {
InjectableClassRegistry,
JitDeclarationRegistry,
NoopReferencesRegistry,
ResourceLoader,
ResourceLoaderContext,
Expand Down Expand Up @@ -105,6 +106,7 @@ function setup(
);
const resourceLoader = new StubResourceLoader();
const importTracker = new ImportedSymbolsTracker();
const jitDeclarationRegistry = new JitDeclarationRegistry();

const handler = new ComponentDecoratorHandler(
reflectionHost,
Expand Down Expand Up @@ -144,6 +146,7 @@ function setup(
/* enableBlockSyntax */ true,
/* enableLetSyntax */ true,
/* localCompilationExtraImportsTracker */ null,
jitDeclarationRegistry,
);
return {reflectionHost, handler, resourceLoader, metaRegistry};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {

import {extractDirectiveMetadata} from './shared';
import {DirectiveSymbol} from './symbol';
import {JitDeclarationRegistry} from '../../common/src/jit_declaration_registry';

const FIELD_DECORATORS = [
'Input',
Expand Down Expand Up @@ -133,7 +134,7 @@ export class DirectiveDecoratorHandler
private importTracker: ImportedSymbolsTracker,
private includeClassMetadata: boolean,
private readonly compilationMode: CompilationMode,
private readonly generateExtraImportsInLocalMode: boolean,
private readonly jitDeclarationRegistry: JitDeclarationRegistry,
) {}

readonly precedence = HandlerPrecedence.PRIMARY;
Expand Down Expand Up @@ -189,9 +190,14 @@ export class DirectiveDecoratorHandler
this.compilationMode,
/* defaultSelector */ null,
);
if (directiveResult === undefined) {
// `extractDirectiveMetadata` returns `jitForced = true` when the `@Directive` has
// set `jit: true`. In this case, compilation of the decorator is skipped. Returning
// an empty object signifies that no analysis was produced.
if (directiveResult.jitForced) {
this.jitDeclarationRegistry.jitDeclarations.add(node);
return {};
}

const analysis = directiveResult.metadata;

let providersRequiringFactory: Set<Reference<ClassDeclaration>> | null = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export function extractDirectiveMetadata(
defaultSelector: string | null,
):
| {
jitForced: false;
decorator: Map<string, ts.Expression>;
metadata: R3DirectiveMetadata;
inputs: ClassPropertyMapping<InputMapping>;
Expand All @@ -125,7 +126,7 @@ export function extractDirectiveMetadata(
hostDirectives: HostDirectiveMeta[] | null;
rawHostDirectives: ts.Expression | null;
}
| undefined {
| {jitForced: true} {
let directive: Map<string, ts.Expression>;
if (decorator.args === null || decorator.args.length === 0) {
directive = new Map<string, ts.Expression>();
Expand All @@ -149,7 +150,7 @@ export function extractDirectiveMetadata(

if (directive.has('jit')) {
// The only allowed value is true, so there's no need to expand further.
return undefined;
return {jitForced: true};
}

const members = reflector.getMembersOfClass(clazz);
Expand Down Expand Up @@ -407,6 +408,7 @@ export function extractDirectiveMetadata(
null,
};
return {
jitForced: false,
decorator: directive,
metadata,
inputs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../../scope';
import {getDeclaration, makeProgram} from '../../../testing';
import {CompilationMode} from '../../../transform';
import {InjectableClassRegistry, NoopReferencesRegistry} from '../../common';
import {
InjectableClassRegistry,
JitDeclarationRegistry,
NoopReferencesRegistry,
} from '../../common';
import {DirectiveDecoratorHandler} from '../index';

runInEachFileSystem(() => {
Expand Down Expand Up @@ -190,6 +194,8 @@ runInEachFileSystem(() => {
);
const injectableRegistry = new InjectableClassRegistry(reflectionHost, /* isCore */ false);
const importTracker = new ImportedSymbolsTracker();
const jitDeclarationRegistry = new JitDeclarationRegistry();

const handler = new DirectiveDecoratorHandler(
reflectionHost,
evaluator,
Expand All @@ -207,7 +213,7 @@ runInEachFileSystem(() => {
importTracker,
/*includeClassMetadata*/ true,
/*compilationMode */ CompilationMode.FULL,
/*generateExtraImportsInLocalMode*/ false,
jitDeclarationRegistry,
);

const DirNode = getDeclaration(program, _('/entry.ts'), dirName, isNamedClassDeclaration);
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-cli/src/ngtsc/annotations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export {
ReferencesRegistry,
ResourceLoader,
ResourceLoaderContext,
JitDeclarationRegistry,
} from './common';
export {ComponentDecoratorHandler} from './component';
export {
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-cli/src/ngtsc/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/shims",
"//packages/compiler-cli/src/ngtsc/shims:api",
"//packages/compiler-cli/src/ngtsc/transform",
"//packages/compiler-cli/src/ngtsc/transform/jit",
"//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/typecheck/api",
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
Expand Down
45 changes: 43 additions & 2 deletions packages/compiler-cli/src/ngtsc/core/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
PipeDecoratorHandler,
ReferencesRegistry,
} from '../../annotations';
import {InjectableClassRegistry} from '../../annotations/common';
import {InjectableClassRegistry, JitDeclarationRegistry} from '../../annotations/common';
import {CycleAnalyzer, CycleHandlingStrategy, ImportGraph} from '../../cycles';
import {
COMPILER_ERRORS_WITH_GUIDES,
Expand Down Expand Up @@ -124,6 +124,7 @@ import {DiagnosticCategoryLabel, NgCompilerAdapter, NgCompilerOptions} from '../

import {coreHasSymbol} from './core_version';
import {coreVersionSupportsFeature} from './feature_detection';
import {angularJitApplicationTransform} from '../../transform/jit';

/**
* State information about a compilation which is only generated once some data is requested from
Expand All @@ -145,6 +146,8 @@ interface LazyCompilationState {
extendedTemplateChecker: ExtendedTemplateChecker | null;
templateSemanticsChecker: TemplateSemanticsChecker | null;
sourceFileValidator: SourceFileValidator | null;
jitDeclarationRegistry: JitDeclarationRegistry;
supportJitMode: boolean;

/**
* Only available in local compilation mode when option `generateExtraImportsInLocalMode` is set.
Expand Down Expand Up @@ -814,6 +817,39 @@ export class NgCompiler {
defaultImportTracker.importPreservingTransformer(),
];

// If there are JIT declarations, wire up the JIT transform and efficiently
// run it against the target declarations.
if (compilation.supportJitMode && compilation.jitDeclarationRegistry.jitDeclarations.size > 0) {
const {jitDeclarations} = compilation.jitDeclarationRegistry;
const jitDeclarationsArray = Array.from(jitDeclarations);
const jitDeclarationOriginalNodes = new Set(
jitDeclarationsArray.map((d) => ts.getOriginalNode(d)),
);
const sourceFilesWithJit = new Set(
jitDeclarationsArray.map((d) => d.getSourceFile().fileName),
);

before.push((ctx) => {
const reflectionHost = new TypeScriptReflectionHost(this.inputProgram.getTypeChecker());
const jitTransform = angularJitApplicationTransform(
this.inputProgram,
compilation.isCore,
(node) => {
// Class may be synthetic at this point due to Ivy transform.
node = ts.getOriginalNode(node, ts.isClassDeclaration);
return reflectionHost.isClass(node) && jitDeclarationOriginalNodes.has(node);
},
)(ctx);

return (sourceFile) => {
if (!sourceFilesWithJit.has(sourceFile.fileName)) {
return sourceFile;
}
return jitTransform(sourceFile);
};
});
}

const afterDeclarations: ts.TransformerFactory<ts.SourceFile>[] = [];

// In local compilation mode we don't make use of .d.ts files for Angular compilation, so their
Expand Down Expand Up @@ -1361,6 +1397,8 @@ export class NgCompiler {
);
}

const jitDeclarationRegistry = new JitDeclarationRegistry();

// Set up the IvyCompilation, which manages state for the Ivy transformer.
const handlers: DecoratorHandler<unknown, unknown, SemanticSymbol | null, unknown>[] = [
new ComponentDecoratorHandler(
Expand Down Expand Up @@ -1401,6 +1439,7 @@ export class NgCompiler {
this.enableBlockSyntax,
this.enableLetSyntax,
localCompilationExtraImportsTracker,
jitDeclarationRegistry,
),

// TODO(alxhub): understand why the cast here is necessary (something to do with `null`
Expand All @@ -1422,7 +1461,7 @@ export class NgCompiler {
importTracker,
supportTestBed,
compilationMode,
!!this.options.generateExtraImportsInLocalMode,
jitDeclarationRegistry,
) as Readonly<DecoratorHandler<unknown, unknown, SemanticSymbol | null, unknown>>,
// Pipe handler must be before injectable handler in list so pipe factories are printed
// before injectable factories (so injectable factories can delegate to them)
Expand Down Expand Up @@ -1545,8 +1584,10 @@ export class NgCompiler {
resourceRegistry,
extendedTemplateChecker,
localCompilationExtraImportsTracker,
jitDeclarationRegistry,
templateSemanticsChecker,
sourceFileValidator,
supportJitMode,
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ load("//tools:defaults.bzl", "ts_library")
package(default_visibility = ["//visibility:public"])

ts_library(
name = "jit_transforms",
name = "jit",
srcs = glob(["**/*.ts"]),
deps = [
"//packages/compiler",
Expand Down
13 changes: 13 additions & 0 deletions packages/compiler-cli/src/ngtsc/transform/jit/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @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.io/license
*/

export {
angularJitApplicationTransform,
getDownlevelDecoratorsTransform,
getInitializerApiJitTransform,
} from './src/index';
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

import ts from 'typescript';

import {isAliasImportDeclaration, loadIsReferencedAliasDeclarationPatch} from '../../ngtsc/imports';
import {Decorator, ReflectionHost} from '../../ngtsc/reflection';
import {isAliasImportDeclaration, loadIsReferencedAliasDeclarationPatch} from '../../../imports';
import {Decorator, ReflectionHost} from '../../../reflection';

/**
* Whether a given decorator should be treated as an Angular decorator.
Expand Down Expand Up @@ -271,13 +271,15 @@ interface ParameterDecorationInfo {
* @param diagnostics List which will be populated with diagnostics if any.
* @param isCore Whether the current TypeScript program is for the `@angular/core` package.
* @param isClosureCompilerEnabled Whether closure annotations need to be added where needed.
* @param shouldTransformClass Optional function to check if a given class should be transformed.
*/
export function getDownlevelDecoratorsTransform(
typeChecker: ts.TypeChecker,
host: ReflectionHost,
diagnostics: ts.Diagnostic[],
isCore: boolean,
isClosureCompilerEnabled: boolean,
shouldTransformClass?: (node: ts.ClassDeclaration) => boolean,
): ts.TransformerFactory<ts.SourceFile> {
function addJSDocTypeAnnotation(node: ts.Node, jsdocType: string): void {
if (!isClosureCompilerEnabled) {
Expand Down Expand Up @@ -599,7 +601,10 @@ export function getDownlevelDecoratorsTransform(
* class declaration that are decorated with an Angular decorator.
*/
function decoratorDownlevelVisitor(node: ts.Node): ts.Node {
if (ts.isClassDeclaration(node)) {
if (
ts.isClassDeclaration(node) &&
(shouldTransformClass === undefined || shouldTransformClass(node))
) {
return transformClassDeclaration(node);
}
return ts.visitEachChild(node, decoratorDownlevelVisitor, context);
Expand Down
Loading