Repository navigation
Conversation
8ebef16 to
4041f11
Compare
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 angular#28077, FW-1035
Prior to this change, a module's imports and exports would be used verbatim as an injectors' imports. This is detrimental for tree-shaking, as a module's exports could reference declarations that would then prevent such declarations from being eligible for tree-shaking. Since an injector actually only needs NgModule references as its imports, we may safely filter out any declarations from the list of module exports. This makes them eligible for tree-shaking once again.
The defineInjector function specifies its providers and imports array to be optional, so if no providers/imports are present these keys may be omitted. This commit updates the compiler to only generate the keys when necessary.
f7f5a9a to
9c94276
Compare
| if (scope !== null) { | ||
| const context = getSourceFile(node); | ||
| for (const exportRef of analysis.exports) { | ||
| if (isNgModule(exportRef.node, scope.compilation)) { |
There was a problem hiding this comment.
I am not too certain about using the module scope to figure out if the ref is a module. It does however conveniently provide us with information on both refs from the program, as well as resolved refs from typings files.
There was a problem hiding this comment.
I actually like the approach of filtering out any exports from the scope, instead of filtering and including only known modules. It feels more robust.
| .toContain( | ||
| 'i0.defineInjector({ factory: function TestModule_Factory(t) ' + | ||
| '{ return new (t || TestModule)(); }, imports: [[OtherModule, RouterModule.forRoot()],' + | ||
| '\n OtherModule,\n RouterModule] });'); |
There was a problem hiding this comment.
Using the ts.Printer, you're going to get whitespace attached to existing nodes.
|
|
||
| const jsContents = env.getContents('test.js'); | ||
| expect(jsContents) | ||
| .toContain( |
There was a problem hiding this comment.
We don't need to match the whole structure of defineInjector, it's enough to assert that it contains imports: [...]. You can also use a regex to ignore the whitespace.
| if (scope !== null) { | ||
| const context = getSourceFile(node); | ||
| for (const exportRef of analysis.exports) { | ||
| if (isNgModule(exportRef.node, scope.compilation)) { |
There was a problem hiding this comment.
I actually like the approach of filtering out any exports from the scope, instead of filtering and including only known modules. It feels more robust.
| .toContain( | ||
| 'i0.defineInjector({ factory: function TestModule_Factory(t) ' + | ||
| '{ return new (t || TestModule)(); }, imports: [[OtherModule, RouterModule.forRoot()],' + | ||
| '\n OtherModule,\n RouterModule] });'); |
There was a problem hiding this comment.
Using the ts.Printer, you're going to get whitespace attached to existing nodes.
Prior to this change, a module's imports and exports would be used verbatim as an injectors' imports. This is detrimental for tree-shaking, as a module's exports could reference declarations that would then prevent such declarations from being eligible for tree-shaking. Since an injector actually only needs NgModule references as its imports, we may safely filter out any declarations from the list of module exports. This makes them eligible for tree-shaking once again. PR Close #29598
…ar#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 angular#28077, FW-1035 PR Close angular#29598
Prior to this change, a module's imports and exports would be used verbatim as an injectors' imports. This is detrimental for tree-shaking, as a module's exports could reference declarations that would then prevent such declarations from being eligible for tree-shaking. Since an injector actually only needs NgModule references as its imports, we may safely filter out any declarations from the list of module exports. This makes them eligible for tree-shaking once again. PR Close angular#29598
…gular#29598) The defineInjector function specifies its providers and imports array to be optional, so if no providers/imports are present these keys may be omitted. This commit updates the compiler to only generate the keys when necessary. PR Close angular#29598
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Prior to this change, all module metadata would be included in the
defineNgModulecall that is set as thengModuleDeffield of moduletypes. 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
feat(ivy): exclude declarations from injector imports
Prior to this change, a module's imports and exports would be used verbatim
as an injectors' imports. This is detrimental for tree-shaking, as a
module's exports could reference declarations that would then prevent such
declarations from being eligible for tree-shaking.
Since an injector actually only needs NgModule references as its imports,
we may safely filter out any declarations from the list of module exports.
This makes them eligible for tree-shaking once again.
feat(ivy): do not emit empty providers/imports for defineInjector
The defineInjector function specifies its providers and imports array to
be optional, so if no providers/imports are present these keys may be
omitted. This commit updates the compiler to only generate the keys when
necessary.