├── .gitattributes ├── .gitignore ├── .travis.yml ├── generators └── app │ ├── templates │ ├── _jest.ts │ ├── travis.yml │ ├── src │ │ ├── sample.service.ts │ │ ├── sample.directive.ts │ │ ├── sample.component.ts │ │ ├── sample.pipe.ts │ │ ├── _tsconfig.spec.json │ │ ├── _tsconfig.es5.json │ │ ├── _package.json │ │ ├── index.ts │ │ └── sample.component.spec.ts │ ├── bs-config.json │ ├── _tsconfig.json │ ├── playground │ │ ├── tsconfig.json │ │ ├── _index.ts │ │ ├── _index.html │ │ ├── systemjs-angular-loader.js │ │ └── _systemjs.config.js │ ├── gitignore │ ├── npmignore │ ├── _jest-global-mocks.ts │ ├── README.MD │ ├── _package_jest.json │ ├── _package.json │ ├── _tslint.json │ ├── tools │ │ └── gulp │ │ │ └── inline-resources.js │ └── gulpfile.js │ ├── playground.js │ └── index.js ├── .editorconfig ├── package.json ├── LICENSE ├── gulpfile.js ├── test └── app.js ├── .eslintrc ├── guides └── import_non_angular_libraries.md └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .idea 4 | .vscode/* 5 | *.log 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - v10 4 | - v8 5 | - v6 6 | -------------------------------------------------------------------------------- /generators/app/templates/_jest.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular'; 2 | import './jest-global-mocks'; 3 | -------------------------------------------------------------------------------- /generators/app/templates/travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '4.2.1' 5 | -------------------------------------------------------------------------------- /generators/app/templates/src/sample.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class SampleService { 5 | 6 | constructor() { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /generators/app/templates/bs-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": { 3 | "baseDir": "src", 4 | "routes": { 5 | "/": "playground", 6 | "/node_modules/": "node_modules", 7 | "/dist/": "dist", 8 | "/.playground": ".playground" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /generators/app/templates/src/sample.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[sampleDirective]' 5 | }) 6 | export class SampleDirective { 7 | 8 | constructor(private el: ElementRef) { 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /generators/app/templates/src/sample.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'sample-component', 5 | template: `

Sample component

` 6 | }) 7 | export class SampleComponent { 8 | 9 | constructor() { 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /generators/app/templates/_tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src", 4 | "experimentalDecorators": true, 5 | "moduleResolution": "node", 6 | "rootDir": "./src", 7 | "lib": [ 8 | "es2015", 9 | "dom" 10 | ], 11 | "skipLibCheck": true, 12 | "types": [] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /generators/app/templates/src/sample.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, PipeTransform, Pipe } from '@angular/core'; 2 | 3 | /** 4 | * Transforms any input value 5 | */ 6 | @Pipe({ 7 | name: 'samplePipe' 8 | }) 9 | @Injectable() 10 | export class SamplePipe implements PipeTransform { 11 | transform(value: any, args: any[] = null): string { 12 | return value; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /generators/app/templates/playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "../.playground", 4 | "target": "es5", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "lib": [ "es2015", "dom" ], 11 | "noImplicitAny": true, 12 | "suppressImplicitAnyIndexErrors": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /generators/app/templates/src/_tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.es5.json", 3 | "compilerOptions": { 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "outDir": "../out-tsc/spec", 7 | "module": "commonjs", 8 | "target": "es6", 9 | "baseUrl": "", 10 | "types": [ 11 | "jest", 12 | "node" 13 | ] 14 | }, 15 | "files": [ 16 | "**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /generators/app/templates/gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules/* 3 | npm-debug.log 4 | 5 | # TypeScript 6 | src/*.js 7 | src/*.map 8 | src/*.d.ts 9 | 10 | # JetBrains 11 | .idea 12 | .project 13 | .settings 14 | .idea/* 15 | *.iml 16 | 17 | # VS Code 18 | .vscode/* 19 | 20 | # Windows 21 | Thumbs.db 22 | Desktop.ini 23 | 24 | # Mac 25 | .DS_Store 26 | **/.DS_Store 27 | 28 | # Ngc generated files 29 | **/*.ngfactory.ts 30 | 31 | # Build files 32 | dist/* 33 | 34 | # Playground tmp files 35 | .playground 36 | -------------------------------------------------------------------------------- /generators/app/templates/npmignore: -------------------------------------------------------------------------------- 1 | # Node 2 | node_modules/* 3 | npm-debug.log 4 | docs/* 5 | # DO NOT IGNORE TYPESCRIPT FILES FOR NPM 6 | # TypeScript 7 | # *.js 8 | # *.map 9 | # *.d.ts 10 | 11 | # JetBrains 12 | .idea 13 | .project 14 | .settings 15 | .idea/* 16 | *.iml 17 | 18 | # VS Code 19 | .vscode/* 20 | 21 | # Windows 22 | Thumbs.db 23 | Desktop.ini 24 | 25 | # Mac 26 | .DS_Store 27 | **/.DS_Store 28 | 29 | # Ngc generated files 30 | **/*.ngfactory.ts 31 | 32 | # Library files 33 | src/* 34 | build/* 35 | -------------------------------------------------------------------------------- /generators/app/templates/_jest-global-mocks.ts: -------------------------------------------------------------------------------- 1 | const mock = () => { 2 | let storage = {}; 3 | return { 4 | getItem: key => key in storage ? storage[key] : null, 5 | setItem: (key, value) => storage[key] = value || '', 6 | removeItem: key => delete storage[key], 7 | clear: () => storage = {}, 8 | }; 9 | }; 10 | 11 | Object.defineProperty(window, 'localStorage', {value: mock()}); 12 | Object.defineProperty(window, 'sessionStorage', {value: mock()}); 13 | Object.defineProperty(window, 'getComputedStyle', { 14 | value: () => ['-webkit-appearance'] 15 | }); 16 | -------------------------------------------------------------------------------- /generators/app/templates/playground/_index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is only for local test 3 | */ 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { NgModule } from '@angular/core'; 6 | import { Component } from '@angular/core'; 7 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 8 | 9 | import { SampleModule } from '<%= props.scope %><%= props.libraryName.kebabCase %>'; 10 | 11 | @Component({ 12 | selector: 'app', 13 | template: `` 14 | }) 15 | class AppComponent {} 16 | 17 | @NgModule({ 18 | bootstrap: [ AppComponent ], 19 | declarations: [ AppComponent ], 20 | imports: [ BrowserModule, SampleModule ] 21 | }) 22 | class AppModule {} 23 | 24 | platformBrowserDynamic().bootstrapModule(AppModule); 25 | -------------------------------------------------------------------------------- /generators/app/templates/playground/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= props.scope %><%= props.libraryName.original %> Playground 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | Loading AppComponent content here ... 22 | 23 | 24 | -------------------------------------------------------------------------------- /generators/app/templates/src/_tsconfig.es5.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "module": "es2015", 5 | "target": "es5", 6 | "baseUrl": ".", 7 | "stripInternal": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "moduleResolution": "node", 11 | "outDir": "../build", 12 | "rootDir": ".", 13 | "lib": [ 14 | "es2015", 15 | "dom" 16 | ], 17 | "skipLibCheck": true, 18 | "types": [] 19 | }, 20 | "angularCompilerOptions": { 21 | "annotateForClosureCompiler": true, 22 | "strictMetadataEmit": true, 23 | "skipTemplateCodegen": true, 24 | "flatModuleOutFile": "<%= props.libraryName.kebabCase %>.js", 25 | "flatModuleId": "<%= props.scope %><%= props.libraryName.kebabCase %>" 26 | }, 27 | "files": [ 28 | "./index.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /generators/app/templates/src/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.scope%><%= props.libraryName.kebabCase %>", 3 | "version": "0.1.0", 4 | "repository": { 5 | "type": "git", 6 | "url": "<%= props.gitRepositoryUrl %>" 7 | }, 8 | "author": { 9 | "name": "<%= props.author.name %>", 10 | "email": "<%= props.author.email %>" 11 | }, 12 | "keywords": [ 13 | "angular" 14 | ], 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "<%= props.gitRepositoryUrl %>/issues" 18 | }, 19 | "main": "<%= props.libraryName.kebabCase %>.umd.js", 20 | "module": "<%= props.libraryName.kebabCase %>.js", 21 | "jsnext:main": "<%= props.libraryName.kebabCase %>.js", 22 | "typings": "<%= props.libraryName.kebabCase %>.d.ts", 23 | "peerDependencies": { 24 | "@angular/core": "^4.0.0", 25 | "rxjs": "^5.1.0", 26 | "zone.js": "^0.8.4" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /generators/app/templates/src/index.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, ModuleWithProviders } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { SampleComponent } from './sample.component'; 4 | import { SampleDirective } from './sample.directive'; 5 | import { SamplePipe } from './sample.pipe'; 6 | import { SampleService } from './sample.service'; 7 | 8 | export * from './sample.component'; 9 | export * from './sample.directive'; 10 | export * from './sample.pipe'; 11 | export * from './sample.service'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | CommonModule 16 | ], 17 | declarations: [ 18 | SampleComponent, 19 | SampleDirective, 20 | SamplePipe 21 | ], 22 | exports: [ 23 | SampleComponent, 24 | SampleDirective, 25 | SamplePipe 26 | ] 27 | }) 28 | export class SampleModule { 29 | static forRoot(): ModuleWithProviders { 30 | return { 31 | ngModule: SampleModule, 32 | providers: [SampleService] 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /generators/app/templates/src/sample.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { DebugElement } from '@angular/core'; 4 | 5 | import { SampleComponent } from './sample.component'; 6 | 7 | describe('SampleComponent', () => { 8 | 9 | let comp: SampleComponent; 10 | let fixture: ComponentFixture; 11 | let de: DebugElement; 12 | let el: HTMLElement; 13 | 14 | beforeEach(() => { 15 | TestBed.configureTestingModule({ 16 | declarations: [ SampleComponent ], // declare the test component 17 | }); 18 | 19 | fixture = TestBed.createComponent(SampleComponent); 20 | 21 | comp = fixture.componentInstance; // BannerComponent test instance 22 | 23 | // query for the title

by CSS element selector 24 | de = fixture.debugElement.query(By.css('h1')); 25 | el = de.nativeElement; 26 | }); 27 | 28 | it('Should be false', () => { 29 | expect(false).toBe(true); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-angular2-library", 3 | "version": "12.5.0", 4 | "description": "Generator to create an Angular 2 library", 5 | "homepage": "https://github.com/jvandemo/generator-angular2-library", 6 | "author": { 7 | "name": "Jurgen Van de Moere", 8 | "email": "jurgen.van.de.moere@gmail.com", 9 | "url": "http://www.jvandemo.com" 10 | }, 11 | "files": [ 12 | "generators" 13 | ], 14 | "main": "generators/index.js", 15 | "keywords": [ 16 | "yeoman-generator" 17 | ], 18 | "license": "MIT", 19 | "dependencies": { 20 | "chalk": "^1.1.3", 21 | "underscore.string": "^3.3.4", 22 | "yeoman-generator": "^2.0.5", 23 | "yosay": "^2.0.0" 24 | }, 25 | "devDependencies": { 26 | "yeoman-assert": "^3.1.1", 27 | "gulp": "^3.9.1", 28 | "gulp-eslint": "^2.0.0", 29 | "gulp-exclude-gitignore": "^1.0.0", 30 | "gulp-istanbul": "^0.10.4", 31 | "gulp-mocha": "^2.2.0", 32 | "gulp-plumber": "^1.1.0", 33 | "gulp-nsp": "^3.0.1", 34 | "gulp-coveralls": "^0.1.4" 35 | }, 36 | "repository": "jvandemo/generator-angular2-library", 37 | "scripts": { 38 | "prepublish": "gulp prepublish", 39 | "test": "gulp" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jurgen Van de Moere (http://www.jvandemo.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /generators/app/playground.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const setupPlayground = 4 | (generator) => { 5 | // Copy playground 6 | generator.fs.copyTpl( 7 | generator.templatePath('playground/_systemjs.config.js'), 8 | generator.destinationPath('playground/systemjs.config.js'), 9 | { 10 | props: generator.props 11 | } 12 | ); 13 | 14 | generator.fs.copy( 15 | generator.templatePath('playground/systemjs-angular-loader.js'), 16 | generator.destinationPath('playground/systemjs-angular-loader.js') 17 | ); 18 | 19 | generator.fs.copyTpl( 20 | generator.templatePath('playground/_index.ts'), 21 | generator.destinationPath('playground/index.ts'), 22 | { 23 | props: generator.props 24 | } 25 | ); 26 | 27 | generator.fs.copyTpl( 28 | generator.templatePath('playground/_index.html'), 29 | generator.destinationPath('playground/index.html'), 30 | { 31 | props: generator.props 32 | } 33 | ); 34 | 35 | generator.fs.copy( 36 | generator.templatePath('playground/tsconfig.json'), 37 | generator.destinationPath('playground/tsconfig.json') 38 | ); 39 | 40 | generator.fs.copy( 41 | generator.templatePath('bs-config.json'), 42 | generator.destinationPath('bs-config.json') 43 | ); 44 | }; 45 | 46 | module.exports = setupPlayground; 47 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var gulp = require('gulp'); 4 | var eslint = require('gulp-eslint'); 5 | var excludeGitignore = require('gulp-exclude-gitignore'); 6 | var mocha = require('gulp-mocha'); 7 | var istanbul = require('gulp-istanbul'); 8 | var nsp = require('gulp-nsp'); 9 | var plumber = require('gulp-plumber'); 10 | var coveralls = require('gulp-coveralls'); 11 | 12 | gulp.task('static', function () { 13 | return gulp.src('**/*.js') 14 | .pipe(excludeGitignore()) 15 | .pipe(eslint()) 16 | .pipe(eslint.format()) 17 | .pipe(eslint.failAfterError()); 18 | }); 19 | 20 | gulp.task('nsp', function (cb) { 21 | nsp({package: path.resolve('package.json')}, cb); 22 | }); 23 | 24 | gulp.task('pre-test', function () { 25 | return gulp.src('generators/**/*.js') 26 | .pipe(istanbul({ 27 | includeUntested: true 28 | })) 29 | .pipe(istanbul.hookRequire()); 30 | }); 31 | 32 | gulp.task('test', ['pre-test'], function (cb) { 33 | var mochaErr; 34 | 35 | gulp.src('test/**/*.js') 36 | .pipe(plumber()) 37 | .pipe(mocha({reporter: 'spec', timeout: 60000})) 38 | .on('error', function (err) { 39 | mochaErr = err; 40 | }) 41 | .pipe(istanbul.writeReports()) 42 | .on('end', function () { 43 | cb(mochaErr); 44 | }); 45 | }); 46 | 47 | gulp.task('coveralls', ['test'], function () { 48 | if (!process.env.CI) { 49 | return; 50 | } 51 | 52 | return gulp.src(path.join(__dirname, 'coverage/lcov.info')) 53 | .pipe(coveralls()); 54 | }); 55 | 56 | gulp.task('prepublish', ['nsp']); 57 | gulp.task('default', ['static', 'test']); 58 | -------------------------------------------------------------------------------- /generators/app/templates/playground/systemjs-angular-loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; 4 | var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; 5 | var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; 6 | 7 | module.exports.translate = function (load){ 8 | if (load.source.indexOf('moduleId') !== -1) { 9 | return load; 10 | } 11 | 12 | // eslint-disable-next-line 13 | var url = document.createElement('a'); 14 | url.href = load.address; 15 | 16 | var basePathParts = url.pathname.split('/'); 17 | 18 | basePathParts.pop(); 19 | var basePath = basePathParts.join('/'); 20 | 21 | // eslint-disable-next-line 22 | var baseHref = document.createElement('a'); 23 | baseHref.href = this.baseURL; 24 | baseHref = baseHref.pathname; 25 | 26 | if (!baseHref.startsWith('/base/')) { // it is not karma 27 | basePath = basePath.replace(baseHref, ''); 28 | } 29 | 30 | load.source = load.source 31 | .replace(templateUrlRegex, function (match, quote, sourceUrl){ 32 | var resolvedUrl = sourceUrl; 33 | 34 | if (sourceUrl.startsWith('.')) { 35 | resolvedUrl = basePath + sourceUrl.substr(1); 36 | } 37 | 38 | return 'templateUrl: "' + resolvedUrl + '"'; 39 | }) 40 | .replace(stylesRegex, function (match, relativeUrls) { 41 | var urls = []; 42 | 43 | while ((match = stringRegex.exec(relativeUrls)) !== null) { 44 | if (match[2].startsWith('.')) { 45 | urls.push('"' + basePath + match[2].substr(1) + '"'); 46 | } else { 47 | urls.push('"' + match[2] + '"'); 48 | } 49 | } 50 | 51 | return 'styleUrls: [' + urls.join(', ') + ']'; 52 | }); 53 | 54 | return load; 55 | }; 56 | -------------------------------------------------------------------------------- /generators/app/templates/README.MD: -------------------------------------------------------------------------------- 1 | # <%= props.scope %><%= props.libraryName.kebabCase %> 2 | 3 | ## Installation 4 | 5 | To install this library, run: 6 | 7 | ```bash 8 | $ npm install <%= props.scope%><%= props.libraryName.kebabCase %> --save 9 | ``` 10 | 11 | ## Consuming your library 12 | 13 | Once you have published your library to npm, you can import your library in any Angular application by running: 14 | 15 | ```bash 16 | $ npm install <%= props.scope %><%= props.libraryName.kebabCase %> 17 | ``` 18 | 19 | and then from your Angular `AppModule`: 20 | 21 | ```typescript 22 | import { BrowserModule } from '@angular/platform-browser'; 23 | import { NgModule } from '@angular/core'; 24 | 25 | import { AppComponent } from './app.component'; 26 | 27 | // Import your library 28 | import { SampleModule } from '<%= props.scope %><%= props.libraryName.kebabCase %>'; 29 | 30 | @NgModule({ 31 | declarations: [ 32 | AppComponent 33 | ], 34 | imports: [ 35 | BrowserModule, 36 | 37 | // Specify your library as an import 38 | LibraryModule 39 | ], 40 | providers: [], 41 | bootstrap: [AppComponent] 42 | }) 43 | export class AppModule { } 44 | ``` 45 | 46 | Once your library is imported, you can use its components, directives and pipes in your Angular application: 47 | 48 | ```xml 49 | 50 |

51 | {{title}} 52 |

53 | 54 | ``` 55 | 56 | ## Development 57 | 58 | To generate all `*.js`, `*.d.ts` and `*.metadata.json` files: 59 | 60 | ```bash 61 | $ npm run build 62 | ``` 63 | 64 | To lint all `*.ts` files: 65 | 66 | ```bash 67 | $ npm run lint 68 | ``` 69 | 70 | ## License 71 | 72 | MIT © [<%= props.author.name %>](mailto:<%= props.author.email %>) 73 | -------------------------------------------------------------------------------- /test/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var assert = require('yeoman-assert'); 4 | var helpers = require('yeoman-test'); 5 | 6 | describe('generator-angular-2-library:app', function () { 7 | 8 | before(function (done) { 9 | 10 | helpers.run(path.join(__dirname, '../generators/app')) 11 | .withOptions({}) 12 | .withPrompts({libraryName: 'angular2-library-name'}) 13 | .on('end', done); 14 | 15 | }); 16 | 17 | it('should create package.json', function () { 18 | assert.file([ 19 | 'package.json' 20 | ]); 21 | }); 22 | 23 | it('should create tsconfig.json', function () { 24 | assert.file([ 25 | 'tsconfig.json' 26 | ]); 27 | }); 28 | 29 | it('should create .gitignore', function () { 30 | assert.file([ 31 | '.gitignore' 32 | ]); 33 | }); 34 | 35 | it('should create .npmignore', function () { 36 | assert.file([ 37 | '.npmignore' 38 | ]); 39 | }); 40 | 41 | it('should create README.MD', function () { 42 | assert.file([ 43 | 'README.MD' 44 | ]); 45 | }); 46 | 47 | it('should create main library file', function () { 48 | assert.file([ 49 | 'index.ts' 50 | ]); 51 | }); 52 | 53 | it('should create sample component', function () { 54 | assert.file([ 55 | 'src/sample.component.ts' 56 | ]); 57 | }); 58 | 59 | it('should create sample directive', function () { 60 | assert.file([ 61 | 'src/sample.directive.ts' 62 | ]); 63 | }); 64 | 65 | it('should create sample pipe', function () { 66 | assert.file([ 67 | 'src/sample.pipe.ts' 68 | ]); 69 | }); 70 | 71 | it('should create sample service', function () { 72 | assert.file([ 73 | 'src/sample.service.ts' 74 | ]); 75 | }); 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /generators/app/templates/playground/_systemjs.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * System configuration for Angular samples 4 | * Adjust as necessary for your application needs. 5 | */ 6 | (function () { 7 | System.config({ 8 | paths: { 9 | // paths serve as alias 10 | 'npm:': '../node_modules/' 11 | }, 12 | // map tells the System loader where to look for things 13 | map: { 14 | // our app is within the app folder 15 | app: 'app', 16 | 17 | // angular bundles 18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 19 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 20 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 23 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 24 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 25 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 26 | 27 | // other libraries 28 | rxjs: 'npm:rxjs', 29 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js', 30 | '<%= props.scope %><%= props.libraryName.kebabCase %>': '../dist' 31 | }, 32 | // packages tells the System loader how to load when no filename and/or no extension 33 | packages: { 34 | '.': { 35 | defaultExtension: 'js' 36 | }, 37 | app: { 38 | defaultExtension: 'js', 39 | meta: { 40 | './*.js': { 41 | loader: 'systemjs-angular-loader.js' 42 | } 43 | } 44 | }, 45 | rxjs: { 46 | defaultExtension: 'js' 47 | }, 48 | '<%= props.scope %><%= props.libraryName.kebabCase %>': { 49 | main: '<%= props.libraryName.kebabCase %>.umd.js', 50 | defaultExtension: 'js' 51 | } 52 | } 53 | }); 54 | })(this); 55 | -------------------------------------------------------------------------------- /generators/app/templates/_package_jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.scope %><%= props.libraryName.kebabCase %>", 3 | "version": "0.1.0", 4 | "scripts": { 5 | "build": "gulp build", 6 | "build:watch": "gulp", 7 | "docs": "npm run docs:build", 8 | "docs:build": "compodoc -p tsconfig.json -n <%= props.scope %><%= props.libraryName.original %> -d docs --hideGenerator", 9 | "docs:serve": "npm run docs:build -- -s", 10 | "docs:watch": "npm run docs:build -- -s -w", 11 | "lint": "tslint --type-check --project tsconfig.json src/**/*.ts", 12 | "lite": "lite-server", 13 | "playground:build": "tsc -p playground -w", 14 | "playground": "concurrently \"npm run build:watch\" \"npm run playground:build\" \"npm run lite\"", 15 | "test": "jest", 16 | "test:watch": "jest --watch", 17 | "test:ci": "jest --runInBand" 18 | }, 19 | "jest": { 20 | "preset": "jest-preset-angular", 21 | "setupTestFrameworkScriptFile": "/src/jest.ts" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "<%= props.gitRepositoryUrl %>" 26 | }, 27 | "author": { 28 | "name": "<%= props.author.name %>", 29 | "email": "<%= props.author.email %>" 30 | }, 31 | "keywords": [ 32 | "angular" 33 | ], 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "<%= props.gitRepositoryUrl %>/issues" 37 | }, 38 | "devDependencies": { 39 | "@angular/common": "^5.0.0", 40 | "@angular/compiler": "^5.0.0", 41 | "@angular/compiler-cli": "^5.0.0", 42 | "@angular/core": "^5.0.0", 43 | "@angular/platform-browser": "^5.0.0", 44 | "@angular/platform-browser-dynamic": "^5.0.0", 45 | "@compodoc/compodoc": "^1.0.0-beta.10", 46 | "@types/node": "~6.0.60", 47 | "@types/jest": "^22.0.1", 48 | "angular-in-memory-web-api": "^0.3.2", 49 | "codelyzer": "~3.2.0", 50 | "concurrently": "^3.4.0", 51 | "core-js": "^2.4.1", 52 | "fs-extra": "^5.0.0", 53 | "del": "^2.2.2", 54 | "gulp": "^3.9.1", 55 | "gulp-rename": "^1.2.2", 56 | "gulp-rollup": "^2.11.0", 57 | "jest": "^22.1.4", 58 | "jest-preset-angular": "^5.0.0", 59 | "lite-server": "^2.3.0", 60 | "node-sass": "^4.5.2", 61 | "node-sass-tilde-importer": "^1.0.0", 62 | "node-watch": "^0.5.2", 63 | "protractor": "~5.1.2", 64 | "rollup": "^0.49.3", 65 | "run-sequence": "^1.2.2", 66 | "rxjs": "^5.5.2", 67 | "systemjs": "^0.20.12", 68 | "ts-node": "~3.2.0", 69 | "tslint": "~5.7.0", 70 | "typescript": "~2.4.2", 71 | "zone.js": "^0.8.14" 72 | }, 73 | "engines": { 74 | "node": ">=6.0.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /generators/app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= props.scope %><%= props.libraryName.kebabCase %>", 3 | "version": "0.1.0", 4 | "scripts": { 5 | "build": "gulp build", 6 | "build:watch": "gulp", 7 | "docs": "npm run docs:build", 8 | "docs:build": "compodoc -p tsconfig.json -n <%= props.scope%><%= props.libraryName.original %> -d docs --hideGenerator", 9 | "docs:serve": "npm run docs:build -- -s", 10 | "docs:watch": "npm run docs:build -- -s -w", 11 | "lint": "tslint --type-check --project tsconfig.json src/**/*.ts", 12 | "lite": "lite-server", 13 | "playground:build": "tsc -p playground -w", 14 | "playground": "concurrently \"npm run build:watch\" \"npm run playground:build\" \"npm run lite\"", 15 | "test": "tsc && karma start" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "<%= props.gitRepositoryUrl %>" 20 | }, 21 | "author": { 22 | "name": "<%= props.author.name %>", 23 | "email": "<%= props.author.email %>" 24 | }, 25 | "keywords": [ 26 | "angular" 27 | ], 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "<%= props.gitRepositoryUrl %>/issues" 31 | }, 32 | "devDependencies": { 33 | "@angular/common": "^5.0.0", 34 | "@angular/compiler": "^5.0.0", 35 | "@angular/compiler-cli": "^5.0.0", 36 | "@angular/core": "^5.0.0", 37 | "@angular/platform-browser": "^5.0.0", 38 | "@angular/platform-browser-dynamic": "^5.0.0", 39 | "@compodoc/compodoc": "^1.0.0-beta.10", 40 | "@types/jasmine": "2.5.53", 41 | "@types/node": "~6.0.60", 42 | "angular-in-memory-web-api": "^0.3.2", 43 | "codelyzer": "~3.2.0", 44 | "concurrently": "^3.4.0", 45 | "core-js": "^2.4.1", 46 | "fs-extra": "^5.0.0", 47 | "gulp": "^3.9.1", 48 | "gulp-rename": "^1.2.2", 49 | "gulp-rollup": "^2.15.0", 50 | "jasmine-core": "~2.6.2", 51 | "jasmine-spec-reporter": "~4.1.0", 52 | "karma": "~1.7.0", 53 | "karma-chrome-launcher": "~2.1.1", 54 | "karma-cli": "~1.0.1", 55 | "karma-coverage-istanbul-reporter": "^1.2.1", 56 | "karma-jasmine": "~1.1.0", 57 | "karma-jasmine-html-reporter": "^0.2.2", 58 | "lite-server": "^2.3.0", 59 | "node-sass": "^4.5.2", 60 | "node-sass-tilde-importer": "^1.0.0", 61 | "node-watch": "^0.5.2", 62 | "protractor": "~5.1.2", 63 | "rollup": "^0.49.3", 64 | "run-sequence": "^1.2.2", 65 | "rxjs": "^5.5.2", 66 | "systemjs": "^0.20.12", 67 | "ts-node": "~3.2.0", 68 | "tslint": "~5.7.0", 69 | "typescript": "~2.4.2", 70 | "zone.js": "^0.8.14" 71 | }, 72 | "engines": { 73 | "node": ">=6.0.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "mocha": true, 6 | "es6": true 7 | }, 8 | "rules": { 9 | "array-bracket-spacing": [ 10 | 2, 11 | "never" 12 | ], 13 | "brace-style": [ 14 | 2, 15 | "1tbs" 16 | ], 17 | "consistent-return": 0, 18 | "indent": [ 19 | 2, 20 | 2 21 | ], 22 | "no-multiple-empty-lines": [ 23 | 2, 24 | { 25 | "max": 2 26 | } 27 | ], 28 | "no-use-before-define": [ 29 | 2, 30 | "nofunc" 31 | ], 32 | "one-var": [ 33 | 2, 34 | "never" 35 | ], 36 | "quote-props": [ 37 | 2, 38 | "as-needed" 39 | ], 40 | "quotes": [ 41 | 2, 42 | "single" 43 | ], 44 | "keyword-spacing": 2, 45 | "space-before-function-paren": [ 46 | 2, 47 | { 48 | "anonymous": "always", 49 | "named": "never" 50 | } 51 | ], 52 | "space-in-parens": [ 53 | 2, 54 | "never" 55 | ], 56 | "strict": [ 57 | 2, 58 | "global" 59 | ], 60 | "curly": [ 61 | 2, 62 | "all" 63 | ], 64 | "eol-last": 2, 65 | "key-spacing": [ 66 | 2, 67 | { 68 | "beforeColon": false, 69 | "afterColon": true 70 | } 71 | ], 72 | "no-eval": 2, 73 | "no-with": 2, 74 | "space-infix-ops": 2, 75 | "dot-notation": [ 76 | 2, 77 | { 78 | "allowKeywords": true 79 | } 80 | ], 81 | "eqeqeq": 2, 82 | "no-alert": 2, 83 | "no-caller": 2, 84 | "no-extend-native": 2, 85 | "no-extra-bind": 2, 86 | "no-implied-eval": 2, 87 | "no-iterator": 2, 88 | "no-label-var": 2, 89 | "no-labels": 2, 90 | "no-lone-blocks": 2, 91 | "no-loop-func": 2, 92 | "no-multi-spaces": 2, 93 | "no-multi-str": 2, 94 | "no-native-reassign": 2, 95 | "no-new": 2, 96 | "no-new-func": 2, 97 | "no-new-wrappers": 2, 98 | "no-octal-escape": 2, 99 | "no-proto": 2, 100 | "no-return-assign": 2, 101 | "no-script-url": 2, 102 | "no-sequences": 2, 103 | "no-unused-expressions": 2, 104 | "yoda": 2, 105 | "no-shadow": 2, 106 | "no-shadow-restricted-names": 2, 107 | "no-undef-init": 2, 108 | "camelcase": 2, 109 | "comma-spacing": 2, 110 | "new-cap": 0, 111 | "new-parens": 2, 112 | "no-array-constructor": 2, 113 | "no-extra-parens": 2, 114 | "no-new-object": 2, 115 | "no-spaced-func": 2, 116 | "no-trailing-spaces": 2, 117 | "no-underscore-dangle": 2, 118 | "semi": 2, 119 | "semi-spacing": [ 120 | 2, 121 | { 122 | "before": false, 123 | "after": true 124 | } 125 | ] 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /generators/app/templates/_tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "class-name": true, 7 | "comment-format": [ 8 | true, 9 | "check-space" 10 | ], 11 | "curly": true, 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [ 15 | true, 16 | "spaces" 17 | ], 18 | "label-position": true, 19 | "max-line-length": [ 20 | true, 21 | 140 22 | ], 23 | "member-access": false, 24 | "member-ordering": [ 25 | true, 26 | "static-before-instance", 27 | "variables-before-functions" 28 | ], 29 | "no-arg": true, 30 | "no-bitwise": true, 31 | "no-console": [ 32 | true, 33 | "debug", 34 | "info", 35 | "time", 36 | "timeEnd", 37 | "trace" 38 | ], 39 | "no-construct": true, 40 | "no-debugger": true, 41 | "no-duplicate-variable": true, 42 | "no-empty": false, 43 | "no-eval": true, 44 | "no-inferrable-types": true, 45 | "no-shadowed-variable": true, 46 | "no-string-literal": false, 47 | "no-switch-case-fall-through": true, 48 | "no-trailing-whitespace": true, 49 | "no-unused-expression": true, 50 | "no-unused-variable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | true, 68 | "always" 69 | ], 70 | "triple-equals": [ 71 | true, 72 | "allow-null-check" 73 | ], 74 | "typedef-whitespace": [ 75 | true, 76 | { 77 | "call-signature": "nospace", 78 | "index-signature": "nospace", 79 | "parameter": "nospace", 80 | "property-declaration": "nospace", 81 | "variable-declaration": "nospace" 82 | } 83 | ], 84 | "variable-name": false, 85 | "whitespace": [ 86 | true, 87 | "check-branch", 88 | "check-decl", 89 | "check-operator", 90 | "check-separator", 91 | "check-type" 92 | ], 93 | "directive-selector": [true, "attribute", "", "camelCase"], 94 | "component-selector": [true, "element", "", "kebab-case"], 95 | "use-input-property-decorator": true, 96 | "use-output-property-decorator": true, 97 | "use-host-property-decorator": true, 98 | "no-input-rename": true, 99 | "no-output-rename": true, 100 | "use-life-cycle-interface": true, 101 | "use-pipe-transform-interface": true, 102 | "component-class-suffix": true, 103 | "directive-class-suffix": true 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /generators/app/templates/tools/gulp/inline-resources.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // https://github.com/filipesilva/angular-quickstart-lib/blob/master/inline-resources.js 3 | 'use strict'; 4 | 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | const glob = require('glob'); 8 | const sass = require('node-sass'); 9 | const tildeImporter = require('node-sass-tilde-importer'); 10 | 11 | /** 12 | * Simple Promiseify function that takes a Node API and return a version that supports promises. 13 | * We use promises instead of synchronized functions to make the process less I/O bound and 14 | * faster. It also simplifies the code. 15 | */ 16 | function promiseify(fn) { 17 | return function () { 18 | const args = [].slice.call(arguments, 0); 19 | return new Promise((resolve, reject) => { 20 | fn.apply(this, args.concat([function (err, value) { 21 | if (err) { 22 | reject(err); 23 | } else { 24 | resolve(value); 25 | } 26 | }])); 27 | }); 28 | }; 29 | } 30 | 31 | const readFile = promiseify(fs.readFile); 32 | const writeFile = promiseify(fs.writeFile); 33 | 34 | /** 35 | * Inline resources in a tsc/ngc compilation. 36 | * @param projectPath {string} Path to the project. 37 | */ 38 | function inlineResources(projectPath) { 39 | 40 | // Match only TypeScript files in projectPath. 41 | const files = glob.sync('**/*.ts', {cwd: projectPath}); 42 | 43 | // For each file, inline the templates and styles under it and write the new file. 44 | return Promise.all(files.map(filePath => { 45 | const fullFilePath = path.join(projectPath, filePath); 46 | return readFile(fullFilePath, 'utf-8') 47 | .then(content => inlineResourcesFromString(content, url => { 48 | // Resolve the template url. 49 | return path.join(path.dirname(fullFilePath), url); 50 | })) 51 | .then(content => writeFile(fullFilePath, content)) 52 | .catch(err => { 53 | console.error('An error occured: ', err); 54 | }); 55 | })); 56 | } 57 | 58 | /** 59 | * Inline resources from a string content. 60 | * @param content {string} The source file's content. 61 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 62 | * @returns {string} The content with resources inlined. 63 | */ 64 | function inlineResourcesFromString(content, urlResolver) { 65 | // Curry through the inlining functions. 66 | return [ 67 | inlineTemplate, 68 | inlineStyle, 69 | removeModuleId 70 | ].reduce((content, fn) => fn(content, urlResolver), content); 71 | } 72 | 73 | /** 74 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and 75 | * replace with `template: ...` (with the content of the file included). 76 | * @param content {string} The source file's content. 77 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 78 | * @return {string} The content with all templates inlined. 79 | */ 80 | function inlineTemplate(content, urlResolver) { 81 | return content.replace(/templateUrl:\s*(['"])([^\1]+?\.html)\1/g, function (fullMatch, quote, templateUrl) { 82 | const templateFile = urlResolver(templateUrl); 83 | const templateContent = fs.readFileSync(templateFile, 'utf-8'); 84 | const shortenedTemplate = templateContent 85 | .replace(/([\n\r]\s*)+/gm, ' ') 86 | .replace(/"/g, '\\"'); 87 | return `template: "${shortenedTemplate}"`; 88 | }); 89 | } 90 | 91 | 92 | /** 93 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and 94 | * replace with `styles: [...]` (with the content of the file included). 95 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 96 | * @param content {string} The source file's content. 97 | * @return {string} The content with all styles inlined. 98 | */ 99 | function inlineStyle(content, urlResolver) { 100 | return content.replace(/styleUrls\s*:\s*(\[[\s\S]*?\])/gm, function (m, styleUrls) { 101 | const urls = eval(styleUrls); 102 | return 'styles: [' 103 | + urls.map(styleUrl => { 104 | const styleFile = urlResolver(styleUrl); 105 | const originContent = fs.readFileSync(styleFile, 'utf-8'); 106 | const styleContent = styleFile.endsWith('.scss') ? buildSass(originContent, styleFile) : originContent; 107 | const shortenedStyle = styleContent 108 | .replace(/([\n\r]\s*)+/gm, ' ') 109 | .replace(/"/g, '\\"'); 110 | return `"${shortenedStyle}"`; 111 | }) 112 | .join(',\n') 113 | + ']'; 114 | }); 115 | } 116 | 117 | /** 118 | * build sass content to css 119 | * @param content {string} the css content 120 | * @param sourceFile {string} the scss file sourceFile 121 | * @return {string} the generated css, empty string if error occured 122 | */ 123 | function buildSass(content, sourceFile) { 124 | try { 125 | const result = sass.renderSync({ 126 | data: content, 127 | file: sourceFile, 128 | importer: tildeImporter 129 | }); 130 | return result.css.toString() 131 | } catch (e) { 132 | console.error('\x1b[41m'); 133 | console.error('at ' + sourceFile + ':' + e.line + ":" + e.column); 134 | console.error(e.formatted); 135 | console.error('\x1b[0m'); 136 | return ""; 137 | } 138 | } 139 | 140 | /** 141 | * Remove every mention of `moduleId: module.id`. 142 | * @param content {string} The source file's content. 143 | * @returns {string} The content with all moduleId: mentions removed. 144 | */ 145 | function removeModuleId(content) { 146 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, ''); 147 | } 148 | 149 | module.exports = inlineResources; 150 | module.exports.inlineResourcesFromString = inlineResourcesFromString; 151 | 152 | // Run inlineResources if module is being called directly from the CLI with arguments. 153 | if (require.main === module && process.argv.length > 2) { 154 | console.log('Inlining resources from project:', process.argv[2]); 155 | return inlineResources(process.argv[2]); 156 | } 157 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const chalk = require('chalk'); 3 | const yosay = require('yosay'); 4 | const underscoreString = require('underscore.string'); 5 | const Generator = require('yeoman-generator'); 6 | const setupPlaygorund = require('./playground'); 7 | 8 | module.exports = class extends Generator { 9 | 10 | constructor(args, opts) { 11 | super(args, opts); 12 | } 13 | 14 | initializing() { 15 | // Have Yeoman greet the user. 16 | this.log(yosay( 17 | 'Welcome to the ' + chalk.red('Angular Library') + ' generator!' 18 | )); 19 | } 20 | 21 | prompting() { 22 | const prompts = [ 23 | { 24 | type: 'input', 25 | name: 'authorName', 26 | message: 'Your full name:', 27 | validate: function (input) { 28 | if (/.+/.test(input)) { 29 | return true; 30 | } 31 | return 'Please enter your full name'; 32 | }, 33 | default: this.user.git.name 34 | }, 35 | { 36 | type: 'input', 37 | name: 'authorEmail', 38 | message: 'Your email address:', 39 | validate: function (input) { 40 | if (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(input)) { 41 | return true; 42 | } 43 | return 'Please enter a valid email address'; 44 | }, 45 | default: this.user.git.email 46 | }, 47 | { 48 | type: 'input', 49 | name: 'libraryName', 50 | message: 'Your library name (kebab-case)', 51 | default: underscoreString.slugify(this.appname), 52 | filter: function (x) { 53 | return underscoreString.slugify(x); 54 | } 55 | }, 56 | { 57 | type: 'input', 58 | name: 'scope', 59 | message: 'Your library scope (eg: @angular) leave blank for none', 60 | default: '', 61 | validate: function (x) { 62 | return !x || x.indexOf('@') === 0; 63 | }, 64 | filter: function (x) { 65 | return x ? x + '/' : ''; 66 | } 67 | }, 68 | { 69 | type: 'input', 70 | name: 'gitRepositoryUrl', 71 | message: 'Git repository url', 72 | default: 'https://github.com/username/repo', 73 | store: true 74 | }, 75 | { 76 | type: 'list', 77 | name: 'testFramework', 78 | message: 'Test framework', 79 | choices: [ 80 | 'karma + jasmine', 81 | 'jest' 82 | ] 83 | } 84 | ]; 85 | 86 | return this.prompt(prompts).then(props => { 87 | 88 | this.props = { 89 | 90 | author: { 91 | name: props.authorName, 92 | email: props.authorEmail 93 | }, 94 | 95 | libraryName: { 96 | original: props.libraryName, 97 | kebabCase: props.libraryName 98 | }, 99 | 100 | gitRepositoryUrl: props.gitRepositoryUrl, 101 | 102 | testFramework: props.testFramework, 103 | 104 | scope: props.scope 105 | }; 106 | 107 | }); 108 | } 109 | 110 | writing() { 111 | 112 | // Copy .gitignore 113 | this.fs.copy( 114 | this.templatePath('gitignore'), 115 | this.destinationPath('.gitignore') 116 | ); 117 | 118 | // Copy .npmignore 119 | this.fs.copy( 120 | this.templatePath('npmignore'), 121 | this.destinationPath('.npmignore') 122 | ); 123 | 124 | // Copy .travis.yml 125 | this.fs.copy( 126 | this.templatePath('travis.yml'), 127 | this.destinationPath('.travis.yml') 128 | ); 129 | 130 | // Copy tsconfig.json 131 | this.fs.copyTpl( 132 | this.templatePath('_tsconfig.json'), 133 | this.destinationPath('tsconfig.json'), 134 | { 135 | props: this.props 136 | } 137 | ); 138 | 139 | // Copy tslint.json 140 | this.fs.copyTpl( 141 | this.templatePath('_tslint.json'), 142 | this.destinationPath('tslint.json'), 143 | { 144 | props: this.props 145 | } 146 | ); 147 | 148 | // Copy package.json 149 | if (this.props.testFramework === 'jest') { 150 | this.fs.copyTpl( 151 | this.templatePath('_package_jest.json'), 152 | this.destinationPath('package.json'), 153 | { 154 | props: this.props 155 | } 156 | ); 157 | 158 | this.fs.copyTpl( 159 | this.templatePath('_jest.ts'), 160 | this.destinationPath('src/jest.ts') 161 | ); 162 | 163 | this.fs.copyTpl( 164 | this.templatePath('_jest-global-mocks.ts'), 165 | this.destinationPath('src/jest-global-mocks.ts') 166 | ); 167 | } else { 168 | this.fs.copyTpl( 169 | this.templatePath('_package.json'), 170 | this.destinationPath('package.json'), 171 | { 172 | props: this.props 173 | } 174 | ); 175 | } 176 | 177 | // Copy README 178 | this.fs.copyTpl( 179 | this.templatePath('README.MD'), 180 | this.destinationPath('README.MD'), 181 | { 182 | props: this.props 183 | } 184 | ); 185 | 186 | // Copy tools directory 187 | this.fs.copyTpl( 188 | this.templatePath('tools/**/*'), 189 | this.destinationPath('tools') 190 | ); 191 | 192 | // Copy gulpfile.js 193 | this.fs.copyTpl( 194 | this.templatePath('gulpfile.js'), 195 | this.destinationPath('gulpfile.js'), 196 | { 197 | props: this.props 198 | } 199 | ); 200 | 201 | // Copy src folder 202 | this.fs.copy( 203 | this.templatePath('src/**/*.ts'), 204 | this.destinationPath('src') 205 | ); 206 | 207 | // Copy src/package.json 208 | this.fs.copyTpl( 209 | this.templatePath('src/_package.json'), 210 | this.destinationPath('src/package.json'), 211 | { 212 | props: this.props 213 | } 214 | ); 215 | 216 | // Copy src/tsconfig.es5.json 217 | this.fs.copyTpl( 218 | this.templatePath('src/_tsconfig.es5.json'), 219 | this.destinationPath('src/tsconfig.es5.json'), 220 | { 221 | props: this.props 222 | } 223 | ); 224 | 225 | // Copy src/tsconfig.spec.json 226 | this.fs.copyTpl( 227 | this.templatePath('src/_tsconfig.spec.json'), 228 | this.destinationPath('src/tsconfig.spec.json') 229 | ); 230 | 231 | setupPlaygorund(this); 232 | } 233 | 234 | install() { 235 | this.installDependencies({bower: false}); 236 | } 237 | }; 238 | -------------------------------------------------------------------------------- /generators/app/templates/gulpfile.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var gulp = require('gulp'), 3 | path = require('path'), 4 | ngc = require('@angular/compiler-cli/src/main').main, 5 | rollup = require('gulp-rollup'), 6 | rename = require('gulp-rename'), 7 | fs = require('fs-extra'), 8 | runSequence = require('run-sequence'), 9 | inlineResources = require('./tools/gulp/inline-resources'); 10 | 11 | const rootFolder = path.join(__dirname); 12 | const srcFolder = path.join(rootFolder, 'src'); 13 | const tmpFolder = path.join(rootFolder, '.tmp'); 14 | const buildFolder = path.join(rootFolder, 'build'); 15 | const distFolder = path.join(rootFolder, 'dist'); 16 | 17 | /** 18 | * 1. Delete /dist folder 19 | */ 20 | gulp.task('clean:dist', function () { 21 | 22 | // Delete contents but not dist folder to avoid broken npm links 23 | // when dist directory is removed while npm link references it. 24 | return fs.emptyDirSync(distFolder); 25 | }); 26 | 27 | /** 28 | * 2. Clone the /src folder into /.tmp. If an npm link inside /src has been made, 29 | * then it's likely that a node_modules folder exists. Ignore this folder 30 | * when copying to /.tmp. 31 | */ 32 | gulp.task('copy:source', function () { 33 | return gulp.src([`${srcFolder}/**/*`, `!${srcFolder}/node_modules`]) 34 | .pipe(gulp.dest(tmpFolder)); 35 | }); 36 | 37 | /** 38 | * 3. Inline template (.html) and style (.css) files into the the component .ts files. 39 | * We do this on the /.tmp folder to avoid editing the original /src files 40 | */ 41 | gulp.task('inline-resources', function () { 42 | return Promise.resolve() 43 | .then(() => inlineResources(tmpFolder)); 44 | }); 45 | 46 | 47 | /** 48 | * 4. Run the Angular compiler, ngc, on the /.tmp folder. This will output all 49 | * compiled modules to the /build folder. 50 | * 51 | * As of Angular 5, ngc accepts an array and no longer returns a promise. 52 | */ 53 | gulp.task('ngc', function () { 54 | ngc(['--project', `${tmpFolder}/tsconfig.es5.json`]); 55 | return Promise.resolve() 56 | }); 57 | 58 | /** 59 | * 5. Run rollup inside the /build folder to generate our Flat ES module and place the 60 | * generated file into the /dist folder 61 | */ 62 | gulp.task('rollup:fesm', function () { 63 | return gulp.src(`${buildFolder}/**/*.js`) 64 | // transform the files here. 65 | .pipe(rollup({ 66 | 67 | // Bundle's entry point 68 | // See "input" in https://rollupjs.org/#core-functionality 69 | input: `${buildFolder}/index.js`, 70 | 71 | // Allow mixing of hypothetical and actual files. "Actual" files can be files 72 | // accessed by Rollup or produced by plugins further down the chain. 73 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system 74 | // when subdirectories are used in the `src` directory. 75 | allowRealFiles: true, 76 | 77 | // A list of IDs of modules that should remain external to the bundle 78 | // See "external" in https://rollupjs.org/#core-functionality 79 | external: [ 80 | '@angular/core', 81 | '@angular/common' 82 | ], 83 | 84 | output: { 85 | // Format of generated bundle 86 | // See "format" in https://rollupjs.org/#core-functionality 87 | format: 'es' 88 | } 89 | })) 90 | .pipe(gulp.dest(distFolder)); 91 | }); 92 | 93 | /** 94 | * 6. Run rollup inside the /build folder to generate our UMD module and place the 95 | * generated file into the /dist folder 96 | */ 97 | gulp.task('rollup:umd', function () { 98 | return gulp.src(`${buildFolder}/**/*.js`) 99 | // transform the files here. 100 | .pipe(rollup({ 101 | 102 | // Bundle's entry point 103 | // See "input" in https://rollupjs.org/#core-functionality 104 | input: `${buildFolder}/index.js`, 105 | 106 | // Allow mixing of hypothetical and actual files. "Actual" files can be files 107 | // accessed by Rollup or produced by plugins further down the chain. 108 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system 109 | // when subdirectories are used in the `src` directory. 110 | allowRealFiles: true, 111 | 112 | // A list of IDs of modules that should remain external to the bundle 113 | // See "external" in https://rollupjs.org/#core-functionality 114 | external: [ 115 | '@angular/core', 116 | '@angular/common' 117 | ], 118 | 119 | output: { 120 | // The name to use for the module for UMD/IIFE bundles 121 | // (required for bundles with exports) 122 | // See "name" in https://rollupjs.org/#core-functionality 123 | name: '<%= props.libraryName.original %>', 124 | 125 | // See "globals" in https://rollupjs.org/#core-functionality 126 | globals: { 127 | typescript: 'ts' 128 | }, 129 | 130 | // Format of generated bundle 131 | // See "format" in https://rollupjs.org/#core-functionality 132 | format: 'umd', 133 | 134 | // Export mode to use 135 | // See "exports" in https://rollupjs.org/#danger-zone 136 | exports: 'named' 137 | } 138 | 139 | })) 140 | .pipe(rename('<%= props.libraryName.kebabCase %>.umd.js')) 141 | .pipe(gulp.dest(distFolder)); 142 | }); 143 | 144 | /** 145 | * 7. Copy all the files from /build to /dist, except .js files. We ignore all .js from /build 146 | * because with don't need individual modules anymore, just the Flat ES module generated 147 | * on step 5. 148 | */ 149 | gulp.task('copy:build', function () { 150 | return gulp.src([`${buildFolder}/**/*`, `!${buildFolder}/**/*.js`]) 151 | .pipe(gulp.dest(distFolder)); 152 | }); 153 | 154 | /** 155 | * 8. Copy package.json from /src to /dist 156 | */ 157 | gulp.task('copy:manifest', function () { 158 | return gulp.src([`${srcFolder}/package.json`]) 159 | .pipe(gulp.dest(distFolder)); 160 | }); 161 | 162 | /** 163 | * 9. Copy README.md from / to /dist 164 | */ 165 | gulp.task('copy:readme', function () { 166 | return gulp.src([path.join(rootFolder, 'README.MD')]) 167 | .pipe(gulp.dest(distFolder)); 168 | }); 169 | 170 | /** 171 | * 10. Delete /.tmp folder 172 | */ 173 | gulp.task('clean:tmp', function () { 174 | return deleteFolder(tmpFolder); 175 | }); 176 | 177 | /** 178 | * 11. Delete /build folder 179 | */ 180 | gulp.task('clean:build', function () { 181 | return deleteFolder(buildFolder); 182 | }); 183 | 184 | gulp.task('compile', function () { 185 | runSequence( 186 | 'clean:dist', 187 | 'copy:source', 188 | 'inline-resources', 189 | 'ngc', 190 | 'rollup:fesm', 191 | 'rollup:umd', 192 | 'copy:build', 193 | 'copy:manifest', 194 | 'copy:readme', 195 | 'clean:build', 196 | 'clean:tmp', 197 | function (err) { 198 | if (err) { 199 | console.log('ERROR:', err.message); 200 | deleteFolder(distFolder); 201 | deleteFolder(tmpFolder); 202 | deleteFolder(buildFolder); 203 | } else { 204 | console.log('Compilation finished succesfully'); 205 | } 206 | }); 207 | }); 208 | 209 | /** 210 | * Watch for any change in the /src folder and compile files 211 | */ 212 | gulp.task('watch', function () { 213 | gulp.watch(`${srcFolder}/**/*`, ['compile']); 214 | }); 215 | 216 | gulp.task('clean', function (callback) { 217 | runSequence('clean:dist', 'clean:tmp', 'clean:build', callback); 218 | }); 219 | 220 | gulp.task('build', function (callback) { 221 | runSequence('clean', 'compile', callback); 222 | }); 223 | 224 | gulp.task('build:watch', function (callback) { 225 | runSequence('build', 'watch', callback); 226 | }); 227 | 228 | gulp.task('default', ['build:watch']); 229 | 230 | /** 231 | * Deletes the specified folder 232 | */ 233 | function deleteFolder(folder) { 234 | return fs.removeSync(folder); 235 | } 236 | -------------------------------------------------------------------------------- /guides/import_non_angular_libraries.md: -------------------------------------------------------------------------------- 1 | - Last updated: 2017-08-16 2 | - Written by: [Ka Tam](https://github.com/kktam) 3 | 4 | ## generator-angular-2-library help guide 5 | 6 | ## How to import non Angular libraries into your own project 7 | 8 | To begin, first follow the general installation guide in the [README.md](https://github.com/kktam/generator-angular2-library) of generator-angular2-library. 9 | 10 | The demo projects for instructions described below are in the following Github projects. 11 | 12 | [Full Calendar reusable component project](https://github.com/kktam/fullcalendar-ag4), and 13 | [Full Calendar demo app, using the reusable component](https://github.com/kktam/fullcalendar-app-ag4) 14 | 15 | ### General installation of new generator-angular-2-library based project 16 | 17 | Simply run the generator and install the dependencies to start a new project. 18 | 19 | ``` 20 | yo angular2-library 21 | npm i 22 | npm run build 23 | ``` 24 | 25 | ### Structure of the project 26 | 27 | An important note to make about projects created by generator-angular-2-library is that the project contains 2 package.json files. The first one is located at ROOT\package.json and the second one at ROOT\src\package.json. The first package file is responsible to combine the project, like any other Angular project for build, run and distribution etc. So it has all the regular things a standard package.json would have, such as scripts, dependencies and devDependencies. 28 | 29 | The second package file, however, is only responsible for describing the packaging steps used for creation of UMD builds, as required by npm repository. For more information about npm's requirement in package.json, please goto [npm package.json explained](https://docs.npmjs.com/cli/build) 30 | 31 | ### Import non Angular based 3rd party library 32 | 33 | We will use FullCalendar.io as an example. 34 | 35 | To install FullCalendar.io use yarn or npm to install the npm package 36 | 37 | ``` 38 | npm install fullcalendar 39 | ``` 40 | 41 | This will install the fullcalendar name into the dependencies section of ROOT\package.json. This is important as the library package need to have all its dependencies at any given time in order to compile and run the projects. 42 | 43 | After the first install the ROOT\package.json will look like this 44 | 45 | ``` 46 | "dependencies": { 47 | "fullcalendar": "^3.4.0" 48 | } 49 | ``` 50 | 51 | Next open the ROOT\src\package.json 52 | 53 | The contents of ROOT\src\package.json are not managed either by npm, or by the generator itself. Therefore, the user must edit the contents of the ROOT\src\package.json manually, and **ensure** the peerDependencies section of the file matches all the contents of the dependencies section of ROOT\package.json. 54 | 55 | A common error is that, during the course of re-usable component library development, it is easy to forget to update the ROOT\src\package.json and it is missing a couple of libraries that was in the ROOT\package.json file. As a result, when the re-usable component project is imported into the host application, the running application will throw a module not found exception. 56 | 57 | In order to run libraries created from other technologies such as JQuery or just using pure Javascript, ES2015 support may be required, especially when those libraries were not ES6 compliant. In order to enable ES2015 support, simply open tsconfig.json, and edit following 58 | 59 | ``` 60 | "lib": [ 61 | "es2015", 62 | "es2015.iterable", 63 | "dom" 64 | ], 65 | ``` 66 | 67 | There is also a default setting that needed to be changed, to support ES2015 by the AOT compiler. 68 | The change is the set annotateForClosureCompiler flag to false for ES2015 dependencies. If the reusable component project does not have any ES5 dependencies, this step is not required. 69 | 70 | To change, open the file at ROOT\src\tsconfig.es5.json and edit the following 71 | 72 | ``` 73 | "angularCompilerOptions": { 74 | "annotateForClosureCompiler": false, 75 | ... 76 | }, 77 | ``` 78 | 79 | If the setting is not done correctly, then compiling the library will result in error. This is documented in Angular's [AOT issue](https://github.com/angular/angular/issues/16084) 80 | 81 | ### Setting up Types for TypeScript 82 | 83 | Since Angular 4 uses TypeScript for tooling and automation, and much of Angular 4's library is written in TypeScript. Therefore all of non-Angular based libraries used in an Angular project must be coupled with a "type" definition. Fortunately Angular and the open source community have created a lot of type definitions that are ready to use. Please go to [@types](https://www.npmjs.com/~types) npm repository for a complete list of type definition available. 84 | 85 | In the case of wrapping FullCalendar in our re-usable component, we will need @types/fullcalendar. Since we will also need jquery to locate elements in native DOM, and create javascript component directly on it (ES5 ways of creating most JavaScript components), the final dependencies for ROOT\package.json will now look like this: 86 | 87 | ``` 88 | "dependencies": { 89 | "@types/fullcalendar": "^2.7.44", 90 | "@types/jquery": "3.2.5", 91 | "fullcalendar": "^3.4.0", 92 | "jasmine": "^2.6.0", 93 | "jquery": "^3.2.1" 94 | } 95 | ``` 96 | 97 | You may need to install some extra typings that the types depends on. In my case, I have to install the following typings to compile all the dependencies. 98 | 99 | ``` 100 | typings install core-js es6-shim jasmine node --save 101 | ``` 102 | 103 | ### Instantiate the jQuery components 104 | 105 | First of all, the $ symbol we got to use and familiar with JQuery cannot be used in Angular 4 projects. Therefore, to use JQuery, first import and rename the imported component. Then use .default command call the static typed [constructor](http://definitelytyped.org/docs/angularjs--angular-route/interfaces/jquerystatic.html), like so: 106 | 107 | ``` 108 | import * as jqueryProxy from 'jquery' 109 | const jquery: JQueryStatic = (jqueryProxy).default || jqueryProxy; 110 | ``` 111 | 112 | finally to instantiate the JavaScript typed component, one can hook to the ngAfterViewInit event, and use jquery to search for element install underneath it. 113 | 114 | ``` 115 | ngAfterViewInit() { 116 | setTimeout(() => { 117 | jquery('calendar-component').fullCalendar(this.options); 118 | }, 100); 119 | } 120 | ``` 121 | 122 | ### Importing CSS provided by 3rd Party library 123 | 124 | Most 3rd party library provides a default suite of CSS files to provide a default theme for use with the library. It is useful to have the re-usable component project bundle the necessary CSS files, instead of having the target users of the re-usable component project, having to download or import the CSS files form a hosted CDN, manually import them again from npm, etc. 125 | 126 | To include native css from 3rd party libraries, create a ROOT\src\styles.css and include all of FullCalendar's css in this file. Once again the ~ import rule will direct to search from the nearest node_modules. 127 | 128 | ``` 129 | @import "~fullcalendar/dist/fullcalendar.css"; 130 | @import "~fullcalendar/dist/fullcalendar.print.css"; 131 | ``` 132 | 133 | generator-angular2-library does not have steps to copy css files manually added into the UMD distribution. 134 | 135 | in ROOT\package.json, install CPX, a copy tool with watches [npm](https://www.npmjs.com/package/cpx) and [github](https://github.com/mysticatea/cpx), and create a step to copy all he necessary css files into dist folder 136 | 137 | ``` 138 | "scripts": { 139 | ... 140 | "build:copy": "cpx 'src/styles.css' dist/", 141 | ... 142 | "devDependencies": { 143 | ... 144 | "cpx": "^1.5.0" 145 | }, 146 | ``` 147 | 148 | 149 | ### Things to add in the Host applications, to support CSS from the Re-usable component library 150 | 151 | If you are using angular-cli to create hosted Angular projects, then you will need to create a new styles.css file under src, and import the merged css styles from the imported re-usable component library, like the following 152 | 153 | src/styles.css 154 | 155 | ``` 156 | +@import "~fullcalendar-ag4/styles.css"; 157 | ``` 158 | 159 | Please note the ~ symbol allows you to specify to the Angular transpiler to search from the nearest node_modules folder. In this case, you do not need to specify relative path, or include "node_modules" in the path. 160 | 161 | If everything goes well, you will see your new project with the renewed CSS loaded on the component. 162 | If you every see the following error from the browser debugger while running the host application, and that would mean the component library CSS is not setup or loaded properly. 163 | 164 | ``` 165 | Uncaught Error: Unexpected value '[object Object]' imported by the module 'AppModule'. Please add a @NgModule annotation. 166 | at syntaxError (compiler.es5.js:1689) 167 | at compiler.es5.js:15373 168 | at Array.forEach () 169 | at CompileMetadataResolver.webpackJsonp.../../../compiler/@angular/compiler.es5.js.CompileMetadataResolver.getNgModuleMetadata (compiler.es5.js:15356) 170 | at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._loadModules (compiler.es5.js:26679) 171 | at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._compileModuleAndComponents (compiler.es5.js:26652) 172 | at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler.compileModuleAsync (compiler.es5.js:26581) 173 | at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_._bootstrapModuleWithZone (core.es5.js:4595) 174 | at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_.bootstrapModule (core.es5.js:4581) 175 | at Object.../../../../../src/main.ts (main.ts:11) 176 | ``` 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![generator-angular-2-library](https://cloud.githubusercontent.com/assets/1859381/24447242/901c8a1a-1470-11e7-8b55-2484b7825722.jpg) 2 | [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] 3 | 4 | [Yeoman](http://yeoman.io) generator to create a standalone [Angular](https://angular.io/) library in seconds. 5 | 6 | If you want to create an Angular library with directives, services and/or pipes, then this generator is just what you need. 7 | 8 | This generator aligns with the [official Angular Package Format](https://goo.gl/AMOU5G) and automatically generates a [Flat ES Module](http://angularjs.blogspot.be/2017/03/angular-400-now-available.html), a UMD bundle, a single metadata.json and type definitions to make your library ready for AOT compilation by the consuming Angular application. 9 | 10 | Watch [Jason Aden's talk](https://www.youtube.com/watch?v=unICbsPGFIA) to learn more about the Angular Package Format. 11 | 12 | More specifically, the latest version of this generator: 13 | 14 | - supports Angular 5 15 | - creates and configures `package.json` for the development of your library 16 | - creates and configures a second `package.json` for the distribution of your library 17 | - creates and configures `tsconfig.json` for your editor during development 18 | - creates and configures `tslint.json` for linting purposes 19 | - creates and configures `.gitignore`, `.npmignore` and `.travis.yml` 20 | - creates the main library file, a sample directive, a sample component, a sample service and a sample pipe 21 | - configures [tslint](https://palantir.github.io/tslint/) for you with [codelyzer](https://github.com/mgechev/codelyzer) support 22 | - creates and configures build scripts to generate a Flat ES Module (FESM), type definitions and metadata files for your library to make it ready for AOT compilation 23 | - creates and configures build scripts to generate a Universal Module Definition (UMD) bundle to use your library in Node.js, SystemJS and with script tags (Plunker, Fiddle, etc) 24 | - inlines templates automatically for you so you can use external HTML templates 25 | - inlines styles automatically for you so you can use external CSS templates 26 | - supports .scss files 27 | - supports unit tests and code coverage using [jest](https://facebook.github.io/jest/) 28 | 29 | This generator is built for Angular version 2 and above, hence the name generator-angular2-library. If you are looking for a similar generator for AngularJS 1.x, please visit [generator-angularjs-library](https://github.com/jvandemo/generator-angularjs-library). 30 | 31 | ## Quick start 32 | 33 | ![generator-angular2-library-v10](https://cloud.githubusercontent.com/assets/1859381/25838669/89e03f04-3494-11e7-8a45-1daea0ecab1e.gif) 34 | 35 | First, install [Yeoman](http://yeoman.io) and generator-angular2-library using [npm](https://www.npmjs.com/) (assuming you already have [node.js](https://nodejs.org/) pre-installed). 36 | 37 | ```bash 38 | $ npm install -g yo 39 | $ npm install -g generator-angular2-library 40 | ``` 41 | 42 | make a new directory and `cd` into it: 43 | 44 | ```bash 45 | $ mkdir angular-library-name 46 | $ cd angular-library-name 47 | ``` 48 | 49 | and generate your new library: 50 | 51 | ```bash 52 | $ yo angular2-library 53 | ``` 54 | 55 | The generator will prompt you for: 56 | 57 | ```bash 58 | ? Your full name: Jurgen Van de Moere 59 | ? Your email address: jurgen.van.de.moere@gmail.com 60 | ? Your library name (kebab case): angular-library-name 61 | ? Git repository url: https://github.com/jvandemo/angular2-library-name 62 | ``` 63 | 64 | and create the following files for you: 65 | 66 | ```bash 67 | . 68 | ├── README.MD 69 | ├── gulpfile.js 70 | ├── package.json 71 | ├── src 72 | │ ├── index.ts 73 | │ ├── package.json 74 | │ ├── sample.component.ts 75 | │ ├── sample.directive.ts 76 | │ ├── sample.pipe.ts 77 | │ ├── sample.service.ts 78 | │ └── tsconfig.es5.json 79 | ├── tsconfig.json 80 | └── tslint.json 81 | ``` 82 | 83 | You can then add or edit `*.ts` files in the `src/` directory and run: 84 | 85 | ```bash 86 | $ npm run build 87 | ``` 88 | 89 | to automatically create all `*.js`, `*.d.ts` and `*.metadata.json` files in the `dist` directory: 90 | 91 | ```bash 92 | dist 93 | ├── index.d.ts # Typings for AOT compilation 94 | ├── index.js # Flat ES Module (FESM) for use with webpack 95 | ├── lib.d.ts # Typings for AOT compilation 96 | ├── lib.metadata.json # Metadata for AOT compilation 97 | ├── lib.umd.js # UMD bundle for use with Node.js, SystemJS or script tag 98 | ├── package.json # package.json for consumer of your library 99 | ├── sample.component.d.ts # Typings for AOT compilation 100 | ├── sample.directive.d.ts # Typings for AOT compilation 101 | ├── sample.pipe.d.ts # Typings for AOT compilation 102 | └── sample.service.d.ts # Typings for AOT compilation 103 | ``` 104 | 105 | Finally you publish your library to NPM by publishing the contents of the `dist` directory: 106 | 107 | ```bash 108 | $ npm publish dist 109 | ``` 110 | 111 | ## TypeScript config 112 | 113 | The generator creates 2 TypeScript config files: 114 | 115 | - `tsconfig.json` is used to configure your editor during development and is not used for building your library 116 | - `src/tsconfig.es5.json` is used by the Angular compiler to build the files in the `dist` directory when you run `npm run build` 117 | 118 | ## Linting your code 119 | 120 | Your library comes pre-configured with tslint and codelyzer support. To lint your code: 121 | 122 | ```bash 123 | $ npm run lint 124 | ``` 125 | 126 | ## Building your library 127 | 128 | From the root of your library directory, run: 129 | 130 | ```bash 131 | $ npm run build 132 | ``` 133 | 134 | This will generate a `dist` directory with: 135 | 136 | - a `package.json` file specifically for distribution with Angular listed in the `peerDependencies` 137 | - `sample-library.js`: a Flat ES Module (FESM) file that contains all your library code in a single file 138 | - `sample-library.umd.js`: a Universal Module Definition (UMD) bundle file that contains all your library code in UMD format for use in Node.js, SystemJS or via a script tag (e.g. in Plunker, Fiddle, etc) 139 | - `*.d.ts`: type definitions for you library 140 | - `sample-library.metadata.json`: metadata for your library to support AOT compilation 141 | 142 | ## Generating documentation for your library 143 | 144 | From the root of your library directory, run: 145 | 146 | ```bash 147 | $ npm run docs:build 148 | ``` 149 | This will generate a `docs` directory with all documentation of your library. 150 | 151 | To serve your documentation, run: 152 | 153 | ```bash 154 | $ npm run docs:serve 155 | ``` 156 | 157 | and navigate your browser to `http://localhost:8080`. 158 | 159 | To automatically rebuild your documentation every time a file in the `src` directory changes, run: 160 | 161 | ```bash 162 | $ npm run docs:watch 163 | ``` 164 | 165 | For more features, check out the [compodoc website](https://compodoc.github.io/website/). 166 | 167 | ## Publishing your library to NPM 168 | 169 | To publish your library to NPM, first generate the `dist` directory: 170 | 171 | ```bash 172 | $ npm run build 173 | ``` 174 | 175 | and then publish the contents of the `dist` directory to NPM: 176 | 177 | ```bash 178 | $ npm publish dist 179 | ``` 180 | 181 | ## Consuming your library 182 | 183 | Once you have published your library to the NPM registry, you can import it in any Angular application by first installing it using NPM: 184 | 185 | ```bash 186 | $ npm install sample-library # use the name you used to publish to npm 187 | ``` 188 | 189 | and then importing your library in your Angular `AppModule` (or whatever module you wish to import your library into): 190 | 191 | ```typescript 192 | import { BrowserModule } from '@angular/platform-browser'; 193 | import { NgModule } from '@angular/core'; 194 | 195 | import { AppComponent } from './app.component'; 196 | 197 | // Import your library 198 | import { SampleModule } from 'sample-library'; 199 | 200 | @NgModule({ 201 | declarations: [ 202 | AppComponent 203 | ], 204 | imports: [ 205 | BrowserModule, 206 | 207 | // Specify your library as an import 208 | SampleModule.forRoot() 209 | ], 210 | providers: [], 211 | bootstrap: [AppComponent] 212 | }) 213 | export class AppModule { } 214 | ``` 215 | 216 | Once your shared library is imported, you can use its components, directives and pipes in your Angular application templates: 217 | 218 | ```xml 219 | 220 |

{{ title }}

221 | 222 | This component is part of the shared library and will now work as expected. 223 | 224 | ``` 225 | 226 | and if you need to access a service from your shared library, you can inject it using Dependency Injection: 227 | 228 | ```typescript 229 | import { Component } from '@angular/core'; 230 | 231 | // Import the shared service 232 | import { SampleService } from 'sample-library'; 233 | 234 | @Component({ 235 | template: 'Injecting a service from the shared library' 236 | }) 237 | export class HomeComponent { 238 | 239 | // Inject the service using Angular DI 240 | constructor(private sampleService: SampleService){ 241 | 242 | } 243 | 244 | } 245 | ``` 246 | 247 | To learn more about Angular Dependency Injection, check out the [Official Angular Documentation](https://angular.io/docs/ts/latest/cookbook/dependency-injection.html). 248 | 249 | ## Preview your library during development 250 | 251 | To preview your library code during development, start the playground: 252 | 253 | ```bash 254 | $ npm run playground 255 | ``` 256 | 257 | Changes to your library code will be updated live in the browser window: 258 | 259 | ![playground](https://user-images.githubusercontent.com/1859381/30514111-576fcf4e-9b0f-11e7-837d-169d08667c2c.gif) 260 | 261 | ## Consuming your library in a local application during development 262 | 263 | To consume your library in a local application before you publish it to npm, you can follow the following steps: 264 | 265 | 1. Create your library: 266 | ``` 267 | $ yo angular2-library 268 | ``` 269 | Let's assume you name your library `sample-library`. 270 | 271 | 2. Navigate to the `sample-library` directory: 272 | ``` 273 | $ cd sample-library 274 | ``` 275 | 276 | 3. Compile your library files: 277 | ``` 278 | $ npm run build 279 | ``` 280 | 281 | 4. From the `sample-library/dist` directory, create a symlink in the global node_modules directory to the `dist` directory of your library: 282 | ``` 283 | $ cd dist 284 | $ npm link 285 | ``` 286 | 287 | 5. Create a new Angular app. Let's assume you use angular-cli: 288 | ``` 289 | $ cd /your-projects-path 290 | $ ng new my-app 291 | ``` 292 | 293 | 6. Navigate to the `my-app` directory: 294 | ``` 295 | $ cd my-app 296 | ``` 297 | 298 | 7. From the `my-app` directory, link the global `sample-library` directory to node_modules of the `my-app` directory: 299 | ``` 300 | $ npm link sample-library 301 | ``` 302 | 303 | 8. Import `SampleModule` in your Angular application: 304 | 305 | ```typescript 306 | import { BrowserModule } from '@angular/platform-browser'; 307 | import { NgModule } from '@angular/core'; 308 | 309 | import { AppComponent } from './app.component'; 310 | 311 | // Import your library 312 | import { SampleModule } from 'sample-library'; 313 | 314 | @NgModule({ 315 | declarations: [ 316 | AppComponent 317 | ], 318 | imports: [ 319 | BrowserModule, 320 | 321 | // Specify your library as an import 322 | SampleModule.forRoot() 323 | ], 324 | providers: [], 325 | bootstrap: [AppComponent] 326 | }) 327 | export class AppModule { } 328 | ``` 329 | 330 | 9. Once your shared library is imported, you can use its components, directives and pipes in your Angular application templates: 331 | 332 | ```xml 333 | 334 |

{{ title }}

335 | 336 | This component is part of the shared library and will now work as expected. 337 | 338 | ``` 339 | 340 | and if you need to access a service from your shared library, you can inject it using Dependency Injection: 341 | 342 | ```typescript 343 | import { Component } from '@angular/core'; 344 | 345 | // Import the shared service 346 | import { SampleService } from 'sample-library'; 347 | 348 | @Component({ 349 | template: 'Injecting a service from the shared library' 350 | }) 351 | export class HomeComponent { 352 | 353 | // Inject the service using Angular DI 354 | constructor(private sampleService: SampleService){ 355 | 356 | } 357 | 358 | } 359 | ``` 360 | 361 | 10. When you make a change to your library, recompile your library files again from your `sample-library` directory: 362 | ``` 363 | $ npm run build 364 | ``` 365 | 366 | 11. If you want to automatically recompile the library files when a file in `src` changes, run 367 | ``` 368 | $ npm run build:watch 369 | ``` 370 | 371 | 12. If you are using an Angular CLI application to consume your library, make sure to set up a [path mapping](https://github.com/angular/angular-cli/wiki/stories-linked-library#use-typesscript-path-mapping-for-peer-dependencies) in `/src/tsconfig.app.json` of your consuming application (not your library): 372 | ```typescript 373 | { 374 | "compilerOptions": { 375 | // ... 376 | // Note: these paths are relative to `baseUrl` path. 377 | "paths": { 378 | "@angular/*": [ 379 | "../node_modules/@angular/*" 380 | ] 381 | } 382 | } 383 | } 384 | ``` 385 | 386 | When you npm link a library with peer dependencies, the [consuming application searches for the peer dependencies in the library's parent directories instead of the application's parent directories](http://codetunnel.io/you-can-finally-npm-link-packages-that-contain-peer-dependencies). 387 | 388 | If you get `Error: Unexpected value '[object Object]' imported by the module 'AppModule'. Please add a @NgModule annotation.`, then try: 389 | 390 | ``` 391 | $ ng serve --preserve-symlinks 392 | ``` 393 | 394 | to make sure the consuming application searches for the peer dependencies in the application's node_modules directory. 395 | 396 | ## Frequently asked questions 397 | 398 | #### How can I configure Karma? 399 | 400 | Currently, the generator does not create a custom Karma configuration for running unit tests. 401 | 402 | If your library requires a custom Karma setup, please check out [this tutorial on how to configure Karma for your library](https://github.com/raphael-volt/ng2-testable-lib) (Credits to [Raphael](https://github.com/raphael-volt)). 403 | 404 | As soon as official recommendations are available on how to set up Karma for testing libraries, this generator will be updated accordingly. 405 | 406 | #### How can I use a scoped package name? 407 | 408 | First update the package name in `src/package.json`: 409 | 410 | ```javascript 411 | "name": "@scope/library-name" 412 | ``` 413 | 414 | and then also update `flatModuleId` in `src/tsconfig.es5.json` accordingly: 415 | 416 | ```javascript 417 | "flatModuleId": "@scope/library-name" 418 | ``` 419 | 420 | See [#75](https://github.com/jvandemo/generator-angular2-library/issues/75) for more information. 421 | 422 | #### How can I avoid recompilation during development 423 | 424 | If you experience issues ([#72](https://github.com/jvandemo/generator-angular2-library/issues/72)) or want to avoid constant recompilation of your library during development, you can also `npm link src` instead of `npm link dist` in step 4 of the process above. 425 | 426 | This will let you consume the TypeScript code directly from the `src` directory of your library instead of the generated bundle from the `dist` directory. This increases development speed if you are testing your library in a local Angular application, but remember to test the generated bundle using `npm link dist` after you finish writing your code, to ensure that your generated bundle is working as expected before you publish your library to NPM. 427 | 428 | #### How can I use .scss files? 429 | 430 | Simply store your styles in a file with a filename extension of `scss` and reference it in your component's `styleUrls` property. 431 | 432 | So if you have a `sample.component.scss`: 433 | 434 | ```scss 435 | h1 { 436 | color: red; 437 | } 438 | ``` 439 | 440 | then reference it in your component's `styleUrls` in `sample.component.ts` accordingly: 441 | 442 | ```typescript 443 | @Component({ 444 | selector: 'sample-component', 445 | template: `

Sample component

`, 446 | styleUrls: [ 447 | 'sample.component.scss' 448 | ] 449 | }) 450 | ``` 451 | 452 | The .scss files will automatically be compiled and inlined in your library bundle. 453 | 454 | #### How can I import .scss files 455 | 456 | To import a .scss file in an existing .scss file, you can specify a relative path: 457 | 458 | ``` 459 | @import '../relative/path/to/other.scss'; 460 | ``` 461 | 462 | or use a tilde to import a file from the nearest parent `node_modules` directory: 463 | 464 | ``` 465 | @import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; 466 | ``` 467 | 468 | #### How can I see which version of the generator I have installed 469 | 470 | From the command line, run: 471 | 472 | ``` 473 | $ npm ls -g --depth=1 2>/dev/null | grep generator- 474 | ``` 475 | 476 | #### How can I update my generator to the latest version? 477 | 478 | From the command line, run 479 | 480 | ```bash 481 | $ yo 482 | ``` 483 | and select the option *Update your generators*. 484 | 485 | #### What if my library depends on a third party library? 486 | 487 | If your library depends on a third party library such as Angular Material or PrimeNG, you don't have to include the third party library in your library. 488 | 489 | Instead, you should add the third party library as a peer dependency to the `peerDependencies` property in `src/package.json` of your library: 490 | 491 | ```javascript 492 | "peerDependencies": { 493 | "@angular/core": "^4.0.0", 494 | "rxjs": "^5.1.0", 495 | "zone.js": "^0.8.4" 496 | } 497 | ``` 498 | 499 | This causes a warning to be displayed when the consuming application runs `npm install` and does not have the third party library installed that your library depends on. 500 | 501 | The generator already adds `@angular/core`, `rxjs` and `zone.js` as peer dependencies for you by default. 502 | 503 | Consider the following scenario where your library depends on a third party library called "PrimeNG". 504 | 505 | In your Angular library: 506 | 507 | 1. run `npm install primeng --save` to install PrimeNG and add it as a devDependency to `package.json` in the root directory 508 | 2. add PrimeNG as a peerDependency in `src/package.json`, *NOT* as dependency or devDependency (`src/package.json` is the package.json that is distributed with your library, so you must specify primeng as peer dependency here, *NOT* in the package.json file in the root of your library) 509 | 3. import the necessary PrimeNG Angular module(s) in your library Angular module 510 | 4. write code that uses PrimeNG components 511 | 5. build your library and publish it (or link it locally) 512 | 513 | In the consuming Angular application 514 | 515 | 1. run `npm install yourlibrary` to install your library (which should display a warning if PrimeNG is not installed) or link it locally 516 | 2. run `npm install primeng` to install PrimeNG if it is not installed yet 517 | 3. import the necessary PrimeNG Angular module(s) in your Angular application module (usually `AppModule`) (this step is not needed if your library exports the PrimeNG module(s) in its module metadata) 518 | 4. import your library module in your Angular application module (usually `AppModule`) 519 | 5. you can now use your library components 520 | 521 | To see a fully documented example, check out [this guide](./guides/import_non_angular_libraries.md). 522 | 523 | #### How can I upgrade my library to support Angular 5 524 | 525 | Version 12 or later of this generator supports Angular 5. 526 | 527 | If you have an existing library that was generated with an earlier version of this generator: 528 | 529 | 1. update the versions of the Angular packages in `package.json` to Angular 5 ([example](https://github.com/jvandemo/generator-angular2-library/blob/master/generators/app/templates/_package.json)) 530 | 2. replace the `ngc` script in your `gulpfile.js` with: 531 | 532 | ``` 533 | gulp.task('ngc', function () { 534 | ngc([ '--project', `${tmpFolder}/tsconfig.es5.json` ]); 535 | return Promise.resolve() 536 | }); 537 | ``` 538 | 539 | See [#230](https://github.com/jvandemo/generator-angular2-library/issues/230) for more information. 540 | 541 | ## Issues 542 | 543 | Please report bugs and issues [here](https://github.com/jvandemo/generator-angular2-library/issues). 544 | 545 | ## Development 546 | 547 | To run the generator unit tests: 548 | 549 | ```bash 550 | $ npm run test 551 | ``` 552 | 553 | ## License 554 | 555 | MIT © [Jurgen Van de Moere](http://www.jvandemo.com) 556 | 557 | ## Change log 558 | 559 | ### v12.4.1 560 | 561 | - Fix tslint rule [#286](https://github.com/jvandemo/generator-angular2-library/pull/286) (Credits to [Mathias Wittlock](https://github.com/wittlock)) 562 | 563 | ### v12.4.0 564 | 565 | - Add prompt to ask for scope [#283](https://github.com/jvandemo/generator-angular2-library/pull/283) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 566 | 567 | ### v12.3.0 568 | 569 | - Update rollup options [#270](https://github.com/jvandemo/generator-angular2-library/pull/270) (Credits to [Zura Gabievi](https://github.com/zgabievi)) 570 | - Fix mkdir error [#269](https://github.com/jvandemo/generator-angular2-library/pull/269) (Credits to [Louis Amstutz](https://github.com/lamstutz)) 571 | 572 | ### v12.2.1 573 | 574 | - Update system.js config to use single quotes 575 | 576 | ### v12.2.0 577 | 578 | - Added default extension to playground system.js config to fix [#146](https://github.com/jvandemo/generator-angular2-library/pull/146) 579 | 580 | ### v12.1.0 581 | 582 | - Fixed issue with deleting .tmp folder after failed build (See [#261](https://github.com/jvandemo/generator-angular2-library/pull/261)) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 583 | - Updated package_jest.json (See [#267](https://github.com/jvandemo/generator-angular2-library/pull/267)) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 584 | 585 | ### v12.0.0 586 | 587 | - Updated packages to Angular 5 588 | - Updated ngc gulp script (See [#230](https://github.com/jvandemo/generator-angular2-library/issues/230)) (Credits to [Filip Lauc](https://github.com/flauc)) 589 | 590 | ### v11.4.0 591 | 592 | - Updated rollup and gulp-rollup configuration (See [#190](https://github.com/jvandemo/generator-angular2-library/pull/190)) (Credits to [Daniel Geri](https://github.com/danielgeri)) 593 | 594 | ### v11.3.0 595 | 596 | - Added playground (See [#146](https://github.com/jvandemo/generator-angular2-library/pull/146)) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 597 | 598 | ### v11.2.0 599 | 600 | - Added guide on how depend on third party library (See [#172](https://github.com/jvandemo/generator-angular2-library/pull/172)) (Credits to [Ka Tam](https://github.com/kktam)) 601 | 602 | ### v11.1.0 603 | 604 | - Added `main` and `jsnext:main` properties to package.json 605 | 606 | ### v11.0.3 607 | 608 | - Added FAQ on how to add third party library 609 | - Updated jest support (See [#91](https://github.com/jvandemo/generator-angular2-library/pull/158)) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 610 | 611 | ### v11.0.2 612 | 613 | - Fixed package.json for [Jest](https://facebook.github.io/jest/) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 614 | 615 | ### v11.0.1 616 | 617 | - Updated `styleUrls` to fix [#140](https://github.com/jvandemo/generator-angular2-library/issues/140) 618 | 619 | ### v11.0.0 620 | 621 | - Added support for [Jest](https://facebook.github.io/jest/) (Credits to [Fabrizio Fortunato](https://github.com/izifortune)) 622 | - Updated Compodoc (Credits to [Artem Kuznetsov](https://github.com/artemsky)) 623 | 624 | ### v10.2.2 625 | 626 | - Avoid deletion of dist directory to prevent npm link errors (See [#91](https://github.com/jvandemo/generator-angular2-library/issues/91)) (Credits to [Filipe Silva](https://github.com/filipesilva) and [Brenden Niedermeyer](https://github.com/bniedermeyer)) 627 | 628 | ### v10.2.1 629 | 630 | - Allow real files in rollup to fix [#105](https://github.com/jvandemo/generator-angular2-library/issues/105) 631 | 632 | ### v10.2.0 633 | 634 | - Add support for scss imports ([#100](https://github.com/jvandemo/generator-angular2-library/pull/100))(Credits to [rtrompier](https://github.com/rtrompier)) 635 | 636 | ### v10.1.1 637 | 638 | - Fix README 639 | 640 | ### v10.1.0 641 | 642 | - Copy README to dist directory ([#85](https://github.com/jvandemo/generator-angular2-library/pull/85)) (Credits to [David](https://github.com/dbfannin)) 643 | 644 | ### v10.0.0 645 | 646 | - Added support for generating UMD bundle 647 | 648 | ### v9.3.0 649 | 650 | - Added support for .scss files (Credits to [Thomas Deblock](https://github.com/deblockt)) 651 | 652 | ### v9.2.0 653 | 654 | - Added convenience scripts for generating documentation 655 | 656 | ### v9.1.0 657 | 658 | - Added compodoc for generating documentation ([#76](https://github.com/jvandemo/generator-angular2-library/pull/76)) 659 | - Removed comments from TypeScript config files to allow JSON validity checks 660 | 661 | ### v9.0.0 662 | 663 | - Added Gulp for support on Mac, Linux and Windows (Credits to [Carlos Roso](https://github.com/caroso1222)) 664 | - Added template inlining (Credits to [Filipe Silva](https://github.com/filipesilva)) 665 | - Added style inlining (Credits to [Filipe Silva](https://github.com/filipesilva)) 666 | 667 | ### v8.2.1 668 | 669 | - Updated TypeScript files in gitignore 670 | 671 | ### v8.2.0 672 | 673 | - Added build:watch script 674 | - Added dist folder to gitignore 675 | 676 | ### v8.1.0 677 | 678 | - Remove prepublish script 679 | 680 | ### v8.0.0 681 | 682 | - Update build process 683 | - Add support for AOT compilation 684 | 685 | ### v7.0.0 686 | 687 | - Update to Angular 4 688 | 689 | ### v6.0.0 690 | 691 | - Update to Yeoman 1.x 692 | 693 | ### v5.6.0 694 | 695 | - Ignore files generated by ngc in .gitignore 696 | 697 | ### v5.5.2 698 | 699 | - Remove obsolete files in package.json 700 | 701 | ### v5.5.1 702 | 703 | - Add README.md to package.json so NPM registry can display it 704 | 705 | ### v5.5.0 706 | 707 | - Update devDependencies 708 | 709 | ### v5.4.0 710 | 711 | - Update to latest tslint and codelyzer 712 | 713 | ### v5.3.0 714 | 715 | - Update TypeScript version to fix #41 716 | 717 | ### v5.2.1 718 | 719 | - Fix eslint errors 720 | - Remove duplicate dependency 721 | 722 | ### v5.2.0 723 | 724 | - Suggest better default library name 725 | 726 | ### v5.1.0 727 | 728 | - Add support for AOT compilation 729 | - Update Angular 2 references to just Angular 730 | 731 | ### v5.0.0 732 | 733 | - Replace typings with @types (#29) 734 | 735 | ### v4.0.0 736 | 737 | - Remove default keyword when exporting module to fix #23 738 | 739 | ### v3.0.4 740 | 741 | - Updated version of Codelyzer 742 | - Updated selector of sample component to kebab case to fix #21 743 | 744 | ### v3.0.3 745 | 746 | - Fixed unit tests 747 | 748 | ### v3.0.2 749 | 750 | - Fixed `README.md` example code 751 | 752 | ### v3.0.1 753 | 754 | - Fixed `tsconfig.json` files 755 | 756 | ### v3.0.0 757 | 758 | - Added support for `NgModule` 759 | 760 | ### v2.2.0 761 | 762 | - Updated dependencies in package.json to Angular 2 final 763 | 764 | ### v2.1.0 765 | 766 | - Updated templates to Angular 2.0.0 RC3 syntax 767 | 768 | ### v2.0.0 769 | 770 | - Updated with file structure using `src` and `dist` directory 771 | 772 | ### v1.1.1 773 | 774 | - Updated templates to Angular 2.0.0 RC1 syntax 775 | 776 | ### v1.1.0 777 | 778 | - Added codelyzer support 779 | - Added tslint support 780 | - Added typings support 781 | 782 | ### v1.0.0 783 | 784 | - BREAKING CHANGE: Updated to support [Angular 2.0.0-rc.1](https://github.com/angular/angular/blob/master/CHANGELOG.md#200-rc1-2016-05-03) 785 | 786 | ### v0.6.0 787 | 788 | - Updated dependency versions 789 | 790 | ### v0.5.0 791 | 792 | - Added `browser.d.ts` to files in `tsconfig.json` instead of using tripleslash (see #9) 793 | 794 | ### v0.4.0 795 | 796 | - Added reference to Angular typings 797 | 798 | ### v0.3.1 799 | 800 | - Removed explicit RxJS dependency 801 | 802 | ### v0.3.0 803 | 804 | - Updated to Angular 2 beta 805 | 806 | ### v0.2.0 807 | 808 | - Added documentation 809 | - Added support for `PROVIDERS`, `DIRECTIVES` and `PIPES` 810 | 811 | ### v0.1.0 812 | 813 | - Added documentation 814 | - Added boilerplate scaffolding 815 | - Initial version 816 | 817 | [npm-image]: https://badge.fury.io/js/generator-angular2-library.svg 818 | [npm-url]: https://npmjs.org/package/generator-angular2-library 819 | [travis-image]: https://travis-ci.org/jvandemo/generator-angular2-library.svg?branch=master 820 | [travis-url]: https://travis-ci.org/jvandemo/generator-angular2-library 821 | [daviddm-image]: https://david-dm.org/jvandemo/generator-angular2-library.svg?theme=shields.io 822 | [daviddm-url]: https://david-dm.org/jvandemo/generator-angular2-library 823 | [coveralls-image]: https://coveralls.io/repos/jvandemo/generator-angular2-library/badge.svg 824 | [coveralls-url]: https://coveralls.io/r/jvandemo/generator-angular2-library 825 | --------------------------------------------------------------------------------