From 5738c4b66aa1ffee09ac54b7f7ec1c773823cf19 Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Fri, 31 Mar 2017 09:20:59 -0700 Subject: [PATCH] docs(universal): add guide (#3378) * docs(universal): add guide * gulpfile: Replace 'rm -rf' with 'node rimraf' so install-example-angular will work on Windows * Get universal working * doc wip * gulpfile: Add platform-server to install-example-angular * Update toh code in universal sample - remove moduleId * Update typescript to 2.2.1 when we install-example-angular --build * move example files; add graphs * demo and docs wip * doc wip * Fix toc * add toc, link --- gulpfile.js | 9 +- public/docs/_examples/universal/ts/.gitignore | 8 + .../_examples/universal/ts/bs-config.aot.js | 18 + .../_examples/universal/ts/bs-config.uni.js | 41 + .../universal/ts/example-config.json | 0 .../_examples/universal/ts/package.steve.json | 62 ++ .../ts/src/app/app-routing.module.ts | 19 + .../universal/ts/src/app/app.component.css | 29 + .../universal/ts/src/app/app.component.ts | 19 + .../universal/ts/src/app/app.module.ts | 54 ++ .../ts/src/app/dashboard.component.css | 62 ++ .../ts/src/app/dashboard.component.html | 10 + .../ts/src/app/dashboard.component.ts | 22 + .../ts/src/app/hero-detail.component.css | 30 + .../ts/src/app/hero-detail.component.html | 14 + .../ts/src/app/hero-detail.component.ts | 40 + .../ts/src/app/hero-search.component.css | 21 + .../ts/src/app/hero-search.component.html | 11 + .../ts/src/app/hero-search.component.ts | 69 ++ .../ts/src/app/hero-search.service.ts | 20 + .../universal/ts/src/app/hero.service.ts | 87 ++ .../_examples/universal/ts/src/app/hero.ts | 4 + .../universal/ts/src/app/heroes.component.css | 68 ++ .../ts/src/app/heroes.component.html | 29 + .../universal/ts/src/app/heroes.component.ts | 61 ++ .../ts/src/app/in-memory-data.service.ts | 19 + .../_examples/universal/ts/src/index-aot.html | 18 + .../_examples/universal/ts/src/index.html | 26 + .../_examples/universal/ts/src/main-aot.ts | 5 + .../docs/_examples/universal/ts/src/main.ts | 6 + .../universal/ts/src/uni/app.server.ts | 21 + .../universal/ts/src/uni/server-aot.ts | 40 + .../universal/ts/src/uni/universal-engine.ts | 38 + .../_examples/universal/ts/tsconfig-aot.json | 27 + .../_examples/universal/ts/tsconfig-uni.json | 27 + .../docs/_examples/universal/ts/tsconfig.json | 20 + .../universal/ts/webpack.config.aot.js | 30 + .../universal/ts/webpack.config.uni.js | 30 + public/docs/ts/latest/guide/_data.json | 5 + .../ts/latest/guide/universal-img/pie-aot.png | Bin 0 -> 11986 bytes .../ts/latest/guide/universal-img/pie-jit.png | Bin 0 -> 12410 bytes .../guide/universal-img/timeline-aot.png | Bin 0 -> 4759 bytes .../guide/universal-img/timeline-jit.png | Bin 0 -> 4377 bytes .../guide/universal-img/toh-aot-local-pie.png | Bin 0 -> 14102 bytes .../universal-img/toh-aot-throttled-pie.png | Bin 0 -> 12190 bytes .../guide/universal-img/toh-jit-local-pie.png | Bin 0 -> 12727 bytes .../universal-img/toh-jit-throttled-pie.png | Bin 0 -> 13664 bytes .../guide/universal-img/toh-uni-local-pie.png | Bin 0 -> 12863 bytes .../universal-img/toh-uni-throttled-pie.png | Bin 0 -> 13201 bytes public/docs/ts/latest/guide/universal.md | 818 ++++++++++++++++++ 50 files changed, 1934 insertions(+), 3 deletions(-) create mode 100644 public/docs/_examples/universal/ts/.gitignore create mode 100644 public/docs/_examples/universal/ts/bs-config.aot.js create mode 100644 public/docs/_examples/universal/ts/bs-config.uni.js create mode 100644 public/docs/_examples/universal/ts/example-config.json create mode 100644 public/docs/_examples/universal/ts/package.steve.json create mode 100644 public/docs/_examples/universal/ts/src/app/app-routing.module.ts create mode 100644 public/docs/_examples/universal/ts/src/app/app.component.css create mode 100644 public/docs/_examples/universal/ts/src/app/app.component.ts create mode 100644 public/docs/_examples/universal/ts/src/app/app.module.ts create mode 100644 public/docs/_examples/universal/ts/src/app/dashboard.component.css create mode 100644 public/docs/_examples/universal/ts/src/app/dashboard.component.html create mode 100644 public/docs/_examples/universal/ts/src/app/dashboard.component.ts create mode 100644 public/docs/_examples/universal/ts/src/app/hero-detail.component.css create mode 100644 public/docs/_examples/universal/ts/src/app/hero-detail.component.html create mode 100644 public/docs/_examples/universal/ts/src/app/hero-detail.component.ts create mode 100644 public/docs/_examples/universal/ts/src/app/hero-search.component.css create mode 100644 public/docs/_examples/universal/ts/src/app/hero-search.component.html create mode 100644 public/docs/_examples/universal/ts/src/app/hero-search.component.ts create mode 100644 public/docs/_examples/universal/ts/src/app/hero-search.service.ts create mode 100644 public/docs/_examples/universal/ts/src/app/hero.service.ts create mode 100644 public/docs/_examples/universal/ts/src/app/hero.ts create mode 100644 public/docs/_examples/universal/ts/src/app/heroes.component.css create mode 100644 public/docs/_examples/universal/ts/src/app/heroes.component.html create mode 100644 public/docs/_examples/universal/ts/src/app/heroes.component.ts create mode 100644 public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts create mode 100644 public/docs/_examples/universal/ts/src/index-aot.html create mode 100644 public/docs/_examples/universal/ts/src/index.html create mode 100644 public/docs/_examples/universal/ts/src/main-aot.ts create mode 100644 public/docs/_examples/universal/ts/src/main.ts create mode 100644 public/docs/_examples/universal/ts/src/uni/app.server.ts create mode 100644 public/docs/_examples/universal/ts/src/uni/server-aot.ts create mode 100644 public/docs/_examples/universal/ts/src/uni/universal-engine.ts create mode 100644 public/docs/_examples/universal/ts/tsconfig-aot.json create mode 100644 public/docs/_examples/universal/ts/tsconfig-uni.json create mode 100644 public/docs/_examples/universal/ts/tsconfig.json create mode 100644 public/docs/_examples/universal/ts/webpack.config.aot.js create mode 100644 public/docs/_examples/universal/ts/webpack.config.uni.js create mode 100644 public/docs/ts/latest/guide/universal-img/pie-aot.png create mode 100644 public/docs/ts/latest/guide/universal-img/pie-jit.png create mode 100644 public/docs/ts/latest/guide/universal-img/timeline-aot.png create mode 100644 public/docs/ts/latest/guide/universal-img/timeline-jit.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-aot-local-pie.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-aot-throttled-pie.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-jit-local-pie.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-jit-throttled-pie.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-uni-local-pie.png create mode 100644 public/docs/ts/latest/guide/universal-img/toh-uni-throttled-pie.png create mode 100644 public/docs/ts/latest/guide/universal.md diff --git a/gulpfile.js b/gulpfile.js index daf7dadf7e..b6a3900b24 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -502,7 +502,7 @@ function installExampleAngular() { var template; var libs = [ 'core', 'common', 'compiler', 'compiler-cli', - 'platform-browser', 'platform-browser-dynamic', + 'platform-browser', 'platform-browser-dynamic', 'platform-server', 'forms', 'http', 'router', 'upgrade']; var build = argv.build; @@ -522,13 +522,16 @@ function installExampleAngular() { : `git+https://github.com/angular/${lib}-builds${build}`; }); - if (argv.build) { sources.push('@angular/tsc-wrapped');} // tsc-wrapped needed for builds + if (argv.build) { + sources.push('@angular/tsc-wrapped'); // tsc-wrapped needed for builds + sources.push('typescript@2.2.1'); // recent builds need recent TypeScript + } sources.push('@angular/router-deprecated'); gutil.log(`Installing Angular packages from ${build === 'npm' ? 'NPM' : 'BUILD ' + build}`); - var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH}); + var spawnInfo = spawnExt('node', ['node_modules/rimraf/bin.js', 'node_modules/@angular'], { cwd: EXAMPLES_PATH}); return spawnInfo.promise .then(() => { spawnInfo = spawnExt('npm', ['install', ...sources], {cwd: EXAMPLES_PATH}); diff --git a/public/docs/_examples/universal/ts/.gitignore b/public/docs/_examples/universal/ts/.gitignore new file mode 100644 index 0000000000..62993511f8 --- /dev/null +++ b/public/docs/_examples/universal/ts/.gitignore @@ -0,0 +1,8 @@ +aot/**/*.ts +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.metadata.json +**/*.js +dist +!app/tsconfig.json +!/*.js diff --git a/public/docs/_examples/universal/ts/bs-config.aot.js b/public/docs/_examples/universal/ts/bs-config.aot.js new file mode 100644 index 0000000000..7bb795b9e2 --- /dev/null +++ b/public/docs/_examples/universal/ts/bs-config.aot.js @@ -0,0 +1,18 @@ +module.exports = { + port: 3100, + server: { + baseDir: "src", + routes: { + "/node_modules": "node_modules" + }, + middleware: { + // overrides the fallback middleware to use index-aot + 1: require('connect-history-api-fallback')({ index: '/index-aot.html' }) + } + } + // ,"snippetOptions": { + // "rule": { + // "match": "/dummy/" // disable browsersync by giving it an invalid injection target + // } + // } +}; diff --git a/public/docs/_examples/universal/ts/bs-config.uni.js b/public/docs/_examples/universal/ts/bs-config.uni.js new file mode 100644 index 0000000000..e15de19940 --- /dev/null +++ b/public/docs/_examples/universal/ts/bs-config.uni.js @@ -0,0 +1,41 @@ +module.exports = function(bs) { + + return { + "open": true, + "port": 3200, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": [ + testMiddleware + ] + } + }; + +}; + +function testMiddleware (req, res, next) { + + var routes = []; //['/', '/dashboard', '/heroes']; + var prefixRoutes = ['/detail/', '/styles.css']; + var url = req.originalUrl; + + if (routes.indexOf(url) >= 0 || prefixRoutes.some(function(r) { return url.startsWith(r); })) { + console.log('test handling ' + url); + res.setHeader('Content-Type', 'text/css'); + res.end("this should be css"); + return; + } + + console.log('test skipping ' + url); + // var parsed = require("url").parse(req.url); + // if (parsed.pathname.match(/\.less$/)) { + // return less(parsed.pathname).then(function (o) { + // res.setHeader('Content-Type', 'text/css'); + // res.end(o.css); + // }); + // } + next(); +} diff --git a/public/docs/_examples/universal/ts/example-config.json b/public/docs/_examples/universal/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/universal/ts/package.steve.json b/public/docs/_examples/universal/ts/package.steve.json new file mode 100644 index 0000000000..15ef45e849 --- /dev/null +++ b/public/docs/_examples/universal/ts/package.steve.json @@ -0,0 +1,62 @@ +{ + "name": "toh-universal", + "version": "1.0.0", + "description": "Tour-of-Heroes application with ng-universal server-side rendering", + "scripts": { + "build": "tsc -p src/", + "build:watch": "tsc -w", + "build:aot": "webpack --config webpack.config.aot.js", + "build:uni": "webpack --config webpack.config.uni.js", + + "serve": "lite-server -c=bs-config.json", + "serve:aot": "lite-server -c=bs-config.aot.js", + "serve:uni": "node src/dist/server.js", + "serve:uni2": "lite-server -c bs-config.uni.js", + + "prestart": "npm run build", + "start": "concurrently \"npm run build:watch\" \"npm run serve\"", + + "lint": "tslint ./src/**/*.ts -t verbose", + "ngc": "ngc", + "clean": "rimraf src/dist && rimraf src/app/*.js* && rimraf src/uni/*.js* && rimraf src/main.js*" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@angular/common": "angular/common-builds", + "@angular/compiler": "angular/compiler-builds", + "@angular/compiler-cli": "angular/compiler-cli-builds", + "@angular/core": "angular/core-builds", + "@angular/forms": "angular/forms-builds", + "@angular/http": "angular/http-builds", + "@angular/platform-browser": "angular/platform-browser-builds", + "@angular/platform-browser-dynamic": "angular/platform-browser-dynamic-builds", + "@angular/platform-server": "angular/platform-server-builds", + "@angular/router": "angular/router-builds", + + "angular-in-memory-web-api": "^0.3.1", + "systemjs": "0.19.40", + "core-js": "^2.4.1", + "rxjs": "5.1.1", + "zone.js": "^0.7.7" + }, + "devDependencies": { + "concurrently": "^3.2.0", + "lite-server": "^2.2.2", + "typescript": "~2.1.6", + + "canonical-path": "0.0.2", + "tslint": "^3.15.1", + "lodash": "^4.16.4", + "rimraf": "^2.5.4", + + "@types/node": "^6.0.46", + + "@ngtools/webpack": "^1.2.11", + "@types/express": "^4.0.35", + "raw-loader": "^0.5.1", + "webpack": "^2.2.1" + }, + "repository": {} +} diff --git a/public/docs/_examples/universal/ts/src/app/app-routing.module.ts b/public/docs/_examples/universal/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..bc070f6c31 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/universal/ts/src/app/app.component.css b/public/docs/_examples/universal/ts/src/app/app.component.css new file mode 100644 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/universal/ts/src/app/app.component.ts b/public/docs/_examples/universal/ts/src/app/app.component.ts new file mode 100644 index 0000000000..a9fe05a9a8 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

{{title}}

+ + + `, + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/universal/ts/src/app/app.module.ts b/public/docs/_examples/universal/ts/src/app/app.module.ts new file mode 100644 index 0000000000..e078044928 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.module.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 +// Imports for loading & configuring the in-memory web api +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { InMemoryDataService } from './in-memory-data.service'; + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroService } from './hero.service'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +@NgModule({ + imports: [ + BrowserModule.withServerTransition({ + appId: 'toh-universal' + }), + FormsModule, + HttpModule, + // #enddocregion v1 + // #docregion in-mem-web-api + InMemoryWebApiModule.forRoot(InMemoryDataService), + // #enddocregion in-mem-web-api + // #docregion v1 + AppRoutingModule + ], + // #docregion search + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + providers: [ HeroService ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.css b/public/docs/_examples/universal/ts/src/app/dashboard.component.css new file mode 100644 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.html b/public/docs/_examples/universal/ts/src/app/dashboard.component.html new file mode 100644 index 0000000000..db8546ccd2 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.html @@ -0,0 +1,10 @@ + +

Top Heroes

+
+ +
+

{{hero.name}}

+
+
+
+ diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.ts b/public/docs/_examples/universal/ts/src/app/dashboard.component.ts new file mode 100644 index 0000000000..9960aa77d4 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.ts @@ -0,0 +1,22 @@ +// #docregion , search +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +// #enddocregion search +export class DashboardComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit(): void { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.css b/public/docs/_examples/universal/ts/src/app/hero-detail.component.css new file mode 100644 index 0000000000..ab2437efd8 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.css @@ -0,0 +1,30 @@ +/* #docregion */ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.html b/public/docs/_examples/universal/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..32fe6d4391 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + +
+

{{hero.name}} details!

+
+ {{hero.id}}
+
+ + +
+ + + + +
diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts b/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..b3bbbd2f3d --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts @@ -0,0 +1,40 @@ +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + + ngOnInit(): void { + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); + } + + // #docregion save + save(): void { + this.heroService.update(this.hero) + .then(() => this.goBack()); + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.css b/public/docs/_examples/universal/ts/src/app/hero-search.component.css new file mode 100644 index 0000000000..9bf8d13457 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.css @@ -0,0 +1,21 @@ +/* #docregion */ +.search-result{ + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; +} + +.search-result:hover { + color: #eee; + background-color: #607D8B; +} + +#search-box{ + width: 200px; + height: 20px; +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.html b/public/docs/_examples/universal/ts/src/app/hero-search.component.html new file mode 100644 index 0000000000..08c0560c5b --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.html @@ -0,0 +1,11 @@ + +
+

Hero Search

+ +
+
+ {{hero.name}} +
+
+
diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.ts b/public/docs/_examples/universal/ts/src/app/hero-search.component.ts new file mode 100644 index 0000000000..8b2d32f06b --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.ts @@ -0,0 +1,69 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; + +// Observable class extensions +import 'rxjs/add/observable/of'; + +// Observable operators +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +// #enddocregion rxjs-imports + +import { HeroSearchService } from './hero-search.service'; +import { Hero } from './hero'; + +@Component({ + selector: 'hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ], + providers: [HeroSearchService] +}) +export class HeroSearchComponent implements OnInit { + // #docregion search + heroes: Observable; + // #enddocregion search + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor( + private heroSearchService: HeroSearchService, + private router: Router) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + // #docregion search + + ngOnInit(): void { + this.heroes = this.searchTerms + .debounceTime(300) // wait 300ms after each keystroke before considering the term + .distinctUntilChanged() // ignore if next search term is same as previous + .switchMap(term => term // switch to new observable each time the term changes + // return the http search observable + ? this.heroSearchService.search(term) + // or the observable of empty heroes if there was no search term + : Observable.of([])) + .catch(error => { + // TODO: add real error handling + console.log(error); + return Observable.of([]); + }); + } + // #enddocregion search + + gotoDetail(hero: Hero): void { + let link = ['/detail', hero.id]; + this.router.navigate(link); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.service.ts b/public/docs/_examples/universal/ts/src/app/hero-search.service.ts new file mode 100644 index 0000000000..d24e0fba41 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +import { Hero } from './hero'; + +@Injectable() +export class HeroSearchService { + + constructor(private http: Http) {} + + search(term: string): Observable { + return this.http + .get(`app/heroes/?name=${term}`) + .map(response => response.json().data as Hero[]); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero.service.ts b/public/docs/_examples/universal/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..18af476123 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero.service.ts @@ -0,0 +1,87 @@ +// #docplaster +// #docregion , imports +import { Injectable } from '@angular/core'; +import { Headers, Http } from '@angular/http'; + +// #docregion rxjs +import 'rxjs/add/operator/toPromise'; +// #enddocregion rxjs + +import { Hero } from './hero'; +// #enddocregion imports + +@Injectable() +export class HeroService { + + // #docregion update + private headers = new Headers({'Content-Type': 'application/json'}); + // #enddocregion update + // #docregion getHeroes + private heroesUrl = 'api/heroes'; // URL to web api + + constructor(private http: Http) { } + + getHeroes(): Promise { + return this.http.get(this.heroesUrl) + // #docregion to-promise + .toPromise() + // #enddocregion to-promise + // #docregion to-data + .then(response => response.json().data as Hero[]) + // #enddocregion to-data + // #docregion catch + .catch(this.handleError); + // #enddocregion catch + } + + // #enddocregion getHeroes + + // #docregion getHero + getHero(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.get(url) + .toPromise() + .then(response => response.json().data as Hero) + .catch(this.handleError); + } + // #enddocregion getHero + + // #docregion delete + delete(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.delete(url, {headers: this.headers}) + .toPromise() + .then(() => null) + .catch(this.handleError); + } + // #enddocregion delete + + // #docregion create + create(name: string): Promise { + return this.http + .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers}) + .toPromise() + .then(res => res.json().data) + .catch(this.handleError); + } + // #enddocregion create + // #docregion update + + update(hero: Hero): Promise { + const url = `${this.heroesUrl}/${hero.id}`; + return this.http + .put(url, JSON.stringify(hero), {headers: this.headers}) + .toPromise() + .then(() => hero) + .catch(this.handleError); + } + // #enddocregion update + + // #docregion getHeroes, handleError + private handleError(error: any): Promise { + console.error('An error occurred', error); // for demo purposes only + return Promise.reject(error.message || error); + } + // #enddocregion getHeroes, handleError +} + diff --git a/public/docs/_examples/universal/ts/src/app/hero.ts b/public/docs/_examples/universal/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.css b/public/docs/_examples/universal/ts/src/app/heroes.component.css new file mode 100644 index 0000000000..d2c958a911 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.css @@ -0,0 +1,68 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +/* #docregion additions */ +button.delete { + float:right; + margin-top: 2px; + margin-right: .8em; + background-color: gray !important; + color:white; +} diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.html b/public/docs/_examples/universal/ts/src/app/heroes.component.html new file mode 100644 index 0000000000..392d241d52 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.html @@ -0,0 +1,29 @@ + +

My Heroes

+ +
+ + +
+ +
    + +
  • + {{hero.id}} + {{hero.name}} + + + +
  • + +
+
+

+ {{selectedHero.name | uppercase}} is my hero +

+ +
diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.ts b/public/docs/_examples/universal/ts/src/app/heroes.component.ts new file mode 100644 index 0000000000..6350b803c4 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.ts @@ -0,0 +1,61 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private heroService: HeroService, + private router: Router) { } + + getHeroes(): void { + this.heroService + .getHeroes() + .then(heroes => this.heroes = heroes); + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + this.heroService.create(name) + .then(hero => { + this.heroes.push(hero); + this.selectedHero = null; + }); + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + this.heroService + .delete(hero.id) + .then(() => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts b/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts new file mode 100644 index 0000000000..c915955e22 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts @@ -0,0 +1,19 @@ +// #docregion , init +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class InMemoryDataService implements InMemoryDbService { + createDb() { + let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/universal/ts/src/index-aot.html b/public/docs/_examples/universal/ts/src/index-aot.html new file mode 100644 index 0000000000..096bfbb512 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/index-aot.html @@ -0,0 +1,18 @@ + + + + + Angular Tour of Heroes + + + + + + + + Loading... + + + + + diff --git a/public/docs/_examples/universal/ts/src/index.html b/public/docs/_examples/universal/ts/src/index.html new file mode 100644 index 0000000000..727b1fc833 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + Angular Universal Tour of Heroes + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/universal/ts/src/main-aot.ts b/public/docs/_examples/universal/ts/src/main-aot.ts new file mode 100644 index 0000000000..fcb35dc9dc --- /dev/null +++ b/public/docs/_examples/universal/ts/src/main-aot.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/universal/ts/src/main.ts b/public/docs/_examples/universal/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/universal/ts/src/uni/app.server.ts b/public/docs/_examples/universal/ts/src/uni/app.server.ts new file mode 100644 index 0000000000..585470cd09 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/app.server.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { APP_BASE_HREF } from '@angular/common'; +import { ServerModule } from '@angular/platform-server'; +import { AppComponent } from '../app/app.component'; +import { AppModule } from '../app/app.module'; + +@NgModule({ + imports: [ + ServerModule, + AppModule + ], + bootstrap: [ + AppComponent + ], + providers: [ + {provide: APP_BASE_HREF, useValue: '/'} + // { provide: NgModuleFactoryLoader, useClass: ServerRouterLoader } + ] +}) +export class AppServerModule { +} diff --git a/public/docs/_examples/universal/ts/src/uni/server-aot.ts b/public/docs/_examples/universal/ts/src/uni/server-aot.ts new file mode 100644 index 0000000000..38eb3f6b33 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/server-aot.ts @@ -0,0 +1,40 @@ +import 'zone.js/dist/zone-node'; +import { enableProdMode } from '@angular/core'; +// import { AppServerModule } from './app.server'; +import { AppServerModuleNgFactory } from '../../aot/src/uni/app.server.ngfactory'; +import * as express from 'express'; +import { ngUniversalEngine } from './universal-engine'; + +enableProdMode(); + +const server = express(); + +// set our angular engine as the handler for html files, so it will be used to render them. +server.engine('html', ngUniversalEngine({ + bootstrap: [AppServerModuleNgFactory] +})); + +// set default view directory +server.set('views', 'src'); + +// handle requests for routes in the app. ngExpressEngine does the rendering. +server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req, res) => { + res.render('index-aot.html', {req}); +}); + +// handle requests for static files +server.get(['/*.js', '/*.css'], (req, res, next) => { + let fileName: string = req.originalUrl; + console.log(fileName); + let root = fileName.startsWith('/node_modules/') ? '.' : 'src'; + res.sendFile(fileName, { root: root }, function (err) { + if (err) { + next(err); + } + }); +}); + +// start the server +server.listen(3200, () => { + console.log('listening on port 3200...'); +}); diff --git a/public/docs/_examples/universal/ts/src/uni/universal-engine.ts b/public/docs/_examples/universal/ts/src/uni/universal-engine.ts new file mode 100644 index 0000000000..3c0ac6b528 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/universal-engine.ts @@ -0,0 +1,38 @@ +/** + * Express/Connect middleware for rendering pages using Angular Universal + */ +import * as fs from 'fs'; +import { renderModuleFactory } from '@angular/platform-server'; + +const templateCache = {}; // cache for page templates +const outputCache = {}; // cache for rendered pages + +export function ngUniversalEngine(setupOptions: any) { + + return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) { + let url: string = options.req.url; + let html: string = outputCache[url]; + if (html) { + // return already-built page for this url + console.log('from cache: ' + url); + callback(null, html); + return; + } + + console.log('building: ' + url); + if (!templateCache[filePath]) { + let file = fs.readFileSync(filePath); + templateCache[filePath] = file.toString(); + } + + // render the page via angular platform-server + let appModuleFactory = setupOptions.bootstrap[0]; + renderModuleFactory(appModuleFactory, { + document: templateCache[filePath], + url: url + }).then(str => { + outputCache[url] = str; + callback(null, str); + }); + }; +} diff --git a/public/docs/_examples/universal/ts/tsconfig-aot.json b/public/docs/_examples/universal/ts/tsconfig-aot.json new file mode 100644 index 0000000000..023bf2fb68 --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig-aot.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types/" + ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "entryModule": "./src/app/app.module#AppModule", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/universal/ts/tsconfig-uni.json b/public/docs/_examples/universal/ts/tsconfig-uni.json new file mode 100644 index 0000000000..fcb6a7c92d --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig-uni.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "src/uni/app.server.ts", + "src/uni/server-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "entryModule": "./src/app/app.module#AppModule", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/universal/ts/tsconfig.json b/public/docs/_examples/universal/ts/tsconfig.json new file mode 100644 index 0000000000..58307adfe0 --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*" + ] +} diff --git a/public/docs/_examples/universal/ts/webpack.config.aot.js b/public/docs/_examples/universal/ts/webpack.config.aot.js new file mode 100644 index 0000000000..f16ce50294 --- /dev/null +++ b/public/docs/_examples/universal/ts/webpack.config.aot.js @@ -0,0 +1,30 @@ +const ngtools = require('@ngtools/webpack'); +const webpack = require('webpack'); + +module.exports = { + devtool: 'source-map', + entry: { + main: './src/main-aot.ts' + }, + resolve: { + extensions: ['.ts', '.js'] + }, + target: 'node', + output: { + path: 'src/dist', + filename: 'build.js' + }, + plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-aot.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) + ], + module: { + rules: [ + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + { test: /\.ts$/, loader: '@ngtools/webpack' } + ] + } +} diff --git a/public/docs/_examples/universal/ts/webpack.config.uni.js b/public/docs/_examples/universal/ts/webpack.config.uni.js new file mode 100644 index 0000000000..1ccccb6f1a --- /dev/null +++ b/public/docs/_examples/universal/ts/webpack.config.uni.js @@ -0,0 +1,30 @@ +const ngtools = require('@ngtools/webpack'); +const webpack = require('webpack'); + +module.exports = { + devtool: 'source-map', + entry: { + main: ['./src/uni/app.server.ts', './src/uni/server-aot.ts'] + }, + resolve: { + extensions: ['.ts', '.js'] + }, + target: 'node', + output: { + path: 'src/dist', + filename: 'server.js' + }, + plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-uni.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) + ], + module: { + rules: [ + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + { test: /\.ts$/, loader: '@ngtools/webpack' } + ] + } +} diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 7a0c4aab83..4e8bb691c7 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -200,5 +200,10 @@ "webpack": { "title": "Webpack: an introduction", "intro": "Create Angular applications with a Webpack based tooling." + }, + + "universal": { + "title": "Angular Universal", + "intro": "How to use Angular Universal." } } diff --git a/public/docs/ts/latest/guide/universal-img/pie-aot.png b/public/docs/ts/latest/guide/universal-img/pie-aot.png new file mode 100644 index 0000000000000000000000000000000000000000..df7f2ce3da4fa7c26fbf629619b1118376ceebbc GIT binary patch literal 11986 zcmch-XIv9q)IADFFG7HTqS6rvO+i4U2_^!e1`?X|CPnEYy`xEx-b4^Ef`&*h(tD96 zD82V0(m{Ir56^pl@3&h%-46uLgqbA}WrdIkO}K##FAVMjk{&jGk9N#M5>h z-b6&A&()wxNN=-^kEbzU*vVzXWrE@jYt^3iB4`O$_zPMK1`v+8mLtQ*`fMu$)r{VV>WnZ&=C*9lYQ=B+|L(k#7cfMZQ_hEB$v$-Os zLvKs~&X))tS{?YBHa%@7B#&5Jqg+h4w*iJf#>@MrB-d!6P58J=7Gm;{>Mux%Y(Uk5%RlwQdnI&TiE{o zh#Vo(&2o!j+s_o%X>T|kLk>6pH3It-X zc7OQU^4am;fl&(6(37{DzG&Rn zmfH!}L<$&W7llvztlSys@3*RX7o&Jl>9bKj(gOsK+D~r&-|E0H_44WS44-zh%=1aC z)`&-UvdDqofpt*yHOS82p>O$y)rad5&X>zS(>Cf~zI<7a`}?zk#!5XfhC|V8RF|!{ z<+$>$snw)F%Nx4VrKdMzRd$u7KfEM4>^!gg*ROuySKYq^Ei_(aSO3WIEir>y|2aca zvSz#wGLaXLKh=JnN*%`0U#`p`10e?|Y_ccQp6XZgpam;&adM&nhp?9OQ~f7C7JGb)PP#`R~@mw#Tf%tttNZG3>Lb*ZwYc zCcuhmLl;cc=@B0#o@*7)6I%(GzUZy+TMZd1Wu+dp_fMmHuohl1MuZ z3!4iu>@*oSDYrqILU*u`&Ni?_?k`&JN^hY@KPtJmzUW$UPFBC_j#jqLr4GdXg|(W7 zr&%*#qNA^$D*n1>@sX#IvMy4ZqjA4dbcL~YqG<&{RQy0g#>EI^cI?^F6~kT z9{z#Z!OFgWXZbEi@;dlIED)nnIS5=I-|-bI8S-ig%Q59#owqieUmC>o*mG`bp&3gM z@|w;6b32SIoaPhT!cbIE2%?7J*Bp@W zxz{mfi!wd|8Ivh;Tk!67_4NN-I`a7XyH0wkuNYCE4ry)%xKpGi`_sXf8&{LX^hCo=i0*IIqy zIYQC4suBD8o{-h9B%zJ+(U|kx)=3p4u4{i$lT#tpZ8nhJByz2b`TlFiloUr;lIVk_ z#^X-0sCS17IPN@rmq&B;SO25Mpb?V%?EmXkQ$yrSYDhTR+v{+o;RI5-hH!A!+v z0cY`T}qN*hzo8CkRJ!#;PmS7$I~KQS@LGJ>~Qj ztkqv$_<5`iiwL0)w`MA=R8N*t%&GkjR{XaDJT6=F0#~Oo4QVyc^+*2&tUU5qIn(mk z>*w-VoA`F{$V5Bh`@v+b&j0{K698U*D#}r8xV)&5@%@LtDeqh617yda0OI^y>Q14V z8GcjwAF?b1sG}{cAvZGTYr;A{KHhV*v+z>Bhw+sd0m%qLkTQ4gHHA^|wMn2k5h6*O z8OAR*J*5>H$EG)N9q#6Eah+wS;k^4{6!cO+mKPEv_)9xaJ{*{ycD~gNAj+sl`orIo zRUTi9RCX6p$Wr(e7D6A}6^`CLbZI!(KlXygHXna|}J(m^-f8X`~k##O%)_OEOd;Ppx@WH zfv5v$!4=gh*T^}I;TX;zCE>nj|BLgqv;HkThZKPO<;vqjL$;Xt<57t&TMBk-uDnK~V$^Z5m~wtpUr{k~qC$V? zkxhd&$HCH#Nz=qO6^;NKvg$;4@Ovv7p(c@#h@NY66ddKKzbffC zNM|)g@79BvsoL37YXbuRJG|AW^6%e200ggJ?qJl~t|OM~Kd$3)8cJDv^7q^D2QrB7 zlP6)v+b#4Pm#$Z2Yqwi$!f8(qbidb}N-YvHulh7;=*-f0&6J>W7bKifdN&3RKS}51A~-io zHqItvogRdPh5}9xQd1?KkI%4@sI$KAN)#OCSR(_u!qlJxTzdLH|{q}DRUDl5v|IswLeZVgu}qemzKcNRWYKf z4Lwu074KT6`l=Zt)rPlDE=3G>^9M@EpUNP>m#aGqKWLt@hm@BAu#d|`Q8J<`Lj7Ri z?J6lrNh2X|04~pa*Z3R|OJ>Cdbu77QivBG9P_q^O;U2wA153f`ZxYdOgC$3lVoGPd_Y#hQuPE%x` zGuoIT-JV+K_;C1(;B)ZsWcXxDDYz&v1S&6$8i9%qP(4@ACa4EH|#_mBC2_O2F!FUHyGfaFjkEHn!M z`A9EWE7dR_ADCgq%L%(Z?txquQ4>RE6sLI~w* z8c~KN@Sf$(XX-NZv5NyK0ao%WK(huP|Nc%^GeKY{&Jkf79!D&ANQZflK!)JEAKYeK z@F)|7!10&kK1eD>x|U^FwgHaQ4KCV(C($Kv$z`6kgmG zo2zGZw;KnaCnFBngCoeFLZC?oT6@3Fd#dqWLiyGDkG~)7Ue+6;bmzIixGvQoV{`fZ z@VrO}m8C6+g-@0=he$|ZZLO!w9w&j3*NZ6WX?(Ror*W}xi*)Sk9hqbg*Mc%#J%sJj4QW+_;m$~W{C1(8w!b_-pM0@bV{69?@LdhJC<5=rJ6=?A7PW8PK5<1HVFM zk!oQjZzdMMgD1)%47|Pc&=2=GmDXGeo>dfRKR~i&$apLp5);5~Xh)rn#OzN>w7$s> zId-@YU!5Cb`4N0mGBsQY19@-^q(Nru@2Mzy0e~O>d}MV7RJU#Xm68o+W{XTI>suE; zNY@DKyfs}nOt6(Tb*vsX3?*?JHoQzIkP=#EV#~hmhK3xQm)XY|)p)(^e3Rt&JSU*a zd^K5p`q;b~A8V5o=yM&47_D@(zONh%rH|b*O`-kK?R7zpxgJcTI>~I3;?Df=&0h70 z{figE89a`T+yu|G-N6mk-Ma+dP%1kIsbJ(I#ct4A#bIMk8$+&naqOxe^Z0Tv-d>Q34a8w%OX#E6 zyTf`vNOnt6PBKv)60a-&DsYd+=VI{v*u~rlu|)(D)BhofJeIo5vV~j%$chR$ z3?;Xnp)6^Cjn{_pTv|Qn7i4`Fs}3APKu6F_RAoS!bNZzpJox9vF>4o#&gH&A+W9TK z5(;MEh9TjyIIRP zZr{MUYBHDUrm4HOb6_bKpX~q{#H+Atp*3^{KeN>mPO6F@emxvV#8u*#U%Gbj72>+G zhVrL3l|=_AhAEY+Uajd1r7t}me9!i8d#W!K zxb>4>kR%4{XcmyGoB>PnT(PU%w2!xtA zu~3`8*z25q*Q00q>)P7SzNJ|(3n-iuk@M`Qz03+O!!^dxNNJOn>pFnoGeMUD17l+j z`9Yg+3;w;oZ;kcv@1(G8@~VGLF>8@l##>7K$7q0*Mu5lpq`QeB0`@pn zQ_1?V%&y|K5b@v}6c`L7wX-yd+J|-M!HItELYP1?$hDhP+6OH3IL5(9l({K8D zqJ_Ug4UjU?Am`R#58bBor|q9~5len~;!nTGNL%#}4CswYynhGA4fu#D;G(v<%elZVMy0f7k zRl`bG%L5qdi^O7TZ6rj3*gG0t{h0HcT6wEbv>NwRP{Y#))QljMv3#|Z5C0Yb5&J{; z!j!POSYr%i#FlLokV32nvZ2uZ={mpE50A}6_Bjc{-<$W4i6OCx`1x^A3biPyf{(Rm zFS`LZ?(d20u7*4sBKULQ8*|QZt0}#R)m*94@|f!u_412o27dxxX(u z?fd6D%bp{t*ziG3=&dAJBpBuceStF;W4bV9pOje;vMJZ%&b~Z3tCTs}5*5l0sThvD84N!JYl`a==;Zqe2Qgwi*)=Q7UKH28Thn z);BiF#UwhEJKtWv16lvgN*b{*?=o457}fOyl2t{MMci{1KfB*64@ZWgBnH(OTe%7Q zMV#dvY8Z&}c%XNTjN7`WCJ+!>{hXI`e?v+DTCcz*XVM`SDfzWCB|Q;OVwp>o&HDTT zg$$S#A=IME?zIXMC|6f6k0+^DQwv1RL%zY3ZFUcaO#~5qeTB8VaD4eg5P9_{|C0H$ z*`~0U_N+LnB2#VE%H3tHwP8p(nvn1vgNU1=nmB^RjOtY}XRR3O2Kqcso zx9GrE?TQ};3*$h{R!>F-(vZr70B&WR*u|_q9CEI%R@ZJVwC&O>45x;|a3m)oc)9a` z127IA%VPBiy*NYFN>zMWxQ~)5W-r{3lbbO-Hav@y^T^Z3=Wfs6e?Yj7(`7vD?l%h^ zYF~f?54c30eeZdrGIs&%=@4@UpN$;JU_9EYMxXEh9n$CR6q;e$i*yGoEj~gQw7#Fe z!6r|dIJC9MHtQ?bTM1Kv0ka z<~_vf*Z8>ck<@KBEJ0RB(yEoxjh0Nx&>UPPh#=pQxs7*>C*hJXDO*i;o~vB*~SQ%YK^Rd#MEx_#IW{~8p4tOYi9EyNW@-)wbRXDM&G{Fs_1zxjrc@WL+rI-(lT66zuRDh| z*H^Y{p8hwPK8BE-IM=zFL9}C?Xc+>7=gv0J4zi3G1Xl_qp!rO1gVgi*TE*dq8pD~= z!@t6*n0kiupGAg(SaKVkBfz21p{bOW#i-MmzVh7MPTHH|*`q_EFh(4;XW=TNx{c8; ze*ukR7v^SX`68JCa_sF>p^mo2*K~p_MYyh+e=J4DrboR$gA9>Kp6qn|0lT?Pf#;^g zN)5%`Y|oTlsyj-;VSn{G%qY^w~_FiGv@TeqgRe@3>d%m@d*ITrYh3kb7l2- z#x5LZPLr@yQ*z5wJY5I5zoTSR_=};9J~n;QC6k9IIkpTGm$=_SaZSI6bbDEm7D51V z<9xp@WPUlEWL=(*DE;2Qodp$k7%JsXw(Q*9`=Wb%yw)oA2aI~U?X!jrc+cI|;rRHiiuG3vqQld8iY^gPdVl>!6 zAvyDppN;((I`}9q5m)FFGYU;w`sGQ)GjmTBT()kS%*pXhKfgr1J5I`Z^2X6b4%b*i zP*5g5%`$lS_#y=e0##`_{s45pNz#ANEquQbIF+^ z(HFxMxrW10=nN<^OxQavq$7RPH$znT_D|o8aKfA+w_nMwqAfxQz?|3eh+!?*qCg=$ zrG@4ijY;XCSF8E|*sPVENtycJHQYP5i6@eCd+i>gFt!sYlZVcb> z^Gv@hUhY!$Nv^Sw>5SnUMJYqgJvDbVdIUyvZR<3xgnjym)BS#BDIG8^gz5-~J1AZC zxAKx|{Ev67pt_7CMSy@fQP&QhGZO+f;ZXTJ1`OkAI$X3}?a#6Mje{LbpF_c*?DSt` z%GnIN#s?_@lWRMx;33@=&bbed?FD7eW+<-TE}H*v3$aA;HS*;mQ(l-O%eLk%C4dKo z(ws6KUC)Fhv3$cQed9#DdUB74l#Y%rAkVl$R)o9%e^5aU4e4Wx{4nd?>b~1DHKUEh zY%D$1%1N0`j`5Q_!Z_x7%ywD2_H3wemK`~G@DLu)5okEg7abs|SbWLuX_dzc^|Om$ zI98y4DJL>IsT!#BWG$8=JWes;P65>+msvoXucof#50|9{0BC}b0}#t!LcK47U%|~> zGv5JXRkDg8VkzkG^}{T;@&L2RHmPT1faPT*{5RiF}$i8$j)@* zZ)0zq75fl~5~5^LF>T&+Ha9CAwPU^=Yew4jhY$zypoU6q*S_s4i>A<4KLZRFBJvhE zC)@$zm;-_PFoIDQHrn|^>!0e8Fe;UK9AVh;Kt~9LXa)-M&=dXAYdja5%q%bjT#pHn zgIjhW@yYl^JXn5Vx?)Vs&LC!Kf_1PT2;y?=R;D98&uy3~X4YO!1^Yq+TXT-fMHx=zo+mY?dQT zi$Wu_pIr1AXKbDqO6@9JBGC~0l+uHuKcszJ+C>_3n^QF#@qxAUT5^J0?g4pqoowl~ zLcQ*8jNW}Tbl1Ck)Vx8`#Yoe9v>tM`${*;Hcqut14_F&1BrEeuA*;}&x@IM3=5?`b z2(tac;p<%rF_td&yoTxtskCS!8ZIVnjQy8jZ*DXi5_0V8=a+9!Dk8TL@dh11sEad5 z;1xyWyg)a=R2_%oU>0M;K;x&P>XVsa572_=`|eK$9!hKs)3MZK=}L1iq`;rGW&`cK zl=Dn~zp%67gS$=ZfP8B>%1BEiQ7TZ9X`9CE29SKXHzOOHSh(<S83=)d&=r`T^h z3xRI=Myv7+Cm*b*?5TJ2u9~CXF;NA!oWxAPtAI z+*+W6^SvK_mCN)4picgvS8NSuT_nT6z8!CDL__Zvzl26XN%@teP$ z?d|_qpL20D-bX>R%gf8RUp|~?KyAJqHCn$#O44=iK9d6lvtokzq9ME4v?+Z;{>Q%@9?Ypwv4&{KJ^&-ux|9pF{r zJI_YbnFdAElUOqRCI(R%Kp)2Z4~wp*Hf+kU&$ql<1p95tlu~3{mna`WX+l7jRG&>k zIxa|tf9XA+t_Xo7qOh5b&eKnwN=bg!>)CNyqpLG3yA!pNl7DEUZLoGRvW1zKP|)E@ z=Q0_@R{Q14T?w0xSOuPSB|t2EAOKVb703U={J1ZzUK#KZ&NNjW^Yj&wNb5Hgu|EVA z)k62@^rwB>%8Ocm{FNFzRXx&_$|~L5=*fZu6~y^+sXbw_(9;?qV7>e^*xp*KcZ=;HW9@xF8Ya zi5!P~109p%q~UQ6+Pu*F@9^${Y!AK|o{l>VZFV9_;$5U7H6wyj61@^U`SeG*zb z-w`?{3CX)FxD%^}0J~Dy8zx`;I?)qNjKK+X#ycR$p1v$@54~$Ka?5awR@mN00RFP0 z7T7G$^2A%q%~JAtW){u!^w_9i^Ztl&z5$x=#ay^L%jlNd=G2pq zN$F^@jIpE;!m2V1)%gJF2>oe#?*wS+4|9X>j{;@{qwg4=*{e-+^0$ka1KsrkMH zh^#QY1*wWzM!S(oP`>5>52^fjJL(?CV^Q?o;*ZW(+RQGcuzn$4-@TSK4{1a;L*M)J z@45fHexvT)GMZ9_QPDU`v>fNX4#5ISZlV{{wN=}i_W%K6;Oshwf{95^<}5l~L6DE| zk5s?F#9@yc0rtM`^Ym(pj6XWd9~7%*`fXMz%u@y8j5~MC(8t=p8nZ^;fKrsg$j7wp z{5e(sx4|9L!YUL(p%xVtWe3>NhIeg;DGv>zv!O|sD$%zctdU$rDPrc|n=V74NoPMl z%8p3U?#j!*fkmbbDRNc>?fO*6v7h8XD=oVFH#A@AF4N53#B>AZZ&*wSyDd znCB-j9C)+#DvfY}u9LWdnutMnMot#xCKJ#a>gtiNz_aldzl3Q4QhVIme9->q_2CZo zZ-Hse$W_8$oB`B!?qnp;$v|kI`VEB0tJ+!q=s$%0hCU%+7kp_7wF?F?R1T5yVWvxmoWjX?k#bb+-jF>Wb^-a{F1&hB48RdH8mR(JhgWg>XYUp z448aIY5{Wv`wzCH+LIMg!M7c|(~_qp{R~6!>Yk3vz)zxBQq?Z4G=HA z`q8Iw+9RrA0!N-(ywt9eR(|GZ&1qWaJ5>M3XmiQ~hKT1+!F7=|%f8+$Gj(uDF`m}; zG9}+FC^1a&EH1t${c;>xMsA9*oukWx2~W8XbN>Lywb5V-nZo2NS)Y~LpKQULVzr;6 zbA*l$M2Efzz-t$^khZH*ET1jzQ(Qbp-3ceR1fL0`^59S^MgFNBz`MX&GgkoUS6j7v z(RJ5X#9)BZgA@BLcOIP*Q2R-Wmr+0&&TjZ9dKXC0GVTBhVE{velQmHlXSDNR&%LRj zdRC!f@DLmiko+~eTT-K{8GwnlXaeY}O{P6I;v_tv#Nr0u07T!^O4)ig(sO5Xg`ePm z_*;cz>>Q0)tR|mlLG^YEhxqI*@828~<0Am=vj~wG3t49><Uit<<6%4w#Gs@qqVzq+p6y#O#9PH4m$hY06zO5RZ^pE@(&LKD^|8|7 z@f^!W{%-o}W%*7}P4pg$Ra~1%5o_c`E8xDtP@kf@0JX5o z$Va8=$`M^l$itELs9UE-3s_w1)fDdAAg5(@V0j!BH5#L|2cS4u+0!UCTLZoy<2)MM zfWjOAdzEz!Wti=`pPHlN4EE{mdu8|Y11kM1+?(1e*RL?(@1UTpciXv}{N~R2;f$C+ zFfm48iHM8irDL}vcfT|8oEA|2o>J*KVh@3#(H~ookW{U5*SY3VSkhJ%g^PR3k-PB7 zd_9BjW|VcENtJuf4ad~;hj%-a^{-3?VpqO72LL1fpH15TZ(FM6{UzD=);CiI@G&{S Phfbsh(}ET#TZH}}_n}8N literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/pie-jit.png b/public/docs/ts/latest/guide/universal-img/pie-jit.png new file mode 100644 index 0000000000000000000000000000000000000000..b91927b173b7c42274cc94bdf0a21d9e1f494cb3 GIT binary patch literal 12410 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 C&45+_ literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/timeline-jit.png b/public/docs/ts/latest/guide/universal-img/timeline-jit.png new file mode 100644 index 0000000000000000000000000000000000000000..6b3bd0d2acb97a81268f431c8de486e39fda16fa GIT binary patch literal 4377 zcmc(jXHZjH*T+MTD25`DA{~_`C4wM5AiXyOgdz{2SLrRFQ~`kq0wMyU5Q-F~1OXG^ za*;@tB8Ul6q$d>VMc@f~-+5>5yx-ps=gisX{AaDT*P6ZeZ=GaQV;v?&E=B+Vz@(>p z#~c8ls-rxI0O=|BY9#pV16828js~D+;L0*(K>KE8@ZwBwuguUB|b3ZAc?{VjuI<40d#)f`O3O3(5>2 z%`pKy5VCPa`GQRnzYzXqN?%`}u7N=+G3NAmczhgYCl>H?RxAAEU~wKp@Xd-`$HI&Y z6s@APO0Zb_wHA_O^N(~T#E*|@5G5sU38_XSxsFces{@@XDk=es1))7Rnux6K{mp9}N4+Ak7b-uN8ss9nQrI`wTGxBnOqB0qfp*vkD+lC`)x?MJdb{QTt=+XragfTk zsXwadcAz%+hOO}8KtWb=a`L?c9P&ut*TQE*I{xo)>)Za*?MyT5u}LHyJ8c$(X>bFF z@)5ayJhgp)|Go0b{tt+<@)hMa{~3*q4{dFZyW|PB$M-aGCx>1(tsy?2d@7lE>Dfj) zQ|Kqgs^O`F(KMj(jQ5WjW4-5lvOBWgX9swD1mo~7BTQenHm== zi<+n&ln|qjR$t-9kY*dwB^_V{U(^P4x(M!vwc-t%rsBMEutrl6TCL*x`kU@FAWbeqkj{{odw+j_UD(grX&K%czWbc)v^HPQ-4|aT?B

z;Be~e@2Bh4_~QqT!tT$eb^u52(&k9oi*;x4WlUZZzS6&9qD2^DsZEc{e(QrwPZD54 zCmFr^-r2b$)K^;m^bQnVpdc;HY#3M+eYni6%8>$i_DpL!*D?B>WPnaB`;z-^H($&J z2;VhqN)P!yCQIb(?he}INr$4b=pZT4DfbOMICi`)^C? zAa#|uO+Ezh3)O>#d_TlQolA!Y=T^ED_Ll$t#!Mz5zC@H-AdDmP-gyXitn_B_#^`LN z)tguX`KSN!quz2#e3!vH)UO>L6C1r?8&nCVwC#W2rTvSg%AtL%=+Mqgs-kQZj&7U9 zoYS+V-F~IOn<)EL`GZqu;`DllWpAz&h+3%QI;!~-CVyuQlbT3p$eq4X%T4gVib;=|=1 zfRG1|W0SZ+@F&{yS|}>SC1qmR*A!W?+C*TT{!5_x*#B4vP{Gf>=S37>AAU<9J0fTURMSezq=& zDswtN346Y7l_nnu5lQalrPq!1#$lDi=_+Q_6-YDvtMLrw77+;%IjP(Fk|Q zgV+!N`u}g!mWjMu?$L*y?oD6O~1CWJBJlfqmF{IQl@FC z9Yzkl9Iejoj@(-z)7iwtw8i(#2bhaoVtrFq*4;v+(~2YGHv~wEz-F?OWgf8ZKrhZa z^fZK%i>G0CUBe(y>^ZzLvET`nFx5ZxD6pl~rRGhn`jMaH#f!+gtc~zKWxLoewrajqQU2$YFKE8VR&EdQT5o7#fHl-0P zI9ZfXcti4OkgF%@a#2b5lWISGy^O_ z&lTZeA0MB}2E3tvxz_JJ za*O+B>1rucx3;OMz92MTIm7To02zHgv(7e@j~2Ows>xPQKe$ahH)u{#>3qaV)|-+*@c;v z-BmD`*5Z%9$lmqA1hQ3(RG><{XYtQ0`26Om^}AQC21apJZO2SrixTnPWv7+l9UqAO zoVL<(5D!{9j z*39eq^PfHQ_nqTV!CJ4PZUk%UshrOkxYNfH^`i2&kdLg#drMMFexV=+t7E>be)X5( zL7%CL+;FoZThsKo1b#ccE1~6twah={by=o&?VygWcONy{_7RCQf(MV0LT3`cueELm ze(8Xg);D<4WkkS`-16c&<>13+WQ8HSF`e9`izgTn7Z*1`XH)IM-61tvC95|Rygcd$ zE_sNSf3&pIU|!$o|MqXb@2{%F#bXTa*7K9r)^>fjIaGo<^>v0Z!Cp63BX6`UoZOiw zsJ{je55j09FWtO0s=KL*4^o16%hvU!ZbsO5VjQrgbYmftk6)!SiQixtWgG zqpv~Hjz*;k!(%dO5?kvyyB7M=n@R4^?vDU8M3P;%R=ZZ#B<0RQj@MtPg7vXVGF*sx zoE7f-u+q=Jq<|&&H~T|d=@zvRiTBsW2n2BoNt_1fl?k0J@m+5X zTQTmuYa;i}K@%uo@xv|T6S)uZZnIUd3ySVw2Ycs7VH=fx=?km@?*Qdu>o(-9*y$#+ z#bLgTk`}6$HxpVcSOnrLtA8aMK>|e`t4@5)%}{A+X*QkWVy?nKfu~598Lvt)#=3_O zsl39px~4<~;!St66KX3eMesfLd=@N-Gf{!s{tHUp!Ef5~EiWN3(-0RDb3C)gggF>D zDHM$A@9VRU6BmQwhNuPNKmXbe?2UtD`@Q8i2zbpf#r2R`BTZ<$?M!&Jc_>Z^%%V|# zU-tg)`MiPxN%Vurl8caIFbGcZ9`jZUSp0FwJ+$7?Bpqzgu3}DSQ$cc$us1wqU~`P2 zcuXrTQoP$^ITIvvjwob>T2||ANU(M!c;)Tq@+0}Ao{TLtm3VbCl1M;-c;B2tmtIgq z4~26Ljf_4KiFPvV#FyTv;GiHp9j(irC*!n1j-9v2qg{K@+r5zW7O+FnCr!U1tR6_7FSkv8G4`H?&sU5MZht@A zOD8)kaX4^2imTzWei3QYzkpa~Lbv|YJ+SPZ6moMET^ozspW5Bo{A+=y?)?E?QIvL{oPve($W`pj$j`{S8=JwKMRhR33C!1ZIr04Jb-F$^Be37dY zUb+Raq5pH_Q|O86&w+2jF!8S5V)NihGG4C2@r%+g5?}A~Z((cF7>@-;5g}G(fSbur zI>RYtGOz2St}g->w0V5Y6nF~zs?x`t`bHBCgs7cy%f{QtX98eYk|7Hs8l{NuDJB3A zoRprfTOI_vig(>gLL8F&r=H5d6&&oGXWp&8UMp(0_JvxWAgw zVTHkDi7X%KxZsjho3OP$&CP~!mu>I$m}$xPvo)7JEAGGRu13_xCKk}!5{T?p~`#^{34Lrqv! z7L*9$Uk-i#w#r7E_wHYjup&aTJ+D^)A?~sbAxC$tVkJ_1X;3a_s6C~uyw1PXO)S|4 zq4c?wmX~Ws<$VUHgBc5gmQz0R!T6tgosn)kr9J*bv=9DG(EnS$-&OgY;4_&0L*8dR z{3psY?)|sHw{rNyqob>qlDSzL#VBh^hdee9bkPdqaIwdQTmObbbgn~$9;3 z0Uns1m&cixpD(UzFt{EwE^0I$t#r)kvWzPoZulU|yq|VxfTTAyaCLK|fv);vo|D1{ z4=!=WUg#-4F)yMT%{+fuQdhM|N;PgpXftNv7v$$C=;>|B?+k#Rmhqh$jeD{G1<1%- A5C8xG literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/toh-aot-local-pie.png b/public/docs/ts/latest/guide/universal-img/toh-aot-local-pie.png new file mode 100644 index 0000000000000000000000000000000000000000..b19edd6a749984f11e0236482e86d0efa874058a GIT binary patch literal 14102 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 literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/toh-jit-local-pie.png b/public/docs/ts/latest/guide/universal-img/toh-jit-local-pie.png new file mode 100644 index 0000000000000000000000000000000000000000..fd1f73a5bd45d7da93bc8e09301c881ec3c207f2 GIT binary patch literal 12727 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 literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/toh-jit-throttled-pie.png b/public/docs/ts/latest/guide/universal-img/toh-jit-throttled-pie.png new file mode 100644 index 0000000000000000000000000000000000000000..72866418cd5e7902d47f3deaed7707de710b3847 GIT binary patch literal 13664 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 A9{>OV literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/toh-uni-local-pie.png b/public/docs/ts/latest/guide/universal-img/toh-uni-local-pie.png new file mode 100644 index 0000000000000000000000000000000000000000..a6725ea4ce10ca31bea8c07ac7d9675076356c4a GIT binary patch literal 12863 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 X%}2`Jv;7FG3n3?^Bv~qM82CQ`VS#$> literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal-img/toh-uni-throttled-pie.png b/public/docs/ts/latest/guide/universal-img/toh-uni-throttled-pie.png new file mode 100644 index 0000000000000000000000000000000000000000..d076da9d66ecb810161b04776a46ccd99f889178 GIT binary patch literal 13201 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 MiOY%=it2g)e`qreRsaA1 literal 0 HcmV?d00001 diff --git a/public/docs/ts/latest/guide/universal.md b/public/docs/ts/latest/guide/universal.md new file mode 100644 index 0000000000..3aa78760e0 --- /dev/null +++ b/public/docs/ts/latest/guide/universal.md @@ -0,0 +1,818 @@ +**Note: This build setup described in this guide is experimental and subject to change.** + +# Angular Universal + + +## Table of Contents + +* [Overview](#overview) + * [How does it work?](#how-does-it-work) + * [Why do it?](#why-do-it) + * [SEO / No JavaScript](#seo-no-javascript) + * [Startup Performance](#startup-performance) + * [The Example](#the-example) +* [Preparation](#preparation) + * [Installing the tools](#installing-the-tools) + * [Component-relative URLs](#component-relative-urls) + * [Server Transition](#server-transition) +* [Configuration - AOT](#configuration-aot) + * [Main Entry Point](#main-entry-point) + * [Creating the tsconfig-aot.json](#creating-the-tsconfig-aot-json) + * [Webpack Configuration](#webpack-configuration) + * [Loader](#loader) + * [Plugin](#plugin) + * [Input](#input) + * [Output](#output) +* [Build - AOT](#build-aot) + * [Source Maps](#source-maps) +* [Serve - AOT](#serve-aot) + * [Lite Server Configuration](#lite-server-configuration) + * [Serve Command](#serve-command) +* [Configuration - Universal](#configuration-universal) + * [Server Code](#server-code) + * [App Server Module](#app-server-module) + * [Universal Engine](#universal-engine) + * [Web Server](#web-server) + * [Creating the tsconfig-uni.json](#creating-the-tsconfig-uni-json) + * [Creating the webpack.config.uni.js](#creating-the-webpack-config-uni-js) + * [The entry points](#the-entry-points) + * [The output file](#the-output-file) +* [Build and Serve - Universal](#build-and-serve-universal) + * [Exercising Universal](#exercising-universal) + * [Disabling the Client App](#disabling-the-client-app) + * [Throttling](#throttling) +* [Conclusion](#conclusion) + +# Overview + +Angular Universal is a technology that lets Angular applications run outside of the browser. Using Universal, you can run your Angular application on any [Node.js](https://nodejs.org/en/) server. You can use it to generate the HTML output on-demand, or generate HTML files ahead of time. + +## How does it work? + +Angular Universal works by compiling the app to make it capable of running on the server, a form of _Ahead of Time_ compilation ([AOT](../cookbook/aot-compiler.html)). It's different from regular AOT because the app is compiled using `platform-server` instead of `platform-browser`. This changes the app behavior to make it capable of rendering to an HTML string on the server instead of the browser DOM. + +The resulting app is necessarily limited. For example, a Universal app does not handle browser events such as mouse or keyboard inputs, nor send AJAX requests. + +> An available tool called [Preboot](https://universal.angular.io/api/preboot/index.html) will record browser events so they can be played back into the full Angular app once it is loaded. + +In this guide, we will use Webpack to create an AOT-compiled version of the app, and then build on that to create a Universal server for the app. + +## Why do it? + +Why would you want to create a static version of your app? There are two main reasons: + +1. SEO / No JavaScript +1. Startup performance + +### SEO / No JavaScript + +Your highly-interactive Angular app may not be easily digestible to search engines. Using Angular Universal, you can generate a static version of your app with navigation through the pages. This makes the content of your app searchable, linkable, and navigable without JavaScript. It also makes a site preview available to search engines and social media. + +### Startup Performance + +Application startup time is critical for user engagement. While AOT compilation speeds up application start times, it may not be enough, especially on mobile devices with slow connections. [53% of mobile site visits are abandoned](https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/) if pages take longer than 3 seconds to load. Your app needs to load quickly, to engage users before they decide to do something else. + +With Angular Universal, you can generate landing pages for the app that look like the complete app. The pages are pure HTML, and can display even if JavaScript is disabled. The pages do not handle browser events, but they _do_ support navigation through the site use [routerLink](../guide/router.html#!#router-link). + +The recommended scenario is to serve a static version of the landing page, then load your Angular app behind it. This gives the appearance of near-instant performance, and offers the full interactive experience once the full app is loaded. Better than a "loading" spinner, it's a real screen that engages the user. + +#### Startup Comparison + +To illustrate the impact of Universal, we have used the [Timeline feature in Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/timeline-tool). Timeline offers many ways to inspect the performance of your app. Here we have used it to compare the uncached startup performance of the _Tour of Heroes_ app. Tour of Heroes is a simple demo app without much code or content, so it is smaller than the real apps you will build. + +The test was done by measuring the time from browser refresh until the Tour of Heroes Dashboard is fully displayed. The numbers and bars below represent the time from the initial request until the Dashboard page is visible in the app, so lower numbers are better. + +First, a PC browser with a local server, where browser performance and network response are very fast: + + + + + + + + + + + + + + + + + + + + + + +
Load TimeTime Allocation
JIT1.01sJIT local time allocation
AOT0.29sAOT local time allocation
Universal0.04sUniversal local time allocation
+ +You can see that the AOT-compiled version loaded faster than the JIT version (288ms versus 1000ms), and that most of the difference was in JavaScript execution. The universal version was the fastest (40ms), with no JavaScript to execute. + +The difference may not seem significant, since all are sufficiently fast. But how would the app perform on a slower device with a slower network connection? [CPU Throttling](https://developers.google.com/web/updates/2016/09/devtools-digest#cpu_throttling_for_a_mobile-first_world) and [Network Throttling](https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#throttling) can help you find out. + +The test was repeated using a simulated 5x slower CPU and simulated 3G network (750kb/s). + + + + + + + + + + + + + + + + + + + + + + +
Load TimeTime Allocation
JIT37.3sJIT 3G time allocation
AOT5.5sAOT 3G time allocation
Universal0.4sUniversal 3G time allocation
+ +In this mobile scenario, the JIT app spends almost 30 seconds just waiting for its many files to load, followed by 6.5 seconds executing JavaScript. The AOT-compiled app is much better, spending just 4 seconds to load the bundle and 1.3 seconds to execute it, but still much more than the 3-second limit. + +The Universal app displays the Dashboard page in just 0.4 seconds, since it displays without waiting for the JavaScript to load. The app would not be fully functional until its JavaScript bundles have loaded, which would be comparable to the load time for the AOT app, but the user can view the first page immediately. + +> If you want your app to be usable on slow networks, AOT is a must. Universal should be considered if first impressions are important. + +## The Example + +This guide uses the _Tour of Heroes_ app as an example. The app files remain the same, but additional support files are created to support building and serving the AOT and Universal versions. + +The AOT and Universal versions of the app are both compiled by the AOT compiler. The difference is that AOT version gets compiled into a bundle that is sent to the client, while the Universal version is compiled into a web server that serves pages that are rendered from the app. + +To build and run the AOT version, you need to create: + + - an `index-aot.html` file + - a main entry point, `main-aot.ts` + - a TypeScript config file, `tsconfig-aot.json` + - a Webpack config file, `webpack.config.aot.js` + - a lite-server config file, `bs-config.aot.js` + + To build and run the Universal version, you need to create: + + - a server-side app module, `app.server.ts` + - a Universal app renderer, `universal-engine.ts` + - an express web server to handle requests, `server-aot.ts` + - a TypeScript config file, `tsconfig-uni.json` + - a Webpack config file, `webpack.config.uni.js` + +The folder structure will look like this: + +```shell +src/ index.html index file for JIT version + index-aot.html index file for AOT version * + main.ts bootstrapper for JIT version + main-aot.ts bootstrapper for AOT version * + style.css styles for JIT version + systemjs.config.js SystemJS configuration for JIT version + systemjs-angular-loader.js component loader that allows relative paths + tsconfig.json TypeScript configuration for JIT version + app/ app.module.ts application code + ... ... + uni/ app.server.ts server-side application module * + server-aot.ts express web server * + universal-engine.ts server-side app renderer * + dist/ build.js AOT-compiled application bundle * + server.js AOT-compiled server bundle * +bs-config.json config file for lite server, JIT version +bs-config.aot.js config file for lite server, AOT version * +package.json npm configuration +tsconfig-aot.json TypeScript configuration for AOT version * +tsconfig-uni.json TypeScript configuration for Universal version * +webpack.config.aot.js Webpack configuration for AOT version * +webpack.config.uni.js Webpack configuration for Universal version * +``` +The files marked with * are new and not in the original Tour of Heroes demo. This guide covers the new files in the sections below. + +# Preparation + +## Installing the tools + +To get started, you need to install the necessary modules for AOT and Webpack. + + - `@angular/compiler-cli` - The ngc compiler that compiles Angular applications + - `@angular/platform-server` - Server-side components needed for compilation + - `webpack` - The Webpack JavaScript bundler + - `@ngtools/webpack` - The Webpack loader and plugin for bundling compiled applications + - `raw-loader` - The Webpack loader for text files + - `express` - The web server for serving the Universal application + +You can install them with the following commands: + +``` +npm install @angular/compiler-cli @angular/platform-server --save-dev +npm install webpack @ngtools/webpack raw-loader express --save-dev +``` + +## Component-relative 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. +For example, an `'./app.component.html'` URL means that the template file is a sibling of its companion app.component.ts file. +(The leading `./` is needed by Webpack to recognize that the string represents a path and not a module name.) + +SystemJS allows both absolute and relative URLs (via [systemjs-angular-loader]()), so you could have both in your app. Before building your app with AOT and Universal, you will need to convert them. + +From this: + +```ts + @Component({ + selector: 'my-component', + templateUrl: 'app/demo/components/my.component.html' + }) +``` +To this: + +```ts + @Component({ + selector: 'my-component', + templateUrl: './my.component.html' + }) +``` + +## Server Transition + +When a client-side Angular app bootstraps into a Universal page, it replaces the HTML that was there with its own rendered components. This transition is enabled by a shared id between the client and server apps. The id is defined using `BrowserModule.withServerTransition` in the AppModule that is shared by the client and server. + +Open file `src/app.module.ts` and find the `BrowserModule` import. Then replace this: + +```ts +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + ... +``` + +with this: +```ts +@NgModule({ + imports: [ + BrowserModule.withServerTransition({ + appId: 'toh-universal' + }), + FormsModule, + ... +``` + +# Configuration - AOT + +## Main Entry Point + +In the JIT-compiled app, `main.ts` is the entry point that bootstraps the app module. +An AOT-compiled app bootstraps differently, using `platformBrowser` instead of `platformBrowserDynamic` and using the *factory* that is created by pre-compiling the app module. A separate main entry point is needed. + +In the `src` directory, create a `main-aot.ts` like the one shown here: + +```ts +import { platformBrowser } from '@angular/platform-browser'; +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); +``` + +There's a chicken-and-egg problem here. +The `AppModuleNgFactory` won't exist until the app is compiled, but the `main-aot.ts` won't compile because `AppModuleNgFactory` doesn't exist yet. + +One way around this problem is to compile `app.module.ts` before `main-aot.ts`. You can tell the compiler to do that using the `files` array in the `tsconfig-aot.json`, which you will create in the next section. + +```json +"files": [ + "src/app/app.module.ts", + "src/main-aot.ts" +], +``` + +Since `app.module.ts` appears first in the array, it will be compiled into an `ngfactory` first. So `AppModuleNgFactory` will be available for `main-aot.ts`. + +## Creating the tsconfig-aot.json + +The AOT compiler transpiles TypeScript into JavaScript (like `tsc`), and compiles your app's components, services, etc. into executable JavaScript code. +You configure it using a JSON file similar to `tsconfig.json`. There are a few differences: + + - The `module` setting must be `es2015`. + This creates JavaScript output with `import` statements (instead of `require()`) that can be compiled and bundled. + - The `files` setting includes the app module and the main AOT bootstrapper. See more about this in the section below. + - There is a new `angularCompilerOptions` section with the following settings: + - `genDir` - the output directory that will contain the compiled `ngfactory` code. When compiling via Webpack, this is used as a temporary directory. + - `entryModule` - the root module of the app, expressed as **path/to/file#ClassName**. + - `skipMetadataEmit` - set to `true` because you don't need metadata in the bundled application + +Create a `tsconfig-aot.json` file in the project rood directory by copying your `tsconfig.json` and applying the changes described above. It should look like this: + +```json +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ "node_modules/@types/" ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "entryModule": "./src/app/app.module#AppModule", + "skipMetadataEmit" : true + } +} +``` + +## Webpack Configuration + +The [Webpack Introduction](webpack.html) explains how to configure Webpack to bundle your Angular application. +Using Webpack for AOT is similar, but uses different [loaders](webpack.html#loaders) and [plugins](webpack.html#plugins). + +Create a `webpack.config.aot.js` file in the project root directory, and add the content shown below. The salient parts are explained in the following sections. + +```ts +const ngtools = require('@ngtools/webpack'); +const webpack = require('webpack'); + +module.exports = { + devtool: 'source-map', + entry: { + main: './src/main-aot.ts' + }, + resolve: { + extensions: ['.ts', '.js'] + }, + target: 'node', + output: { + path: 'src/dist', + filename: 'build.js' + }, + plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-aot.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) + ], + module: { + rules: [ + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + { test: /\.ts$/, loader: '@ngtools/webpack' } + ] + } +} +``` + +### Loader +For AOT, the **loader** to use for TypeScript files is `@ngtools/webpack`. +This loads TypeScript files and interprets the Angular decorators to prepare for AOT compilation. +Since it is used for TypeScript files, configure the loader for `*.ts`: + +```ts +module: { + rules: [ + ... + { test: /\.ts$/, loader: '@ngtools/webpack' } // use ngtools loader for typescript + ] +} +``` + +When CSS and HTML files are encountered while processing the TypeScript, the [raw-loader](https://webpack.js.org/loaders/raw-loader/) is used. +It simply loads the file as a string, allowing Webpack to include it in the bundle. + +For more complex loading scenarios, see the [Webpack Introduction](https://angular.io/docs/ts/latest/guide/webpack.html#loaders). + +### Plugin + +The AOT **plugin** is called `ngtools.AotPlugin`, and performs TypeScript compilation and Angular compilation +using the same underlying compiler as `ngc`. +The plugin accepts [several options](https://www.npmjs.com/package/@ngtools/webpack#options), but the only required option is `tsConfigPath`. + +> Despite the [ngtools documentation](https://www.npmjs.com/package/@ngtools/webpack#options), the `entryModule` option must be in the `tsconfig-aot.json`, not inside the Webpack config. + +```ts +plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-aot.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) +], +``` + +The `tsConfigPath` tells the plugin where to find the TypeScript configuration file to use when compiling. +This should be the AOT-specific `tsconfig-aot.json` described above. + +The `UglifyJsPlugin` minifies the JavaScript output by removing spaces and shortening names. It slows down the build, so you can leave it off during development. + +### Input + +Webpack's inputs are the source files for your application. +You just need to give it the [entry point(s)](webpack.html#entries-outputs), and +Webpack follows the dependency graph to find what files it needs to bundle. + +When performing AOT, the entry point is the `main-aot.ts` file described above. +Starting there, Webpack will pull in your app code and imported dependencies. +It will pull in the Angular libraries used by the app, but it will *not* pull in the Angular compiler, since it's not needed in an AOT-compiled app. + +```ts +entry: { + main: './src/main-aot.ts' +}, +``` + +The [Webpack Introduction](webpack.html#entries-outputs) describes how to create separate bundles for +app code, vendor libraries, and polyfills. For simplicity, this example shows a single-bundle scenario. + +### Output + +After the plugin compiles the app files, Webpack bundles them into one or more output bundles. +These are the JavaScript files that will be loaded by the browser to run the app. Tell Webpack where to put the bundles: + +```ts +output: { + path: 'src/dist', + filename: 'build.js' +}, +``` + +We put them in a `dist` directory under `src`, so the server can find them. + +# Build - AOT + +Now that you've created the TypeScript and Webpack config files, you can build the application. First add the build command to the `scripts` section of your `package.json`. + +```json +"scripts": { + "build:aot": "webpack --config webpack.config.aot.js" + ... +} +``` + +Then, from the command prompt, type + +```shell +npm run build:aot +``` + +to build the output bundle. + +As configured above, this transpiles the TypeScript files, Angular-compiles the components, and +Webpacks the results into a single output file, `src/dist/build.js`. +It also generates a [source map](https://webpack.js.org/configuration/devtool/), `src/dist/build.js.map` that +relates the bundle code to the source code. + +## Source Maps + +Source maps let you use the browser's [dev tools](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) to set breakpoints in your source code, even though the browser is actually running an AOT-compiled bundle. + +Examining the source map is a useful exercise because it shows the names of the files that are included in the bundle, +in the order that Webpack included them. + +Look at the `src/dist/build.js.map`: + +```js +{"version":3,"sources":[ +"webpack:///webpack/bootstrap 097108a2a4bbafeb64bb", +"webpack:///./~/rxjs/Observable.js", +"webpack:///./~/rxjs/Subscriber.js", +"webpack:///./~/@angular/core/@angular/core.es5.js", +"webpack:///./~/@angular/common/@angular/common.es5.js", +"webpack:///./~/@angular/router/@angular/router.es5.js", +"webpack:///./~/rxjs/util/root.js", +"webpack:///./~/@angular/http/@angular/http.es5.js", +"webpack:///./src/app/hero.service.ts", +... +``` + +This shows that Webpack has included `rxjs` and `@angular` libraries ahead of the app's own `hero.service.ts`. + +If you create [multiple bundles](webpack.html#multiple-bundles), +look at the source maps to make sure the same file isn't included in more than one bundle. + +# Serve - AOT + +Now you've built the app bundle, so its time to test out the app. + +## Lite Server Configuration + +The [lite-server](https://github.com/johnpapa/lite-server) is used in the [Quickstart](../quickstart.html) and +Tour of Heroes examples to run and test the application in development. +To use it for the AOT app-compiled app, create a new configuration file, `bs-config.aot.js`. +It's different from the JIT version because it uses the `index-aot.html` as its default file. +It also uses a new port number so you can run the versions side-by-side. Here's the file: + +```ts +module.exports = { + port: 3100, + server: { + baseDir: "src", + routes: { + "/node_modules": "node_modules" + }, + middleware: { + // overrides the fallback middleware to use index-aot + 1: require('connect-history-api-fallback')({ index: '/index-aot.html' }) + } + } +}; +``` +> Note that the above must be a JavaScript file, not JSON, because of the call to `require`. + +## Serve Command + +Add the serve command to the `scripts` section of your `package.json`. The command launches lite-server using the configuration file created above. + +```json +"scripts": { + "serve:aot": "lite-server -c=bs-config.aot.js", + ... +} +``` + +Then, from the command prompt, type + +```shell +npm run serve:aot +``` + +The server starts with BrowserSync, so it starts the browser and loads the page showing the Tour of Heroes app. You can use the app and test that it behaves the same as the JIT version. + +Now you've built a working app using Webpack and AOT. + +# Configuration - Universal + +Now you can use a similar approach to build the Universal app. + +## Server Code + +The code specific to Universal is in three files: + + 1. The app server module + 2. The Universal engine + 3. The web server + +We'll go through these one at a time. + +### App Server Module + +The app server module is an Angular module that imports both the client-side app module and Angular's ServerModule. It tells Angular how to bootstrap the application when running on the server. + +Create an `app.server.ts` file in the `src/uni` directory and add the following code: + +```ts +import { NgModule } from '@angular/core'; +import { APP_BASE_HREF } from '@angular/common'; +import { ServerModule } from '@angular/platform-server'; +import { AppComponent } from '../app/app.component'; +import { AppModule } from '../app/app.module'; + +@NgModule({ + imports: [ + ServerModule, + AppModule + ], + bootstrap: [ + AppComponent + ], + providers: [ + {provide: APP_BASE_HREF, useValue: '/'} + ] +}) +export class AppServerModule { +} +``` + +### Universal Engine + +The Universal Engine is the heart of a Universal application. It is the code that takes an HTML template and a route url, and renders the HTML for the page. The HTML output is the result of rendering the components that are displayed for the given route. + +The rendered output could be stored as static HTML files to be served later. The demo code below serves the rendered pages directly, but it caches the output in memory, so that a given route only needs to be rendered once. + +Create the `universal-engine.ts` file in the `src/uni` directory, and add the following code: + +```ts +import * as fs from 'fs'; +import { renderModuleFactory } from '@angular/platform-server'; + +const templateCache = {}; // cache for page templates +const outputCache = {}; // cache for rendered pages + +export function ngUniversalEngine(setupOptions: any) { + + return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) { + let url: string = options.req.url; + let html: string = outputCache[url]; + if (html) { + // return already-built page for this url + console.log('from cache: ' + url); + callback(null, html); + return; + } + + console.log('building: ' + url); + if (!templateCache[filePath]) { + let file = fs.readFileSync(filePath); + templateCache[filePath] = file.toString(); + } + + // render the page via angular platform-server + let appModuleFactory = setupOptions.bootstrap[0]; + renderModuleFactory(appModuleFactory, { + document: templateCache[filePath], + url: url + }).then(str => { + outputCache[url] = str; + callback(null, str); + }); + }; +} + +``` + +### Web Server + +The web server accepts HTTP requests and sends back the response. For requests that are routes within the app, it creates the response by calling the Universal engine to render a page. For static file requests, it returns the file contents. + +This web server is based on the popular [Express](https://expressjs.com/) web framework. Other web serving techniques would work for Universal, as long as they can send the appropriate requests to the universal engine. + +Create the `server-aot.ts` file in the `src/uni` directory, and add the following code: + +```ts +import 'zone.js/dist/zone-node'; +import { enableProdMode } from '@angular/core'; +import { AppServerModuleNgFactory } from '../../aot/src/uni/app.server.ngfactory'; +import * as express from 'express'; +import { ngUniversalEngine } from './universal-engine'; + +enableProdMode(); + +const server = express(); + +// set our angular engine as the handler for html files, so it will be used to render them. +server.engine('html', ngUniversalEngine({ + bootstrap: [AppServerModuleNgFactory] +})); + +// set default view directory +server.set('views', 'src'); + +// handle requests for routes in the app. ngExpressEngine does the rendering. +server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req, res) => { + res.render('index-aot.html', {req}); +}); + +// handle requests for static files +server.get(['/*.js', '/*.css'], (req, res, next) => { + let fileName: string = req.originalUrl; + console.log(fileName); + let root = fileName.startsWith('/node_modules/') ? '.' : 'src'; + res.sendFile(fileName, { root: root }, function (err) { + if (err) { + next(err); + } + }); +}); + +// start the server +server.listen(3200, () => { + console.log('listening on port 3200...'); +}); + +``` + +Note that the server depends on `AppServerModuleNgFactory`, which has not been built yet. We have a compilation problem similar to that faced in `main-aot.ts`. We solve it the same way, in `tsconfig-uni.json`. + +## Creating the tsconfig-uni.json + +The TypeScript configuration file for Universal is almost the same as for AOT. The difference is the `files` section. For Universal, the `files` section lists the files for the server-side app module and the web server. + +Create a `tsconfig-uni.json` file in the project root directory by copying your `tsconfig-aot.json` and changing the `files` section as shown below. + +```json + "files": [ + "src/uni/app.server.ts", + "src/uni/server-aot.ts" + ], + ``` + +The `app.server.ts` file appears first, so it can be compiled before the `server-aot.ts` file requires it for its compilation. + +## Creating the webpack.config.uni.js + +The Webpack configuration file for Universal is almost the same as for AOT. There are two differences: + +1. The entry points +2. The output file name + +> You can share code between webpack configurations. See the [Webpack Introduction](webpack.html#!#configure-webpack) for more information. + +Create a `webpack.config.uni.js` in the project root directory by copying the `webpack.config.aot.js`. Then make the changes described in the sections below. + +### The entry points + +For Universal, we name two entry points: the app server module and the web server. This ensures that the code for both appears in the final bundle. + +```ts + entry: { + main: ['./src/uni/app.server.ts', './src/uni/server-aot.ts'] + }, +``` + +### The output file + +The output contains the all the code necessary to run the web server and serve the app. Put it in `src/dist` alongside the client AOT bundle. + +```ts + output: { + path: 'src/dist', + filename: 'server.js' + }, +``` + +# Build and Serve - Universal + +Now you can build and run the Universal application. First add the build and serve commands to the `scripts` section of your `package.json`. + +```json +"scripts": { + "build:uni": "webpack --config webpack.config.uni.js", + "serve:uni": "node src/dist/server.js", + ... +} +``` + +Then, from the command prompt, type + +```shell +npm run build:uni +``` + +to build the server bundle. Once it is created, type + +```shell +npm run serve:uni +``` + +to start the server. The console window should say + +```shell +listening on port 3200... +``` + +## Exercising Universal + +Open a browser to http://localhost:3200/ and you should be greeted by the familiar Tour of Heroes dashboard page. Meanwhile, the console window shows: + +```shell +building: / +/styles.css +/node_modules/core-js/client/shim.min.js +/node_modules/zone.js/dist/zone.min.js +/dist/build.js +``` + +The first line shows that the server received a request for '/' and passed it to the Universal engine, which then built the HTML page from your Angular application. If you reload the page for the same URL, the console will report 'from cache' instead of 'building', and the server will return HTML that was previously rendered for that URL. + +The remaining lines in the console show static files that were requested and returned by the server. The three .js files are needed for running the AOT version of the app. When the .js files are loaded into the browser, the Universal-rendered page is replaced by the Angular client app. + +### Disabling the Client App + +To see how the Universal app behaves on its own, go to the `src/dist` directory and temporarily rename the `build.js` file to `build.tmp.js`. Then reload the browser, and the Universal app will display without loading the Angular code. + +Now you can see the limitations of the Universal app. Navigation using `routerLink` works correctly: you can go from the Dashboard to the Heroes page and back, and you can click on a hero on the Dashboard page to display the Details page. But you cannot go to the Details from the Heroes page, because that uses a click event rather than a router link. The Hero Search on the Dashboard page does not work, nor does saving changes. + +### Throttling + +Now rename `build.tmp.js` back to `build.js` so the app can load again. Then open the Chrome Dev Tools and go to the Network tab, and find the [Network Throttling](https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#throttling) dropdown. Try 3G and other network speeds to see how long it takes for the app to load under various conditions. + +# Conclusion + +Angular Universal can greatly improve the perceived startup performance of your app. The slower the network, the more advantageous it becomes to have Universal display the first page to the user. + + + + + + +