feat(ivy): emit module scope metadata using pure function call (#29598)
Prior to this change, all module metadata would be included in the `defineNgModule` call that is set as the `ngModuleDef` field of module types. Part of the metadata is scope information like declarations, imports and exports that is used for computing the transitive module scope in JIT environments, preventing those references from being tree-shaken for production builds. This change moves the metadata for scope computations to a pure function call that patches the scope references onto the module type. Because the function is marked pure, it may be tree-shaken out during production builds such that references to declarations and exports are dropped, which in turn allows for tree-shaken any declaration that is not otherwise referenced. Fixes #28077, FW-1035 PR Close #29598
This commit is contained in:
@ -487,16 +487,15 @@ export function renderDefinitions(
|
||||
const name = compiledClass.declaration.name;
|
||||
const translate = (stmt: Statement) =>
|
||||
translateStatement(stmt, imports, NOOP_DEFAULT_IMPORT_RECORDER);
|
||||
const definitions =
|
||||
compiledClass.compilation
|
||||
.map(
|
||||
c => c.statements.map(statement => translate(statement))
|
||||
.concat(translate(createAssignmentStatement(name, c.name, c.initializer)))
|
||||
.map(
|
||||
statement =>
|
||||
printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile))
|
||||
.join('\n'))
|
||||
.join('\n');
|
||||
const print = (stmt: Statement) =>
|
||||
printer.printNode(ts.EmitHint.Unspecified, translate(stmt), sourceFile);
|
||||
const definitions = compiledClass.compilation
|
||||
.map(
|
||||
c => [createAssignmentStatement(name, c.name, c.initializer)]
|
||||
.concat(c.statements)
|
||||
.map(print)
|
||||
.join('\n'))
|
||||
.join('\n');
|
||||
return definitions;
|
||||
}
|
||||
|
||||
|
@ -151,16 +151,17 @@ describe('Renderer', () => {
|
||||
moduleWithProvidersAnalyses);
|
||||
const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy;
|
||||
expect(addDefinitionsSpy.calls.first().args[2])
|
||||
.toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||
type: Component,
|
||||
args: [{ selector: 'a', template: '{{ person!.name }}' }]
|
||||
}], null, null);
|
||||
A.ngComponentDef = ɵngcc0.ɵdefineComponent({ type: A, selectors: [["a"]], factory: function A_Factory(t) { return new (t || A)(); }, consts: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) {
|
||||
.toEqual(
|
||||
`A.ngComponentDef = ɵngcc0.ɵdefineComponent({ type: A, selectors: [["a"]], factory: function A_Factory(t) { return new (t || A)(); }, consts: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) {
|
||||
ɵngcc0.ɵtext(0);
|
||||
} if (rf & 2) {
|
||||
ɵngcc0.ɵselect(0);
|
||||
ɵngcc0.ɵtextBinding(0, ɵngcc0.ɵinterpolation1("", ctx.person.name, ""));
|
||||
} }, encapsulation: 2 });`);
|
||||
} }, encapsulation: 2 });
|
||||
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||
type: Component,
|
||||
args: [{ selector: 'a', template: '{{ person!.name }}' }]
|
||||
}], null, null);`);
|
||||
});
|
||||
|
||||
|
||||
@ -195,11 +196,12 @@ A.ngComponentDef = ɵngcc0.ɵdefineComponent({ type: A, selectors: [["a"]], fact
|
||||
decorators: [jasmine.objectContaining({name: 'Directive'})],
|
||||
}));
|
||||
expect(addDefinitionsSpy.calls.first().args[2])
|
||||
.toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||
.toEqual(
|
||||
`A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });
|
||||
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
|
||||
type: Directive,
|
||||
args: [{ selector: '[a]' }]
|
||||
}], null, { foo: [] });
|
||||
A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`);
|
||||
}], null, { foo: [] });`);
|
||||
});
|
||||
|
||||
it('should call removeDecorators with the source code, a map of class decorators that have been analyzed',
|
||||
|
Reference in New Issue
Block a user