477 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			477 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
include ../_util-fns
 | 
						|
  
 | 
						|
:marked
 | 
						|
  This cookbook describes how to radically improve performance by compiling _Ahead of Time_ (AoT) 
 | 
						|
  during a build process.
 | 
						|
 | 
						|
a#toc
 | 
						|
:marked
 | 
						|
  ## Table of Contents
 | 
						|
  * [Overview](#overview)
 | 
						|
  * [_Ahead-of-Time_ vs _Just-in-Time_](#aot-jit)
 | 
						|
  * [Compile with AoT](#compile)
 | 
						|
  * [Bootstrap](#bootstrap)
 | 
						|
  * [Tree Shaking](#tree-shaking)
 | 
						|
  * [Load the bundle](#load)
 | 
						|
  * [Serve the app](#serve)
 | 
						|
  * [Source Code](#source-code)
 | 
						|
  * [Tour of Heroes](#toh)
 | 
						|
 | 
						|
a#overview
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Overview
 | 
						|
 | 
						|
  An Angular application consist largely of components and their HTML templates.
 | 
						|
  Before the browser can render the application, 
 | 
						|
  the components and templates must be converted to executable JavaScript by the _Angular compiler_.
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    <a href="https://www.youtube.com/watch?v=kW9cJsvcsGo" target="_blank">Watch compiler author Tobias Bosch explain the Angular Compiler</a> at AngularConnect 2016.
 | 
						|
:marked
 | 
						|
  You can compile the app in the browser, at runtime, as the application loads, using the **_Just-in-Time_ (JiT) compiler**. 
 | 
						|
  This is the standard development approach shown throughout the documentation.
 | 
						|
  It's great .. but it has shortcomings.
 | 
						|
 | 
						|
  JiT compilation incurs a runtime performance penalty. 
 | 
						|
  Views take longer to render because of the in-browser compilation step. 
 | 
						|
  The application is bigger because it includes the Angular compiler 
 | 
						|
  and a lot of library code that the application won't actually need.
 | 
						|
  Bigger apps take longer to transmit and are slower to load.
 | 
						|
  
 | 
						|
  Compilation can uncover many component-template binding errors.
 | 
						|
  JiT compilation discovers them at runtime which is later than we'd like.
 | 
						|
  
 | 
						|
  The **_Ahead-of-Time_ (AoT) compiler** can catch template errors early and improve performance 
 | 
						|
  by compiling at build time as you'll learn in this chapter.
 | 
						|
 | 
						|
 | 
						|
a#aot-jit
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## _Ahead-of-time_ (AoT) vs _Just-in-time_ (JiT)
 | 
						|
 | 
						|
  There is actually only one Angular compiler. The difference between AoT and JiT is a matter of timing and tooling. 
 | 
						|
  With AoT, the compiler runs once at build time using one set of libraries; 
 | 
						|
  With JiT it runs every time for every user at runtime using a different set of libraries.  
 | 
						|
 | 
						|
  ### Why do AoT compilation?
 | 
						|
 | 
						|
  *Faster rendering*
 | 
						|
 | 
						|
  With AoT, the browser downloads a pre-compiled version of the application. 
 | 
						|
  The browser loads executable code so it can render the application immediately, without waiting to compile the app first.
 | 
						|
 | 
						|
  *Fewer asynchronous requests*
 | 
						|
 | 
						|
  The compiler _inlines_ external html templates and css style sheets within the application JavaScript,
 | 
						|
  eliminating separate ajax requests for those source files.
 | 
						|
 | 
						|
  *Smaller Angular framework download size*
 | 
						|
 | 
						|
  There's no need to download the Angular compiler if the app is already compiled. 
 | 
						|
  The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.
 | 
						|
 | 
						|
 | 
						|
  *Detect template errors earlier*
 | 
						|
 | 
						|
  The AoT compiler detects and reports template binding errors during the build step
 | 
						|
  before users can see them.
 | 
						|
 | 
						|
 | 
						|
  *Better security*
 | 
						|
 | 
						|
  AoT compiles HTML templates and components into JavaScript files long before they are served to the client.
 | 
						|
  With no templates to read and no risky client-side HTML or JavaScript evaluation,
 | 
						|
  there are fewer opportunities for injection attacks.
 | 
						|
 | 
						|
a#compile
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Compile with AoT
 | 
						|
 | 
						|
  ### Prepare for offline compilation
 | 
						|
 | 
						|
  Take the <a href='/docs/ts/latest/quickstart.html'>QuickStart</a> as a starting point.
 | 
						|
  A few minor changes to the lone `app.component` lead to these two class and html files:
 | 
						|
 | 
						|
+makeTabs(
 | 
						|
  `cb-aot-compiler/ts/app/app.component.html,
 | 
						|
   cb-aot-compiler/ts/app/app.component.ts`,
 | 
						|
  null,
 | 
						|
  `app/app.component.html,
 | 
						|
   app/app.component.ts`
 | 
						|
)(format='.')
 | 
						|
 | 
						|
:marked
 | 
						|
  Install a few new npm dependencies with the following command: 
 | 
						|
code-example(format='.').
 | 
						|
  npm install @angular/compiler-cli @angular/platform-server --save
 | 
						|
:marked
 | 
						|
  You will run the `ngc` compiler provided in the `@angular/compiler-cli` npm package
 | 
						|
  instead of the TypeScript compiler (`tsc`). 
 | 
						|
 | 
						|
  `ngc` is a drop-in replacement for `tsc` and is configured much the same way.  
 | 
						|
 | 
						|
  `ngc` requires its own `tsconfig.json` with AoT-oriented settings.
 | 
						|
  Copy the original `tsconfig.json` to a file called `tsconfig-aot.json`, then modify it to look as follows.
 | 
						|
 | 
						|
+makeExample('cb-aot-compiler/ts/tsconfig-aot.json', null, 'tsconfig-aot.json')(format='.')
 | 
						|
 | 
						|
:marked
 | 
						|
  The `compilerOptions` section is unchanged except for one property. 
 | 
						|
  **Set the `module` to `es2015`**. 
 | 
						|
  This is important as explained later in the [Tree Shaking](#tree-shaking) section.
 | 
						|
 | 
						|
  What's really new is the `ngc` section at the bottom called `angularCompilerOptions`. 
 | 
						|
  Its `"genDir"` property tells the compiler 
 | 
						|
  to store the compiled output files in a new `aot` folder.
 | 
						|
 | 
						|
  The `"skipMetadataEmit" : true` property prevents the compiler from generating metadata files with the compiled application. 
 | 
						|
  Metadata files are not necessary when targeting TypeScript files, so there is no reason to include them.
 | 
						|
 | 
						|
  ### Compiling the application
 | 
						|
 | 
						|
  Initiate AoT compilation from the command line using the previously installed `ngc` compiler by executing:
 | 
						|
code-example(format='.').
 | 
						|
  node_modules/.bin/ngc -p tsconfig-aot.json
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    Windows users should surround the `ngc` command in double quotes:
 | 
						|
  code-example(format='.').
 | 
						|
    "node_modules/.bin/ngc" -p tsconfig-aot.json
 | 
						|
:marked
 | 
						|
  `ngc` expects the `-p` switch to point to a `tsconfig.json` file or a folder containing a `tsconfig.json` file.
 | 
						|
 | 
						|
  After `ngc` completes, look for a collection of _NgFactory_ files in the `aot` folder (the folder specified as `genDir` in `tsconfig-aot.json`). 
 | 
						|
 | 
						|
  These factory files are essential to the compiled application. 
 | 
						|
  Each component factory creates an instance of the component at runtime by combining the original class file
 | 
						|
  and a JavaScript representation of the component's template.
 | 
						|
  Note that the original component class is still referenced internally by the generated factory.
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    The curious can open the `aot/app.component.ngfactory.ts` to see the original Angular template syntax
 | 
						|
    in its intermediate, compiled-to-TypeScript form.
 | 
						|
 | 
						|
    JiT compilation generates these same _NgFactories_ in memory where they are largely invisible.
 | 
						|
    AoT compilation reveals them as separate, physical files.
 | 
						|
 | 
						|
:marked
 | 
						|
.alert.is-important
 | 
						|
  :marked
 | 
						|
    Do not edit the _NgFactories_! Re-compilation replaces these files and all edits will be lost. 
 | 
						|
 | 
						|
a#bootstrap
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Bootstrap
 | 
						|
 | 
						|
  The AoT path changes application bootstrapping.
 | 
						|
 | 
						|
  Instead of bootstrapping `AppModule`, you bootstrap the application with the generated module factory, `AppModuleNgFactory`.
 | 
						|
 | 
						|
  Switch from the `platformBrowserDynamic.bootstrap` used in JiT compilation to  
 | 
						|
  `platformBrowser().bootstrapModuleFactory` and pass in the `AppModuleNgFactory`.    
 | 
						|
 | 
						|
  Here is AoT bootstrap in `main.ts` next to the familiar JiT version:
 | 
						|
 | 
						|
+makeTabs(
 | 
						|
  `cb-aot-compiler/ts/app/main.ts,
 | 
						|
   cb-aot-compiler/ts/app/main-jit.ts`,
 | 
						|
  null,
 | 
						|
  `app/main.ts (AoT),
 | 
						|
   app/main.ts (JiT)`
 | 
						|
)
 | 
						|
 | 
						|
:marked
 | 
						|
  Be sure to recompile with `ngc`!
 | 
						|
 | 
						|
a#tree-shaking
 | 
						|
:marked
 | 
						|
  ## Tree Shaking
 | 
						|
 | 
						|
  AoT compilation sets the stage for further optimization through a process called _Tree Shaking_.
 | 
						|
  A Tree Shaker walks the dependency graph, top to bottom, and _shakes out_ unused code like
 | 
						|
  dead needles in a Christmas tree.
 | 
						|
 | 
						|
  Tree Shaking can greatly reduce the downloaded size of the application 
 | 
						|
  by removing unused portions of both source and library code. 
 | 
						|
  In fact, most of the reduction in small apps comes from removing unreferenced Angular features. 
 | 
						|
  
 | 
						|
  For example, this demo application doesn't use anything from the `@angular/forms` library.
 | 
						|
  There is no reason to download Forms-related Angular code and tree shaking ensures that you don't.
 | 
						|
 | 
						|
  Tree Shaking and AoT compilation are separate steps. 
 | 
						|
  Tree Shaking can only target JavaScript code. 
 | 
						|
  AoT compilation converts more of the application to JavaScript, 
 | 
						|
  which in turn makes more of the application "Tree Shakable".
 | 
						|
 | 
						|
  ### Rollup
 | 
						|
 | 
						|
  This cookbook illustrates a Tree Shaking utility called _Rollup_.
 | 
						|
 | 
						|
  Rollup statically analyzes the application by following the trail of `import` and `export` statements.
 | 
						|
  It produces a final code _bundle_ that excludes code that is exported, but never imported.
 | 
						|
 | 
						|
  Rollup can only Tree Shake `ES2015` modules which have `import` and `export` statements.
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    Recall that `tsconfig-aot.json` is configured to produce `ES2015` modules. 
 | 
						|
    It's not important that the code itself be written with `ES2015` syntax such as `class` and `const`. 
 | 
						|
    What matters is that the code uses ES `import` and `export` statements rather than `require` statements.
 | 
						|
:marked
 | 
						|
  Install the Rollup dependencies with this command:
 | 
						|
code-example(format='.').
 | 
						|
  npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev
 | 
						|
:marked
 | 
						|
  Next, create a configuration file (`rollup-config.js`)
 | 
						|
  in the project root directory to tell Rollup how to process the application. 
 | 
						|
  The cookbook configuration file looks like this.
 | 
						|
 | 
						|
+makeExample('cb-aot-compiler/ts/rollup-config.js', null, 'rollup-config.js')(format='.')
 | 
						|
:marked
 | 
						|
  It tells Rollup that the app entry point is `app/main.js` .
 | 
						|
  The `dest` attribute tells Rollup to create a bundle called `build.js` in the `dist` folder.
 | 
						|
  Then there are plugins.
 | 
						|
 | 
						|
:marked
 | 
						|
  ### Rollup Plugins
 | 
						|
 | 
						|
  Optional plugins filter and transform the Rollup inputs and output.
 | 
						|
 | 
						|
  *RxJS*
 | 
						|
  Rollup expects application source code to use `ES2015` modules. 
 | 
						|
  Not all external dependencies are published as `ES2015` modules.
 | 
						|
  In fact, most are not. Many of them are published as _CommonJS_ modules.
 | 
						|
  
 | 
						|
  The _RxJs_ observable library is an essential Angular dependency published as an ES5 JavaScript _CommonJS_ module.
 | 
						|
 | 
						|
  Luckily there is a Rollup plugin that modifies _RxJs_ 
 | 
						|
  to use the ES `import` and `export` statements that Rollup requires.
 | 
						|
  Rollup then preserves in the final bundle the parts of `RxJS` referenced by the application.
 | 
						|
 | 
						|
+makeExample('cb-aot-compiler/ts/rollup-config.js','commonjs','rollup-config.js (CommonJs to ES2015 Plugin)')(format='.')     
 | 
						|
 | 
						|
:marked
 | 
						|
  *Minification* 
 | 
						|
 | 
						|
  Rollup Tree Shaking reduces code size considerably.  Minification makes it smaller still.
 | 
						|
  This cookbook relies on the _uglify_ Rollup plugin to minify and mangle the code.
 | 
						|
 | 
						|
+makeExample('cb-aot-compiler/ts/rollup-config.js','uglify','rollup-config.js (CommonJs to ES2015 Plugin)')(format='.') 
 | 
						|
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    In a production setting, you would also enable gzip on the web server to compress
 | 
						|
    the code into an even smaller package going over the wire.
 | 
						|
 | 
						|
:marked
 | 
						|
  ### Run Rollup
 | 
						|
  Execute the Rollup process with this command:
 | 
						|
code-example(format='.').
 | 
						|
  node_modules/.bin/rollup -c rollup-config.js
 | 
						|
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    Rollup may log many lines with the following warning message:
 | 
						|
  code-example(format='.', language='bash').
 | 
						|
    The `this` keyword is equivalent to `undefined` at the top level of an ES module, and has been rewritten
 | 
						|
  :marked
 | 
						|
    You can safely ignore these warnings.
 | 
						|
 | 
						|
a#load
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Load the Bundle
 | 
						|
 | 
						|
  Loading the generated application bundle does not require a module loader like SystemJS. 
 | 
						|
  Remove the scripts that concern SystemJS.
 | 
						|
  Instead, load the bundle file using a single `script` tag:
 | 
						|
 | 
						|
+makeExample('cb-aot-compiler/ts/index.html','bundle','index.html (load bundle)')(format='.') 
 | 
						|
 | 
						|
a#serve
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Serve the app
 | 
						|
 | 
						|
  You'll need a web server to host the application.
 | 
						|
  Use the same _Lite Server_ employed elsewhere in the documentation:
 | 
						|
code-example(format='.').
 | 
						|
  npm run lite
 | 
						|
:marked
 | 
						|
  The server starts, launches a browser, and the app should appear.
 | 
						|
 | 
						|
a#source-code
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## AoT QuickStart Source Code
 | 
						|
 | 
						|
  Here's the pertinent source code:
 | 
						|
+makeTabs(
 | 
						|
  `cb-aot-compiler/ts/app/app.component.html,
 | 
						|
   cb-aot-compiler/ts/app/app.component.ts,
 | 
						|
   cb-aot-compiler/ts/app/main.ts,
 | 
						|
   cb-aot-compiler/ts/index.html,
 | 
						|
   cb-aot-compiler/ts/tsconfig-aot.json,
 | 
						|
   cb-aot-compiler/ts/rollup-config.js`,
 | 
						|
  null,
 | 
						|
  `app/app.component.html,
 | 
						|
   app/app.component.ts,
 | 
						|
   app/main.ts,
 | 
						|
   index.html,
 | 
						|
   tsconfig-aot.json,
 | 
						|
   rollup-config.js`
 | 
						|
)
 | 
						|
 | 
						|
a#toh
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Tour of Heroes
 | 
						|
 | 
						|
  The sample above is a trivial variation of the QuickStart app. 
 | 
						|
  In this section you apply what you've learned about AoT compilation and Tree Shaking 
 | 
						|
  to an app with more substance, the tutorial [_Tour of Heroes_](../tutorial/toh-pt6.html).
 | 
						|
 | 
						|
  ### JiT in development, AoT in production
 | 
						|
 | 
						|
  Today AoT compilation and Tree Shaking take more time than is practical for development. That will change soon.
 | 
						|
  For now, it's best to JiT compile in development and switch to AoT compilation before deploying to production.
 | 
						|
 | 
						|
  Fortunately, the source code can be compiled either way without change _if_ you account for a few key differences.
 | 
						|
 | 
						|
  ***Index.html***
 | 
						|
 | 
						|
  The JiT and AoT apps are setup and launched so differently that they require their own `index.html` files. 
 | 
						|
  Here they are for comparison:
 | 
						|
 | 
						|
+makeTabs(
 | 
						|
  `toh-6/ts/aot/index.html,
 | 
						|
   toh-6/ts/index.html`,
 | 
						|
  null,
 | 
						|
  `aot/index.html (AoT),
 | 
						|
   index.html (JiT)`
 | 
						|
)
 | 
						|
 | 
						|
:marked
 | 
						|
  They can't be in the same folder. 
 | 
						|
  ***Put the AoT version in the `/aot` folder***.
 | 
						|
 | 
						|
  The JiT version relies on `SystemJS` to load individual modules and requires the `reflect-metadata` shim. 
 | 
						|
  Both scripts appear in its `index.html`.
 | 
						|
 | 
						|
  The AoT version loads the entire application in a single script, `aot/dist/build.js`.
 | 
						|
  It does not need `SystemJS` or the `reflect-metadata` shim; those scripts are absent from its `index.html`
 | 
						|
 | 
						|
  *Component-relative Template URLS*
 | 
						|
 | 
						|
  The AoT compiler requires that `@Component` URLS for external templates and css files be _component-relative_.
 | 
						|
  That means that the value of `@Component.templateUrl` is a URL value relative to the component class file:
 | 
						|
  `foo.component.html` no matter where `foo.component.ts` sits in the project folder structure.
 | 
						|
 | 
						|
  While JiT app URLs are more flexible, stick with _component-relative_ URLs for compatibility with AoT compilation.
 | 
						|
  
 | 
						|
  JiT-compiled apps, using the SystemJS loader and _component-relative_ URLs *must set the* `@Component.moduleId` *property to* `module.id`.
 | 
						|
  The `module` object is undefined when an AoT-compiled app runs. 
 | 
						|
  The app fails unless you assign a global `module` value in the `index.html` like this:
 | 
						|
+makeExample('toh-6/ts/aot/index.html','moduleId')(format='.')  
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    Setting a global `module` is a temporary expedient. 
 | 
						|
:marked
 | 
						|
  *TypeScript configuration*
 | 
						|
 | 
						|
  JiT-compiled apps transpile to `commonjs` modules.
 | 
						|
  AoT-compiled apps transpile to _ES2015_/_ES6_ modules to facilitate Tree Shaking. 
 | 
						|
  AoT requires its own TypeScript configuration settings as well.
 | 
						|
 | 
						|
  You'll need separate TypeScript configuration files such as these:
 | 
						|
 | 
						|
+makeTabs(
 | 
						|
  `toh-6/ts/tsconfig-aot.json,
 | 
						|
   toh-6/ts/tsconfig.json`,
 | 
						|
  null,
 | 
						|
  `tsconfig-aot.json (AoT),
 | 
						|
   tsconfig.json (JiT)`
 | 
						|
)
 | 
						|
 | 
						|
:marked
 | 
						|
  ### Tree Shaking
 | 
						|
 | 
						|
  Rollup does the Tree Shaking as before.
 | 
						|
  
 | 
						|
+makeExample('toh-6/ts/rollup-config.js',null,'rollup-config.js')(format='.')  
 | 
						|
 | 
						|
:marked
 | 
						|
  ### Running the application
 | 
						|
 | 
						|
.alert.is-important
 | 
						|
  :marked
 | 
						|
    The general audience instructions for running the AoT build of the Tour of Heroes app are not ready.
 | 
						|
 | 
						|
    The following instructions presuppose that you have cloned the 
 | 
						|
    <a href="https://github.com/angular/angular.io" target="_blank">angular.io</a> 
 | 
						|
    github repository and prepared it for development as explained in the repo's README.md.
 | 
						|
 | 
						|
    The _Tour of Heroes_ source code is in the `public/docs/_examples/toh-6/ts` folder.
 | 
						|
:marked
 | 
						|
  Run the JiT-compiled app with `npm start` as for all other JiT examples.
 | 
						|
 | 
						|
  Compiling with AoT presupposes certain supporting files, most of them discussed above.
 | 
						|
+makeTabs(
 | 
						|
  `toh-6/ts/aot/index.html,
 | 
						|
   toh-6/ts/aot/bs-config.json,
 | 
						|
   toh-6/ts/copy-dist-files.js,
 | 
						|
   toh-6/ts/rollup-config.js,
 | 
						|
   toh-6/ts/tsconfig-aot.json`,
 | 
						|
  null,
 | 
						|
  `aot/index.html,
 | 
						|
   aot/bs-config.json,
 | 
						|
   copy-dist-files.js,
 | 
						|
   rollup-config.js,
 | 
						|
   tsconfig-aot.json`)
 | 
						|
:marked
 | 
						|
  Extend the `scripts` section of the `package.json` with these npm scripts:
 | 
						|
code-example(format='.').
 | 
						|
  "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
 | 
						|
  "lite:aot": "lite-server -c aot/bs-config.json",
 | 
						|
:marked
 | 
						|
  Copy the AoT distribution files into the `/aot` folder with the node script:
 | 
						|
code-example(format='.').
 | 
						|
  node copy-dist-files
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    You won't do that again until there are updates to `zone.js` or the `core-js` shim for old browsers.
 | 
						|
:marked
 | 
						|
  Now AoT-compile the app and launch it with the `lite` server:
 | 
						|
code-example(format='.').
 | 
						|
  npm run build:aot && npm run lite:aot
 | 
						|
 | 
						|
:marked
 | 
						|
  ### Inspect the Bundle
 | 
						|
 | 
						|
  It's fascinating to see what the generated JavaScript bundle looks like after Rollup. 
 | 
						|
  The code is minified, so you won't learn much from inspecting the bundle directly.
 | 
						|
  But the <a href="https://github.com/danvk/source-map-explorer/blob/master/README.md" target="_blank">source-map-explorer</a> 
 | 
						|
  tool can be quite revealing. 
 | 
						|
 | 
						|
  Install it:
 | 
						|
code-example(format='.').  
 | 
						|
  npm install source-map-explorer --save-dev
 | 
						|
:marked
 | 
						|
  Run the following command to generate the map.
 | 
						|
 | 
						|
code-example(format='.').
 | 
						|
  node_modules/.bin/source-map-explorer aot/dist/build.js
 | 
						|
 | 
						|
:marked
 | 
						|
  The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
 | 
						|
  showing exactly which application and Angular modules and classes are included in the bundle.
 | 
						|
 | 
						|
  Here's the map for _Tour of Heroes_. 
 | 
						|
 | 
						|
a(href="/resources/images/cookbooks/aot-compiler/toh6-bundle.png", target="_blank", title="View larger image")
 | 
						|
  figure.image-display
 | 
						|
    img(src="/resources/images/cookbooks/aot-compiler/toh6-bundle.png" alt="TOH-6-bundle")   
 |