From ab8e8edffa28dc59c4e17b5782ff76be826a06b6 Mon Sep 17 00:00:00 2001 From: Torgeir Helgevold Date: Sun, 16 Oct 2016 16:18:12 -0400 Subject: [PATCH 1/2] docs(cb-third-party-lib) create a third party lib s s s s s c s c s s s s s s s s s s s s s s s s s s s s s s s s s --- gulpfile.js | 6 +- .../docs/_examples/_boilerplate/package.json | 1 + .../_examples/_boilerplate/systemjs.config.js | 3 +- .../docs/_examples/_boilerplate/tsconfig.json | 3 +- .../_examples/cb-third-party-lib/.gitignore | 9 + .../_examples/cb-third-party-lib/e2e-spec.ts | 22 ++ .../hero-profile/hero-profile.component.css | 6 + .../hero-profile/hero-profile.component.html | 7 + .../hero-profile/hero-profile.component.ts | 14 + .../hero-profile/hero-profile.module.ts | 12 + .../cb-third-party-lib/hero-profile/hero.ts | 4 + .../cb-third-party-lib/hero-profile/index.ts | 4 + .../hero-profile/inline-resources.js | 137 ++++++++++ .../hero-profile/package.json | 14 + .../hero-profile/publish.js | 59 +++++ .../hero-profile/rollup-config.js | 10 + .../hero-profile/tsconfig-aot.json | 22 ++ .../ts/app-aot/app.component.ts | 14 + .../ts/app-aot/app.module.ts | 13 + .../cb-third-party-lib/ts/app-aot/main-aot.ts | 3 + .../ts/app/app.component.ts | 14 + .../cb-third-party-lib/ts/app/app.module.ts | 13 + .../cb-third-party-lib/ts/app/main.ts | 5 + .../cb-third-party-lib/ts/example-config.json | 3 + .../cb-third-party-lib/ts/index.html | 32 +++ .../cb-third-party-lib/ts/rollup-config.js | 23 ++ .../cb-third-party-lib/ts/tsconfig-aot.json | 26 ++ public/docs/ts/latest/cookbook/_data.json | 5 + .../ts/latest/cookbook/third-party-lib.jade | 247 ++++++++++++++++++ .../third-party-lib/third-party-lib.png | Bin 0 -> 58016 bytes 30 files changed, 728 insertions(+), 3 deletions(-) create mode 100644 public/docs/_examples/cb-third-party-lib/.gitignore create mode 100644 public/docs/_examples/cb-third-party-lib/e2e-spec.ts create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.css create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.html create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.component.ts create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/hero-profile.module.ts create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/hero.ts create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/index.ts create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/inline-resources.js create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/package.json create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/publish.js create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/rollup-config.js create mode 100644 public/docs/_examples/cb-third-party-lib/hero-profile/tsconfig-aot.json create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app-aot/app.component.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app-aot/app.module.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app-aot/main-aot.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app/app.component.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app/app.module.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/app/main.ts create mode 100644 public/docs/_examples/cb-third-party-lib/ts/example-config.json create mode 100644 public/docs/_examples/cb-third-party-lib/ts/index.html create mode 100644 public/docs/_examples/cb-third-party-lib/ts/rollup-config.js create mode 100644 public/docs/_examples/cb-third-party-lib/ts/tsconfig-aot.json create mode 100644 public/docs/ts/latest/cookbook/third-party-lib.jade create mode 100644 public/resources/images/cookbooks/third-party-lib/third-party-lib.png 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..1bbaee8c06 --- /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 minified JavaScript file. + Consumers of the library have then included the minified JavaScript file, "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 will show 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 will show 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". + + Thee 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 compatability 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` wil create the `umd` bundle, but 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 0000000000000000000000000000000000000000..525a27b88d696a4f8b096dae454c2e03a2c1f8a4 GIT binary patch literal 58016 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 literal 0 HcmV?d00001 From 0ea2b04d5e913841e9f9db913e3c86b99bdef5a8 Mon Sep 17 00:00:00 2001 From: Torgeir Helgevold Date: Mon, 7 Nov 2016 18:26:57 -0500 Subject: [PATCH 2/2] addressing PR review items --- .../docs/ts/latest/cookbook/third-party-lib.jade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/docs/ts/latest/cookbook/third-party-lib.jade b/public/docs/ts/latest/cookbook/third-party-lib.jade index 1bbaee8c06..68200ca119 100644 --- a/public/docs/ts/latest/cookbook/third-party-lib.jade +++ b/public/docs/ts/latest/cookbook/third-party-lib.jade @@ -1,12 +1,12 @@ include ../_util-fns :marked - Traditionally, third party JavaScript libraries have been published in the form of a single minified JavaScript file. - Consumers of the library have then included the minified JavaScript file, "as is", somewhere on the page using a `script` tag. + 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 will show 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. + 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 @@ -31,7 +31,7 @@ include ../_util-fns :marked ## Creating a Third Party Library - This cookbook will show how to create a simple Hero-Profile library and publish it with support for AoT compilation and Tree Shaking. + 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. @@ -111,7 +111,7 @@ include ../_util-fns In addition to supporting AoT, the library code should also be "Tree Shakable". - Thee Shakers work best with `ES2015` JavaScript. + 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. @@ -127,7 +127,7 @@ include ../_util-fns 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 compatability with most common module loading formats. + 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. @@ -154,7 +154,7 @@ include ../_util-fns ## Publish :marked - `Rollup` wil create the `umd` bundle, but but prior to bundling, all external templates or css files must be inlined. + `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`.