diff --git a/gulpfile.js b/gulpfile.js
index 6dac9d40c4..867823c067 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -51,6 +51,8 @@ var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPl
var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker'));
var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils'));
+var publish = require(path.resolve(EXAMPLES_PATH + '/cb-third-party-lib/hero-profile/publish'));
+
const WWW = argv.page ? 'www-pages' : 'www'
const isSilent = !!argv.silent;
@@ -464,7 +466,9 @@ gulp.task('add-example-boilerplate', function(done) {
fsUtils.addSymlink(realPath, linkPath);
});
- return buildStyles(copyExampleBoilerplate, done);
+ publish().then(function(){
+ return buildStyles(copyExampleBoilerplate, done);
+ });
});
diff --git a/public/docs/_examples/_boilerplate/package.json b/public/docs/_examples/_boilerplate/package.json
index 3f255fcbd6..39d440cbd0 100644
--- a/public/docs/_examples/_boilerplate/package.json
+++ b/public/docs/_examples/_boilerplate/package.json
@@ -18,6 +18,7 @@
"build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail",
"build:cli": "ng build",
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
+ "build:aot:jit": "npm run build:aot && npm run tsc",
"copy-dist-files": "node ./copy-dist-files.js",
"i18n": "ng-xi18n"
},
diff --git a/public/docs/_examples/_boilerplate/systemjs.config.js b/public/docs/_examples/_boilerplate/systemjs.config.js
index 457f040fc0..3ae1989388 100644
--- a/public/docs/_examples/_boilerplate/systemjs.config.js
+++ b/public/docs/_examples/_boilerplate/systemjs.config.js
@@ -26,7 +26,8 @@
// other libraries
'rxjs': 'npm:rxjs',
- 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
+ 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
+ 'hero-profile': 'npm:hero-profile/bundles/hero-profile.umd.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
diff --git a/public/docs/_examples/_boilerplate/tsconfig.json b/public/docs/_examples/_boilerplate/tsconfig.json
index d90e457b10..d84cabba2a 100644
--- a/public/docs/_examples/_boilerplate/tsconfig.json
+++ b/public/docs/_examples/_boilerplate/tsconfig.json
@@ -16,6 +16,7 @@
"compileOnSave": true,
"exclude": [
"node_modules/*",
- "**/*-aot.ts"
+ "**/*-aot.ts",
+ "app-aot"
]
}
diff --git a/public/docs/_examples/cb-third-party-lib/.gitignore b/public/docs/_examples/cb-third-party-lib/.gitignore
new file mode 100644
index 0000000000..b8c17ad953
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/.gitignore
@@ -0,0 +1,9 @@
+**/*.ngfactory.ts
+**/*.metadata.json
+**/*.css.shim.ts
+*.js
+!/hero-profile/rollup-config.js
+!/hero-profile/publish.js
+!/hero-profile/inline-resources.js
+!/hero-profile/package.json
+!ts/rollup-config.js
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/e2e-spec.ts b/public/docs/_examples/cb-third-party-lib/e2e-spec.ts
new file mode 100644
index 0000000000..1bcc69f45d
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/e2e-spec.ts
@@ -0,0 +1,22 @@
+'use strict'; // necessary for es6 output in node
+
+import { browser, element, by } from 'protractor';
+
+describe('Third Party Lib Cookbook', function () {
+
+ let expectedMsgAoT = 'Library consumed by AoT application';
+ let expectedMsgJiT = 'Library consumed by JiT application';
+
+ beforeEach(function () {
+ browser.get('');
+ });
+
+ it(`should load AoT compiled version`, function () {
+ expect(element(by.css('.aot')).getText()).toEqual(expectedMsgAoT);
+ });
+
+ it('should load JiT compiled version', function () {
+ expect(element(by.css('.jit')).getText()).toEqual(expectedMsgJiT);
+ });
+
+});
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.css b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.css
new file mode 100644
index 0000000000..9f906ea720
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.css
@@ -0,0 +1,6 @@
+/*#docregion*/
+.bio {
+ border: 1px solid black;
+ padding: 10px;
+ width: 300px;
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.html b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.html
new file mode 100644
index 0000000000..3b7ef9c2c2
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.html
@@ -0,0 +1,7 @@
+
+
+
Featured Hero
+
+
{{hero.name}}
+
{{hero.bio}}
+
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.ts b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.ts
new file mode 100644
index 0000000000..82c451d017
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.ts
@@ -0,0 +1,14 @@
+// #docregion
+import { Component, Input } from '@angular/core';
+
+import { Hero } from './hero';
+
+@Component({
+ moduleId: module.id,
+ selector: 'hero-profile',
+ templateUrl: 'hero-profile.component.html',
+ styleUrls: ['hero-profile.component.css']
+})
+export class HeroProfileComponent {
+ @Input() hero: Hero;
+}
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.module.ts b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.module.ts
new file mode 100644
index 0000000000..692bdd6806
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.module.ts
@@ -0,0 +1,12 @@
+// #docregion
+import { NgModule } from '@angular/core';
+
+import { HeroProfileComponent } from './hero-profile.component';
+
+@NgModule({
+ declarations: [HeroProfileComponent],
+ exports: [HeroProfileComponent]
+})
+export class HeroProfileModule {
+
+}
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/hero.ts b/public/docs/_examples/cb-third-party-lib/hero-profile/hero.ts
new file mode 100644
index 0000000000..09d04629f5
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/hero.ts
@@ -0,0 +1,4 @@
+// #docregion
+export class Hero {
+ constructor(public name: string, public bio: string) {}
+}
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/index.ts b/public/docs/_examples/cb-third-party-lib/hero-profile/index.ts
new file mode 100644
index 0000000000..70556487f5
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/index.ts
@@ -0,0 +1,4 @@
+// #docregion
+export { HeroProfileComponent } from './hero-profile.component';
+export { HeroProfileModule } from './hero-profile.module';
+export { Hero } from './hero';
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/inline-resources.js b/public/docs/_examples/cb-third-party-lib/hero-profile/inline-resources.js
new file mode 100644
index 0000000000..61b5d4b36e
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/inline-resources.js
@@ -0,0 +1,137 @@
+// #docregion
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const glob = require('glob');
+
+/**
+ * Simple Promiseify function that takes a Node API and return a version that supports promises.
+ * We use promises instead of synchronized functions to make the process less I/O bound and
+ * faster. It also simplify the code.
+ */
+function promiseify(fn) {
+ return function() {
+ const args = [].slice.call(arguments, 0);
+ return new Promise((resolve, reject) => {
+ fn.apply(this, args.concat([function (err, value) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(value);
+ }
+ }]));
+ });
+ };
+}
+
+const readFile = promiseify(fs.readFile);
+const writeFile = promiseify(fs.writeFile);
+
+
+function inlineResources(globs) {
+ if (typeof globs == 'string') {
+ globs = [globs];
+ }
+
+ /**
+ * For every argument, inline the templates and styles under it and write the new file.
+ */
+ return Promise.all(globs.map(pattern => {
+ if (pattern.indexOf('*') < 0) {
+ // Argument is a directory target, add glob patterns to include every files.
+ pattern = path.join(pattern, '**', '*');
+ }
+
+ const files = glob.sync(pattern, {})
+ .filter(name => /\.js$/.test(name)); // Matches only JavaScript files.
+
+ // Generate all files content with inlined templates.
+ return Promise.all(files.map(filePath => {
+ return readFile(filePath, 'utf-8')
+ .then(content => inlineResourcesFromString(content, url => {
+ return path.join(path.dirname(filePath), url);
+ }))
+ .then(content => writeFile(filePath, content))
+ .catch(err => {
+ console.error('An error occured: ', err);
+ });
+ }));
+ }));
+}
+
+/**
+ * Inline resources from a string content.
+ * @param content {string} The source file's content.
+ * @param urlResolver {Function} A resolver that takes a URL and return a path.
+ * @returns {string} The content with resources inlined.
+ */
+function inlineResourcesFromString(content, urlResolver) {
+ // Curry through the inlining functions.
+ return [
+ inlineTemplate,
+ inlineStyle,
+ removeModuleId
+ ].reduce((content, fn) => fn(content, urlResolver), content);
+}
+
+if (require.main === module) {
+ inlineResources(process.argv.slice(2));
+}
+
+
+/**
+ * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
+ * replace with `template: ...` (with the content of the file included).
+ * @param content {string} The source file's content.
+ * @param urlResolver {Function} A resolver that takes a URL and return a path.
+ * @return {string} The content with all templates inlined.
+ */
+function inlineTemplate(content, urlResolver) {
+ return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function(m, templateUrl) {
+ const templateFile = urlResolver(templateUrl);
+ const templateContent = fs.readFileSync(templateFile, 'utf-8');
+ const shortenedTemplate = templateContent
+ .replace(/([\n\r]\s*)+/gm, ' ')
+ .replace(/"/g, '\\"');
+ return `template: "${shortenedTemplate}"`;
+ });
+}
+
+
+/**
+ * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
+ * replace with `styles: [...]` (with the content of the file included).
+ * @param urlResolver {Function} A resolver that takes a URL and return a path.
+ * @param content {string} The source file's content.
+ * @return {string} The content with all styles inlined.
+ */
+function inlineStyle(content, urlResolver) {
+ return content.replace(/styleUrls:\s*(\[[\s\S]*?\])/gm, function(m, styleUrls) {
+ const urls = eval(styleUrls);
+ return 'styles: ['
+ + urls.map(styleUrl => {
+ const styleFile = urlResolver(styleUrl);
+ const styleContent = fs.readFileSync(styleFile, 'utf-8');
+ const shortenedStyle = styleContent
+ .replace(/([\n\r]\s*)+/gm, ' ')
+ .replace(/"/g, '\\"');
+ return `"${shortenedStyle}"`;
+ })
+ .join(',\n')
+ + ']';
+ });
+}
+
+
+/**
+ * Remove every mention of `moduleId: module.id`.
+ * @param content {string} The source file's content.
+ * @returns {string} The content with all moduleId: mentions removed.
+ */
+function removeModuleId(content) {
+ return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
+}
+
+module.exports = inlineResources;
+module.exports.inlineResourcesFromString = inlineResourcesFromString;
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/package.json b/public/docs/_examples/cb-third-party-lib/hero-profile/package.json
new file mode 100644
index 0000000000..467a117c77
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "hero-profile",
+ "version": "0.0.1",
+ "main": "bundles/hero-profile.umd.js",
+ "module": "index.js",
+ "typings": "index.d.ts",
+ "author": "",
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/angular/angular.io/blob/master/LICENSE"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/publish.js b/public/docs/_examples/cb-third-party-lib/hero-profile/publish.js
new file mode 100644
index 0000000000..ec370ec220
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/publish.js
@@ -0,0 +1,59 @@
+// #docregion
+function publish() {
+ var inlineResources = require('./inline-resources');
+
+ // AoT compile
+ var spawnNgc = require( 'child_process' ).spawnSync;
+ var ngc = spawnNgc('./public/docs/_examples/node_modules/.bin/ngc', ['-p', './public/docs/_examples/cb-third-party-lib/hero-profile/tsconfig-aot.json']);
+
+ // Copy to node_modules
+ var fs = require('fs');
+ var del = require('del');
+
+ var node_modules_root = './public/docs/_examples/node_modules/hero-profile/';
+
+ del.sync(node_modules_root, {force:true});
+
+ fs.mkdirSync(node_modules_root);
+ fs.mkdirSync(node_modules_root + 'bundles');
+
+ var aotFiles = [
+ 'hero-profile.component.html',
+ 'hero-profile.component.css',
+
+ 'hero-profile.component.d.ts',
+ 'hero-profile.module.d.ts',
+ 'hero.d.ts',
+ 'index.d.ts',
+
+ 'hero-profile.component.js',
+ 'hero-profile.module.js',
+ 'hero.js',
+ 'index.js',
+
+ 'index.metadata.json',
+ 'hero-profile.module.metadata.json',
+ 'hero-profile.component.metadata.json',
+
+ 'package.json'
+ ]
+
+ aotFiles.map(function(f) {
+ var path = f.split('/');
+ var release = node_modules_root + path[path.length-1];
+ fs.createReadStream('./public/docs/_examples/cb-third-party-lib/hero-profile/' + f).pipe(fs.createWriteStream(release));
+ });
+
+ return inlineResources('./public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.*').then(function(){
+
+ // Create umd bundle
+ var spawnRollup = require( 'child_process' ).spawnSync;
+ var rollup = spawnRollup('./public/docs/_examples/node_modules/.bin/rollup', ['-c', './public/docs/_examples/cb-third-party-lib/hero-profile/rollup-config.js']);
+
+ var umd = './public/docs/_examples/cb-third-party-lib/hero-profile/bundles/hero-profile.umd.js';
+ fs.createReadStream(umd).pipe(fs.createWriteStream(node_modules_root + 'bundles/hero-profile.umd.js'));
+
+ });
+}
+
+module.exports = publish;
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/rollup-config.js b/public/docs/_examples/cb-third-party-lib/hero-profile/rollup-config.js
new file mode 100644
index 0000000000..2e02133362
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/rollup-config.js
@@ -0,0 +1,10 @@
+// #docregion
+export default {
+ entry: './public/docs/_examples/cb-third-party-lib/hero-profile/index.js',
+ dest: './public/docs/_examples/cb-third-party-lib/hero-profile/bundles/hero-profile.umd.js',
+ format: 'umd',
+ moduleName: 'ng.heroProfile',
+ globals: {
+ '@angular/core': 'ng.core'
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/hero-profile/tsconfig-aot.json b/public/docs/_examples/cb-third-party-lib/hero-profile/tsconfig-aot.json
new file mode 100644
index 0000000000..5e3cca7517
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/hero-profile/tsconfig-aot.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "es2015",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "declaration": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "noImplicitAny": true,
+ "typeRoots": [
+ "../../node_modules/@types/"
+ ]
+ },
+ "files": [
+ "index.ts"
+ ],
+ "angularCompilerOptions": {
+ "genDir": "aot",
+ "skipMetadataEmit" : false
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.component.ts b/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.component.ts
new file mode 100644
index 0000000000..6fce027213
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.component.ts
@@ -0,0 +1,14 @@
+import { Component } from '@angular/core';
+
+import { Hero } from 'hero-profile';
+
+@Component({
+ selector: 'my-aot-app',
+ template: `
+
Library consumed by AoT application
+
+
`
+})
+export class AppComponent {
+ hero = new Hero('Bombasto', 'Bombastic at times');
+}
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.module.ts b/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.module.ts
new file mode 100644
index 0000000000..bf8970d57c
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app-aot/app.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+
+import { AppComponent } from './app.component';
+import { HeroProfileModule } from 'hero-profile';
+
+@NgModule({
+ imports: [HeroProfileModule, BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {
+}
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app-aot/main-aot.ts b/public/docs/_examples/cb-third-party-lib/ts/app-aot/main-aot.ts
new file mode 100644
index 0000000000..ada092b67b
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app-aot/main-aot.ts
@@ -0,0 +1,3 @@
+import { platformBrowser } from '@angular/platform-browser';
+import { AppModuleNgFactory } from '../aot/app-aot/app.module.ngfactory';
+platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app/app.component.ts b/public/docs/_examples/cb-third-party-lib/ts/app/app.component.ts
new file mode 100644
index 0000000000..3a7dadfe65
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app/app.component.ts
@@ -0,0 +1,14 @@
+import { Component } from '@angular/core';
+
+import { Hero } from 'hero-profile';
+
+@Component({
+ selector: 'my-jit-app',
+ template: `
+
Library consumed by JiT application
+
+
`
+})
+export class AppComponent {
+ hero = new Hero('Magneta', 'Brave as they come');
+}
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app/app.module.ts b/public/docs/_examples/cb-third-party-lib/ts/app/app.module.ts
new file mode 100644
index 0000000000..bf8970d57c
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app/app.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+
+import { AppComponent } from './app.component';
+import { HeroProfileModule } from 'hero-profile';
+
+@NgModule({
+ imports: [HeroProfileModule, BrowserModule],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent]
+})
+export class AppModule {
+}
diff --git a/public/docs/_examples/cb-third-party-lib/ts/app/main.ts b/public/docs/_examples/cb-third-party-lib/ts/app/main.ts
new file mode 100644
index 0000000000..4acf5de663
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/app/main.ts
@@ -0,0 +1,5 @@
+// #docregion
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { AppModule } from './app.module';
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/public/docs/_examples/cb-third-party-lib/ts/example-config.json b/public/docs/_examples/cb-third-party-lib/ts/example-config.json
new file mode 100644
index 0000000000..85a9a43ad0
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/example-config.json
@@ -0,0 +1,3 @@
+{
+ "build": "build:aot:jit"
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-third-party-lib/ts/index.html b/public/docs/_examples/cb-third-party-lib/ts/index.html
new file mode 100644
index 0000000000..52aaa60641
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Third Party Lib
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading app...
+
+ Loading app...
+
+
+
+
+
diff --git a/public/docs/_examples/cb-third-party-lib/ts/rollup-config.js b/public/docs/_examples/cb-third-party-lib/ts/rollup-config.js
new file mode 100644
index 0000000000..603d33408f
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/rollup-config.js
@@ -0,0 +1,23 @@
+// #docregion
+import rollup from 'rollup'
+import nodeResolve from 'rollup-plugin-node-resolve'
+import commonjs from 'rollup-plugin-commonjs';
+import uglify from 'rollup-plugin-uglify'
+
+//paths are relative to the execution path
+export default {
+ entry: 'app-aot/main-aot.js',
+ dest: 'dist/build.js', // output a single application bundle
+ sourceMap: true,
+ sourceMapFile: 'dist/build.js.map',
+ format: 'iife',
+ plugins: [
+ // #docregion nodeResolve
+ nodeResolve({jsnext: true, module: true}),
+ // #enddocregion nodeResolve
+ commonjs({
+ include: ['node_modules/rxjs/**']
+ }),
+ uglify()
+ ]
+}
diff --git a/public/docs/_examples/cb-third-party-lib/ts/tsconfig-aot.json b/public/docs/_examples/cb-third-party-lib/ts/tsconfig-aot.json
new file mode 100644
index 0000000000..85ab089d23
--- /dev/null
+++ b/public/docs/_examples/cb-third-party-lib/ts/tsconfig-aot.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "es2015",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "removeComments": false,
+ "noImplicitAny": true,
+ "suppressImplicitAnyIndexErrors": true,
+ "typeRoots": [
+ "../../node_modules/@types/"
+ ]
+ },
+
+ "files": [
+ "app-aot/app.module.ts",
+ "app-aot/main-aot.ts"
+ ],
+
+ "angularCompilerOptions": {
+ "genDir": "aot",
+ "skipMetadataEmit" : true
+ }
+}
diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json
index 7a45a91e77..9063c851a4 100644
--- a/public/docs/ts/latest/cookbook/_data.json
+++ b/public/docs/ts/latest/cookbook/_data.json
@@ -56,6 +56,11 @@
"intro": "Setting the document or window title using the Title service."
},
+ "third-party-lib": {
+ "title": "Third Party Library",
+ "intro": "Create a third party library with support for AoT, JiT and Tree Shaking"
+ },
+
"ts-to-js": {
"title": "TypeScript to JavaScript",
"intro": "Convert Angular TypeScript examples into ES5 JavaScript"
diff --git a/public/docs/ts/latest/cookbook/third-party-lib.jade b/public/docs/ts/latest/cookbook/third-party-lib.jade
new file mode 100644
index 0000000000..68200ca119
--- /dev/null
+++ b/public/docs/ts/latest/cookbook/third-party-lib.jade
@@ -0,0 +1,247 @@
+include ../_util-fns
+
+:marked
+ Traditionally, third party JavaScript libraries have been published in the form of a single JavaScript file.
+ Consumers of the library have then included the library, "as is", somewhere on the page using a `script` tag.
+
+ Modern web development has changed this process. Instead of publishing a "one size fits all" bundle, developers want to only include the parts of the library they actually need.
+
+ This cookbook shows how to publish a third party library in a way that makes it possible to take advantage of techniques like Ahead of Time Compilation (AoT) and Tree Shaking.
+
+
+:marked
+ ## Table of contents
+
+ [Creating a Third Party Library](#third-party-lib)
+
+ [Supporting AoT](#aot)
+
+ [Preparing the library for Tree Shaking](#tree-shaking)
+
+ [Supporting JiT](#jit)
+
+ [Publish](#publish)
+
+ [Integrate with Application](#integrate-with-app)
+
+ [Final Application](#final-app)
+
+.l-main-section
+
+:marked
+ ## Creating a Third Party Library
+
+ This cookbook shows how to create a simple Hero-Profile library and publish it with support for AoT compilation and Tree Shaking.
+
+ A version of the library intended for JiT compiled applications will also be included.
+
+ The code for the Hero-Profile library can be found below.
+
+ To support both AoT and JiT compilation there are two different tsconfig files.
+
+ `tsconfig.json` for JiT compilation and `tsconfig-aot.json` for AoT compilation.
+
++makeTabs(
+ `cb-third-party-lib/hero-profile/hero-profile.module.ts,
+ cb-third-party-lib/hero-profile/tsconfig-aot.json,
+ cb-third-party-lib/ts/tsconfig.json,
+ cb-third-party-lib/hero-profile/hero-profile.component.html,
+ cb-third-party-lib/hero-profile/hero-profile.component.ts,
+ cb-third-party-lib/hero-profile/hero-profile.component.css,
+ cb-third-party-lib/hero-profile/hero.ts,
+ cb-third-party-lib/hero-profile/package.json`,
+ null,
+ `hero-profile.module.ts,
+ tsconfig-aot.json,
+ tsconfig.json,
+ hero-profile.component.html,
+ hero-profile.component.ts,
+ hero-profile.component.css,
+ hero.ts,
+ package.json`
+)(format='.')
+
+.l-main-section
+
+:marked
+ ## Supporting AoT
+
+ AoT plays an important role in optimizing Angular applications. It's therefore important that third party libraries be published in a format compatible with AoT compilation. Otherwise it will not be possible to include the library in an AoT compiled application.
+
+ Only code written in TypeScript can be AoT compiled.
+
+ Before publishing the library must first be compiled using the `ngc` compiler.
+
+ `ngc` extends the `tsc` compiler by adding extensions to support AoT compilation in addition to regular TypeScript compilation.
+
+:marked
+ AoT compilation outputs three files that must be included in order to be compatible with AoT.
+
+ *Transpiled JavaScript*
+
+ As usual the original TypeScript is transpiled to regular JavaScript.
+
+ *Typings files*
+
+ JavaScript has no way of representing typings. In order to preserve the original typings, `ngc` will generate .d.ts typings files.
+
+ *Meta Data JSON files*
+
+ `ngc` outputs a metadata.json file for every `Component` and `NgModule`. These meta data files represent the information in the original `NgModule` and `Component` decorators.
+
+ The meta data may reference external templates or css files. These external files must be included with the library.
+
+ ### NgFactories
+
+ `ngc` generates a series of files with an `.ngfactory` suffix as well. These files represent the AoT compiled source, but should not be included with the published library.
+
+ Instead the `ngc` compiler in the consuming application will generate `.ngfactory` files based on the JavaScript, Typings and meta data shipped with the library.
+
+ ### Why not publish TypeScript?
+
+ Why not ship TypeScript source instead? After all the library will be part of another TypeScript compilation step when the library is imported by the consuming application?
+
+ Generally it's discouraged to ship TypeScript with third party libraries. It would require the consumer to replicate the complete build environment of the library. Not only typings, but potentially a specific version of `ngc` as well.
+
+ Publishing plain JavaScript with typings and meta data allows the consuming application to remain agnostic of the library's build environment.
+
+
+:marked
+ ## Preparing the library for Tree Shaking
+
+ In addition to supporting AoT, the library code should also be "Tree Shakable".
+
+ Tree Shakers work best with `ES2015` JavaScript.
+
+ `ES2015` `import` and `export` statements make it easier to statically analyse the code to determine which modules are in use by the application.
+
+ By setting the `module` attribute in `tsconfig-aot.json` to `es2015`, the transpiled JavaScript will use `ES2015` modules.
+
+ The library is made up of several independent files. Bundler frameworks like `Rollup` and `Webpack` need a way to determine the entry point to the module. In this example the entry point is `index.js`, the transpiled version of the index.ts TypeScript barrel.
+
+ The entry point to the module is configured using the `module` attribute in `package.json`. In this case `module` is defined as `"module": "index.js"`.
+
+
+:marked
+ ## Supporting JiT
+
+ AoT compiled code is the prefered format for production builds, but due to the long compilation time, it may not be practical to use AoT during development.
+
+ To create a more flexible developer experience, a JiT compatible build of the library should be published as well. The format of the JiT bundle is `umd`, which stands for Universal Module Definition. Shipping the bundle as `umd` ensures compatibility with most common module loading formats.
+
+ The `umd` bundle will ship as a single file containing the JavaScript and inlined versions of any external templates or css.
+
+ The path to the `umd` file identified in package.json as `"main": "bundles/hero-profile.umd.js"`
+
+ In `tsconfig.json` the module for the `umd` bundle is specified as `commonjs`, not `es2015`. This is done to ensure that the bundle can be executed "as is", without further transpilation or bundling.
+
+ To generate the bundle we will be using a framework called `Rollup`.
+
+ The JiT build assumes the following Rollup and TypeScript configuration.
+
++makeTabs(
+ `cb-third-party-lib/hero-profile/rollup-config.js,
+ cb-third-party-lib/ts/tsconfig.json`,
+ null,
+ `rollup-config.js,
+ tsconfig.json`
+)(format='.')
+:marked
+ Generate the `umd` bundle by running `node_modules/.bin/rollup -c rollup-config.js`.
+
+
+:marked
+ ## Publish
+
+:marked
+ `Rollup` outputs the `umd` bundle, but prior to bundling, all external templates or css files must be inlined.
+
+ There are a few options for how to do inlining. This cookbook uses an approach borrowed from `Angular Material 2`.
+
+ The idea is to create a node script that will walk the component code and replace `templateUrl` and `styleUrls` references with inlined html and css.
+
+ Additionally the script will remove references to `module.id` since it's no longer needed after templates and css have been inlined.
+
+ Angular ships with its own set of `umd` bundles. These bundles can be referenced by Rollup when generating the `umd` bundle.
+
+ In this example there is a dependency on `@angular/core`.
+
+ By listing `@angular/core` as a `global` in the configuration, `Rollup` will point to the `@angular/core` umd bundle.
+
+ Normally third party libraries will be published to `npm`. This cookbook simulates publishing by executing all required steps in the `publish.js` script.
+
+ `publish.js` will do the following:
+
+ 1) AoT compile the Hero-Profile library by running `node_modules/.bin/ngc -p tsconfig-aot.json`
+
+ 2) Inline templates and css using the `inline-resources.js` script
+
+ 3) Create an `umd` bundle by running `node_modules/.bin/rollup -c rollup-config.js`
+
++makeTabs(
+ `cb-third-party-lib/hero-profile/publish.js,
+ cb-third-party-lib/hero-profile/inline-resources.js`,
+ null,
+ `publish.js,
+ inline-resources.js`
+)(format='.')
+
+.l-main-section
+
+:marked
+ ## Integrate with Application
+
+ The library is now ready to be integrated with either AoT compiled applications or JiT compiled applications. The following sections describes how to configure both.
+
+ For the purposes of this demo the JiT and the AoT versions are loaded using the same index.html page.
+
+ ### AoT
+
+ AoT compiled applications will integrate the library in the compilation of the application as a whole.
+
+ As in the AoT compilation Cookbook `ngc` is used in combination with `Rollup` to AoT and Tree Shake the application.
+
+ Run the command `ngc -p tsconfig-aot.json && rollup -c rollup-config.js` to execute the combined steps of AoT compilation and Tree Shaking.
+
+ `tsconfig-aot.json` and `rollup-config.js` contain the necessary configuration.
+
++makeTabs(
+ `cb-third-party-lib/ts/rollup-config.js,
+ cb-third-party-lib/ts/tsconfig-aot.json`,
+ null,
+ `rollup-config.js,
+ tsconfig-aot.json`
+)(format='.')
+
+:marked
+ Inside `rollup-config` there is a `nodeResolve` section. This is where the `module` setting from `package.json` comes into play.
+
+ `nodeResolve` will look for either `module` or `jsnext` in `package.json` to determine how to bundle external libraries.
+
++makeExample('cb-third-party-lib/ts/rollup-config.js', 'nodeResolve', 'rollup-config.js')(format=".")
+
+:marked
+ The combined output of `ngc` and `Rollup` is a single `build.js` JavaScript file.
+
+ `build.js` contains the entire application including all Angular dependencies and the third party Hero-Profile library.
+
+ To run the application in AoT mode, include `build.js` as a script tag and the `my-aot-app` root level component tag in `index.html`
+
+ ### JiT
+
+ JiT applications load the `umd` bundle using `SystemJS`. This requires a minor tweak to `systemjs.config.js` to register the `umd` bundle with `SystemJS`.
+
+ Simply add `'hero-profile': 'npm:hero-profile/bundles/hero-profile.umd.js'` to the map section of `systemjs.config.js`.
+
+.l-main-section
+
+:marked
+ ## Final Application
+
+ If you have cloned the `Angular.io` repo, all the steps described in this cookbook can be executed by running the following command:
+
+ `gulp add-example-boilerplate && npm run build:aot:jit && npm run lite`
+
+ After loading both the JiT and AoT versions of the library the final application looks like this:
+figure.image-display
+ img(src="/resources/images/cookbooks/third-party-lib/third-party-lib.png" alt="Third-Party-Library")
\ No newline at end of file
diff --git a/public/resources/images/cookbooks/third-party-lib/third-party-lib.png b/public/resources/images/cookbooks/third-party-lib/third-party-lib.png
new file mode 100644
index 0000000000..525a27b88d
Binary files /dev/null and b/public/resources/images/cookbooks/third-party-lib/third-party-lib.png differ