Angular 2 的 AoT

每个Angular应用程序需要一个编译过程才能在浏览器中运行:Angular提供的丰富的组件和模板不能被浏览器直接理解。 在编译期间,Angular的编译器还通过考虑JavaScript VM的功能(如内联缓存)来提高应用程序运行时性能。

Angular 1.x和Angular 2中的初始编译器称为JiT(Just-in-Time)编译器。 对于AoT,它代表最近在Angular 2中引入的Ahead-of-Time编译器。与在运行时由Angular 2执行的JiT编译相比,AoT提供了一个较小的包,在浏览器中更快的呈现。 使用AoT,与 angular2-starter 原始的1.2 MB相比,我们可以减少428.8 kb,并通过跳过浏览器中的编译减少加载时间。

Characteristic JiT AoT
Compilation target Browser Server
Compilation context Runtime Build
Bundle size Huge (~1.2 MB) Smaller (~400 KB)
Execution Performance - Better
Startup time - Shorter

AoT的要点是将编译从运行时移动到构建过程。这意味着,首先我们可以从捆绑包中删除JiT编译器(大约523kb)以具有更小的构建,其次,浏览器可以执行代码,而无需在运行时等待JiT,这让渲染速度更快。

早期编译还意味着开发人员可以在实际运行代码之前和到达客户端之前找到模板错误。这提供了更强大的应用程序具有更高的安全性,因为更少的客户端HTML和JavaScript被eval。此外,通过在构建过程中引入编译代码,AoT使应用程序更具tree-shakable性,并可开放于各种其他优化。像Rollup和Google Closure这样的Bundler可以发挥这种优势,有效地减少包大小。

此外,AoT编译器还内联HTML模板和CSS文件,并帮助减少应用程序发送的异步请求数量。(注意:这导致了一个配置错误,我们将在后面的部分提到)

AoT 局限

然而,AoT不是完美的。 主要的限制是,由于编译原始代码的方式,AoT不能与常见的代码模式一起使用,例如,模块的默认导出,模板的模板文字以及提供者,路由或声明中的函数。 目前,我们没有“AoT Do’s and Don’ts”的完整列表,Angular团队并未就此问题发布任何内容。 Rangle在这里创建了自己的列表,并且还提供了一个用于使用AoT测试功能的沙盒。AoT的另一个问题是,当应用程序达到一定的复杂性时,与JiT bundle相比,AoT bundle实际上会占用更多的空间。 作为对浏览器具有更简单的逻辑(因此渲染速度更快)的折衷,与“动态”JiT相比,由AoT生成的代码实际上更冗长。

AoT 配置

要在Angular 2中启用AoT,有两种可能的方法:

  • 直接使用ngc
  • 使用@ngtools/webpack

我们推荐第二种方式,因为它最适合Angular + Webpack工具链。

使用原始ngc的一个问题是ngc会尝试内联CSS,而缺少必要的上下文。 例如,index.css中的@import 'basscss-basic'语句将导致类似于Error: Compilation failed. Resource file not found。 它缺少“basscss-basic”实际上是node_modules内部的节点模块的信息。 另一方面,@ngtools/webpack提供了AopPlugin和与其他加载器/插件共享上下文的Webpack加载器。 所以当ngc由@ngtools/webpack调用时,它可以从其他插件收集必要的信息,如postcss-import,以正确理解像@import 'basscss-basic'

配置@ngtools/webpack

首先,从npm获取@ngtools/webpack并将其保存为开发依赖关系:

npm install -D @ngtools/webpack

然后,在Webpack配置文件(通常命名为webpack.config.js)中,添加以下代码:

import {AotPlugin} from '@ngtools/webpack'
exports = { /* ... */
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: '@ngtools/webpack',
      }
    ]
  },
  plugins: [
    new AotPlugin({
      tsConfigPath: 'path/to/tsconfig.json',
      entryModule: 'path/to/app.module#AppModule'
    })
  ]
}

这里@ngtools/webpack替换了其他类型的脚本加载器,如ts-loaderawesome-typescript-loader。 它与AotPlugin一起工作以启用AoT编译。 更多细节可以在 这里找到。(注意,对于由angular-cli生成的项目,打开AoT可以很简单,因为ng build —aot,但是由于angular-cli不允许为复杂的用例定制webpack配置,它可能不够)。