专栏首页张志敏的技术专栏为生产环境编译 Angular 2 应用

为生产环境编译 Angular 2 应用

为生产环境编译 Angular 2 应用

Angular 2 已经发布了 2.1.2 版本, 相信很多人已经在使用(试用)了, 相比 AngularJS 1.x , Angular 2 在性能上有了长足的进步, 同时 Angular 2 也变得非常的庞大, 动辄几兆的脚本, 如何部署到生产环境? 接下来就介绍如何为生产环境编译 Angular 2 应用, 在本文中, 我们将 Angular 2 官方文档中的 Hello Angular 应用编译到 50K 以下, 以用于生产环境。

未经优化的应用

根据 Angular2 官方的 QuickStart 快速创建一个 Hello Angular 应用, 在没有任何优化的情况下, 运行情况如下图所示:

从上图可以看出, 仅仅一个 Hello 应用, 就产生了 40 个请求, 加载了 1.8M 的脚本, 这个在生产环境下(特别是移动端)是无法接受的。

要看这一步的完整源代码, 请移步 GitHub

打包与压缩

传统的方式无非就是进行打包和压缩, 我使用 browserify 和 uglifyjs 来进行打包与压缩, 首先是安装这两个工具类库:

npm i -D browserify uglifyjs

在 package.json 文件中添加这两个 npm 命令:

{
  "scripts": {
    "bundle": "browserify -s main app/main.js > dist/bundle.js",
    "minify": "uglifyjs dist/bundle.js --screw-ie8 --compress --mangle --output dist/bundle.min.js"
  }
}

现在运行这两个命令, 看看会怎么样:

npm run bundle && npm run minify

经过一大堆 WARN 之后, 没有出现 ERROR , 也没有出现 npm-debug.log 文件, 证明没有错误, 现在来分析一下大小:

ls -hl dist
-rw-r--r--   1 zhang  staff   1.4M Nov 14 14:08 bundle.js
-rw-r--r--   1 zhang  staff   528K Nov 14 14:10 bundle.min.js

bundle.js 有 1.4M , 不过 bundle.min.js 被压缩到了 528K , 看起来还不错, 还可以再优化一下, 那就是 gzip 压缩, 通常在服务器上都会启用:

gzip dist/bundle.min.js -c > dist/bundle.min.js.gz && ls -hl dist
-rw-r--r--   1 zhang  staff   1.4M Nov 14 14:08 bundle.js
-rw-r--r--   1 zhang  staff   528K Nov 14 14:10 bundle.min.js
-rw-r--r--   1 zhang  staff   129K Nov 14 14:15 bundle.min.js.gz

经过 gzip 之后, bundle.min.js.gz 有 129K , 似乎应该可以了吧? 但是我觉得还有优化的空间。

要看这一步的完整源代码, 请移步 GitHub

AOT 以及 Tree Shaking

ES2016 (ES6) 有一个很重要的特性, 那就是 Tree Shaking , 可以移除项目中不需要的部分, 接下来我们使用 rollup 进行 Tree Shaking 。

为了能够使用 Tree Shaking , 我们需要将项目中的 TypeScript 编译成 ES2015 脚本, 需要修改 TypeScript 配置, 新建一个 tsconfig-es2015.json 的配置文件, 内容如下:

{
  "compilerOptions": {
    "target": "es2015",
    "module": "es2015",
    "moduleResolution": "node",
    "declaration": false,
    "removeComments": true,
    "noLib": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "es2015", "dom"],
    "sourceMap": true,
    "pretty": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitUseStrict": false,
    "noFallthroughCasesInSwitch": true,
    "typeRoots": [
      "./node_modules/@types",
      "./node_modules"
    ],
    "types": [
    ]
  },
  "files": [
    "app/main-aot.ts"
  ]
}

在 Angular2 应用中, 包含了一个即时编辑器 (JIT) , 在预编译好的应用中不是必需的, 使用 Angular2 的 AOT 编译可以移除即时编译器 (JIT) , 因此需要先安装 Angular 的编译器:

npm i -D @angular/compiler-cli

为了使用 aot 编译出来的文件, main.ts 文件也要做相应的修改, 将 main.ts 文件另存为 main-aot.ts , 修改内容如下:

import { enableProdMode } from '@angular/core';
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from './app.module.ngfactory';
enableProdMode();
const platform = platformBrowser();
platform.bootstrapModuleFactory(AppModuleNgFactory);

不再使用 platform-browser-dynamic , 改为使用 platform-browser

同时 index.html 也另存为 index-aot.html , 也做相应的修改, 不在加载 system.js , 改为直接使用最终的 aot 脚本:

<!--
<script src="node_modules/systemjs/dist/system.src.js"></script>
-->
<!-- 2. Configure SystemJS -->
<!--
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
-->
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
<script src="dist/bundle-aot.min.js"></script>
</body>

接下来的整体的思路是:

  1. 使用 ngc 进行 aot 编译; npm run ngc -- -p tsconfig-es2015.json 这一步将会生成一系列 *.ngfactory.ts *.module.metadata.json 临时文件, 可以更新 .gitignore 来忽略这些文件, 避免对代码库造成污染;
  2. 将 typescript 文件编译成 es2015 (es6) 脚本; npm run tsc -- -p tsconfig-es2015.json
  3. 使用 rollup 进行 tree shaking , 移除项目不使用的功能; rollup -f iife -c rollup.config.js -o dist/bundle-aot-es2015.js
  4. 再次使用 typescript 将 tree shaking 之后的脚本编译成 es5 脚本; tsc --target es5 --allowJs dist/bundle-aot-es2015.js -out dist/bundle-aot.js
  5. 使用 uglifyjs 再次压缩上一部生成的 es5 脚本; uglifyjs dist/bundle-aot.js --screw-ie8 --compress --mangle --output dist/bundle-aot.min.js

这几个命令对应的 npm 脚本如下:

{
  "scripts": {
    "ngc": "ngc",
    "rollup": "rollup -f iife -c rollup.config.js -o dist/bundle-aot-es2015.js",
    "es5": "tsc --target es5 --allowJs dist/bundle-aot-es2015.js -out dist/bundle-aot.js",
    "minify-aot": "uglifyjs dist/bundle-aot.js --screw-ie8 --compress --mangle --output dist/bundle-aot.min.js",
    "prod-aot": "npm run ngc -- -p tsconfig-es2015.json && npm run tsc -- -p tsconfig-es2015.json && rollup && npm run es5 && npm run minify-aot"
  }
}

最终只要运行一个命令即可:

npm run prod-aot

最后来看一下最终的文件大小:

ls -hl
-rw-r--r--  1 zhang  staff   595K Nov 14 15:59 bundle-aot-es2015.js
-rw-r--r--  1 zhang  staff   669K Nov 14 16:01 bundle-aot.js
-rw-r--r--  1 zhang  staff   194K Nov 14 16:01 bundle-aot.min.js
-rw-r--r--  1 zhang  staff    46K Nov 14 16:02 bundle-aot.min.js.gz
-rw-r--r--  1 zhang  staff   1.4M Nov 14 15:54 bundle.js
-rw-r--r--  1 zhang  staff   528K Nov 14 15:54 bundle.min.js
-rw-r--r--  1 zhang  staff   129K Nov 14 16:02 bundle.min.js.gz

最终生成的 bundle-aot.min.js.gz 只有 46K , 比没有使用 aot 编译的最终文件 bundle.min.js.gz 少了将近 2/3 , 可以说 aot + tree shaking 效果非常的显著。

要看这一步的完整源代码, 请移步 GitHub

经过这样的终极编译优化编译之后, 应该可以放心的部署到生产环境了。

参考资料:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 发布 Angular 应用至生产环境

    两年前, 写过一篇使用 rollup 来为生产环境编译 Angular 2 应用的文章, 因为当时还没有 angular-cli 项目。 而如今 Angular...

    beginor
  • 备份和恢复 timescaledb 的超级表 (hypertables)

    下面是使用 PostgreSQL 内置的工具 pg_dump 和 psql 对超级表 conditions 进行备份和恢复的步骤。

    beginor
  • 在 Windows 系统上配置 Apache Git 服务器

    本文介绍如何在 Windows 系统上配置 Apache Git 服务器, 以及使用 AD 进行认证用户认证。

    beginor
  • 一文快速上手Rollup,JavaScript类库打包好帮手

    项目中一直用的都是webpack,前一段需要开发几个类库供其他平台使用,本来打算继续用webpack的,但感觉webpack用来开发js库,不仅繁琐而且打包后的...

    JowayYoung
  • 隐藏在Chrome插件商店中的恶魔——恶意插件User-Agent Swither分析

    ? ? 0x00 插件背景 — User-Agent Swither 是一款Chrome插件,用户切换访问web时候的User-Agent的,这个插件有51万...

    xfkxfk
  • webpack 项目 css/js主域重试

    为了提高网站的访问速度,现在一般会将静态资源放在 CDN 下,而不是放在网站的域名之下。以腾讯课堂为例,其域名为 ke.qq.com,打开控制台,访问 ke....

    IMWeb前端团队
  • webpack 项目 css/js主域重试

    为了提高网站的访问速度,现在一般会将静态资源放在 CDN 下,而不是放在网站的域名之下。以腾讯课堂为例,其域名为 ke.qq.com,打开控制台,访问 ke.q...

    IMWeb前端团队
  • bootstrap大图轮播手机端不能手指滑动解决办法

    网上看了很多解决办法,几乎本质都是一样的,都是引入一个滑动的js插件,加入一段js代码,即可生效,但是我试了hammer.js 和 touchSwipe.js ...

    蓓蕾心晴
  • Node.js-具有示例API的基于角色的授权教程

    1.从https://github.com/cornflourblue/node-role-based-authorization-api下载或克隆教程项目代码...

    ccf19881030
  • 教你利用Node.js漏洞搞事情

    今天我们主要讲下Node.js的一些可以对渗透测试工作有一些帮助的漏洞。为了更好地让大家理解,我会对其中一些代码进行分

    洛米唯熊

扫码关注云+社区

领取腾讯云代金券