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 for Injectable
and remove any places that injectable service, guard, whatever from any Angular decoration's providers: []
.
- 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
}