Skip to content

Commit

Permalink
refactor(compiler): compute the list of dependencies for defer blocks (
Browse files Browse the repository at this point in the history
…#51162)

This commit brings the logic to calculate teh set of dependencies for each defer block. For each dependency we also identify whether it can be defer-loaded or not.

PR Close #51162
  • Loading branch information
AndrewKushnir authored and alxhub committed Aug 1, 2023
1 parent f5116e7 commit 08992a5
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ export class PartialComponentLinkerVersion1<TStatement, TExpression> implements
declarationListEmitMode,
styles: metaObj.has('styles') ? metaObj.getArray('styles').map(entry => entry.getString()) :
[],

// Defer blocks are not yet supported in partial compilation.
deferBlocks: new Map(),
deferrableDeclToImportDecl: new Map(),

encapsulation: metaObj.has('encapsulation') ?
parseEncapsulation(metaObj.getValue('encapsulation')) :
ViewEncapsulation.Emulated,
Expand Down
216 changes: 190 additions & 26 deletions packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {ParsedTemplateWithSource, StyleUrlMeta} from './resources';
* be included here.
*/
export type ComponentMetadataResolvedFields = SubsetOfKeys<
R3ComponentMetadata<R3TemplateDependencyMetadata>, 'declarations'|'declarationListEmitMode'>;
R3ComponentMetadata<R3TemplateDependencyMetadata>,
'declarations'|'declarationListEmitMode'|'deferBlocks'|'deferrableDeclToImportDecl'>;

export interface ComponentAnalysisData {
/**
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler-cli/src/ngtsc/reflection/src/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@ export interface Import {
* This could either be an absolute module name (@angular/core for example) or a relative path.
*/
from: string;

/**
* TypeScript node that represents this import.
*/
node: ts.ImportDeclaration;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,11 @@ export class TypeScriptReflectionHost implements ReflectionHost {
return null;
}

return {from: importDecl.moduleSpecifier.text, name: getExportedName(decl, id)};
return {
from: importDecl.moduleSpecifier.text,
name: getExportedName(decl, id),
node: importDecl,
};
}

/**
Expand Down Expand Up @@ -304,6 +308,7 @@ export class TypeScriptReflectionHost implements ReflectionHost {
return {
from: importDeclaration.moduleSpecifier.text,
name: id.text,
node: namespaceDeclaration.parent.parent,
};
}

Expand Down
20 changes: 20 additions & 0 deletions packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ import {ClassMember, ClassMemberKind, CtorParameter, TypeValueReferenceKind} fro
import {TypeScriptReflectionHost} from '../src/typescript';
import {isNamedClassDeclaration} from '../src/util';

function findFirstImportDeclaration(node: ts.Node): ts.ImportDeclaration|null {
let found: ts.ImportDeclaration|null = null;
const visit = (node: ts.Node): void => {
if (found) return;
if (ts.isImportDeclaration(node)) {
found = node;
return;
}
ts.forEachChild(node, visit);
};
visit(node);
return found;
}

runInEachFileSystem(() => {
describe('reflector', () => {
let _: typeof absoluteFrom;
Expand Down Expand Up @@ -283,9 +297,12 @@ runInEachFileSystem(() => {
}
const Target = foo.type.typeName;
const directImport = host.getImportOfIdentifier(Target);
const sf = foo.getSourceFile();
const importDecl = findFirstImportDeclaration(sf);
expect(directImport).toEqual({
name: 'Target',
from: 'absolute',
node: importDecl as ts.ImportDeclaration,
});
});

Expand All @@ -310,9 +327,12 @@ runInEachFileSystem(() => {
}
const Target = foo.type.typeName.right;
const namespacedImport = host.getImportOfIdentifier(Target);
const sf = foo.getSourceFile();
const importDecl = findFirstImportDeclaration(sf);
expect(namespacedImport).toEqual({
name: 'Target',
from: 'absolute',
node: importDecl as ts.ImportDeclaration,
});
});
});
Expand Down
12 changes: 12 additions & 0 deletions packages/compiler/src/jit_compiler_facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ export class CompilerFacadeImpl implements CompilerFacade {
template,
declarations: facade.declarations.map(convertDeclarationFacadeToMetadata),
declarationListEmitMode: DeclarationListEmitMode.Direct,

// TODO: leaving empty in JIT mode for now,
// to be implemented as one of the next steps.
deferBlocks: new Map(),
deferrableDeclToImportDecl: new Map(),

styles: [...facade.styles, ...template.styles],
encapsulation: facade.encapsulation,
interpolation,
Expand Down Expand Up @@ -470,6 +476,12 @@ function convertDeclareComponentFacadeToMetadata(
viewProviders: decl.viewProviders !== undefined ? new WrappedNodeExpr(decl.viewProviders) :
null,
animations: decl.animations !== undefined ? new WrappedNodeExpr(decl.animations) : null,

// TODO: leaving empty in JIT mode for now,
// to be implemented as one of the next steps.
deferBlocks: new Map(),
deferrableDeclToImportDecl: new Map(),

changeDetection: decl.changeDetection ?? ChangeDetectionStrategy.Default,
encapsulation: decl.encapsulation ?? ViewEncapsulation.Emulated,
interpolation,
Expand Down
37 changes: 37 additions & 0 deletions packages/compiler/src/render3/view/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,31 @@ export const enum DeclarationListEmitMode {
ClosureResolved,
}

/**
* Describes a dependency used within a `{#defer}` block.
*/
export interface DeferBlockTemplateDependency {
/**
* Reference to a dependency.
*/
type: o.WrappedNodeExpr<unknown>;

/**
* Dependency class name.
*/
symbolName: string;

/**
* Whether this dependency can be defer-loaded.
*/
isDeferrable: boolean;

/**
* Import path where this dependency is located.
*/
importPath: string|null;
}

/**
* Information needed to compile a component for the render3 runtime.
*/
Expand All @@ -192,6 +217,18 @@ export interface R3ComponentMetadata<DeclarationT extends R3TemplateDependency>

declarations: DeclarationT[];

/**
* Map of all types that can be defer loaded -> corresponding module specifier
* strings (that can later be used as a value in dynamic imports).
*/
// TODO: fix types! (ClassDeclaration -> ImportDeclaration)
deferrableDeclToImportDecl: Map<any, any>;

/**
* Map of {#defer} blocks -> their corresponding dependencies.
*/
deferBlocks: Map<t.DeferredBlock, Array<DeferBlockTemplateDependency>>;

/**
* Specifies how the 'directives' and/or `pipes` array, if generated, need to be emitted.
*/
Expand Down

0 comments on commit 08992a5

Please sign in to comment.