How to decrease prod bundle size?

2020-01-25 03:25发布

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 Observables, 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.

12条回答
趁早两清
2楼-- · 2020-01-25 04:00

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.

查看更多
Melony?
3楼-- · 2020-01-25 04:00

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:

{
  "extends": ...,
  "compilerOptions":...,
  "exclude": ...,

/* add this one */ 
  "angularCompilerOptions": {
    "enableIvy": true
  }
}
查看更多
手持菜刀,她持情操
4楼-- · 2020-01-25 04:08

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.

查看更多
孤傲高冷的网名
5楼-- · 2020-01-25 04:12

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",

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [initial] [rendered] chunk {1} main.e7496551a26816427b68.bundle.js (main) 2.2 MB {3} [initial] [rendered] chunk {2} styles.056656ed596d26ba0192.bundle.css (styles) 69 bytes {4} [initial] [rendered] chunk {3} vendor.62c2cfe0ca794a5006d1.bundle.js (vendor) 3.84 MB [initial] [rendered] chunk {4} inline.0b9c3de53405d705e757.bundle.js (inline) 0 bytes [entry] [rendered]

After removing Angular2-moment and using DatePipe instead

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [initial] [rendered] chunk {1} main.f2b62721788695a4655c.bundle.js (main) 2.2 MB {3} [initial] [rendered] chunk {2} styles.056656ed596d26ba0192.bundle.css (styles) 69 bytes {4} [initial] [rendered] chunk {3} vendor.e1de06303258c58c9d01.bundle.js (vendor) 3.35 MB [initial] [rendered] chunk {4} inline.3ae24861b3637391ba70.bundle.js (inline) 0 bytes [entry] [rendered]

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.

查看更多
萌系小妹纸
6楼-- · 2020-01-25 04:19

The following solution assumes you are serving your dist/ folder using nodejs. Please use the following app.js in root level

const express = require('express'),http = require('http'),path = require('path'),compression = require('compression');

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));
app.use(compression()) //compressing dist folder 
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
})

const port = process.env.PORT || '4201';
app.set('port', port);

const server = http.createServer(app);
server.listen(port, () => console.log('Running at port ' + port))

Make sure you install dependencies;

npm install compression --save
npm install express --save;

Now build the app

ng build --prod --build-optimizer

If you want to further compress the build say reduce 300kb(approx) from , then follow the below process;

Create a folder called vendor inside the src folder and inside vendor folder create a file rxjs.ts and paste the below code in it;

export {Subject} from 'rxjs/Subject';
export {Observable} from 'rxjs/Observable';
export {Subscription} from 'rxjs/Subscription';

And then add the follwing in the tsconfig.json file in your angular-cli application. Then in the compilerOptions , add the following json;

"paths": {
      "rxjs": [
        "./vendor/rxjs.ts"
      ]
    }

This will make your build size way too smaller. In my project I reduced the size from 11mb to 1mb. Hope it helps

查看更多
放我归山
7楼-- · 2020-01-25 04:19

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

查看更多
登录 后发表回答