Closed dmitrysteblyuk closed 7 years ago
Thats a good question. If you import a module, it will still be imported by ngc
. If you are not using a Module, don't import it. You can see this in ngfactory/tmp/app/shared/app.module.ngfactory.ts
. You can find references to FormsModule
still in bundle.js
.
The bundle can be gzipped and you should see a drastic size reduction.
ngr --build prod
tar -zcvf build/bundle.tar.gz build/bundle.js
When I omit FormsModule heres what I get on the master branch right now.
bundle.js - 353 KB bundle.tar.gz - 90 KB
With FormsModule
bundle.js - 418KB bundle.tar.gz - 102 KB
In the near future, I plan on writing a build that should be even smaller on load with Splittable but there are limitations there while it should support lazy loading. If anyone wants to contribute this build that would be awesome!
You could also build ngc
=> ClosureCompiler
, omitting Rollup to produce a very small bundle. Right now this is not very possible and somewhat impractical for third party libraries from what I understand although @mlavel got it to work. The core team and Contributors are working on it. It is most likely essential for the core team to figure out how to get this build optimal for teams working at Google.
Optimizations for the production build will most likely be better over time, Angular 4 already was a great move in that direction.
@mlaval demos all the ways Angular prod build can be optimized .
So what's the point of treeshaking then if not to remove from the bundle unused components and directives of imported modules? If I import a module but don't include it in NgModule imports then I can use tslint (unused-variables) to find imports I don't use and treeshaking would be absolutely useless.
I was curious to benchmark the prod build post Angular 4 and it is quite impressive
@dmitrysteblyuk It boils down to how the Modules are exported and how well the tool can interpret the code. Rollup isn't the only tool treeshaking the bundle. The core team made a new setting in the compilerOptions
for ngc
called annotateForClosureCompiler
. This should allow ClosureCompiler to interpret ngfactory
and treeshake the codebase further.
Consider this:
If you import
FormsModule but don't inject it via imports
, it will not be compiled by ngc
.
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { routing } from './app.routes';
import { HomeModule } from './shared/components/home/home.module';
@NgModule({
imports: [ BrowserModule,
BrowserAnimationsModule,
HttpModule,
CommonModule,
HomeModule,
routing],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
My bundle looks less optimistic but after gzipping it's about 157kB.
It was just my understanding that rollup can indeed treeshake unused code, and I found it weird that it doesn't apply to angular 2 modules. And then the question is why to use rollup at all if treeshaking has no effect. The case when I do not inject imported modules can be easily (and preferably) handled by lint.
Rollup isn't the only tool that is treeshaking. ngc
, Rollup
, and ClosureCompiler
are all tree shaking and optimizing the bundle.
Ok, thanks. I'll try ClosureCompiler. By the way, do you know by any chance if it can handle lazy loaded modules?
Well 157KB isn't bad. When an application scales its probably more beneficial to lazyload
or prerender
.
@mlaval proved it can be done https://mlaval.github.io/optimize-angular-app/
Thanks for the link! ClosureCompilre produces the smallest bundle indeed. Prerender is also super fast.
I modified app.module a bit by removing routing and all the modules except BrowserModule. Then I run ngr build --prod and the size of the output bundle is 414kB.
If I include FormsModule back in AppModule imports, the bundle is bigger by ~100kB which is about the size of the whole FormsModule minified. Despite FormsModule is never used in the app. So why it's not getting treeshaked?