问题
We are currently trying to optimize a complex angular application (performance & bundle size).
We found that we have partially unused components, but we are not 100% sure about them. Anyway ... The question we are currently asking is how exactly does tree shaking work in Angular.
Question 1) If there are entries inside the declarations, imports or providers array of a module, but the module is not used anywhere, are they also removed with tree shaking or are they included in the final bundle?
Example:
@NgModule({
imports: [
FirstModule,
SecondModule // Is not used anymore (probably) but imported here
],
declarations: [SampleComponent] // Is not used anymore (probably) but imported here
})
export class SampleModule {
}
Info: The routes to that modules/components are already deleted.
Question 2) Is it sufficient to only remove these components from the routing modules so that the tree shaking process is successful?
Question 3) What should be in place for the treeshaking process to work optimally?
Used Angular Version 8.2
回答1:
You can use webpack-bundle-analyzer which will help you visualize the size and the different used components in your final output file. this way you would be sure if a module is used or not and then you can safely delete it.
回答2:
About how tree-shaking works in Angular
Tree-shaking is done primarily in the minification stage and is not specific to Angular. terser
is the minifier they use in the Angular CLI which is a fork of Uglify that supports ES6 syntax.
terser
reads your code and if it is not referenced elsewhere, and it can be certain that removing some code will have no side-effects, then it will remove that code.
terser
can't be certain whether or not classes with decorators have side-effects just in being defined (decorators are function calls). In Angular's production build, they have a webpack plugin called "build-optimizer" that will go to places their decorators are used and add a special comment /*@__PURE__*/
next to the compiled javascript (from Typescript) which terser
recognizes and will remove the decorated class (if it's not referenced elsewhere).
About removing components from the NgModule
The build process just starts from your main.ts
file and crawls all the imports for all the files to include in your build. If, from the main.ts file, your component file is never imported by any of the files the crawling process finds, it will never be included. That's not tree-shaking, it's just not included in the build process at all.
If your module file is the only place the component file is imported, then removing that import will be sufficient not to include the component in your build.
About things you can do
You can make some Angular specific changes to ensure you only build the code you use.
- Use the
{providedIn: root}
decoration option forInjectable
and remove any places that injectable service, guard, whatever from any Angular decoration'sproviders: []
. - Use the Ivy renderer which will mean less of the framework is bundled (if you're not using it).
Additionally, at the call site (not the definition) you may be able to mark any functions without side effects with the /@__PURE__/
comment so that even if they are called somewhere, if the return value could removed via some other optimization the function itself could also be removed. I haven't tested this, but in theory it should work.
I don't know how all the various build stages transform your code and if they move or remove comments before terser
can see them.
You can test it out using this playground tool: https://terser-playground.surge.sh/
Try it with this example:
(function() {
const a = 1;
const b = 2;
const c = /*@__PURE__*/ test();
console.log(a + b);
}());
function test() {
return 3
}
来源:https://stackoverflow.com/questions/60321224/angular-tree-shaking-how-exactly-does-it-work