如何减少产品包的尺寸?

我有一个简单的应用程序,由 angular-cli初始化。

它显示相对于3个路由的一些页面。我有三个组成部分。在这个页面中,我使用 lodash和 Angular 2 HTTP 模块来获取一些数据(使用 RxJS Observablemapsubscribe)。我使用一个简单的 *ngFor来显示这些元素。

但是,尽管事实上我的应用程序真的很简单,我得到了一个巨大的(在我看来)捆绑包和地图。不过我不会谈论 gzip 版本,而是在 gzip 之前讨论大小。这个问题只是一般性的推荐问询。

一些测试结果:

建造

Hash: 8efac7d6208adb8641c1 Time: 10129ms block {0} main.bundle.js, Map (main)18.7 kB {3}[初始][呈现]

块{1} styles.bundle.css,styles.bundle.map,styles.bundle.map (样式)155kB {4}[初始][渲染]

大块{2} scripts.bundle.js,scripts.bundle.map (script)128kB {4}[初始][渲染]

块{3} vendor.bundle.js,vendor.bundle.map (卖方)3.96 MB [首字母][渲染]

块{4} inline.bundle.js,inline.bundle.map (inline)0字节 [进入][渲染]

等等: 10Mb 的供应商捆绑包这样一个简单的应用程序?

生产,刺激

Hash: 09a5f095e33b2980e7cc Time: 23455ms block {0} 主编6273 b0f04a07a1c2ad6c.bundle.js, 6273 b0f04a07a1c2ad6c.bundle.map (main)18.3 kB {3}[初始] [翻译]

块{1} styles.bfdaa4d8a4eb2d0cb019.bundle.css, Bfdaa4d8a4eb2d0cb019.bundle.map, Map (style)154 kB {4}[初始] [翻译]

块{2} scripts.c5b720a078e5464ec211.bundle.js, (脚本)128kB {4}[初始值] [翻译]

大块{3}供应商.07 af2467307e17d85438.bundle.js, 厂商.07 af2467307e17d85438.bundle.map (厂商)3.96 MB [初始] [翻译]

块{4} inline.a345391d459797f81820.bundle.js, A 345391d459797f81820.bundle.map (inline)0 byte [ entry ] [翻译]

再等一下: 这样一个类似的供应商捆绑大小的产品?

ng build --prod --aot

哈希: 517e4425ff872bbe3e5b 时间: 22856ms 块{0} 95 eadabace554e3c2b43.bundle.js, 95 eadabace554e3c2b43.bundle.map (main)130 kB {3}[初始] [翻译]

块{1} styles.e53a388ae1dd2b7f5434.bundle.css, B7f5434.bundle.map, Map (style)154 kB {4}[初始] [翻译]

块{2} scripts.e5c2c90547f3168a7564.bundle.js, 地图(脚本)128kB {4}[初始] [翻译]

块{3}供应商.41 a6c1f57136df286f14.bundle.js, 厂商41 a6c1f57136df286f14.bundle.map (厂商)2.75 MB [初始] [翻译]

块{4}内联.97 c0403c57a46c6a7920.bundle.js, Map (inline)0 byte [ entry ]97 c0403c57a46c6a7920.bundle.map (inline)0 byte [ entry ] [翻译]

ng build --aot

哈希: 040cc91df4df5ffc3c3f 时间: 11011ms 块{0} main.bundle.js, Map (main)130kB {3}[初始][呈现]

块{1} styles.bundle.css,styles.bundle.map,styles.bundle.map (样式)155kB {4}[初始][渲染]

大块{2} scripts.bundle.js,scripts.bundle.map (script)128kB {4}[初始][渲染]

大块{3} vendor.bundle.js,vendor.bundle.map (卖方)2.75 MB [首字母][渲染]

块{4} inline.bundle.js,inline.bundle.map (inline)0字节 [进入][渲染]

所以,关于如何部署我的应用程序,我有几个问题:

  • 为什么供应商包这么大?
  • angular-cli是否正确地使用摇树法?
  • 如何提高捆绑包的大小?
  • 是否需要.map 文件?
  • 测试特性是否包含在捆绑包中? 我不需要它们。
  • 一般性问题: 针对产品包装推荐使用哪些工具?也许 angular-cli(在后台使用 Webpack)不是最佳选择?我们能做得更好吗?

我搜索了很多关于 Stack Overflow 的讨论,但是没有找到任何一般性的问题。

171496 次浏览

首先,厂商的包非常庞大,因为 Angular 2依赖于大量的库。角度2应用程序大约是500KB的最小大小(在某些情况下为250KB,见底部文章)。
angular-cli正确地使用了摇树。
没有是否包含 .map文件,因为它只用于调试。此外,如果您使用热更换模块,删除它,以减轻供应商。

为了进行生产打包,我个人使用 网络包(和 角-斜率也依赖于它) ,因为您可以真正使用 configure everything进行优化或调试。
如果你想使用 Webpack,我同意这是一个有点棘手的第一个视图,但看到教程在网上,你不会感到失望。
否则,使用 angular-cli,它可以很好地完成工作。

使用 提前编译是强制优化应用程序,并收缩角度2应用程序的 250KB

下面是我创建的一个回购(Github.com/jcornat/min-angular)来测试最小的角束大小,我获得 384kB。我相信有一个简单的方法可以优化它。

说到大型应用,使用 角级/角起动器配置,和上面的回购一样,我的大型应用的捆绑包大小(150多个组件)从 8MB(4MB 没有地图文件)变成了 580kB

2020年2月最新情况

由于这个答案得到了广泛的关注,我认为最好用新的角度优化来更新它:

  1. 正如另一位回答者所说,ng build --prod --build-optimizer是一个很好的选择,人们使用较少的角5。对于较新的版本,这是默认使用 ng build --prod完成的
  2. 另一种选择是使用模块块化/延迟加载来更好地将应用程序分割成更小的块
  3. Ivy 渲染引擎默认使用 Angular 9,它提供了更好的捆绑包大小
  4. 确保你的第三方部署是可以动摇的。如果你还没有使用 Rxjsv6,你应该这样做。
  5. 如果所有其他方法都失败了,那么使用像 网络包-捆绑包-分析器这样的工具来查看是什么导致了模块中的膨胀
  6. 检查文件是否已压缩

有些人声称,使用 AOT 编译可以将供应商包的大小减少到250kb。然而,在 BlackHoleGalaxy 的例子中,他使用了 AOT 编译,并且仍然保留了2.75 MB 的供应商捆绑包,ng build --prod --aot比假定的250kb 大10倍。对于 angular2应用程序来说,即使您使用的是 v4.0,这也不是不合常规的。对于真正关心性能的人来说,2.75 MB 仍然太大,尤其是在移动设备上。

有一些事情你可以做,以帮助您的应用程序的性能:

  1. AOT & Tree Shaking (角-cli 可以做到这一点)。与角9 AOT 是默认的产品和开发环境。

  2. 使用角度通用 A.K.A. 服务器端渲染(不使用 cli)

  3. Web Workers (同样,不是在 cli 中,而是一个非常需要的特性)
    参见: < a href = “ https://github.com/angle/angle-cli/questions/2305”rel = “ nofollow noReferrer”> https://github.com/angular/angular-cli/issues/2305

  4. 服务工作者
    参见: < a href = “ https://github.com/angle/angle-cli/questions/4006”rel = “ nofollow noReferrer”> https://github.com/angular/angular-cli/issues/4006

您可能不需要所有这些在一个单一的应用程序,但这些是一些选项,目前存在的角度性能优化。我相信/希望谷歌已经意识到在性能方面的开箱即用的缺点,并计划在未来改进这一点。

下面的参考文献更深入地讨论了我上面提到的一些概念:

Https://medium.com/@areai51/the-4-stages-of-perf-tuning-for-your-angular2-app-922ce5c1b294

Lodash 可以提供一个 bug 代码块到您的捆绑包中,这取决于您如何从中导入代码:

// includes the entire package (very large)
import * as _ from 'lodash';


// depending on your buildchain, may still include the entire package
import { flatten } from 'lodash';


// imports only the code needed for `flatten`
import flatten from 'lodash-es/flatten'

就个人而言,我仍然希望我的公用事业功能的脚印更小。例如,在最小化之后,flatten最多可以贡献到 1.2K。所以我一直在构建一个简化的 loash 函数集合。我对 flatten的实现贡献在 50 bytes左右。你可以在这里查看它是否适合你: https://github.com/simontonsoftware/micro-dash

我希望分享的一件事是导入的库如何增加 dist 的大小。我导入了 angular2-moment 包,而我可以使用从@angle/common 导出的标准 DatePipe 来完成所有需要的日期时间格式化。

与 Angular2-矩 "angular2-moment": "^1.6.0",

大块{0}填充。036982 dc15bb5fc67cb8.bundle.js (填充)191 KB {4}[初始][渲染]块{1} E7496551a26816427b68.bundle.js (main)2.2 MB {3}[初始值] [渲染]块{2}样式。056656 ed596d26ba0192.bundle.css (样式)69字节{4}[初始][呈现]块{3} 供应商.62 c2cfe0ca794a5006d1.bundle.js (供应商)3.84 MB [初始] [呈现] block {4} inline. 0 b9c3de53405d705e757.bundle.js (inline) 0字节[条目][呈现]

在删除 Angular2-moment 之后,使用 DateTube 代替

大块{0}填充。036982 dc15bb5fc67cb8.bundle.js (填充)191 KB {4}[初始][渲染]块{1} Main.f2b62721788695a4655c.bundle.js (main)2.2 MB {3}[初始值] [渲染]块{2}样式。056656 ed596d26ba0192.bundle.css (样式)69字节{4}[初始][呈现]块{3} Vendor.e1de06303258c58c9d01.bundle.js (卖方)3.35 MB [初始值] [呈现]块{4}内联。3 ae24861b3637391ba70.bundle.js (内联) 0字节[条目][呈现]

注意,供应商包减少了 半兆字节!

重点是,即使您已经熟悉外部库,也值得检查角度标准包可以做什么。

使用最新的角度 CLI 版本,并使用命令 < strong > ng build-prod-build-Optimizer 它肯定会 减少的建设大小,针对环境。

这就是构建优化器在底层所做的工作:

构建优化器有两个主要作业。 首先,我们能够将应用程序的某些部分标记为纯的,这改进了现有工具提供的树摇动,删除了不需要的应用程序的其他部分。

构建优化器要做的第二件事是从应用程序的运行时代码中删除角修饰符。修饰符由编译器使用,在运行时不需要,可以删除。这些任务中的每一个都会减小 JavaScript 包的大小,并提高应用程序对用户的启动速度。

注意 : 一个角度5及以上的更新,ng build --prod自动处理以上过程:)

下面的解决方案假设您使用 nodejs 服务 dist/file

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))

确保您安装了依赖项;

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

现在构建应用程序

ng build --prod --build-optimizer

如果您想进一步压缩构建,请减少300kb (大约) 从,然后按照下面的过程;

src文件夹和供应商文件夹内创建一个名为 vendor的文件夹,创建一个 rxjs.ts文件并将下面的代码粘贴到其中;

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

然后将以下内容添加到您的 angle-cli 应用程序的 tsconfig.json文件中。然后在 compilerOptions中,添加以下 json;

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

这将使你的构建大小太小了。在我的项目中,我将大小从11mb 减少到1mb。 希望能有帮助

另一种减少捆绑的方法,是服务 GZIP 而不是 JS。我们从2.6 mb 到543ko。

Https://httpd.apache.org/docs/2.4/mod/mod_deflate.html

我有一个角度5 + 弹簧启动应用程序(application.properties 1.3 +)在压缩的帮助下(链接附在下面)能够将 main.bundle.ts 的大小从2.7 MB 减少到530 KB。

另外,默认情况下—— aot 和—— build-Optimizer 是通过—— prod 模式启用的,您不需要分别指定它们。

Https://stackoverflow.com/a/28216983/9491345

在我的案例中,这确实缩小了规模:

ng build --prod --build-optimizer --optimization.

对于 Angular 5 + ng-build —— prod 默认执行此操作。 运行此命令后,大小从1.7 MB 减少到1.2 MB,但对于我的生产目的来说还不够。

我工作的 Facebook Messenger 平台和信息应用程序需要小于1 MB 运行在信息平台上。我一直在想办法有效地摇晃树木,但还是不行。

检查您是否有名为“ production”的配置用于 ng build —— prod,因为它是 ng build —— configuration = production 的缩写 没有答案解决了我的问题,因为问题就在屏幕前面。我觉得这很常见。 我用 i18n 将所有配置重命名为 production-en,从而使应用程序国际化。 然后我使用 ng build —— prod 构建,假设使用了默认优化,并且应该接近最优,但实际上只执行了 ng build,结果是7mb bundle 而不是250kb。

如果你使用角8 + ,你想减少捆绑的大小,你可以使用常春藤。Ivy 是 Angular 9中的默认视图引擎 只需转到 src/tsconfig.app.json 并添加 angularCompilerOptions 参数,例如:

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


/* add this one */
"angularCompilerOptions": {
"enableIvy": true
}
}

如果你已经运行了 ng build --prod-你不应该有 vendor文件在所有。

如果我只运行 ng build-我得到这些文件:

enter image description here

文件夹的总大小是 ~ 14MB。 Waat! : d

但如果我运行 ng build --prod-我会得到这些文件:

enter image description here

文件夹的总大小是584K。

一样的代码,我在两种情况下都启用了 Ivy 角度是8.2。

所以-我猜你没有添加 --prod到你的构建命令?

百分百有效

ng build --prod --aot --build-optimizer --vendor-chunk=true

摘自角度文档 v9(https://angular.io/guide/workspace-config#alternate-build-configurations) :

默认情况下,定义生产配置,并且 ng 构建 命令具有—— prod 选项,该选项使用此配置生成 生产配置设置默认值,优化应用程序 多种方式,如 捆绑文件最小化多余的空格、, 删除注释和死代码 ,重写代码使用 short, 神秘的名称(“缩小”)。

此外,您还可以使用@angle-Builder/custom- webpack: 浏览器构建器压缩所有可部署性,其中您的定制 webpack.config.js 如下所示:

module.exports = {
entry: {
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash].js'
},
plugins: [
new CompressionPlugin({
deleteOriginalAssets: true,
})
]
};

之后,你必须配置你的 web 服务器来提供压缩内容,例如,使用 nginx,你必须添加到 nginx.conf:

server {
gzip on;
gzip_types      text/plain application/xml;
gzip_proxied    no-cache no-store private expired auth;
gzip_min_length 1000;
...
}

在我的示例中,在 ng build 中使用—— prod 后,dist 文件夹从25 mb 缩小到5 mb,压缩后进一步缩小到1.5 mb。

这里所有的答案都过时了。我刚刚使用 Angular 13CLI 编写了 Angular 的标准样板应用程序“英雄之旅”。最初的点击建设需要10秒,随后在3秒完成。包大小为244kB 之前 Gzip。我用来构建的命令是“ ng build”,没有更改样板项目。

关于这个话题有很多错误的信息。让我们传播事实。

建立文件夹大小,以字节为单位,按框架,. map 文件删除,没有 gzip。

  • Upd 2022/03/02: 角13.2.5-171,580(ng new test-app,scss,no router)。JS 大小153.58 kb,46,90 kb gzip 估计,由 CLI 控制台输出提供。
  • Upd 2022/03/02: 角度13.2.5-249,449(ng 新角度英雄之旅,scss,路由器)。由 CLI 提供的 JS 大小为229.49 kb,gzip 估计值为64.91 kb。
  • 角度13.0.0-264,563(ng 新的角度英雄之旅,scss,路由器)。
  • React 17.0.2 without Router-167.074(npx create-response-app my-app).
  • 用 Router-172,459反应17.0.2(npx create-response-app my-app,将“ response-Router-dom”: “6.0.2”添加到 package.json,将 <App />包装在 <BrowserRouter>内,如所述 给你)。

enter image description here

更新: 2022/05/23,角度14(RC1)

g-zipng build --prod是两个非常有帮助的解决方案。这对你很有帮助。但如果你做了什么,尽力了呢。还是不管用吗?使用惰性载荷模块。还是不行吗?

这是给你的答案。目前,我正在升级我的角13角14项目使用 nx 和我发现的“桶副作用”导致你的 main.js捆绑增加。解决办法很简单。

  1. tsconfig.json构建模块从 "module": "commonjs"改为 "module": "es2020"或 esnext (这里应该使用 es2020解释 https://web.archive.org/web/20220605011837/https://angular.io/guide/migration-update-module-and-target-compiler-options)

enter image description here

  1. sideEffects: false加到 package.json,看看结果:

enter image description here

为什么?

完整的解释是这里是 https://webpack.js.org/guides/tree-shaking/#conclusion,这里是 https://github.com/angular/angular-cli/issues/16799,这里是 https://stackoverflow.com/a/59353152/5748537。但是我可以为你简短地解释一下:

你有模块“ A 是小的”和“ B 是大的”。您可以在 UI 库中编写它们,并将它们导出到 index.ts文件中。在项目中导入 A。最后一个包仍然包括你不想要的 B。

为什么?

因为 commonjs并不聪明。使用 es2020更好,他们知道哪些是使用,哪些不是。但是他们不确定是否应该移除它。你添加 sideEffects: false告诉他们: “清除死代码是安全的”。他们做到了。那你的包袱就小了。这可以在任何现代 JS 框架中使用,包括 React、 VueJS

阅读有关桶副作用的角度项目的问题在这里: https://github.com/angular/angular-cli/issues/16799

我的制作角度网站在这里: https://awread.vn,每天有100个用户。