免责声明: 正如Ben Elliot所指出的,UglifyJs插件是用于Webpack的构建过程中的,因为这些它不能移除未使用的Typescript类 ,转换的时候,使用IIFE实现。 在这篇文章中提到的Bundle的大小不能真正的反应摇树优化但确是最小的。为了能够真正的运用摇树优化,我们需要使用一个不同的模块rollup。 在这篇文章的代码库中引用rollup来替代webpack2,产生一个522k大小的Bundle。在未来的新的博客中会解释这个新的流程。
Angular 2框架是非常大的。 仅仅是创建一个 "hello world " 应用,我们应用的最后的Bundle可能超过2.5M。 如果你有一个50 Mbps的网络连接,这似乎没有问题,但大多数人没有这样的特权。另外,Angular 2 现在已经演变成一个跨平台的框架, 随着创建移动应用相同的代码作为Web应用程序的目标。在高延迟不可靠的3G连接下载2.5 MB是一个大问题。
幸运的是,我们有一些技术来显著减少我们的Bundle的大小。我们已经使用了很多这样的技术--像代码最小化, 连接和压缩。 也有一些新的,如懒加载,摇树优化 和AoT编译。为了协调这些技术,我们选择的工具是webpack,主要是因为它很容易使用与它最接近的竞争对手SystemJS来说,这是个比较成熟的技术。
本文的目的是向你展示如何使用 Webpack 创建一个 Angular 2 的构建系统,并使用上述提及的一些优化措施。我们只使用大部分的技术,而不是所有技术的原因是 Webpack 2 期望的 Angular 编译器和 TypeScript 版本有一些不兼容。Webpack 2 对编译器的要求是 TypeScript 1.9,而为了执行摇树必须要 TypeScript 2.x。这个问题将在下一个版本的 Angular 2 (RC6) 得以修复。我们将继续聚焦摇树并在以后的文章中不再提及 Angular 编译器的问题。
应用结构
在我们开始讨论如何去创建一个有细微差别的Webpack构建系统之前,让我们看看我们的“Hello World”应用程序的文件夹结构。
.
├── dist
├── src
│ ├── app
│ │ ├── app.module.ts
│ │ └── root
│ │ ├── index.ts
│ │ ├── root.component.css
│ │ ├── root.component.html
│ │ └── root.component.ts
│ ├── index.html
│ └── main.ts
├── package.json
├── tsconfig.json
└── typings.json
└── webpack.config.js
在这个例子中,我们有两个文件夹:
src,这里实时存放我们所有的TypeScript的代码dist,这里存放我们构建系统将要被部署的结果
在src目录中,我们定义了一个根模块和一个根组件,还有样式文件和模板文件。 详细查看代码,请查看 blog post repository。
我们把注意力集中在我们的配置文件package.json, tsconfig.json和webpack.config.js文件。
项目依赖项
在我们的项目中包括Angular 2 ,我们需要指定RC5版本的依赖。
package.json
{
...
"dependencies": {
"@angular/common": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/core": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"reflect-metadata": "0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "0.6.12"
}
}
这些库是我们的简单应用程序在某些地方要用到的,以及两个另外两个我们的代码不直接调用的但需要在浏览器中整个都是可用的。 这两个依赖就是 zone.js和 reflect-metadata。 要记住当我们开始谈论 chunks的时候,我们说的是webpack创建的。
接下来,我们将重点讨论项目的开发依赖关系:
{
...
"devDependencies ": {
...
"awesome-typescript-loader ": "2.2.1 ",
"typescript ": "2.0.2 ",
"webpack ": "2.1.0-beta.21 ",
"webpack-dev-server ": "2.1.0-beta.0 "
}
...
}
请注意,以上的库我们都是使用的都是2.X的版本。 这个是必须的,为了我们下一步能够执行摇树优化。
为什么需要TypeScript2 ?
Webpack 2 在没有使用loader的时候就能够识别import语法,这也是为什么它能够执行摇树优化的原因。 但是Webpack能够识别的唯一的东西就是ES2015的语法,对于其他任何新的语法我们需要转换,在这种情况下我们需要使用TypeScript2。
什么是摇树优化? 摇树优化能够在我们最终的Bundle中移除掉我们应用中没有使用到的代码。这是减少应用程序占用空间的最有效的技术之一.。
摇树优化是我们构建系统的最后一件事,它在TypeScript完成代码转换之后。问题是TypeScript1.x转将代码转换为ES5之后不能保存import语法。幸运的是, Typescript 2解决了这个问题现在可以有一个配置文件如下:
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
...
},
...
}
compilerOptions配置项的前两行是摇树优化的配置。 我们告诉TypeScript转换我们的代码到ES5 ("target": "es5")同时保留 为我们的模块保留import关键字 ("module": "es2015")。这种组合在TypeScript1.x中是不允许的。
Webpack配置
Webpack配置是非常标准的。 我们使用awesome-typescript-loader去执行转换以及使用创建一个Bundle的时候使用UglifyJsPlugin。 下面,我们只显示配置文件的相关部分。详细查看该文件,请检查源代码。
webpack.config.js
...
const basePlugins = [
...
];
const prodPlugins = [
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
})
];
const plugins = basePlugins
.concat((process.env.NODE_ENV === 'production ') ? prodPlugins: []);
module.exports = {
entry: {
globals: [
'zone.js ',
'reflect-metadata '
],
app: './src/main.ts ',
},
...
module: {
loaders: [
{ test: /.ts$/, loader: 'awesome-typescript-loader
' },
...
]
},
plugins: plugins
};
对于摇树优化有三件事情需要记住:
- 我们需要使用
awesome-typescript-loader包的2.x版本 。 - 我们需要保持我们的应用和库代码(Angular2)在同一个位置。
- 我们需要缩小文件。
默认情况下, Webpack 2 执行摇树优化移除我们应用的Bundle中模块中没有导出过而且应用没有试用过的代码。 Webpack将负责删除Bundle中所有未使用的引用代码,但不会从Bundle中删除未使用的代码。在这种情况下就需要使用代码缩减器UglifyJsPlugin,它能够智能的移除(变量,函数,类等)Bundle中未使用的代码。
简而言之,当执行树摇优化, Webpack移除连接, UglifyJsPlugin移除代码。
结果
现在是时候看下我们的应用摇树优化之后的Bundle了。 我们在开发模式下执行build,在没有摇树优化之前,首先要有一个文件的大小来做比较。
$ npm run build
...
Asset Size Chunks Chunk Names
app.00ca813ccc0897e68928.js 1.99 MB 0 [emitted] app
globals.00ca813ccc0897e68928.js 676 kB 1 [emitted] globals
index.html 318 bytes [emitted]
...
我们的构建系统创建了两个chunk,app 和 globals。app chunk中包含了我们应用的代码和Angular2本身的代码,而globals chunk文件中包含了我们在全局中需要使用到的全局变量的Javascript文件: zone.js 和 reflect-metadata。 因为我们的应用程序没有明确地依赖于这两个包,global
chunk不能执行摇树优化,但它可以通过minifier优化。
现在让我们开始进行生产环境代码的构建和使用摇树优化以及将代码缩小:
$ npm run build:prod
...
Asset Size Chunks Chunk Names
app.b2aebbcbc8b0f3ad76e0.js 767 kB 0 [emitted] app
globals.b2aebbcbc8b0f3ad76e0.js 322 kB 1 [emitted] globals
index.html 318 bytes [emitted]
...
虽然这两个块的体积有大幅减小,我们能看到 app 块缩小得最多,其体积只有原来的 30% 左右。
结论
这个大约 1M 大小的应用程序还不够好,但是我们对 globals 块已经没法再做什么了,但 app 块我们可以利用 AoT 编译器来获得可能的更佳效果。我们可能在以后写篇新文章继续阐述这个问题。但到这里,当使用 Webpack 构建系统,摇树是一个很好的用来降低 Angular2 应用程序体积的机制。
其他资源
浏览和下载 Rangle 的 Angular 2 训练书
文档 Angular 2 course book 是由 Rangle 内部的 JavaScript 专家团队编著的,覆盖基础内容以及如何开始使用 Angular 2 工具连的使用。