I have a simple app, initialized by angular-cli
.
It display some pages relative to 3 routes. I have 3 components. On one of this page I use lodash
and Angular 2 HTTP modules to get some data (using RxJS Observable
s, map
and subscribe
). I display these elements using a simple *ngFor
.
But, despite the fact my app is really simple, I get a huge (in my opinion) bundle package and maps. I don't talk about gzip versions though but size before gzipping. This question is just a general recommendations inquiry.
Some tests results:
ng build
Hash: 8efac7d6208adb8641c1 Time: 10129ms chunk {0} main.bundle.js, main.bundle.map (main) 18.7 kB {3} [initial] [rendered]
chunk {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 kB {4} [initial] [rendered]
chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 kB {4} [initial] [rendered]
chunk {3} vendor.bundle.js, vendor.bundle.map (vendor) 3.96 MB [initial] [rendered]
chunk {4} inline.bundle.js, inline.bundle.map (inline) 0 bytes [entry] [rendered]
Wait: 10Mb vendor bundle package for such a simple app?
ng build --prod
Hash: 09a5f095e33b2980e7cc Time: 23455ms chunk {0} main.6273b0f04a07a1c2ad6c.bundle.js, main.6273b0f04a07a1c2ad6c.bundle.map (main) 18.3 kB {3} [initial] [rendered]
chunk {1} styles.bfdaa4d8a4eb2d0cb019.bundle.css, styles.bfdaa4d8a4eb2d0cb019.bundle.map, styles.bfdaa4d8a4eb2d0cb019.bundle.map (styles) 154 kB {4} [initial] [rendered]
chunk {2} scripts.c5b720a078e5464ec211.bundle.js, scripts.c5b720a078e5464ec211.bundle.map (scripts) 128 kB {4} [initial] [rendered]
chunk {3} vendor.07af2467307e17d85438.bundle.js, vendor.07af2467307e17d85438.bundle.map (vendor) 3.96 MB [initial] [rendered]
chunk {4} inline.a345391d459797f81820.bundle.js, inline.a345391d459797f81820.bundle.map (inline) 0 bytes [entry] [rendered]
Wait again: such a similar vendor bundle size for prod?
ng build --prod --aot
Hash: 517e4425ff872bbe3e5b Time: 22856ms chunk {0} main.95eadabace554e3c2b43.bundle.js, main.95eadabace554e3c2b43.bundle.map (main) 130 kB {3} [initial] [rendered]
chunk {1} styles.e53a388ae1dd2b7f5434.bundle.css, styles.e53a388ae1dd2b7f5434.bundle.map, styles.e53a388ae1dd2b7f5434.bundle.map (styles) 154 kB {4} [initial] [rendered]
chunk {2} scripts.e5c2c90547f3168a7564.bundle.js, scripts.e5c2c90547f3168a7564.bundle.map (scripts) 128 kB {4} [initial] [rendered]
chunk {3} vendor.41a6c1f57136df286f14.bundle.js, vendor.41a6c1f57136df286f14.bundle.map (vendor) 2.75 MB [initial] [rendered]
chunk {4} inline.97c0403c57a46c6a7920.bundle.js, inline.97c0403c57a46c6a7920.bundle.map (inline) 0 bytes [entry] [rendered]
ng build --aot
Hash: 040cc91df4df5ffc3c3f Time: 11011ms chunk {0} main.bundle.js, main.bundle.map (main) 130 kB {3} [initial] [rendered]
chunk {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 kB {4} [initial] [rendered]
chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 kB {4} [initial] [rendered]
chunk {3} vendor.bundle.js, vendor.bundle.map (vendor) 2.75 MB [initial] [rendered]
chunk {4} inline.bundle.js, inline.bundle.map (inline) 0 bytes [entry] [rendered]
So a few questions for deploying my app on prod:
- Why are the vendor bundles so huge?
- Is tree shaking properly used by
angular-cli
? - How to improve this bundle size?
- Are the .map files required?
- Are the testing features included in bundles? I don't need them in prod.
- Generic question: what are the recommanded tools to pack for prod? Maybe
angular-cli
(using Webpack in the background) is not the best option? Can we do better?
I searched many discussions on Stack Overflow, but I haven't found any generic question.
Check you have configuration named "production" for ng build --prod, since it is shorthand for ng build --configuration=production No answer solved my problem, because the problem was sitting right in front of the screen. I think this might be quite common... I've internationalized the app with i18n renaming all configurations to e.g. production-en. Then I built with ng build --prod assuming, that the default optimization is used and should be close to optimal, but in fact just ng build has been executed resulting in 7mb bundle instead of 250kb.
If you are using Angular 8+ and you want to reduce the size of the bundle you can use Ivy. Just go to src/tsconfig.app.json and add the angularCompilerOptions parameter, for example:
Firstly, vendor bundles are huge simply because Angular 2 relies on a lot of libraries. Minimum size for Angular 2 app is around 500KB (250KB in some cases, see bottom post).
Tree shaking is properly used by
angular-cli
.Do not include
.map
files, because used only for debugging. Moreover, if you use hot replacement module, remove it to lighten vendor.To pack for production, I personnaly use Webpack (and angular-cli relies on it too), because you can really
configure everything
for optimization or debugging.If you want to use
Webpack
, I agree it is a bit tricky a first view, but see tutorials on the net, you won't be disappointed.Else, use
angular-cli
, which get the job done really well.Using Ahead-of-time compilation is mandatory to optimize apps, and shrink Angular 2 app to 250KB.
Here is a repo I created (github.com/JCornat/min-angular) to test minimal Angular bundle size, and I obtain 384kB. I am sure there is easy way to optimize it.
Talking about big apps, using the AngularClass/angular-starter configuration, the same as in the repo above, my bundle size for big apps (150+ components) went from 8MB (4MB without map files) to 580kB.
One thing I wish to share is how imported libraries increase the size of the dist. I had angular2-moment package imported, whereas I could do all the date time formatting I required using the standard DatePipe exported from @angular/common.
With Angular2-Moment
"angular2-moment": "^1.6.0",
After removing Angular2-moment and using DatePipe instead
Note the vendor bundle has reduced half a Megabyte!
Point is it is worth checking what angular standard packages can do even if you are already familiar with an external lib.
The following solution assumes you are serving your dist/ folder using nodejs. Please use the following app.js in root level
Make sure you install dependencies;
Now build the app
Create a folder called
vendor
inside thesrc
folder and inside vendor folder create a filerxjs.ts
and paste the below code in it;And then add the follwing in the
tsconfig.json
file in your angular-cli application. Then in thecompilerOptions
, add the following json;This will make your build size way too smaller. In my project I reduced the size from 11mb to 1mb. Hope it helps
Another way to reduce bundle, is to serve GZIP instead of JS. We went from 2.6mb to 543ko.
https://httpd.apache.org/docs/2.4/mod/mod_deflate.html