├── tools ├── manual_typings │ ├── seed │ │ ├── clean.tmp │ │ ├── operators.d.ts │ │ ├── slash.d.ts │ │ ├── tildify.d.ts │ │ ├── del.d.ts │ │ ├── walk.d.ts │ │ ├── open.d.ts │ │ ├── autoprefixer.d.ts │ │ ├── istream.d.ts │ │ ├── angular2-hot-loader.d.ts │ │ ├── merge-stream.d.ts │ │ ├── karma.d.ts │ │ ├── colorguard.d.ts │ │ ├── doiuse.d.ts │ │ ├── stylelint.d.ts │ │ ├── systemjs-builder.d.ts │ │ ├── cssnano.d.ts │ │ ├── express-history-api-fallback.d.ts │ │ └── postcss-reporter.d.ts │ └── project │ │ └── sample.package.d.ts ├── .gitignore ├── utils │ ├── project │ │ └── sample_util.ts │ ├── project.utils.ts │ ├── seed │ │ ├── karma.start.ts │ │ ├── tsproject.ts │ │ ├── watch.ts │ │ ├── clean.ts │ │ ├── template_locals.ts │ │ ├── code_change_tools.ts │ │ ├── server.ts │ │ └── tasks_tools.ts │ └── seed.utils.ts ├── env │ ├── env-config.interface.ts │ ├── dev.ts │ ├── prod.ts │ └── base.ts ├── config.ts ├── utils.ts ├── tasks │ ├── seed │ │ ├── watch.e2e.ts │ │ ├── serve.coverage.ts │ │ ├── watch.test.ts │ │ ├── server.prod.ts │ │ ├── server.start.ts │ │ ├── watch.dev.ts │ │ ├── serve.docs.ts │ │ ├── webdriver.ts │ │ ├── clean.dev.ts │ │ ├── clean.coverage.ts │ │ ├── clean.all.ts │ │ ├── clean.prod.ts │ │ ├── karma.run.ts │ │ ├── print.banner.ts │ │ ├── serve.coverage.watch.ts │ │ ├── karma.watch.ts │ │ ├── generate.manifest.ts │ │ ├── clear.files.ts │ │ ├── copy.prod.ts │ │ ├── build.bundles.app.ts │ │ ├── minify.bundles.ts │ │ ├── build.bundles.app.exp.ts │ │ ├── tslint.ts │ │ ├── build.assets.dev.ts │ │ ├── build.bundle.rxjs.ts │ │ ├── build.js.test.ts │ │ ├── build.js.tools.ts │ │ ├── build.js.prod.exp.ts │ │ ├── e2e.ts │ │ ├── karma.run.with_coverage.ts │ │ ├── build.bundles.ts │ │ ├── build.assets.prod.ts │ │ ├── build.js.e2e.ts │ │ ├── build.docs.ts │ │ ├── build.js.prod.ts │ │ ├── clean.tools.ts │ │ ├── check.versions.ts │ │ ├── start.deving.ts │ │ ├── compile.ahead.prod.ts │ │ ├── build.index.prod.ts │ │ ├── css-lint.ts │ │ ├── build.index.dev.ts │ │ ├── build.js.dev.ts │ │ └── build.html_css.ts │ ├── typescript_task.ts │ ├── css_task.ts │ ├── assets_task.ts │ ├── project │ │ └── sample.task.ts │ └── task.ts ├── config │ ├── seed.config.interfaces.ts │ ├── banner.txt │ ├── project.config.ts │ ├── seed.tslint.json │ ├── banner-256.txt │ └── seed.config.ts ├── debug.ts └── README.md ├── tslint.json ├── test-config.js ├── src └── client │ ├── assets │ ├── data.json │ └── svg │ │ └── more.svg │ ├── app │ ├── system-config.ts │ ├── app.module.ts │ ├── main.ts │ ├── main-prod.ts │ └── app.ts │ ├── css │ └── main.css │ ├── tsconfig.json │ └── index.html ├── .editorconfig ├── .stylelintrc ├── .github ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── tsconfig.json ├── .gitignore ├── LICENSE ├── protractor.conf.js ├── .jshintrc ├── appveyor.yml ├── .travis.yml ├── test-main.js ├── karma.conf.js ├── gulpfile.ts ├── package.json └── README.md /tools/manual_typings/seed/clean.tmp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | *.js.map 3 | 4 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/operators.d.ts: -------------------------------------------------------------------------------- 1 | import '../../../src/client/app/operators'; 2 | -------------------------------------------------------------------------------- /tools/utils/project/sample_util.ts: -------------------------------------------------------------------------------- 1 | export function myUtil() { 2 | // Code goes here 3 | } 4 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tools/config/seed.tslint.json", 3 | "rules": { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test-config.js: -------------------------------------------------------------------------------- 1 | // Load our SystemJS configuration. 2 | System.config({ 3 | baseURL: '/base/' 4 | }); 5 | 6 | -------------------------------------------------------------------------------- /tools/env/env-config.interface.ts: -------------------------------------------------------------------------------- 1 | export { EnvConfig } from '../../src/client/app/shared/config/env.config'; 2 | 3 | -------------------------------------------------------------------------------- /tools/manual_typings/project/sample.package.d.ts: -------------------------------------------------------------------------------- 1 | // declare module "moment/moment" { 2 | // export = moment; 3 | // } 4 | -------------------------------------------------------------------------------- /src/client/assets/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | "Edsger Dijkstra", 3 | "Donald Knuth", 4 | "Alan Turing", 5 | "Grace Hopper" 6 | ] 7 | -------------------------------------------------------------------------------- /src/client/app/system-config.ts: -------------------------------------------------------------------------------- 1 | declare var System: SystemJSLoader.System; 2 | 3 | System.config(JSON.parse('<%= SYSTEM_CONFIG_DEV %>')); 4 | -------------------------------------------------------------------------------- /tools/config.ts: -------------------------------------------------------------------------------- 1 | import { ProjectConfig } from './config/project.config'; 2 | 3 | const config: ProjectConfig = new ProjectConfig(); 4 | export default config; 5 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/slash.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'slash' { 2 | function slash(path: string): string; 3 | module slash {} 4 | export = slash; 5 | } 6 | -------------------------------------------------------------------------------- /tools/utils/project.utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This barrel file provides the exports for the project specific utilities. 3 | */ 4 | export * from './project/sample_util'; 5 | -------------------------------------------------------------------------------- /tools/env/dev.ts: -------------------------------------------------------------------------------- 1 | import { EnvConfig } from './env-config.interface'; 2 | 3 | const DevConfig: EnvConfig = { 4 | ENV: 'DEV' 5 | }; 6 | 7 | export = DevConfig; 8 | 9 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/tildify.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'tildify' { 2 | function tildify(path: string): string; 3 | module tildify {} 4 | export = tildify; 5 | } 6 | -------------------------------------------------------------------------------- /tools/env/prod.ts: -------------------------------------------------------------------------------- 1 | import { EnvConfig } from './env-config.interface'; 2 | 3 | const ProdConfig: EnvConfig = { 4 | ENV: 'PROD' 5 | }; 6 | 7 | export = ProdConfig; 8 | 9 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/del.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'del' { 2 | var del: IDel; 3 | export = del; 4 | interface IDel { 5 | sync: { 6 | (patterns: any): void; 7 | }; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This barrel file provides the export for the utilities provided by the project and the seed. 3 | */ 4 | export * from './utils/project.utils'; 5 | export * from './utils/seed.utils'; 6 | -------------------------------------------------------------------------------- /tools/env/base.ts: -------------------------------------------------------------------------------- 1 | import { EnvConfig } from './env-config.interface'; 2 | 3 | const BaseConfig: EnvConfig = { 4 | // Sample API url 5 | API: 'https://demo.com' 6 | }; 7 | 8 | export = BaseConfig; 9 | 10 | -------------------------------------------------------------------------------- /tools/tasks/seed/watch.e2e.ts: -------------------------------------------------------------------------------- 1 | import { watch } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, watching for file changes and rebuilding the e2e environment. 5 | */ 6 | export = watch('build.e2e'); 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/serve.coverage.ts: -------------------------------------------------------------------------------- 1 | import { serveCoverage } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, serving unit test coverage report using an `express` server. 5 | */ 6 | export = serveCoverage; 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/watch.test.ts: -------------------------------------------------------------------------------- 1 | import { watch } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, watching for file changes and rebuilding the test environment. 5 | */ 6 | export = watch('build.test'); 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/server.prod.ts: -------------------------------------------------------------------------------- 1 | import { serveProd } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, serving the files of the production environment using an `express` server. 5 | */ 6 | export = serveProd; 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/server.start.ts: -------------------------------------------------------------------------------- 1 | import { serveSPA } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, serving the files of the development environment using an `express` server. 5 | */ 6 | export = serveSPA; 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/watch.dev.ts: -------------------------------------------------------------------------------- 1 | import { watch } from '../../utils'; 2 | 3 | /** 4 | * Executes the build process, watching for file changes and rebuilding the development environment. 5 | */ 6 | export = watch('build.dev'); 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/serve.docs.ts: -------------------------------------------------------------------------------- 1 | // import { serveDocs } from '../../utils'; 2 | // 3 | // /** 4 | // * Executes the build process, serving the application documentation using an `express` server. 5 | // */ 6 | // export = serveDocs; 7 | 8 | -------------------------------------------------------------------------------- /tools/tasks/seed/webdriver.ts: -------------------------------------------------------------------------------- 1 | import { webdriver_update } from 'gulp-protractor'; 2 | 3 | /** 4 | * Executes the build process, installing the selenium webdriver used for the protractor e2e specs. 5 | */ 6 | export = webdriver_update; 7 | -------------------------------------------------------------------------------- /tools/tasks/seed/clean.dev.ts: -------------------------------------------------------------------------------- 1 | import Config from '../../config'; 2 | import { clean } from '../../utils'; 3 | 4 | /** 5 | * Executes the build process, cleaning all files within the `/dist/dev` directory. 6 | */ 7 | export = clean(Config.DEV_DEST); 8 | -------------------------------------------------------------------------------- /tools/tasks/seed/clean.coverage.ts: -------------------------------------------------------------------------------- 1 | import Config from '../../config'; 2 | import { clean } from '../../utils'; 3 | 4 | /** 5 | * Executes the build process, cleaning all files within the `/dist/dev` directory. 6 | */ 7 | export = clean(Config.COVERAGE_DIR); 8 | -------------------------------------------------------------------------------- /tools/tasks/seed/clean.all.ts: -------------------------------------------------------------------------------- 1 | import Config from '../../config'; 2 | import { clean } from '../../utils'; 3 | 4 | /** 5 | * Executes the build process, cleaning all files within the `/dist` directory. 6 | */ 7 | export = clean([Config.DIST_DIR, Config.COVERAGE_DIR]); 8 | -------------------------------------------------------------------------------- /tools/tasks/typescript_task.ts: -------------------------------------------------------------------------------- 1 | import { Task } from './task'; 2 | 3 | export abstract class TypeScriptTask extends Task { 4 | shallRun(files: String[]) { 5 | return files.reduce((a, f) => { 6 | return a || f.endsWith('.ts'); 7 | }, false); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/walk.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'walk' { 2 | interface Walker { 3 | on(eventName: string, cb: Function): any; 4 | } 5 | interface Walk { 6 | walk(path: string, options: any): Walker; 7 | } 8 | const walk: Walk; 9 | export = walk; 10 | } 11 | -------------------------------------------------------------------------------- /tools/tasks/css_task.ts: -------------------------------------------------------------------------------- 1 | import { Task } from './task'; 2 | 3 | export abstract class CssTask extends Task { 4 | 5 | shallRun(files: String[]) { 6 | return files.some(f => 7 | f.endsWith('.css') || f.endsWith('.sass') || f.endsWith('.scss')); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /tools/tasks/seed/clean.prod.ts: -------------------------------------------------------------------------------- 1 | import Config from '../../config'; 2 | import { clean } from '../../utils'; 3 | 4 | /** 5 | * Executes the build process, cleaning all files within the `/dist/dev` and `dist/tmp` directory. 6 | */ 7 | export = clean([Config.PROD_DEST, Config.TMP_DIR]); 8 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/open.d.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/borisyankov/DefinitelyTyped/tree/master/open 2 | // Does not support ES2015 import (import * as open from 'open'). 3 | 4 | declare module 'open' { 5 | function open(target: string, app?: string): void; 6 | module open {} 7 | export = open; 8 | } 9 | -------------------------------------------------------------------------------- /tools/tasks/seed/karma.run.ts: -------------------------------------------------------------------------------- 1 | import { startKarma } from '../../utils/seed/karma.start'; 2 | import Config from '../../config'; 3 | 4 | /** 5 | * Executes the build process, running all unit tests using `karma`. 6 | */ 7 | export = (done: any) => { 8 | return startKarma(done, Config.KARMA_REPORTERS); 9 | }; 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/autoprefixer.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'autoprefixer' { 2 | 3 | interface IOptions { 4 | browsers: string[]; 5 | } 6 | 7 | interface IAutoprefixer { 8 | (opts?: IOptions): NodeJS.ReadWriteStream; 9 | } 10 | 11 | const autoprefixer: IAutoprefixer; 12 | export = autoprefixer; 13 | } 14 | -------------------------------------------------------------------------------- /tools/config/seed.config.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface InjectableDependency { 2 | src: string; 3 | inject: string | boolean; 4 | vendor?: boolean; 5 | env?: string[] | string; 6 | } 7 | 8 | export interface Environments { 9 | DEVELOPMENT: string; 10 | PRODUCTION: string; 11 | [key: string]: string; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/istream.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'isstream' { 2 | function istream(stream: any): boolean; 3 | interface Istream { 4 | isReadable(stream: any): boolean; 5 | isWritable(stream: any): boolean; 6 | isDuplex(stream: any): boolean; 7 | } 8 | module istream {} 9 | export = istream; 10 | } 11 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/angular2-hot-loader.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'angular2-hot-loader' { 2 | export interface Options { 3 | port?: number; 4 | path?: string; 5 | processPath?: Function; 6 | } 7 | export function listen(localConfig?: Options): void; 8 | export function onChange(files: string[]): void; 9 | } 10 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/merge-stream.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'merge-stream' { 2 | function mergeStream(...streams: NodeJS.ReadWriteStream[]): MergeStream; 3 | interface MergeStream extends NodeJS.ReadWriteStream { 4 | add(stream: NodeJS.ReadWriteStream): MergeStream; 5 | } 6 | module mergeStream {} 7 | export = mergeStream; 8 | } 9 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/karma.d.ts: -------------------------------------------------------------------------------- 1 | // Use this minimalistic definition file as bluebird dependency 2 | // generate a lot of errors. 3 | 4 | declare module 'karma' { 5 | var karma: IKarma; 6 | export = karma; 7 | interface IKarma { 8 | server: { 9 | start(options: any, callback: Function): void 10 | }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tools/tasks/assets_task.ts: -------------------------------------------------------------------------------- 1 | import { Task } from './task'; 2 | 3 | export abstract class AssetsTask extends Task { 4 | shallRun(files: String[]) { 5 | return files.reduce((a, f) => { 6 | return a || (!f.endsWith('.css') && !f.endsWith('.sass') && 7 | !f.endsWith('.scss') && !f.endsWith('.ts')); 8 | }, false); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/utils/seed/karma.start.ts: -------------------------------------------------------------------------------- 1 | import * as karma from 'karma'; 2 | import { join } from 'path'; 3 | 4 | export const startKarma = (done: any, config: any = {}) => { 5 | return new (karma).Server(Object.assign({ 6 | configFile: join(process.cwd(), 'karma.conf.js'), 7 | singleRun: true 8 | }, config)).start(done); 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "block-no-empty": null, 5 | "at-rule-empty-line-before": null, 6 | "rule-non-nested-empty-line-before": null, 7 | "selector-pseudo-class-no-unknown" : [ true, { 8 | "ignorePseudoClasses": [ 9 | "host" 10 | ] 11 | }] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/client/assets/svg/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /tools/config/banner.txt: -------------------------------------------------------------------------------- 1 | Welcome to _ _ 2 | __ _ _ __ __ _ _ _| | __ _ _ __ ___ ___ ___ __| | 3 | / _` | '_ \ / _` | | | | |/ _` | '__|____/ __|/ _ \/ _ \/ _` | 4 | | (_| | | | | (_| | |_| | | (_| | | |_____\__ \ __/ __/ (_| | 5 | \__,_|_| |_|\__, |\__,_|_|\__,_|_| |___/\___|\___|\__,_| 6 | |___/ 7 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/colorguard.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'colorguard' { 2 | 3 | interface IOptions { 4 | ignore?: string[]; 5 | threshold?: number; 6 | whitelist?: [string, string][]; 7 | } 8 | 9 | interface IColorguard { 10 | (opts?: IOptions): NodeJS.ReadWriteStream; 11 | } 12 | 13 | const colorguard: IColorguard; 14 | export = colorguard; 15 | } 16 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/doiuse.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'doiuse' { 2 | 3 | interface IOptions { 4 | browsers?: string[]; 5 | ignore?: string[]; 6 | ignoreFiles?: string[]; 7 | onFeatureUsage?: Function; 8 | } 9 | 10 | interface IDoiuse { 11 | (opts?: IOptions): NodeJS.ReadWriteStream; 12 | } 13 | 14 | const doiuse: IDoiuse; 15 | export = doiuse; 16 | } 17 | -------------------------------------------------------------------------------- /tools/utils/seed.utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This barrel file provides the export for the utilities provided by the seed. 3 | */ 4 | export * from './seed/clean'; 5 | export * from './seed/code_change_tools'; 6 | export * from './seed/server'; 7 | export * from './seed/tasks_tools'; 8 | export * from './seed/template_locals'; 9 | export * from './seed/tsproject'; 10 | export * from './seed/watch'; 11 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/stylelint.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'stylelint' { 2 | 3 | interface IOptions { 4 | config?: Object; 5 | configFile?: string; 6 | configBasedir?: string; 7 | configOverrides?: Object; 8 | } 9 | 10 | interface IStylelint { 11 | (opts?: IOptions): NodeJS.ReadWriteStream; 12 | } 13 | 14 | const stylelint: IStylelint; 15 | export = stylelint; 16 | } 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **IMPORTANT**: This repository's issues are reserved for feature requests and bug reports. Do not submit support requests here. 2 | 3 | 4 | **Steps to reproduce and a minimal demo of the problem** 5 | 6 | _What steps should we try in your demo to see the problem?_ 7 | 8 | **Current behavior** 9 | 10 | 11 | **Expected/desired behavior** 12 | 13 | 14 | **Other information** 15 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/systemjs-builder.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'systemjs-builder' { 2 | class Builder { 3 | constructor(configObject?: any, baseUrl?: string, configPath?: string); 4 | bundle(source: string, target: string, options?: any): Promise; 5 | buildStatic(source: string, target: string, options?: any): Promise; 6 | } 7 | 8 | module Builder {} 9 | export = Builder; 10 | } 11 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/cssnano.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'cssnano' { 2 | 3 | interface IOptions { 4 | discardComments?: { 5 | removeAll: boolean; 6 | }; 7 | discardUnused?: boolean; 8 | zindex?: boolean; 9 | reduceIdents?: boolean; 10 | } 11 | 12 | interface ICssnano { 13 | (opts?: IOptions): NodeJS.ReadWriteStream; 14 | } 15 | 16 | const cssnano: ICssnano; 17 | export = cssnano; 18 | } 19 | -------------------------------------------------------------------------------- /tools/debug.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import { argv } from 'yargs'; 3 | 4 | require('../gulpfile'); 5 | 6 | const TASK = argv['task']; 7 | 8 | if (!TASK) { 9 | throw new Error('You must specify a task name.'); 10 | } 11 | 12 | console.log('**********************'); 13 | console.log('* angular2-seed tools '); 14 | console.log('* debugging task:', TASK); 15 | console.log('**********************'); 16 | 17 | gulp.start(TASK); 18 | -------------------------------------------------------------------------------- /tools/tasks/project/sample.task.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | /** 7 | * This sample task copies all TypeScript files over to the appropiate `dist/dev|prod|test` directory, depending on the 8 | * current application environment. 9 | */ 10 | export = () => { 11 | return gulp.src(join(Config.APP_SRC, '**/*.ts')) 12 | .pipe(gulp.dest(Config.APP_DEST)); 13 | }; 14 | -------------------------------------------------------------------------------- /src/client/css/main.css: -------------------------------------------------------------------------------- 1 | button { 2 | background-color: #106cc8; 3 | border-style: none; 4 | color: rgba(255, 255, 255, 0.87); 5 | cursor: pointer; 6 | display: inline-block; 7 | font-size: 14px; 8 | height: 40px; 9 | padding: 8px 18px; 10 | text-decoration: none; 11 | } 12 | 13 | body { 14 | font-size: 16px; 15 | font-family: San Francisco Text; 16 | } 17 | 18 | input { 19 | padding: 8px; 20 | font-size: 16px; 21 | color: #777; 22 | } 23 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/express-history-api-fallback.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'express-history-api-fallback' { 2 | 3 | import { RequestHandler } from 'express'; 4 | 5 | interface IOptions { 6 | maxAge?: number; 7 | root?: string; 8 | lastModified?: number; 9 | headers?: { [key: string]: string; }; 10 | dotfiles?: boolean; 11 | } 12 | 13 | function fallback(index: string, options?: IOptions): RequestHandler; 14 | 15 | module fallback {} 16 | 17 | export = fallback; 18 | } 19 | -------------------------------------------------------------------------------- /tools/manual_typings/seed/postcss-reporter.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'postcss-reporter' { 2 | 3 | interface IOptions { 4 | clearMessages?: boolean; 5 | formatter?: Function; 6 | plugins?: string[]; 7 | throwError?: boolean; 8 | sortByPosition?: boolean; 9 | positionless?: string; 10 | noIcon?: boolean; 11 | noPlugin?: boolean; 12 | } 13 | 14 | interface IPostcssReporter { 15 | (opts?: IOptions): NodeJS.ReadWriteStream; 16 | } 17 | 18 | const postcssReporter: IPostcssReporter; 19 | export = postcssReporter; 20 | } 21 | -------------------------------------------------------------------------------- /tools/tasks/seed/print.banner.ts: -------------------------------------------------------------------------------- 1 | import Config from '../../config'; 2 | import { readFile } from 'fs'; 3 | import * as util from 'gulp-util'; 4 | import { join } from 'path'; 5 | 6 | export = (done: any) => { 7 | let bannerPath = join(Config.TOOLS_DIR, 'config', 'banner.txt'); 8 | if (require('supports-color').has256) { 9 | bannerPath = join(Config.TOOLS_DIR, 'config', 'banner-256.txt'); 10 | } 11 | readFile(bannerPath, (e, content) => { 12 | if (!e) { 13 | console.log(util.colors.green(content.toString())); 14 | } 15 | done(); 16 | }); 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /tools/tasks/seed/serve.coverage.watch.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import * as browserSync from 'browser-sync'; 3 | 4 | import Config from '../../config'; 5 | 6 | export = () => { 7 | let coverageFolder = Config.COVERAGE_DIR; 8 | let watchedFiles: string[] = [join(coverageFolder, '**')]; 9 | 10 | // Serve files from the coverage of this project 11 | browserSync.create().init({ 12 | server: { 13 | baseDir: './' + coverageFolder 14 | }, 15 | port: Config.COVERAGE_PORT, 16 | files: watchedFiles, 17 | logFileChanges: false 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /tools/tasks/seed/karma.watch.ts: -------------------------------------------------------------------------------- 1 | import { startKarma } from '../../utils/seed/karma.start'; 2 | /** 3 | * Executes the build process, running all unit tests using `karma`. 4 | */ 5 | export = (done: any) => setTimeout(() => { 6 | return startKarma(done, { 7 | singleRun: false 8 | }); 9 | }, 10 | // On some OS, the default max opened file descriptor limit might cause karma to not start. 11 | // By setting this timeout, there should be enough time before other tasks release the descriptors. 12 | // Karma itself can have as many opened files as it needs, it uses graceful-fs. 13 | 1000); 14 | -------------------------------------------------------------------------------- /tools/tasks/seed/generate.manifest.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | 3 | import Config from '../../config'; 4 | 5 | /** 6 | * Executes the build process, generating the manifest file using `angular2-service-worker`. 7 | */ 8 | export = () => { 9 | return require('angular2-service-worker') 10 | .gulpGenManifest({ 11 | group: [{ 12 | name: 'css', 13 | sources: gulp.src(`${Config.APP_DEST}/**/*.css`) 14 | }, { 15 | name: 'js', 16 | sources: gulp.src(`${Config.APP_DEST}/**/*.js`) 17 | }] 18 | }) 19 | .pipe(gulp.dest(Config.APP_DEST)); 20 | }; 21 | -------------------------------------------------------------------------------- /tools/tasks/seed/clear.files.ts: -------------------------------------------------------------------------------- 1 | import * as del from 'del'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | /** 7 | * Removes all the js, js.map and metadata.json from the src and tools directories 8 | */ 9 | export = () => { 10 | let source = [ 11 | 'gulpfile.js', 12 | 'gulpfile.js.map', 13 | join(Config.TOOLS_DIR, '**/*.js'), 14 | join(Config.TOOLS_DIR, '**/*.js.map'), 15 | join(Config.TOOLS_DIR, '**/*.metadata.json'), 16 | join(Config.APP_SRC, '**/*.js'), 17 | join(Config.APP_SRC, '**/*.js.map'), 18 | join(Config.APP_SRC, '**/*.metadata.json') 19 | ]; 20 | 21 | return del.sync(source); 22 | }; 23 | -------------------------------------------------------------------------------- /src/client/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { APP_BASE_HREF } from '@angular/common'; 4 | import { FormsModule } from '@angular/forms'; 5 | 6 | import { AppComponent, TodoAppComponent, TodoComponent, TodoInputComponent, FooterComponent, TodoList } from './app'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | BrowserModule, 11 | FormsModule 12 | ], 13 | declarations: [ 14 | AppComponent, 15 | TodoComponent, 16 | TodoInputComponent, 17 | TodoAppComponent!, 18 | FooterComponent 19 | ], 20 | bootstrap: [AppComponent] 21 | }) 22 | export class AppModule {} 23 | 24 | -------------------------------------------------------------------------------- /tools/tasks/seed/copy.prod.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | /** 7 | * Executes the build task, copying all TypeScript files over to the `dist/tmp` directory. 8 | */ 9 | export = () => { 10 | return gulp.src([ 11 | join(Config.APP_SRC, '**/*.ts'), 12 | join(Config.APP_SRC, '**/*.html'), 13 | join(Config.APP_SRC, '**/*.css'), 14 | join(Config.APP_SRC, '**/*.json'), 15 | join(Config.APP_SRC, '*.json'), 16 | '!' + join(Config.APP_SRC, '**/*.spec.ts'), 17 | '!' + join(Config.APP_SRC, '**/*.e2e-spec.ts') 18 | ]) 19 | .pipe(gulp.dest(Config.TMP_DIR)); 20 | }; 21 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.bundles.app.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import * as Builder from 'systemjs-builder'; 3 | 4 | import Config from '../../config'; 5 | 6 | const BUNDLER_OPTIONS = { 7 | format: 'cjs', 8 | minify: true, 9 | mangle: false 10 | }; 11 | 12 | /** 13 | * Executes the build process, bundling the JavaScript files using the SystemJS builder. 14 | */ 15 | export = (done: any) => { 16 | let builder = new Builder(Config.SYSTEM_BUILDER_CONFIG); 17 | builder 18 | .buildStatic(join(Config.TMP_DIR, Config.BOOTSTRAP_PROD_MODULE), 19 | join(Config.JS_DEST, Config.JS_PROD_APP_BUNDLE), 20 | BUNDLER_OPTIONS) 21 | .then(() => done()) 22 | .catch((err: any) => done(err)); 23 | }; 24 | -------------------------------------------------------------------------------- /tools/tasks/seed/minify.bundles.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import * as merge from 'merge-stream'; 4 | import { join } from 'path'; 5 | 6 | import Config from '../../config'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | const getTask = (target: string, destDir: string) => { 11 | return gulp.src(join(destDir, target)) 12 | .pipe(plugins.uglify({ 13 | compress: true, 14 | mangle: true 15 | })) 16 | .pipe(gulp.dest(destDir)); 17 | }; 18 | 19 | export = () => { 20 | return merge( 21 | getTask(Config.JS_PROD_APP_BUNDLE, Config.JS_DEST), 22 | getTask(Config.JS_PROD_SHIMS_BUNDLE, Config.JS_DEST) 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.bundles.app.exp.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import * as Builder from 'systemjs-builder'; 3 | 4 | import Config from '../../config'; 5 | 6 | const BUNDLER_OPTIONS = { 7 | format: 'cjs', 8 | minify: true, 9 | mangle: false 10 | }; 11 | 12 | /** 13 | * Executes the build process, bundling the JavaScript files using the SystemJS builder. 14 | */ 15 | export = (done: any) => { 16 | let builder = new Builder(Config.SYSTEM_BUILDER_CONFIG); 17 | builder 18 | .buildStatic(join(Config.TMP_DIR, Config.BOOTSTRAP_FACTORY_PROD_MODULE), 19 | join(Config.JS_DEST, Config.JS_PROD_APP_BUNDLE), 20 | BUNDLER_OPTIONS) 21 | .then(() => done()) 22 | .catch((err: any) => done(err)); 23 | }; 24 | -------------------------------------------------------------------------------- /tools/tasks/seed/tslint.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | 7 | const plugins = gulpLoadPlugins(); 8 | 9 | /** 10 | * Executes the build process, linting the TypeScript files using `codelyzer`. 11 | */ 12 | export = () => { 13 | let src = [ 14 | join(Config.APP_SRC, '**/*.ts'), 15 | '!' + join(Config.APP_SRC, '**/*.d.ts'), 16 | join(Config.TOOLS_DIR, '**/*.ts'), 17 | '!' + join(Config.TOOLS_DIR, '**/*.d.ts') 18 | ]; 19 | 20 | return gulp.src(src) 21 | .pipe(plugins.tslint()) 22 | .pipe(plugins.tslint.report({ 23 | emitError: require('is-ci') 24 | })); 25 | }; 26 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.assets.dev.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import { join } from 'path'; 3 | 4 | import { AssetsTask } from '../assets_task'; 5 | import Config from '../../config'; 6 | 7 | /** 8 | * Executes the build process, copying the assets located in `src/client` over to the appropriate 9 | * `dist/dev` directory. 10 | */ 11 | export = 12 | class BuildAssetsTask extends AssetsTask { 13 | run() { 14 | let paths: string[] = [ 15 | join(Config.APP_SRC, '**'), 16 | '!' + join(Config.APP_SRC, '**', '*.ts'), 17 | '!' + join(Config.APP_SRC, '**', '*.scss'), 18 | '!' + join(Config.APP_SRC, '**', '*.sass') 19 | ].concat(Config.TEMP_FILES.map((p) => { return '!' + p; })); 20 | 21 | return gulp.src(paths) 22 | .pipe(gulp.dest(Config.APP_DEST)); 23 | } 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Submitting Pull Requests 2 | 3 | **Please follow these basic steps to simplify pull request reviews - if you don't you'll probably just be asked to anyway.** 4 | 5 | * Please rebase your branch against the current master 6 | * Run ```npm install``` to make sure your development dependencies are up-to-date 7 | * Please ensure that the test suite passes **and** that code is lint free before submitting a PR by running: 8 | * ```npm test``` 9 | * If you've added new functionality, **please** include tests which validate its behaviour 10 | * Make reference to possible [issues](https://github.com/mgechev/angular2-seed/issues) on PR comment 11 | 12 | ## Submitting bug reports 13 | 14 | * Please detail the affected browser(s) and operating system(s) 15 | * Please be sure to state which version of node **and** npm you're using 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "lib": ["es6", "es2015", "dom"], 11 | "sourceMap": true, 12 | "pretty": true, 13 | "allowUnreachableCode": false, 14 | "allowUnusedLabels": false, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitUseStrict": false, 18 | "noFallthroughCasesInSwitch": true, 19 | "typeRoots": [ 20 | "./node_modules/@types", 21 | "./node_modules" 22 | ], 23 | "types": [ 24 | "node" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "dist", 30 | "src" 31 | ], 32 | "compileOnSave": false 33 | } 34 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.bundle.rxjs.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Temporary fix. See https://github.com/angular/angular/issues/9359 3 | */ 4 | 5 | const Builder = require('systemjs-builder'); 6 | 7 | export = (done: any) => { 8 | const options = { 9 | normalize: true, 10 | runtime: false, 11 | sourceMaps: true, 12 | sourceMapContents: true, 13 | minify: true, 14 | mangle: false 15 | }; 16 | var builder = new Builder('./'); 17 | builder.config({ 18 | paths: { 19 | 'n:*': 'node_modules/*', 20 | 'rxjs/*': 'node_modules/rxjs/*.js', 21 | }, 22 | map: { 23 | 'rxjs': 'n:rxjs', 24 | }, 25 | packages: { 26 | 'rxjs': {main: 'Rx.js', defaultExtension: 'js'}, 27 | } 28 | }); 29 | builder.bundle('rxjs', 'node_modules/.tmp/Rx.min.js', options) 30 | .then(() => done()) 31 | .catch((error:any) => done(error)); 32 | }; 33 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.test.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | import { makeTsProject } from '../../utils'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | /** 11 | * Executes the build process, transpiling the TypeScript files (excluding the spec and e2e-spec files) for the test 12 | * environment. 13 | */ 14 | export = () => { 15 | let tsProject = makeTsProject(); 16 | let src = [ 17 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts', 18 | join(Config.APP_SRC, '**/*.spec.ts') 19 | ]; 20 | let result = gulp.src(src) 21 | .pipe(plugins.plumber()) 22 | .pipe(plugins.sourcemaps.init()) 23 | .pipe(tsProject()); 24 | 25 | return result.js 26 | .pipe(plugins.sourcemaps.write()) 27 | .pipe(gulp.dest(Config.APP_DEST)); 28 | }; 29 | -------------------------------------------------------------------------------- /tools/utils/seed/tsproject.ts: -------------------------------------------------------------------------------- 1 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | const plugins = gulpLoadPlugins(); 7 | 8 | let tsProjects: any = {}; 9 | 10 | /** 11 | * Creates a TypeScript project with the given options using the gulp typescript plugin. 12 | * @param {Object} options - The additional options for the project configuration. 13 | */ 14 | export function makeTsProject(options: Object = {}, pathToTsConfig: string = Config.APP_SRC) { 15 | let optionsHash = JSON.stringify(options); 16 | if (!tsProjects[optionsHash]) { 17 | let config = Object.assign({ 18 | typescript: require('typescript') 19 | }, options); 20 | tsProjects[optionsHash] = 21 | plugins.typescript.createProject(join(pathToTsConfig, 'tsconfig.json'), config); 22 | } 23 | return tsProjects[optionsHash]; 24 | } 25 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.tools.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | import { makeTsProject, templateLocals, } from '../../utils'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | /** 11 | * Executes the build process, transpiling the TypeScript files within the `tools` directory. 12 | */ 13 | export = () => { 14 | let tsProject = makeTsProject(); 15 | let src = [ 16 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts', 17 | join(Config.TOOLS_DIR, '**/*.ts') 18 | ]; 19 | let result = gulp.src(src, { base: './' }) 20 | .pipe(plugins.plumber()) 21 | .pipe(plugins.sourcemaps.init()) 22 | .pipe(tsProject()); 23 | 24 | return result.js 25 | .pipe(plugins.sourcemaps.write()) 26 | .pipe(plugins.template(templateLocals())) 27 | .pipe(gulp.dest('./')); 28 | }; 29 | -------------------------------------------------------------------------------- /src/client/app/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstraps the application and makes the ROUTER_PROVIDERS and the APP_BASE_HREF available to it. 3 | * @see https://angular.io/docs/ts/latest/api/platform-browser-dynamic/index/bootstrap-function.html 4 | */ 5 | import { enableProdMode } from '@angular/core'; 6 | // The browser platform with a compiler 7 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 8 | // Load i18n providers 9 | // import { TranslationProviders } from './i18n.providers'; 10 | 11 | // The app module 12 | import { AppModule } from './app.module'; 13 | 14 | if (String('<%= ENV %>') === 'prod') { enableProdMode(); } 15 | 16 | // Compile and launch the module with i18n providers 17 | // let TP = new TranslationProviders(); 18 | // TP.getTranslationFile().then((providers: any) => { 19 | // const options: any = { providers }; 20 | platformBrowserDynamic().bootstrapModule(AppModule/*, options*/); 21 | // }); 22 | -------------------------------------------------------------------------------- /tools/utils/seed/watch.ts: -------------------------------------------------------------------------------- 1 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 2 | import { join } from 'path'; 3 | import * as runSequence from 'run-sequence'; 4 | 5 | import Config from '../../config'; 6 | import { changeFileManager } from './code_change_tools'; 7 | import { notifyLiveReload } from '../../utils'; 8 | 9 | const plugins = gulpLoadPlugins(); 10 | 11 | /** 12 | * Watches the task with the given taskname. 13 | * @param {string} taskname - The name of the task. 14 | */ 15 | export function watch(taskname: string) { 16 | return function () { 17 | let paths:string[]=[ 18 | join(Config.APP_SRC,'**') 19 | ].concat(Config.TEMP_FILES.map((p) => { return '!'+p; })); 20 | 21 | plugins.watch(paths, (e: any) => { 22 | changeFileManager.addFile(e.path); 23 | 24 | runSequence(taskname, () => { 25 | changeFileManager.clear(); 26 | notifyLiveReload(e); 27 | }); 28 | }); 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": false, 6 | "removeComments": true, 7 | "noLib": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "sourceMap": true, 11 | "pretty": true, 12 | "allowUnreachableCode": false, 13 | "allowUnusedLabels": false, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitUseStrict": false, 17 | "noFallthroughCasesInSwitch": true, 18 | "typeRoots": [ 19 | "../../node_modules/@types", 20 | "../../node_modules" 21 | ], 22 | "types": [ 23 | "core-js", 24 | "express", 25 | "jasmine", 26 | "node", 27 | "protractor", 28 | "systemjs" 29 | ] 30 | }, 31 | "exclude": [ 32 | "node_modules", 33 | "dist", 34 | "src" 35 | ], 36 | "compileOnSave": false 37 | } 38 | -------------------------------------------------------------------------------- /tools/utils/seed/clean.ts: -------------------------------------------------------------------------------- 1 | import * as util from 'gulp-util'; 2 | import * as rimraf from 'rimraf'; 3 | 4 | /** 5 | * Cleans the given path(s) using `rimraf`. 6 | * @param {string or string[]} paths - The path or list of paths to clean. 7 | */ 8 | export function clean(paths: string|string[]): (done: () => void) => void { 9 | return done => { 10 | let pathsToClean: string[]; 11 | if (paths instanceof Array) { 12 | pathsToClean = paths; 13 | } else { 14 | pathsToClean = [paths]; 15 | } 16 | 17 | let promises = pathsToClean.map(p => { 18 | return new Promise(resolve => { 19 | rimraf(p, e => { 20 | if (e) { 21 | util.log('Clean task failed with', e); 22 | } else { 23 | util.log('Deleted', util.colors.yellow(p || '-')); 24 | } 25 | resolve(); 26 | }); 27 | }); 28 | }); 29 | Promise.all(promises).then(() => done()); 30 | }; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tools/tasks/task.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Base class for all tasks. 3 | */ 4 | export abstract class Task { 5 | /** 6 | * Override this task if you want to implement some custom 7 | * task activation mechanism. By default each task will be always executed. 8 | * 9 | * @param {string[]} files A list of files changed since the previous watch. 10 | */ 11 | shallRun(files: string[]): boolean { 12 | return true; 13 | } 14 | 15 | /** 16 | * Implements your task behavior. 17 | * 18 | * @param {any} done A function which should be activated once your task completes. 19 | * @return {ReadWriteStream | Promise | void} This method can either return a promise 20 | * which should be resolved once your task execution completes, a stream 21 | * which should throw an end event once your task execution completes 22 | * or nothing in case you will manually invoke the `done` method. 23 | */ 24 | abstract run(done?: any): any | Promise | void; 25 | } 26 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.prod.exp.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | import { makeTsProject, templateLocals } from '../../utils'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | /** 11 | * Executes the build process, transpiling the TypeScript files for the production environment. 12 | */ 13 | 14 | export = () => { 15 | let tsProject = makeTsProject({}, Config.TMP_DIR); 16 | let src = [ 17 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts', 18 | join(Config.TMP_DIR, '**/*.ts') 19 | ]; 20 | let result = gulp.src(src) 21 | .pipe(plugins.plumber()) 22 | .pipe(tsProject()) 23 | .once('error', function(e: any) { 24 | this.once('finish', () => process.exit(1)); 25 | }); 26 | 27 | 28 | return result.js 29 | .pipe(plugins.template(templateLocals())) 30 | .pipe(gulp.dest(Config.TMP_DIR)) 31 | .on('error', (e: any) => { 32 | console.log(e); 33 | }); 34 | }; 35 | -------------------------------------------------------------------------------- /src/client/app/main-prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstraps the application and makes the ROUTER_PROVIDERS and the APP_BASE_HREF available to it. 3 | * @see https://angular.io/docs/ts/latest/api/platform-browser-dynamic/index/bootstrap-function.html 4 | */ 5 | import { enableProdMode } from '@angular/core'; 6 | import { platformBrowser } from '@angular/platform-browser'; 7 | 8 | import { AppModuleNgFactory } from './app.module.ngfactory'; 9 | 10 | enableProdMode(); 11 | 12 | platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); 13 | 14 | // In order to start the Service Worker located at "./worker.js" 15 | // uncomment this line. More about Service Workers here 16 | // https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers 17 | // 18 | // if ('serviceWorker' in navigator) { 19 | // (navigator).serviceWorker.register('./worker.js').then((registration: any) => 20 | // console.log('ServiceWorker registration successful with scope: ', registration.scope)) 21 | // .catch((err: any) => 22 | // console.log('ServiceWorker registration failed: ', err)); 23 | // } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | coverage_js 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Compiled binary addons (http://nodejs.org/api/addons.html) 21 | build/Release 22 | 23 | # Dependency directory 24 | # Commenting this out is preferred by some people, see 25 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 26 | node_modules 27 | typings 28 | ts-node 29 | 30 | # Users Environment Variables 31 | .lock-wscript 32 | .tsdrc 33 | .typingsrc 34 | 35 | #IDE configuration files 36 | .idea 37 | .vscode 38 | *.iml 39 | 40 | /tools/**/*.js 41 | dist 42 | dev 43 | docs 44 | lib 45 | test 46 | tmp 47 | 48 | gulpfile.js 49 | gulpfile.js.map 50 | 51 | # OS X trash files 52 | .DS_Store 53 | src/client/app/shared/config/env.config.js 54 | src/client/app/shared/config/env.config.js.map 55 | -------------------------------------------------------------------------------- /tools/tasks/seed/e2e.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import * as history from 'express-history-api-fallback'; 3 | import * as gulp from 'gulp'; 4 | import { resolve } from 'path'; 5 | import { protractor } from 'gulp-protractor'; 6 | 7 | class Protractor { 8 | server(port: number, dir: string) { 9 | let app = express(); 10 | let root = resolve(process.cwd(), dir); 11 | app.use(express.static(root)); 12 | app.use(history('index.html', { root })); 13 | return new Promise((resolve, reject) => { 14 | let server = app.listen(port, () => { 15 | resolve(server); 16 | }); 17 | }); 18 | } 19 | } 20 | 21 | /** 22 | * Executes the build process, running all e2e specs using `protractor`. 23 | */ 24 | export = (done: any) => { 25 | new Protractor() 26 | .server(5555, './dist/prod') 27 | .then((server: any) => { 28 | gulp 29 | .src('./dist/dev/**/*.e2e-spec.js') 30 | .pipe(protractor({ configFile: 'protractor.conf.js' })) 31 | .on('error', (error: string) => { throw error; }) 32 | .on('end', () => { server.close(done); }); 33 | }); 34 | }; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Minko Gechev 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tools/tasks/seed/karma.run.with_coverage.ts: -------------------------------------------------------------------------------- 1 | import * as karma from 'karma'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | let repeatableStartKarma = (done: any, config: any = {}) => { 7 | return new (karma).Server(Object.assign({ 8 | configFile: join(process.cwd(), 'karma.conf.js'), 9 | singleRun: true 10 | }, config), (exitCode: any) => { 11 | // Karma run is finished but do not exit the process for failure. Rather just mark this task as done. 12 | done(); 13 | }).start(); 14 | }; 15 | 16 | export = (done: any) => { 17 | return repeatableStartKarma(done, { 18 | preprocessors: { 19 | 'dist/**/!(*spec|index|*.module|*.routes).js': ['coverage'] 20 | }, 21 | reporters: ['mocha', 'coverage', 'karma-remap-istanbul'], 22 | coverageReporter: { 23 | dir: 'coverage_js/', 24 | reporters: [ 25 | { type: 'json', subdir: '.', file: 'coverage-final.json' }, 26 | { type: 'html', subdir: '.' } 27 | ] 28 | }, 29 | remapIstanbulReporter: { 30 | reports: { 31 | html: Config.COVERAGE_DIR 32 | } 33 | }, 34 | singleRun: true 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.bundles.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import * as merge from 'merge-stream'; 4 | 5 | import Config from '../../config'; 6 | 7 | const plugins = gulpLoadPlugins(); 8 | 9 | /** 10 | * Executes the build process, bundling the shim files. 11 | */ 12 | export = () => merge(bundleShims()); 13 | 14 | /** 15 | * Returns the shim files to be injected. 16 | */ 17 | function getShims() { 18 | let libs = Config.DEPENDENCIES 19 | .filter(d => /\.js$/.test(d.src)); 20 | 21 | return libs.filter(l => l.inject === 'shims') 22 | .concat(libs.filter(l => l.inject === 'libs')) 23 | .concat(libs.filter(l => l.inject === true)) 24 | .map(l => l.src); 25 | } 26 | 27 | /** 28 | * Bundles the shim files. 29 | */ 30 | function bundleShims() { 31 | return gulp.src(getShims()) 32 | .pipe(plugins.concat(Config.JS_PROD_SHIMS_BUNDLE)) 33 | // Strip the first (global) 'use strict' added by reflect-metadata, but don't strip any others to avoid unintended scope leaks. 34 | .pipe(plugins.replace(/('|")use strict\1;var Reflect;/, 'var Reflect;')) 35 | .pipe(gulp.dest(Config.JS_DEST)); 36 | } 37 | -------------------------------------------------------------------------------- /src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= APP_TITLE %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Loading... 16 | 17 | 21 | 22 | 23 | 24 | 25 | <% if (ENV === 'dev') { %> 26 | 27 | <% } %> 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | <% if (ENV === 'dev') { %> 36 | 43 | <% } %> 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tools/utils/seed/template_locals.ts: -------------------------------------------------------------------------------- 1 | import * as util from 'gulp-util'; 2 | import { argv } from 'yargs'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | 7 | const getConfig = (path: string, env: string): any => { 8 | const configPath = join(path, env); 9 | let config: any; 10 | try { 11 | config = require(configPath); 12 | } catch (e) { 13 | config = null; 14 | util.log(util.colors.red(e.message)); 15 | } 16 | 17 | return config; 18 | }; 19 | 20 | /** 21 | * Returns the project configuration (consisting of the base configuration provided by seed.config.ts and the additional 22 | * project specific overrides as defined in project.config.ts) 23 | */ 24 | export function templateLocals() { 25 | const configEnvName = argv['config-env'] || 'dev'; 26 | const configPath = Config.getPluginConfig('environment-config'); 27 | const baseConfig = getConfig(configPath, 'base'); 28 | const config = getConfig(configPath, configEnvName); 29 | 30 | if (!config) { 31 | throw new Error('Invalid configuration name'); 32 | } 33 | 34 | return Object.assign(Config, { 35 | ENV_CONFIG: JSON.stringify(Object.assign(baseConfig, config)) 36 | }); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.assets.prod.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import { join } from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | // TODO There should be more elegant to prevent empty directories from copying 7 | var onlyDirs = function (es: any) { 8 | return es.map(function (file: any, cb: any) { 9 | if (file.stat.isFile()) { 10 | return cb(null, file); 11 | } else { 12 | return cb(); 13 | } 14 | }); 15 | }; 16 | 17 | /** 18 | * Executes the build process, copying the assets located in `src/client` over to the appropriate 19 | * `dist/prod` directory. 20 | */ 21 | export = () => { 22 | let es: any = require('event-stream'); 23 | return gulp.src([ 24 | join(Config.APP_SRC, '**'), 25 | '!' + join(Config.APP_SRC, 'tsconfig.json'), 26 | '!' + join(Config.APP_SRC, '**', '*.ts'), 27 | '!' + join(Config.APP_SRC, '**', '*.css'), 28 | '!' + join(Config.APP_SRC, '**', '*.html'), 29 | '!' + join(Config.APP_SRC, '**', '*.scss'), 30 | '!' + join(Config.APP_SRC, '**', '*.sass'), 31 | '!' + join(Config.ASSETS_SRC, '**', '*.js') 32 | ].concat(Config.TEMP_FILES.map((p) => { return '!' + p; }))) 33 | .pipe(onlyDirs(es)) 34 | .pipe(gulp.dest(Config.APP_DEST)); 35 | }; 36 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | import { makeTsProject, templateLocals } from '../../utils'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | const jsonSystemConfig = JSON.stringify(Config.SYSTEM_CONFIG_DEV); 10 | 11 | /** 12 | * Executes the build process, transpiling the TypeScript files (including the e2e-spec files, excluding the spec files) 13 | * for the e2e environment. 14 | */ 15 | export = () => { 16 | let tsProject = makeTsProject(); 17 | let src = [ 18 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts', 19 | join(Config.APP_SRC, '**/*.ts'), 20 | '!' + join(Config.APP_SRC, '**/*.spec.ts'), 21 | '!' + join(Config.TMP_DIR, `**/${Config.NG_FACTORY_FILE}.ts`) 22 | ]; 23 | let result = gulp.src(src) 24 | .pipe(plugins.plumber()) 25 | .pipe(plugins.sourcemaps.init()) 26 | .pipe(tsProject()); 27 | 28 | return result.js 29 | .pipe(plugins.sourcemaps.write()) 30 | .pipe(plugins.template(Object.assign(templateLocals(), { 31 | SYSTEM_CONFIG_DEV: jsonSystemConfig 32 | }))) 33 | .pipe(gulp.dest(Config.APP_DEST)); 34 | }; 35 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.docs.ts: -------------------------------------------------------------------------------- 1 | // import * as gulp from 'gulp'; 2 | // import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | // import { join } from 'path'; 4 | // 5 | // import { APP_SRC, APP_TITLE, DOCS_DEST } from '../../config'; 6 | // 7 | // const plugins = gulpLoadPlugins(); 8 | // 9 | // /** 10 | // * Executes the build process, building the documentation for the TypeScript 11 | // * files (excluding spec and e2e-spec files) using `typedoc`. 12 | // */ 13 | // export = () => { 14 | // 15 | // let src = [ 16 | // 'typings/index.d.ts', 17 | // join(APP_SRC, '**/*.ts'), 18 | // '!' + join(APP_SRC, '**/*.spec.ts'), 19 | // '!' + join(APP_SRC, '**/*.e2e-spec.ts') 20 | // ]; 21 | // 22 | // return gulp.src(src) 23 | // .pipe(plugins.typedoc({ 24 | // // TypeScript options (see typescript docs) 25 | // module: 'commonjs', 26 | // target: 'es5', 27 | // // excludeExternals: true, 28 | // includeDeclarations: true, 29 | // // Output options (see typedoc docs) 30 | // out: DOCS_DEST, 31 | // json: join(DOCS_DEST, 'data/docs.json'), 32 | // name: APP_TITLE, 33 | // ignoreCompilerErrors: false, 34 | // experimentalDecorators: true, 35 | // version: true 36 | // })); 37 | // }; 38 | 39 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | baseUrl: 'http://localhost:5555/', 3 | 4 | specs: [ 5 | './dist/dev/**/*.e2e-spec.js' 6 | ], 7 | 8 | exclude: [], 9 | 10 | // 'jasmine' by default will use the latest jasmine framework 11 | framework: 'jasmine', 12 | 13 | // allScriptsTimeout: 110000, 14 | 15 | jasmineNodeOpts: { 16 | // showTiming: true, 17 | showColors: true, 18 | isVerbose: false, 19 | includeStackTrace: false, 20 | // defaultTimeoutInterval: 400000 21 | }, 22 | 23 | directConnect: true, 24 | 25 | capabilities: { 26 | browserName: 'chrome' 27 | }, 28 | 29 | onPrepare: function() { 30 | const SpecReporter = require('jasmine-spec-reporter'); 31 | // add jasmine spec reporter 32 | jasmine.getEnv().addReporter(new SpecReporter({ displayStacktrace: true })); 33 | 34 | browser.ignoreSynchronization = false; 35 | }, 36 | 37 | 38 | /** 39 | * Angular 2 configuration 40 | * 41 | * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching 42 | * `rootEl` 43 | */ 44 | useAllAngular2AppRoots: true 45 | }; 46 | 47 | if (process.env.TRAVIS) { 48 | config.capabilities = { 49 | browserName: 'firefox' 50 | }; 51 | } 52 | 53 | exports.config = config; 54 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.prod.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | 5 | import Config from '../../config'; 6 | import { makeTsProject, templateLocals } from '../../utils'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | const INLINE_OPTIONS = { 11 | base: Config.TMP_DIR, 12 | useRelativePaths: true, 13 | removeLineBreaks: true 14 | }; 15 | 16 | /** 17 | * Executes the build process, transpiling the TypeScript files for the production environment. 18 | */ 19 | 20 | export = () => { 21 | let tsProject = makeTsProject({}, Config.TMP_DIR); 22 | let src = [ 23 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts', 24 | join(Config.TMP_DIR, '**/*.ts'), 25 | '!' + join(Config.TMP_DIR, `**/${Config.NG_FACTORY_FILE}.ts`) 26 | ]; 27 | let result = gulp.src(src) 28 | .pipe(plugins.plumber()) 29 | .pipe(plugins.inlineNg2Template(INLINE_OPTIONS)) 30 | .pipe(tsProject()) 31 | .once('error', function(e: any) { 32 | this.once('finish', () => process.exit(1)); 33 | }); 34 | 35 | 36 | return result.js 37 | .pipe(plugins.template(templateLocals())) 38 | .pipe(gulp.dest(Config.TMP_DIR)) 39 | .on('error', (e: any) => { 40 | console.log(e); 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 140, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "ng": false 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tools/tasks/seed/clean.tools.ts: -------------------------------------------------------------------------------- 1 | import { lstatSync, readdirSync } from 'fs'; 2 | import * as util from 'gulp-util'; 3 | import * as rimraf from 'rimraf'; 4 | import { join } from 'path'; 5 | 6 | import Config from '../../config'; 7 | 8 | /** 9 | * Executes the build process, deleting all JavaScrip files (which were transpiled from the TypeScript sources) with in 10 | * the `tools` directory. 11 | */ 12 | export = (done: any) => { 13 | deleteAndWalk(Config.TOOLS_DIR); 14 | done(); 15 | }; 16 | 17 | /** 18 | * Recursively walks along the given path and deletes all JavaScript files. 19 | * @param {any} path - The path to walk and clean. 20 | */ 21 | function walk(path: any) { 22 | let files = readdirSync(path); 23 | for (let i = 0; i < files.length; i += 1) { 24 | let curPath = join(path, files[i]); 25 | if (lstatSync(curPath).isDirectory()) { // recurse 26 | deleteAndWalk(curPath); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Deletes the JavaScript file with the given path. 33 | * @param {any} path - The path of the JavaScript file to be deleted. 34 | */ 35 | function deleteAndWalk(path: any) { 36 | try { 37 | rimraf.sync(join(path, '*.js')); 38 | util.log('Deleted', util.colors.yellow(`${path}/*.js`)); 39 | } catch (e) { 40 | util.log('Error while deleting', util.colors.yellow(`${path}/*.js`), e); 41 | } 42 | walk(path); 43 | } 44 | -------------------------------------------------------------------------------- /tools/tasks/seed/check.versions.ts: -------------------------------------------------------------------------------- 1 | import * as util from 'gulp-util'; 2 | import Config from '../../config'; 3 | 4 | function reportError(message: string) { 5 | console.error(util.colors.white.bgRed.bold(message)); 6 | process.exit(1); 7 | } 8 | 9 | /** 10 | * Executes the build process, verifying that the installed NodeJS and NPM version matches the required versions as 11 | * defined in the application configuration. 12 | */ 13 | export = () => { 14 | let exec = require('child_process').exec; 15 | let semver = require('semver'); 16 | 17 | exec('npm --version', 18 | function(error: Error, stdout: NodeBuffer, stderr: NodeBuffer) { 19 | if (error !== null) { 20 | reportError('npm preinstall error: ' + error + stderr); 21 | } 22 | 23 | if (!semver.gte(stdout, Config.VERSION_NPM)) { 24 | reportError('NPM is not in required version! Required is ' + Config.VERSION_NPM + ' and you\'re using ' + stdout); 25 | } 26 | }); 27 | 28 | exec('node --version', 29 | function(error: Error, stdout: NodeBuffer, stderr: NodeBuffer) { 30 | if (error !== null) { 31 | reportError('npm preinstall error: ' + error + stderr); 32 | } 33 | 34 | if (!semver.gte(stdout, Config.VERSION_NODE)) { 35 | reportError('NODE is not in required version! Required is ' + Config.VERSION_NODE + ' and you\'re using ' + stdout); 36 | } 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /tools/config/project.config.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | 3 | import { SeedConfig } from './seed.config'; 4 | 5 | /** 6 | * This class extends the basic seed configuration, allowing for project specific overrides. A few examples can be found 7 | * below. 8 | */ 9 | export class ProjectConfig extends SeedConfig { 10 | 11 | PROJECT_TASKS_DIR = join(process.cwd(), this.TOOLS_DIR, 'tasks', 'project'); 12 | 13 | constructor() { 14 | super(); 15 | // this.APP_TITLE = 'Put name of your app here'; 16 | 17 | /* Enable typeless compiler runs (faster) between typed compiler runs. */ 18 | // this.TYPED_COMPILE_INTERVAL = 5; 19 | 20 | // Add `NPM` third-party libraries to be injected/bundled. 21 | this.NPM_DEPENDENCIES = [ 22 | ...this.NPM_DEPENDENCIES, 23 | // {src: 'jquery/dist/jquery.min.js', inject: 'libs'}, 24 | // {src: 'lodash/lodash.min.js', inject: 'libs'}, 25 | ]; 26 | 27 | // Add `local` third-party libraries to be injected/bundled. 28 | this.APP_ASSETS = [ 29 | ...this.APP_ASSETS, 30 | // {src: `${this.APP_SRC}/your-path-to-lib/libs/jquery-ui.js`, inject: true, vendor: false} 31 | // {src: `${this.CSS_SRC}/path-to-lib/test-lib.css`, inject: true, vendor: false}, 32 | ]; 33 | 34 | /* Add to or override NPM module configurations: */ 35 | // this.mergeObject(this.PLUGIN_CONFIGS['browser-sync'], { ghostMode: false }); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # AppVeyor file 2 | # http://www.appveyor.com/docs/appveyor-yml 3 | # This file: cloned from https://github.com/gruntjs/grunt/blob/master/appveyor.yml 4 | 5 | # Build version format 6 | version: "{build}" 7 | 8 | # Test against this version of Node.js 9 | environment: 10 | nodejs_version: "Stable" 11 | # https://github.com/DefinitelyTyped/tsd#tsdrc 12 | # Token has no scope (read-only access to public information) 13 | TSD_GITHUB_TOKEN: "9b18c72997769f3867ef2ec470e626d39661795d" 14 | 15 | build: off 16 | 17 | clone_depth: 10 18 | 19 | # Fix line endings on Windows 20 | init: 21 | - git config --global core.autocrlf true 22 | 23 | install: 24 | - ps: Install-Product node $env:nodejs_version 25 | - npm install -g npm 26 | - ps: $env:path = $env:appdata + "\npm;" + $env:path 27 | - npm install && npm install karma-ie-launcher 28 | 29 | test_script: 30 | # Output useful info for debugging. 31 | - node --version && npm --version 32 | # We test multiple Windows shells because of prior stdout buffering issues 33 | # filed against Grunt. https://github.com/joyent/node/issues/3584 34 | - ps: "npm --version # PowerShell" # Pass comment to PS for easier debugging 35 | - npm run tests.all 36 | 37 | notifications: 38 | - provider: Webhook 39 | url: https://webhooks.gitter.im/e/cfd8ce5ddee6f3a0b0c9 40 | on_build_success: false 41 | on_build_failure: true 42 | on_build_status_changed: true 43 | 44 | cache: node_modules 45 | -------------------------------------------------------------------------------- /tools/tasks/seed/start.deving.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | import * as runSequence from 'run-sequence'; 5 | 6 | import Config from '../../config'; 7 | 8 | const plugins = gulpLoadPlugins(); 9 | 10 | import { notifyLiveReload } from '../../utils'; 11 | 12 | function watchAppFiles(path: string, fileChangeCallback: (e: any, done: () => void) => void) { 13 | 14 | let paths: string[] = [ 15 | join(Config.APP_SRC, path) 16 | ].concat(Config.TEMP_FILES.map((p) => { return '!' + p; })); 17 | 18 | let busyWithCall : boolean = false; 19 | let changesWaiting : any = null; 20 | let afterCall = () => { 21 | busyWithCall = false; 22 | if (changesWaiting) { 23 | fileChangeCallback(changesWaiting, afterCall); 24 | changesWaiting = null; 25 | } 26 | }; 27 | plugins.watch(paths, (e: any) => { 28 | if (busyWithCall) { 29 | changesWaiting = e; 30 | return; 31 | } 32 | busyWithCall = true; 33 | fileChangeCallback(e, afterCall); 34 | }); 35 | 36 | } 37 | 38 | gulp.task('watch.while_deving', function () { 39 | watchAppFiles('**/!(*.ts)', (e: any, done: any) => 40 | runSequence('build.assets.dev', 'build.html_css', 'build.index.dev', () => { notifyLiveReload(e); done(); })); 41 | watchAppFiles('**/(*.ts)', (e: any, done: any) => 42 | runSequence('build.js.dev', 'build.index.dev', () => { 43 | notifyLiveReload(e); 44 | runSequence('build.js.test', 'karma.run.with_coverage', done); 45 | })); 46 | }); 47 | 48 | export = (done: any) => 49 | runSequence('build.test', 50 | 'watch.while_deving', 51 | 'server.start', 52 | 'karma.run.with_coverage', 53 | 'serve.coverage.watch', 54 | done); 55 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 4 4 | - 5 5 | - stable 6 | 7 | sudo: false 8 | 9 | addons: 10 | firefox: "39.0" 11 | 12 | os: 13 | - linux 14 | - osx 15 | 16 | matrix: 17 | exclude: 18 | - os: osx 19 | node_js: 4 20 | - os: osx 21 | node_js: 5 22 | 23 | before_install: 24 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi 25 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew outdated xctool || brew upgrade xctool; fi 26 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CHROME_BIN=chromium-browser; fi # Karma CI 27 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew cask install google-chrome; fi # Karma CI 28 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DISPLAY=:99.0; fi 29 | 30 | before_script: 31 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh -e /etc/init.d/xvfb start; fi 32 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then nohup bash -c "webdriver-manager start 2>&1 &"; fi # Protractor CI 33 | 34 | after_failure: 35 | - cat /home/travis/build/mgechev/angular-seed/npm-debug.log 36 | 37 | branches: 38 | only: master 39 | 40 | notifications: 41 | email: true 42 | webhooks: 43 | urls: https://webhooks.gitter.im/e/565e4b2fed3b96c1b964 44 | on_success: change # options: [always|never|change] default: always 45 | on_failure: always # options: [always|never|change] default: always 46 | on_start: never # options: [always|never|change] default: always 47 | 48 | env: 49 | global: 50 | # https://github.com/DefinitelyTyped/tsd#tsdrc 51 | # Token has no scope (read-only access to public information) 52 | - TSD_GITHUB_TOKEN=9b18c72997769f3867ef2ec470e626d39661795d 53 | 54 | cache: 55 | directories: node_modules 56 | 57 | script: 58 | - npm run tests.all 59 | -------------------------------------------------------------------------------- /tools/tasks/seed/compile.ahead.prod.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import * as ts from 'typescript'; 3 | import * as tsc from '@angular/tsc-wrapped'; 4 | import { argv } from 'yargs'; 5 | import { join } from 'path'; 6 | import { writeFileSync, readFileSync } from 'fs'; 7 | import { CodeGenerator } from '@angular/compiler-cli'; 8 | 9 | import Config from '../../config'; 10 | 11 | function codegen( 12 | ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program, 13 | host: ts.CompilerHost) { 14 | return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen(); 15 | } 16 | 17 | const copyFile = (name: string, from: string, to: string, mod: any = (f: string) => f) => { 18 | const file = readFileSync(join(from, name)); 19 | writeFileSync(join(to, name), mod(file.toString())); 20 | }; 21 | 22 | export = (done: any) => { 23 | // Note: dirty hack until we're able to set config easier 24 | copyFile('tsconfig.json', Config.TMP_DIR, join(Config.TMP_DIR, Config.BOOTSTRAP_DIR), (content: string) => { 25 | const parsed = JSON.parse(content); 26 | parsed.files = parsed.files || []; 27 | parsed.files.push('main.ts'); 28 | return JSON.stringify(parsed, null, 2); 29 | }); 30 | const args = argv; 31 | 32 | // If a translation, tell the compiler 33 | if(args.lang) { 34 | args['i18nFile'] = `./src/client/assets/locale/messages.${args.lang}.xlf`; 35 | args['locale'] = args.lang; 36 | args['i18nFormat'] = 'xlf'; 37 | } 38 | 39 | const cliOptions = new tsc.NgcCliOptions(args); 40 | tsc.main(join(Config.TMP_DIR, Config.BOOTSTRAP_DIR), cliOptions, codegen) 41 | .then(done) 42 | .catch(e => { 43 | console.error(e.stack); 44 | console.error('Compilation failed'); 45 | process.exit(1); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /tools/config/seed.tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../node_modules/codelyzer"], 3 | "rules": { 4 | "class-name": true, 5 | "curly": false, 6 | "eofline": true, 7 | "indent": ["spaces"], 8 | "max-line-length": [true, 140], 9 | "member-ordering": [true, 10 | "public-before-private", 11 | "static-before-instance", 12 | "variables-before-functions" 13 | ], 14 | "no-arg": true, 15 | "no-construct": true, 16 | "no-duplicate-key": true, 17 | "no-duplicate-variable": true, 18 | "no-empty": true, 19 | "no-eval": true, 20 | "no-trailing-whitespace": true, 21 | "no-unused-expression": true, 22 | "no-unused-variable": true, 23 | "no-unreachable": true, 24 | "no-use-before-declare": true, 25 | "one-line": [true, 26 | "check-open-brace", 27 | "check-catch", 28 | "check-else", 29 | "check-whitespace" 30 | ], 31 | "quotemark": [true, "single"], 32 | "semicolon": [true, "always"], 33 | "trailing-comma": true, 34 | "triple-equals": true, 35 | "variable-name": false, 36 | 37 | "directive-selector-name": [true, "camelCase"], 38 | "component-selector-name": [true, "kebab-case"], 39 | "directive-selector-type": [true, "attribute"], 40 | "component-selector-type": [true, "element"], 41 | "use-input-property-decorator": true, 42 | "use-output-property-decorator": true, 43 | "use-host-property-decorator": true, 44 | "no-input-rename": true, 45 | "no-output-rename": true, 46 | "use-life-cycle-interface": true, 47 | "use-pipe-transform-interface": true, 48 | "component-class-suffix": true, 49 | "directive-class-suffix": true, 50 | "import-destructuring-spacing": true, 51 | "templates-use-public": true, 52 | "no-access-missing-member": true, 53 | "invoke-injectable": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tools/utils/seed/code_change_tools.ts: -------------------------------------------------------------------------------- 1 | import * as browserSync from 'browser-sync'; 2 | // import * as path from 'path'; 3 | 4 | import Config from '../../config'; 5 | 6 | class ChangeFileManager { 7 | private _files: string[] = []; 8 | private _pristine = true; 9 | 10 | get lastChangedFiles() { 11 | return this._files.slice(); 12 | } 13 | 14 | get pristine() { 15 | return this._pristine; 16 | } 17 | 18 | addFile(file: string) { 19 | this._pristine = false; 20 | this._files.push(file); 21 | } 22 | 23 | addFiles(files: string[]) { 24 | files.forEach(f => this.addFile(f)); 25 | } 26 | 27 | clear() { 28 | this._files = []; 29 | } 30 | } 31 | 32 | export let changeFileManager = new ChangeFileManager(); 33 | 34 | /** 35 | * Initialises BrowserSync with the configuration defined in seed.config.ts (or if overriden: project.config.ts). 36 | */ 37 | let runServer = () => { 38 | browserSync.init(Config.getPluginConfig('browser-sync')); 39 | }; 40 | 41 | /** 42 | * Runs BrowserSync as the listening process for the application. 43 | */ 44 | let listen = () => { 45 | // if (ENABLE_HOT_LOADING) { 46 | // ng2HotLoader.listen({ 47 | // port: HOT_LOADER_PORT, 48 | // processPath: file => { 49 | // return file.replace(join(PROJECT_ROOT, APP_SRC), join('dist', 'dev')); 50 | // } 51 | // }); 52 | // } 53 | runServer(); 54 | }; 55 | 56 | /** 57 | * Provides a flag to mark which files have changed and reloads BrowserSync accordingly. 58 | */ 59 | let changed = (files: any) => { 60 | if (!(files instanceof Array)) { 61 | files = [files]; 62 | } 63 | 64 | // let onlyStylesChanged = 65 | // files 66 | // .map((f:string) => path.parse(f).ext) 67 | // .reduce((prev:string, current:string) => prev && (current === '.scss' || current === '.css'), true); 68 | // 69 | // if (ENABLE_HOT_LOADING) { 70 | // ng2HotLoader.onChange(files); 71 | // } else { 72 | //TODO: Figure out why you can't pass a file to reload 73 | // if (onlyStylesChanged === false) { 74 | browserSync.reload(files); 75 | // } else { 76 | // browserSync.reload('*.css'); 77 | // } 78 | //} 79 | }; 80 | 81 | export { listen, changed }; 82 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.index.prod.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join, sep, normalize } from 'path'; 4 | import * as slash from 'slash'; 5 | 6 | import Config from '../../config'; 7 | import { templateLocals } from '../../utils'; 8 | 9 | const plugins = gulpLoadPlugins(); 10 | 11 | /** 12 | * Executes the build process, injecting the JavaScript and CSS dependencies into the `index.html` for the production 13 | * environment. 14 | */ 15 | export = () => { 16 | return gulp.src(join(Config.APP_SRC, 'index.html')) 17 | .pipe(injectJs()) 18 | .pipe(injectCss()) 19 | .pipe(plugins.template(templateLocals())) 20 | .pipe(gulp.dest(Config.APP_DEST)); 21 | }; 22 | 23 | /** 24 | * Injects the given file array and transforms the path of the files. 25 | * @param {Array} files - The files to be injected. 26 | */ 27 | function inject(...files: Array) { 28 | return plugins.inject(gulp.src(files, { read: false }), { 29 | files, 30 | transform: transformPath() 31 | }); 32 | } 33 | 34 | /** 35 | * Injects the bundled JavaScript shims and application bundles for the production environment. 36 | */ 37 | function injectJs() { 38 | return inject(join(Config.JS_DEST, Config.JS_PROD_SHIMS_BUNDLE), join(Config.JS_DEST, Config.JS_PROD_APP_BUNDLE)); 39 | } 40 | 41 | /** 42 | * Injects the bundled CSS files for the production environment. 43 | */ 44 | function injectCss() { 45 | return inject(join(Config.CSS_DEST, Config.CSS_PROD_BUNDLE)); 46 | } 47 | 48 | /** 49 | * Transform the path of a dependency to its location within the `dist` directory according to the applications 50 | * environment. 51 | */ 52 | function transformPath() { 53 | return function(filepath: string) { 54 | let path: Array = normalize(filepath).split(sep); 55 | let slice_after = path.indexOf(Config.APP_DEST); 56 | if (slice_after>-1) { 57 | slice_after++; 58 | } else { 59 | slice_after = 3; 60 | } 61 | arguments[0] = Config.APP_BASE + path.slice(slice_after, path.length).join(sep) + `?${Date.now()}`; 62 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments)); 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /tools/tasks/seed/css-lint.ts: -------------------------------------------------------------------------------- 1 | import * as colorguard from 'colorguard'; 2 | import * as doiuse from 'doiuse'; 3 | import * as gulp from 'gulp'; 4 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 5 | import * as merge from 'merge-stream'; 6 | import * as reporter from 'postcss-reporter'; 7 | import * as stylelint from 'stylelint'; 8 | import { join } from 'path'; 9 | 10 | import Config from '../../config'; 11 | 12 | const plugins = gulpLoadPlugins(); 13 | 14 | const isProd = Config.ENV === 'prod'; 15 | var stylesheetType = Config.ENABLE_SCSS ? 'scss' : 'css'; 16 | 17 | const processors = [ 18 | doiuse({ 19 | browsers: Config.BROWSER_LIST, 20 | }), 21 | colorguard({ 22 | whitelist: Config.COLOR_GUARD_WHITE_LIST 23 | }), 24 | stylelint(), 25 | reporter({clearMessages: true}) 26 | ]; 27 | 28 | function lintComponentStylesheets() { 29 | return gulp.src([ 30 | join(Config.APP_SRC, '**', `*.${stylesheetType}`), 31 | `!${join(Config.APP_SRC, 'assets', '**', '*.scss')}`, 32 | `!${join(Config.CSS_SRC, '**', '*.css')}` 33 | ]).pipe(isProd ? plugins.cached('css-lint') : plugins.util.noop()) 34 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint() : plugins.postcss(processors)) 35 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint.format() : plugins.util.noop()) 36 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint.failOnError() : plugins.util.noop()); 37 | } 38 | 39 | function lintExternalStylesheets() { 40 | return gulp.src(getExternalStylesheets().map(r => r.src)) 41 | .pipe(isProd ? plugins.cached('css-lint') : plugins.util.noop()) 42 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint() : plugins.postcss(processors)) 43 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint.format() : plugins.util.noop()) 44 | .pipe(Config.ENABLE_SCSS ? plugins.sassLint.failOnError() : plugins.util.noop()); 45 | } 46 | 47 | function getExternalStylesheets() { 48 | let stylesheets = Config.ENABLE_SCSS ? Config.DEPENDENCIES : Config.APP_ASSETS; 49 | return stylesheets 50 | .filter(d => new RegExp(`\.${stylesheetType}$`) 51 | .test(d.src) && !d.vendor); 52 | } 53 | 54 | /** 55 | * Executes the build process, linting the component and external CSS files using `stylelint`. 56 | */ 57 | export = () => merge(lintComponentStylesheets(), lintExternalStylesheets()); 58 | -------------------------------------------------------------------------------- /test-main.js: -------------------------------------------------------------------------------- 1 | if (!Object.hasOwnProperty('name')) { 2 | Object.defineProperty(Function.prototype, 'name', { 3 | get: function () { 4 | var matches = this.toString().match(/^\s*function\s*(\S*)\s*\(/); 5 | var name = matches && matches.length > 1 ? matches[1] : ""; 6 | Object.defineProperty(this, 'name', { value: name }); 7 | return name; 8 | } 9 | }); 10 | } 11 | 12 | // Turn on full stack traces in errors to help debugging 13 | Error.stackTraceLimit = Infinity; 14 | 15 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; 16 | 17 | // Cancel Karma's synchronous start, 18 | // we will call `__karma__.start()` later, once all the specs are loaded. 19 | __karma__.loaded = function () { }; 20 | 21 | Promise.all([ 22 | System.import('@angular/core/testing'), 23 | System.import('@angular/platform-browser-dynamic/testing') 24 | ]).then(function (providers) { 25 | var testing = providers[0]; 26 | var testingBrowser = providers[1]; 27 | 28 | testing.TestBed.initTestEnvironment( 29 | testingBrowser.BrowserDynamicTestingModule, 30 | testingBrowser.platformBrowserDynamicTesting() 31 | ); 32 | }).then(function () { 33 | return Promise.all( 34 | Object.keys(window.__karma__.files) // All files served by Karma. 35 | .filter(onlySpecFiles) 36 | .map(file2moduleName) 37 | .map(function (path) { 38 | return System.import(path).then(function (module) { 39 | if (module.hasOwnProperty('main')) { 40 | module.main(); 41 | } else { 42 | throw new Error('Module ' + path + ' does not implement main() method.'); 43 | } 44 | }); 45 | })); 46 | }) 47 | .then(function () { 48 | __karma__.start(); 49 | }, function (error) { 50 | console.error(error.stack || error); 51 | __karma__.start(); 52 | }); 53 | 54 | function onlySpecFiles(path) { 55 | // check for individual files, if not given, always matches to all 56 | var patternMatched = __karma__.config.files ? 57 | path.match(new RegExp(__karma__.config.files)) : true; 58 | 59 | return patternMatched && /[\.|_]spec\.js$/.test(path); 60 | } 61 | 62 | // Normalize paths to module names. 63 | function file2moduleName(filePath) { 64 | return filePath.replace(/\\/g, '/') 65 | .replace(/^\/base\//, '') 66 | .replace(/\.js$/, ''); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /tools/utils/seed/server.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import * as fallback from 'express-history-api-fallback'; 3 | import * as openResource from 'open'; 4 | import { resolve } from 'path'; 5 | 6 | import * as codeChangeTool from './code_change_tools'; 7 | import Config from '../../config'; 8 | 9 | /** 10 | * Serves the Single Page Application. More specifically, calls the `listen` method, which itself launches BrowserSync. 11 | */ 12 | export function serveSPA() { 13 | codeChangeTool.listen(); 14 | } 15 | 16 | /** 17 | * This utility method is used to notify that a file change has happened and subsequently calls the `changed` method, 18 | * which itself initiates a BrowserSync reload. 19 | * @param {any} e - The file that has changed. 20 | */ 21 | export function notifyLiveReload(e:any) { 22 | let fileName = e.path; 23 | codeChangeTool.changed(fileName); 24 | } 25 | 26 | /** 27 | * Starts a new `express` server, serving the static documentation files. 28 | */ 29 | export function serveDocs() { 30 | let server = express(); 31 | 32 | server.use( 33 | Config.APP_BASE, 34 | express.static(resolve(process.cwd(), Config.DOCS_DEST)) 35 | ); 36 | 37 | server.listen(Config.DOCS_PORT, () => 38 | openResource('http://localhost:' + Config.DOCS_PORT + Config.APP_BASE) 39 | ); 40 | } 41 | 42 | /** 43 | * Starts a new `express` server, serving the static unit test code coverage report. 44 | */ 45 | export function serveCoverage() { 46 | let server = express(); 47 | let compression = require('compression'); 48 | server.use(compression()); 49 | 50 | server.use( 51 | Config.APP_BASE, 52 | express.static(resolve(process.cwd(), 'coverage')) 53 | ); 54 | 55 | server.listen(Config.COVERAGE_PORT, () => 56 | openResource('http://localhost:' + Config.COVERAGE_PORT + Config.APP_BASE) 57 | ); 58 | } 59 | 60 | /** 61 | * Starts a new `express` server, serving the built files from `dist/prod`. 62 | */ 63 | export function serveProd() { 64 | let root = resolve(process.cwd(), Config.PROD_DEST); 65 | let server = express(); 66 | let compression = require('compression'); 67 | server.use(compression()); 68 | 69 | server.use(Config.APP_BASE, express.static(root)); 70 | 71 | server.use(fallback('index.html', { root })); 72 | 73 | server.listen(Config.PORT, () => 74 | openResource('http://localhost:' + Config.PORT + Config.APP_BASE) 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.index.dev.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 3 | import { join } from 'path'; 4 | import * as slash from 'slash'; 5 | 6 | import Config from '../../config'; 7 | import { templateLocals } from '../../utils'; 8 | 9 | const plugins = gulpLoadPlugins(); 10 | 11 | 12 | /** 13 | * Executes the build process, injecting the shims and libs into the `index.hml` for the development environment. 14 | */ 15 | export = () => { 16 | return gulp.src(join(Config.APP_SRC, 'index.html')) 17 | .pipe(inject('shims')) 18 | .pipe(inject('libs')) 19 | .pipe(inject()) 20 | .pipe(plugins.template(templateLocals())) 21 | .pipe(gulp.dest(Config.APP_DEST)); 22 | }; 23 | 24 | /** 25 | * Injects the file with the given name. 26 | * @param {string} name - The file to be injected. 27 | */ 28 | function inject(name?: string) { 29 | return plugins.inject(gulp.src(getInjectablesDependenciesRef(name), { read: false }), { 30 | name, 31 | transform: transformPath() 32 | }); 33 | } 34 | 35 | /** 36 | * Returns the injectable dependency, mapping its filename to its path. 37 | * @param {string} name - The dependency to be mapped. 38 | */ 39 | function getInjectablesDependenciesRef(name?: string) { 40 | return Config.DEPENDENCIES 41 | .filter(dep => dep['inject'] && dep['inject'] === (name || true)) 42 | .map(mapPath); 43 | } 44 | 45 | /** 46 | * Maps the path of the given dependency to its path according to the applications environment. 47 | * @param {any} dep - The dependency to be mapped. 48 | */ 49 | function mapPath(dep: any) { 50 | let envPath = dep.src; 51 | if (envPath.startsWith(Config.APP_SRC) && !envPath.endsWith('.scss')) { 52 | envPath = join(Config.APP_DEST, envPath.replace(Config.APP_SRC, '')); 53 | } else if (envPath.startsWith(Config.APP_SRC) && envPath.endsWith('.scss')) { 54 | envPath = envPath.replace(Config.ASSETS_SRC, Config.CSS_DEST).replace('.scss', '.css'); 55 | } 56 | return envPath; 57 | } 58 | 59 | /** 60 | * Transform the path of a dependency to its location within the `dist` directory according to the applications 61 | * environment. 62 | */ 63 | function transformPath() { 64 | return function (filepath: string) { 65 | if (filepath.startsWith(`/${Config.APP_DEST}`)) { 66 | filepath = filepath.replace(`/${Config.APP_DEST}`, ''); 67 | } 68 | arguments[0] = join(Config.APP_BASE, filepath) + `?${Date.now()}`; 69 | return slash(plugins.inject.transform.apply(plugins.inject.transform, arguments)); 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /tools/utils/seed/tasks_tools.ts: -------------------------------------------------------------------------------- 1 | import { existsSync, lstatSync, readdirSync } from 'fs'; 2 | import * as gulp from 'gulp'; 3 | import * as util from 'gulp-util'; 4 | import * as isstream from 'isstream'; 5 | import { join } from 'path'; 6 | import * as tildify from 'tildify'; 7 | 8 | import { changeFileManager } from './code_change_tools'; 9 | import { Task } from '../../tasks/task'; 10 | 11 | /** 12 | * Loads the tasks within the given path. 13 | * @param {string} path - The path to load the tasks from. 14 | */ 15 | export function loadTasks(path: string): void { 16 | util.log('Loading tasks folder', util.colors.yellow(path)); 17 | readDir(path, taskname => registerTask(taskname, path)); 18 | } 19 | 20 | function normalizeTask(task: any, taskName: string) { 21 | if (task instanceof Task) { 22 | return task; 23 | } 24 | if (task.prototype && task.prototype instanceof Task) { 25 | return new task(); 26 | } 27 | if (typeof task === 'function') { 28 | return new class AnonTask extends Task { 29 | run(done: any) { 30 | if (task.length > 0) { 31 | return task(done); 32 | } 33 | 34 | const taskReturnedValue = task(); 35 | if (isstream(taskReturnedValue)) { 36 | return taskReturnedValue; 37 | } 38 | 39 | done(); 40 | } 41 | }; 42 | } 43 | throw new Error(taskName + ' should be instance of the class ' + 44 | 'Task, a function or a class which extends Task.'); 45 | } 46 | 47 | /** 48 | * Registers the task by the given taskname and path. 49 | * @param {string} taskname - The name of the task. 50 | * @param {string} path - The path of the task. 51 | */ 52 | function registerTask(taskname: string, path: string): void { 53 | const TASK = join(path, taskname); 54 | util.log('Registering task', util.colors.yellow(tildify(TASK))); 55 | 56 | gulp.task(taskname, (done: any) => { 57 | const task = normalizeTask(require(TASK), TASK); 58 | 59 | if (changeFileManager.pristine || task.shallRun(changeFileManager.lastChangedFiles)) { 60 | return task.run(done); 61 | } else { 62 | done(); 63 | } 64 | }); 65 | } 66 | 67 | /** 68 | * Reads the files in the given root directory and executes the given callback per found file. 69 | * @param {string} root - The root directory to read. 70 | * @param {function} cb - The callback to execute per found file. 71 | */ 72 | function readDir(root: string, cb: (taskname: string) => void) { 73 | if (!existsSync(root)) { 74 | return; 75 | } 76 | 77 | walk(root); 78 | 79 | function walk(path: string) { 80 | let files = readdirSync(path); 81 | for (let i = 0; i < files.length; i += 1) { 82 | let file = files[i]; 83 | let curPath = join(path, file); 84 | if (lstatSync(curPath).isFile() && /\.ts$/.test(file)) { 85 | let taskname = file.replace(/\.ts$/, ''); 86 | cb(taskname); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.js.dev.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as gulp from 'gulp'; 3 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 4 | import * as merge from 'merge-stream'; 5 | import * as util from 'gulp-util'; 6 | import { join/*, sep, relative*/ } from 'path'; 7 | 8 | import Config from '../../config'; 9 | import { makeTsProject, templateLocals } from '../../utils'; 10 | import { TypeScriptTask } from '../typescript_task'; 11 | 12 | const plugins = gulpLoadPlugins(); 13 | 14 | const jsonSystemConfig = JSON.stringify(Config.SYSTEM_CONFIG_DEV); 15 | 16 | let typedBuildCounter = Config.TYPED_COMPILE_INTERVAL; // Always start with the typed build. 17 | 18 | /** 19 | * Executes the build process, transpiling the TypeScript files (except the spec and e2e-spec files) for the development 20 | * environment. 21 | */ 22 | export = 23 | class BuildJsDev extends TypeScriptTask { 24 | run() { 25 | let tsProject: any; 26 | let typings = gulp.src([ 27 | Config.TOOLS_DIR + '/manual_typings/**/*.d.ts' 28 | ]); 29 | let src = [ 30 | join(Config.APP_SRC, '**/*.ts'), 31 | '!' + join(Config.APP_SRC, '**/*.spec.ts'), 32 | '!' + join(Config.APP_SRC, '**/*.e2e-spec.ts'), 33 | '!' + join(Config.APP_SRC, `**/${Config.NG_FACTORY_FILE}.ts`) 34 | ]; 35 | 36 | let projectFiles = gulp.src(src); 37 | let result: any; 38 | let isFullCompile = true; 39 | 40 | // Only do a typed build every X builds, otherwise do a typeless build to speed things up 41 | if (typedBuildCounter < Config.TYPED_COMPILE_INTERVAL) { 42 | isFullCompile = false; 43 | tsProject = makeTsProject({isolatedModules: true}); 44 | projectFiles = projectFiles.pipe(plugins.cached()); 45 | util.log('Performing typeless TypeScript compile.'); 46 | } else { 47 | tsProject = makeTsProject(); 48 | projectFiles = merge(typings, projectFiles); 49 | } 50 | 51 | result = projectFiles 52 | .pipe(plugins.plumber()) 53 | .pipe(plugins.sourcemaps.init()) 54 | .pipe(tsProject()) 55 | .on('error', () => { 56 | typedBuildCounter = Config.TYPED_COMPILE_INTERVAL; 57 | }); 58 | 59 | if (isFullCompile) { 60 | typedBuildCounter = 0; 61 | } else { 62 | typedBuildCounter++; 63 | } 64 | 65 | return result.js 66 | .pipe(plugins.sourcemaps.write()) 67 | // Use for debugging with Webstorm/IntelliJ 68 | // https://github.com/mgechev/angular2-seed/issues/1220 69 | // .pipe(plugins.sourcemaps.write('.', { 70 | // includeContent: false, 71 | // sourceRoot: (file: any) => 72 | // relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC 73 | // })) 74 | .pipe(plugins.template(Object.assign( 75 | templateLocals(), { 76 | SYSTEM_CONFIG_DEV: jsonSystemConfig 77 | } 78 | ))) 79 | .pipe(gulp.dest(Config.APP_DEST)); 80 | } 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /src/client/app/app.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, Output, EventEmitter, /*ContentChild, */ViewChild} from '@angular/core'; 2 | 3 | interface Todo { 4 | title: string; 5 | completed: boolean; 6 | } 7 | 8 | export class TodoList { 9 | private todos: Todo[] = []; 10 | add(todo: Todo) { 11 | this.todos.push(todo); 12 | } 13 | remove(todo: Todo) { 14 | this.todos.splice(this.todos.indexOf(todo), 1); 15 | } 16 | set(todo: Todo, index: number) { 17 | this.todos[index] = todo; 18 | } 19 | get(index: number) { 20 | return this.todos[index]; 21 | } 22 | getAll() { 23 | return this.todos; 24 | } 25 | } 26 | 27 | @Component({ 28 | selector: 'todo-item', 29 | styles: [ 30 | `.completed { 31 | text-decoration: line-through; 32 | }` 33 | ], 34 | template: ` 35 |
36 | 39 | {{todo.title}} 40 |
41 | ` 42 | }) 43 | export class TodoComponent { 44 | @Output() onCompletionChange = new EventEmitter(); 45 | @Input() todo: Todo; 46 | completionChanged(todo: Todo) { 47 | this.onCompletionChange.emit(todo); 48 | } 49 | } 50 | 51 | @Component({ 52 | selector: 'todo-input', 53 | template: ` 54 | 55 | 56 | ` 57 | }) 58 | export class TodoInputComponent { 59 | title: string; 60 | @Output() onTodo = new EventEmitter(); 61 | addTodo() { 62 | this.onTodo.emit({ 63 | title: this.title, 64 | completed: false 65 | }); 66 | this.title = ''; 67 | } 68 | } 69 | 70 | @Component({ 71 | selector: 'app-footer', 72 | template: '' 73 | }) 74 | export class FooterComponent { 75 | constructor(private todos: TodoList) {} 76 | } 77 | 78 | @Component({ 79 | selector: 'todo-app', 80 | viewProviders: [TodoList], 81 | template: ` 82 |
83 | Add todo: 84 | 85 |
86 |
87 |

Todo list

88 | 89 | 90 |
91 | 92 | ` 93 | }) 94 | export class TodoAppComponent { 95 | @ViewChild(TodoInputComponent) 96 | input: TodoInputComponent; 97 | 98 | constructor(private todos: TodoList) {} 99 | addTodo(todo: Todo) { 100 | this.todos.add(todo); 101 | } 102 | ngAfterViewInit() { 103 | // console.log(this.input); 104 | } 105 | } 106 | 107 | @Component({ 108 | selector: 'demo-app', 109 | styles: [ 110 | 'todo-app { margin-top: 20px; margin-left: 20px; }' 111 | ], 112 | template: ` 113 | 114 | 115 | 116 | Yet another todo app! 117 | 118 | 119 | 120 | ` 121 | }) 122 | export class AppComponent {} 123 | 124 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Jul 15 2015 09:44:02 GMT+0200 (Romance Daylight Time) 3 | 'use strict'; 4 | 5 | var argv = require('yargs').argv; 6 | 7 | module.exports = function (config) { 8 | config.set({ 9 | 10 | // base path that will be used to resolve all patterns (eg. files, exclude) 11 | basePath: './', 12 | 13 | 14 | // frameworks to use 15 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 16 | frameworks: ['jasmine'], 17 | 18 | 19 | // list of files / patterns to load in the browser 20 | files: [ 21 | // Polyfills. 22 | 'node_modules/core-js/client/shim.min.js', 23 | 24 | 'node_modules/traceur/bin/traceur.js', 25 | 26 | // System.js for module loading 27 | 'node_modules/systemjs/dist/system.src.js', 28 | 29 | // Zone.js dependencies 30 | 'node_modules/zone.js/dist/zone.js', 31 | 'node_modules/zone.js/dist/long-stack-trace-zone.js', 32 | 'node_modules/zone.js/dist/async-test.js', 33 | 'node_modules/zone.js/dist/fake-async-test.js', 34 | 'node_modules/zone.js/dist/sync-test.js', 35 | 'node_modules/zone.js/dist/proxy.js', 36 | 'node_modules/zone.js/dist/jasmine-patch.js', 37 | 38 | // RxJs. 39 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false }, 40 | { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false }, 41 | 42 | // paths loaded via module imports 43 | // Angular itself 44 | { pattern: 'node_modules/@angular/**/*.js', included: false, watched: true }, 45 | { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false }, 46 | 47 | { pattern: 'dist/dev/**/*.js', included: false, watched: true }, 48 | { pattern: 'dist/dev/**/*.html', included: false, watched: true, served: true }, 49 | { pattern: 'dist/dev/**/*.css', included: false, watched: true, served: true }, 50 | { pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: false, watched: false }, // PhantomJS2 (and possibly others) might require it 51 | 52 | // suppress annoying 404 warnings for resources, images, etc. 53 | { pattern: 'dist/dev/assets/**/*', watched: false, included: false, served: true }, 54 | 55 | 'test-config.js', 56 | 'dist/dev/app/system-config.js', 57 | 'test-main.js' 58 | ], 59 | 60 | // must go along with above, suppress annoying 404 warnings. 61 | proxies: { 62 | '/assets/': '/base/dist/dev/assets/' 63 | }, 64 | 65 | // list of files to exclude 66 | exclude: [ 67 | 'node_modules/**/*spec.js' 68 | ], 69 | 70 | 71 | // preprocess matching files before serving them to the browser 72 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 73 | 74 | // test results reporter to use 75 | // possible values: 'dots', 'progress' 76 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 77 | reporters: ['mocha'], 78 | 79 | 80 | // web server port 81 | port: 9876, 82 | 83 | 84 | // enable / disable colors in the output (reporters and logs) 85 | colors: true, 86 | 87 | 88 | // level of logging 89 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 90 | logLevel: config.LOG_INFO, 91 | 92 | 93 | // enable / disable watching file and executing tests whenever any file changes 94 | autoWatch: true, 95 | 96 | 97 | // start these browsers 98 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 99 | browsers: [ 100 | 'Chrome' 101 | ], 102 | 103 | 104 | customLaunchers: { 105 | Chrome_travis_ci: { 106 | base: 'Chrome', 107 | flags: ['--no-sandbox'] 108 | } 109 | }, 110 | 111 | // Continuous Integration mode 112 | // if true, Karma captures browsers, runs the tests and exits 113 | singleRun: false, 114 | 115 | // Passing command line arguments to tests 116 | client: { 117 | files: argv.files 118 | } 119 | }); 120 | 121 | if (process.env.APPVEYOR) { 122 | config.browsers = ['IE']; 123 | config.singleRun = true; 124 | config.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough 125 | } 126 | 127 | if (process.env.TRAVIS || process.env.CIRCLECI) { 128 | config.browsers = ['Chrome_travis_ci']; 129 | config.singleRun = true; 130 | config.browserNoActivityTimeout = 90000; 131 | } 132 | }; 133 | -------------------------------------------------------------------------------- /gulpfile.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from 'gulp'; 2 | import * as util from 'gulp-util'; 3 | import * as runSequence from 'run-sequence'; 4 | 5 | import Config from './tools/config'; 6 | import { loadTasks } from './tools/utils'; 7 | 8 | 9 | loadTasks(Config.SEED_TASKS_DIR); 10 | loadTasks(Config.PROJECT_TASKS_DIR); 11 | 12 | 13 | // -------------- 14 | // Build dev. 15 | gulp.task('build.dev', (done: any) => 16 | runSequence(//'clean.dev', 17 | // 'tslint', 18 | // 'css-lint', 19 | 'build.assets.dev', 20 | 'build.html_css', 21 | 'build.js.dev', 22 | 'build.index.dev', 23 | done)); 24 | 25 | // -------------- 26 | // Build dev watch. 27 | gulp.task('build.dev.watch', (done: any) => 28 | runSequence('build.dev', 29 | 'watch.dev', 30 | done)); 31 | 32 | // -------------- 33 | // Build e2e. 34 | gulp.task('build.e2e', (done: any) => 35 | runSequence('clean.dev', 36 | 'tslint', 37 | 'build.assets.dev', 38 | 'build.js.e2e', 39 | 'build.index.dev', 40 | done)); 41 | 42 | // -------------- 43 | // Build prod. 44 | gulp.task('build.prod', (done: any) => 45 | runSequence('clean.prod', 46 | 'tslint', 47 | 'css-lint', 48 | 'build.assets.prod', 49 | 'build.html_css', 50 | 'copy.prod', 51 | 'build.js.prod', 52 | 'build.bundles', 53 | 'build.bundles.app', 54 | 'minify.bundles', 55 | 'build.index.prod', 56 | done)); 57 | 58 | // -------------- 59 | // Build prod. 60 | gulp.task('build.prod.exp', (done: any) => 61 | runSequence('clean.prod', 62 | 'tslint', 63 | 'css-lint', 64 | 'build.assets.prod', 65 | 'build.html_css', 66 | 'copy.prod', 67 | 'compile.ahead.prod', 68 | 'build.js.prod.exp', 69 | 'build.bundles', 70 | 'build.bundles.app.exp', 71 | 'minify.bundles', 72 | 'build.index.prod', 73 | done)); 74 | 75 | // -------------- 76 | // Build test. 77 | gulp.task('build.test', (done: any) => 78 | runSequence('clean.once', 79 | 'tslint', 80 | 'build.assets.dev', 81 | 'build.html_css', 82 | 'build.js.dev', 83 | 'build.js.test', 84 | 'build.index.dev', 85 | done)); 86 | 87 | // -------------- 88 | // Build test watch. 89 | gulp.task('test.watch', (done: any) => 90 | runSequence('build.test', 91 | 'watch.test', 92 | 'karma.watch', 93 | done)); 94 | 95 | // -------------- 96 | // Build tools. 97 | gulp.task('build.tools', (done: any) => 98 | runSequence('clean.tools', 99 | 'build.js.tools', 100 | done)); 101 | 102 | // -------------- 103 | // Docs 104 | // gulp.task('docs', (done: any) => 105 | // runSequence('build.docs', 106 | // 'serve.docs', 107 | // done)); 108 | 109 | // -------------- 110 | // Serve dev 111 | gulp.task('serve.dev', (done: any) => 112 | runSequence('build.dev', 113 | 'server.start', 114 | 'watch.dev', 115 | done)); 116 | 117 | // -------------- 118 | // Serve e2e 119 | gulp.task('serve.e2e', (done: any) => 120 | runSequence('build.e2e', 121 | 'server.start', 122 | 'watch.e2e', 123 | done)); 124 | 125 | 126 | // -------------- 127 | // Serve prod 128 | gulp.task('serve.prod', (done: any) => 129 | runSequence('build.prod', 130 | 'server.prod', 131 | done)); 132 | 133 | 134 | // -------------- 135 | // Test. 136 | gulp.task('test', (done: any) => 137 | runSequence('build.test', 138 | 'karma.run', 139 | done)); 140 | 141 | // -------------- 142 | // Clean directories after i18n 143 | // TODO: find a better way to do it 144 | gulp.task('clean.i18n', (done: any) => 145 | runSequence('clear.files', 146 | done)); 147 | 148 | // -------------- 149 | // Clean dev/coverage that will only run once 150 | // this prevents karma watchers from being broken when directories are deleted 151 | let firstRun = true; 152 | gulp.task('clean.once', (done: any) => { 153 | if (firstRun) { 154 | firstRun = false; 155 | runSequence('clean.dev', 'clean.coverage', done); 156 | } else { 157 | util.log('Skipping clean on rebuild'); 158 | done(); 159 | } 160 | }); 161 | -------------------------------------------------------------------------------- /tools/tasks/seed/build.html_css.ts: -------------------------------------------------------------------------------- 1 | import * as autoprefixer from 'autoprefixer'; 2 | import * as cssnano from 'cssnano'; 3 | import * as gulp from 'gulp'; 4 | import * as gulpLoadPlugins from 'gulp-load-plugins'; 5 | import * as merge from 'merge-stream'; 6 | import * as util from 'gulp-util'; 7 | import { join } from 'path'; 8 | 9 | import Config from '../../config'; 10 | import { CssTask } from '../css_task'; 11 | 12 | const plugins = gulpLoadPlugins(); 13 | const cleanCss = require('gulp-clean-css'); 14 | const gulpConcatCssConfig = Config.getPluginConfig('gulp-concat-css'); 15 | 16 | const processors = [ 17 | autoprefixer({ 18 | browsers: Config.BROWSER_LIST 19 | }) 20 | ]; 21 | 22 | const reportPostCssError = (e: any) => util.log(util.colors.red(e.message)); 23 | 24 | const isProd = Config.ENV === 'prod'; 25 | 26 | if (isProd) { 27 | processors.push( 28 | cssnano({ 29 | discardComments: {removeAll: true}, 30 | discardUnused: false, // unsafe, see http://goo.gl/RtrzwF 31 | zindex: false, // unsafe, see http://goo.gl/vZ4gbQ 32 | reduceIdents: false // unsafe, see http://goo.gl/tNOPv0 33 | }) 34 | ); 35 | } 36 | 37 | /** 38 | * Copies all HTML files in `src/client` over to the `dist/tmp` directory. 39 | */ 40 | function prepareTemplates() { 41 | return gulp.src(join(Config.APP_SRC, '**', '*.html')) 42 | .pipe(gulp.dest(Config.TMP_DIR)); 43 | } 44 | 45 | /** 46 | * Execute the appropriate component-stylesheet processing method based on user stylesheet preference. 47 | */ 48 | function processComponentStylesheets() { 49 | return Config.ENABLE_SCSS ? processComponentScss() : processComponentCss(); 50 | } 51 | 52 | /** 53 | * Process scss files referenced from Angular component `styleUrls` metadata 54 | */ 55 | function processComponentScss() { 56 | return gulp.src(join(Config.APP_SRC, '**', '*.scss')) 57 | .pipe(isProd ? plugins.cached('process-component-scss') : plugins.util.noop()) 58 | .pipe(isProd ? plugins.progeny() : plugins.util.noop()) 59 | .pipe(plugins.sourcemaps.init()) 60 | .pipe(plugins.sass(Config.getPluginConfig('gulp-sass')).on('error', plugins.sass.logError)) 61 | .pipe(plugins.postcss(processors)) 62 | .on('error', reportPostCssError) 63 | .pipe(plugins.sourcemaps.write(isProd ? '.' : '')) 64 | .pipe(gulp.dest(isProd ? Config.TMP_DIR : Config.APP_DEST)); 65 | } 66 | 67 | /** 68 | * Processes the CSS files within `src/client` excluding those in `src/client/assets` using `postcss` with the 69 | * configured processors. 70 | */ 71 | function processComponentCss() { 72 | return gulp.src([ 73 | join(Config.APP_SRC, '**', '*.css'), 74 | '!' + join(Config.APP_SRC, 'assets', '**', '*.css') 75 | ]) 76 | .pipe(isProd ? plugins.cached('process-component-css') : plugins.util.noop()) 77 | .pipe(plugins.postcss(processors)) 78 | .on('error', reportPostCssError) 79 | .pipe(gulp.dest(isProd ? Config.TMP_DIR : Config.APP_DEST)); 80 | } 81 | 82 | /** 83 | * Execute external-stylesheet processing method based on presence of --scss flag. 84 | */ 85 | function processExternalStylesheets() { 86 | return Config.ENABLE_SCSS ? processAllExternalStylesheets() : processExternalCss(); 87 | } 88 | 89 | /** 90 | * Process scss stylesheets located in `src/client/css` and any css dependencies specified in 91 | * the global project configuration. 92 | */ 93 | function processAllExternalStylesheets() { 94 | return merge(getExternalCssStream(), getExternalScssStream()) 95 | .pipe(isProd ? plugins.concatCss(gulpConcatCssConfig.targetFile, gulpConcatCssConfig.options) : plugins.util.noop()) 96 | .pipe(plugins.postcss(processors)) 97 | .on('error', reportPostCssError) 98 | .pipe(isProd ? cleanCss() : plugins.util.noop()) 99 | .pipe(gulp.dest(Config.CSS_DEST)); 100 | } 101 | 102 | /** 103 | * Get a stream of external css files for subsequent processing. 104 | */ 105 | function getExternalCssStream() { 106 | return gulp.src(getExternalCss()) 107 | .pipe(isProd ? plugins.cached('process-external-css') : plugins.util.noop()); 108 | } 109 | 110 | /** 111 | * Get an array of filenames referring to all external css stylesheets. 112 | */ 113 | function getExternalCss() { 114 | return Config.DEPENDENCIES.filter(dep => /\.css$/.test(dep.src)).map(dep => dep.src); 115 | } 116 | 117 | /** 118 | * Get a stream of external scss files for subsequent processing. 119 | */ 120 | function getExternalScssStream() { 121 | return gulp.src(getExternalScss()) 122 | .pipe(isProd ? plugins.cached('process-external-scss') : plugins.util.noop()) 123 | .pipe(isProd ? plugins.progeny() : plugins.util.noop()) 124 | .pipe(plugins.sass(Config.getPluginConfig('gulp-sass')).on('error', plugins.sass.logError)); 125 | } 126 | 127 | /** 128 | * Get an array of filenames referring to external scss stylesheets located in the global DEPENDENCIES 129 | * as well as in `src/css`. 130 | */ 131 | function getExternalScss() { 132 | return Config.DEPENDENCIES.filter(dep => /\.scss$/.test(dep.src)).map(dep => dep.src) 133 | .concat([join(Config.CSS_SRC, '**', '*.scss')]); 134 | } 135 | 136 | /** 137 | * Processes the external CSS files using `postcss` with the configured processors. 138 | */ 139 | function processExternalCss() { 140 | return getExternalCssStream() 141 | .pipe(plugins.postcss(processors)) 142 | .pipe(isProd ? plugins.concatCss(gulpConcatCssConfig.targetFile, gulpConcatCssConfig.options) : plugins.util.noop()) 143 | .on('error', reportPostCssError) 144 | .pipe(isProd ? cleanCss() : plugins.util.noop()) 145 | .pipe(gulp.dest(Config.CSS_DEST)); 146 | } 147 | 148 | /** 149 | * Executes the build process, processing the HTML and CSS files. 150 | */ 151 | export = 152 | class BuildHtmlCss extends CssTask { 153 | 154 | shallRun(files: String[]) { 155 | return super.shallRun(files) || files.some(f => f.endsWith('.html')); 156 | } 157 | 158 | run() { 159 | return merge(processComponentStylesheets(), prepareTemplates(), processExternalStylesheets()); 160 | } 161 | }; 162 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-seed", 3 | "version": "0.0.0", 4 | "description": "High-quality, modular starter (seed) project for Angular 2 apps with statically typed build and AoT", 5 | "repository": { 6 | "url": "https://github.com/mgechev/angular2-seed" 7 | }, 8 | "scripts": { 9 | "build.dev": "gulp build.dev --color --config-env dev", 10 | "build.dev.watch": "gulp build.dev.watch --color", 11 | "build.e2e": "gulp build.e2e --color", 12 | "build.prod": "gulp build.prod --color --config-env prod", 13 | "build.prod.exp": "gulp build.prod.exp --color --config-env prod", 14 | "build.test": "gulp build.test --color", 15 | "test.watch": "gulp test.watch --color", 16 | "generate.manifest": "gulp generate.manifest --color", 17 | "e2e": "protractor", 18 | "e2e.live": "protractor --elementExplorer", 19 | "gulp": "gulp", 20 | "i18n": "ng-xi18n && gulp clean.i18n", 21 | "lint": "gulp tslint", 22 | "karma": "karma", 23 | "karma.start": "karma start", 24 | "postinstall": "gulp check.versions && gulp build.bundle.rxjs && npm prune && gulp webdriver && gulp print.banner", 25 | "reinstall": "npm cache clean && npm install", 26 | "serve.coverage": "remap-istanbul -b src/ -i coverage/coverage-final.json -o coverage -t html && npm run gulp -- serve.coverage --color", 27 | "serve.dev": "gulp serve.dev --color --config-env dev", 28 | "serve.e2e": "gulp serve.e2e --color", 29 | "serve.prod": "gulp serve.prod --color --config-env prod", 30 | "start": "gulp serve.dev --color", 31 | "start.deving": "gulp start.deving --color", 32 | "tasks.list": "gulp --tasks-simple --color", 33 | "test": "gulp test --color", 34 | "e2e.ci": "gulp build.prod --color && gulp build.js.e2e --color && gulp e2e --color", 35 | "tests.all": "npm test && npm run e2e.ci", 36 | "webdriver-start": "webdriver-manager start", 37 | "webdriver-update": "webdriver-manager update" 38 | }, 39 | "author": "Minko Gechev ", 40 | "license": "MIT", 41 | "devDependencies": { 42 | "@angular/compiler-cli": "^0.6.1", 43 | "@angular/platform-server": "^2.0.0", 44 | "@angular/tsc-wrapped": "^0.3.0", 45 | "@types/async": "^2.0.31", 46 | "@types/browser-sync": "^0.0.32", 47 | "@types/connect-livereload": "^0.5.29", 48 | "@types/core-js": "^0.9.32", 49 | "@types/express": "^4.0.32", 50 | "@types/gulp": "^3.8.31", 51 | "@types/gulp-load-plugins": "^0.0.27", 52 | "@types/gulp-protractor": "^1.0.28", 53 | "@types/gulp-sass": "^0.0.28", 54 | "@types/gulp-shell": "^0.0.28", 55 | "@types/gulp-util": "^3.0.28", 56 | "@types/jasmine": "^2.2.33", 57 | "@types/node": "^6.0.38", 58 | "@types/protractor": "^1.5.18", 59 | "@types/rimraf": "^0.0.27", 60 | "@types/run-sequence": "^0.0.27", 61 | "@types/selenium-webdriver": "2.44.*", 62 | "@types/systemjs": "^0.19.30", 63 | "@types/yargs": "^0.0.30", 64 | "@types/zone.js": "^0.0.26", 65 | "async": "^2.0.1", 66 | "autoprefixer": "^6.3.7", 67 | "browser-sync": "^2.13.0", 68 | "codelyzer": "1.0.0-beta.1", 69 | "colorguard": "^1.2.0", 70 | "compression": "^1.6.2", 71 | "connect": "^3.4.1", 72 | "connect-history-api-fallback": "^1.3.0", 73 | "connect-livereload": "^0.5.4", 74 | "cssnano": "^3.7.3", 75 | "deep-extend": "^0.4.1", 76 | "del": "^2.2.2", 77 | "doiuse": "^2.4.1", 78 | "event-stream": "^3.3.3", 79 | "express": "~4.14.0", 80 | "express-history-api-fallback": "^2.0.0", 81 | "extend": "^3.0.0", 82 | "gulp": "^3.9.1", 83 | "gulp-cached": "^1.1.0", 84 | "gulp-clean-css": "^2.0.11", 85 | "gulp-concat": "^2.6.0", 86 | "gulp-concat-css": "^2.3.0", 87 | "gulp-filter": "^4.0.0", 88 | "gulp-inject": "^4.1.0", 89 | "gulp-inline-ng2-template": "^3.0.1", 90 | "gulp-load-plugins": "^1.2.4", 91 | "gulp-plumber": "~1.1.0", 92 | "gulp-postcss": "^6.1.1", 93 | "gulp-progeny": "^0.3.1", 94 | "gulp-protractor": "^2.4.0", 95 | "gulp-replace": "^0.5.4", 96 | "gulp-sass": "^2.3.2", 97 | "gulp-sass-lint": "^1.2.0", 98 | "gulp-sourcemaps": "2.0.0-alpha", 99 | "gulp-template": "^4.0.0", 100 | "gulp-tslint": "^6.0.1", 101 | "gulp-typescript": "^3.0.1", 102 | "gulp-uglify": "^2.0.0", 103 | "gulp-util": "^3.0.7", 104 | "gulp-watch": "^4.3.8", 105 | "is-ci": "^1.0.9", 106 | "isstream": "^0.1.2", 107 | "jasmine-core": "~2.4.1", 108 | "jasmine-spec-reporter": "^2.5.0", 109 | "karma": "~0.13.22", 110 | "karma-chrome-launcher": "~1.0.1", 111 | "karma-coverage": "^1.1.0", 112 | "karma-jasmine": "~1.0.2", 113 | "karma-mocha-reporter": "^2.0.4", 114 | "karma-remap-istanbul": "^0.2.1", 115 | "merge-stream": "^1.0.0", 116 | "open": "0.0.5", 117 | "postcss-reporter": "^1.4.1", 118 | "protractor": "^3.3.0", 119 | "remap-istanbul": "^0.6.4", 120 | "rimraf": "^2.5.3", 121 | "run-sequence": "^1.2.2", 122 | "semver": "^5.3.0", 123 | "serve-static": "^1.11.1", 124 | "slash": "~1.0.0", 125 | "stylelint": "^7.0.2", 126 | "stylelint-config-standard": "^11.0.0", 127 | "supports-color": "^3.1.2", 128 | "systemjs-builder": "0.15.31", 129 | "tildify": "^1.2.0", 130 | "traceur": "^0.0.111", 131 | "ts-node": "^1.0.0", 132 | "tslint": "^3.13.0", 133 | "tslint-stylish": "2.1.0-beta", 134 | "typescript": "^2.0.2", 135 | "walk": "^2.3.9", 136 | "yargs": "^4.8.0" 137 | }, 138 | "dependencies": { 139 | "@angular/common": "^2.0.1", 140 | "@angular/compiler": "^2.0.1", 141 | "@angular/core": "^2.0.1", 142 | "@angular/forms": "^2.0.1", 143 | "@angular/http": "^2.0.1", 144 | "@angular/platform-browser": "^2.0.1", 145 | "@angular/platform-browser-dynamic": "^2.0.1", 146 | "@angular/router": "^3.0.1", 147 | "core-js": "^2.4.1", 148 | "es-module-loader": "^1.0.0", 149 | "reflect-metadata": "^0.1.8", 150 | "rxjs": "5.0.0-beta.12", 151 | "systemjs": "0.19.39", 152 | "zone.js": "0.6.25" 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /tools/config/banner-256.txt: -------------------------------------------------------------------------------- 1 | 2 | Welcome to angular-seed 3 |                                     4 |                                     5 |                                     6 |                                     7 |                                     8 |                                     9 |                                     10 |                                     11 |                                     12 |                                     13 |                                     14 |                                     15 |                                     16 |                                     17 |                                     18 |                                     19 |                                     20 |                                     21 |                                     22 |  23 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools documentation 2 | 3 | This document contains information about the tools section of the `angular2-seed`. 4 | 5 | ## General Information 6 | 7 | The root of this folder contains the following files: 8 | 9 | | Filename | Description | 10 | | :----------- | :---------- | 11 | | `.gitignore` | Adds the generated `*.js` and `.js.map` files to the list of ignores files for git | 12 | | `config.ts` | Exports the project configuration, which contains of the basic configuration provided by `/config/seed.config.ts` and the project specific overrides defined by `/config/project.config.ts` | 13 | | `debug.ts` | Provides the ability to debug a specific build task | 14 | | `README.md` | The documentation of the tools section | 15 | | `utils.ts` | Exports the utilities provided by the seed barrel file (`/utils/seed.utils.ts`) and the project specific barrel file (`/utils/project.utils.ts`) | 16 | 17 | The subfolders provide further folders to distinguish between files which are provided by the seed (located in the corresponding `seed` folder) and files which can be specific by project (to be located in the corresponding `project` folder). This helps you to include updates from the `angular2-seed` without causing conflicts with you personal customisations. 18 | 19 | ## Configuration 20 | 21 | The configuration of the seed contains of a basic configuration provided by `/config/seed.config.ts` file. You can add your own custom configuration within the `/config/project.config.ts` file, which extends the seed configuration. 22 | 23 | ## Environment Configuration 24 | 25 | The environment configuration files in `/tools/env` provide a way for you to set and override configuration settings based on a given environment. The `/tools/env/base.ts` configuration is set up in all environments (dev|test|staging|prod), whereas the `/tools/env/dev.ts` is specific to the dev environment, as is `/tools/env/prod.ts` specific to the prod environment. 26 | 27 | ## Manual Typings 28 | 29 | The `manual_typings` folder contains manual TypeScript typings provided by the seed (`/manual_typings/seed`) and project specific TypeScript typings (`/manual_typings/project`). As for the project specific typings there is a sample provided (`/manual_typings/project/sample.package.d.ts`) to help you get started. 30 | 31 | ## Tasks 32 | 33 | The `tasks` folder contains tasks provided by the seed (`/tasks/seed`) and project specific tasks (`/tasks/project`). As for the project specific tasks there is a sample provided (`/tasks/project/sample.task.ts`) to help you get started. 34 | 35 | The seed provides the following tasks: 36 | 37 | | Filename | Description | 38 | | :--------------------- | :---------- | 39 | | `build.assets.dev.ts` | Copies the assets (located in `src/client/assets`) over to the `dist/dev/assets` directory | 40 | | `build.assets.prod.ts` | Copies the assets (located in `src/client/assets`) over to the `dist/prod/assets` directory | 41 | | `build.bundles.app.ts` | Bundles the JavaScript files using the SystemJS Builder | 42 | | `build.bundles.ts` | Bundles the JavaScript shim dependencies | 43 | | `build.docs.ts` | Builds the documentation for the TypeScript files using `typedoc` | 44 | | `build.html_css.ts` | Builds the `html` and `css` files and applies CSS postprocessing | 45 | | `build.index.dev.ts` | Builds the `index.html` for the `dev` environment | 46 | | `build.index.prod.ts` | Builds the `index.html` for the `prod` environment | 47 | | `build.js.dev.ts` | Transpiles the TypeScript files (excluding specs and e2e specs) for the `dev` environment | 48 | | `build.js.e2e.ts` | Transpiles the TypeScript files (excluding specs and e2e specs) for the `e2e` environment | 49 | | `build.js.prod.ts` | Transpiles the TypeScript files (excluding specs and e2e specs) for the `prod` environment | 50 | | `build.js.test.ts` | Transpiles the TypeScript files (excluding specs and e2e specs) for the `test` environment | 51 | | `build.js.tools.ts` | Transpiles the TypeScript files located in `/tools` | 52 | | `check.versions.ts` | Checks if the required Node and NPM (as defined in `/config/seed.config.ts`) are installed | 53 | | `clean.all.ts` | Cleans all files within the `/dist` directory | 54 | | `clean.coverage.ts` | Cleans all files within the `/coverage` directory | 55 | | `clean.dev.ts` | Cleans all files within the `/dist/dev` directory | 56 | | `clean.prod.ts` | Cleans all files within the `/dist/prod` directory | 57 | | `clean.tools.ts` | Cleans all JavaScript files (which got transpiled from the TypeScript files) within the `/tools` directory | 58 | | `copy.js.prod.ts` | Copies all TypeScript files (excluding specs and e2e specs) over to the `/tmp` dir | 59 | | `css-lint.ts` | Lints all `css` files using `stylelint` | 60 | | `e2e.ts` | Runs all e2e specs using `protractor` | 61 | | `generate.manifest.ts` | Generates a `manifest` file for the application | 62 | | `karma.start.ts` | Starts the unit tests using `karma` | 63 | | `serve.coverage.ts` | Serves the unit test coverage report using an `express` server | 64 | | `serve.docs.ts` | Serves the application documentation using an `express` server | 65 | | `server.prod.ts` | Serves the files from `/dist/prod` using an `express` server | 66 | | `server.start.ts` | Serves the files from `/dist/dev` using an `express` server | 67 | | `tslint.ts` | Lints the TypeScript files using `codelyzer` | 68 | | `watch.dev.ts` | Watches for code changes and rebuilds the files in `/dist/dev` | 69 | | `watch.e2e.ts` | Watches for code changes and rebuilds the files in `/dist/e2e` | 70 | | `watch.test.ts` | Watches for code changes and rebuilds the files in `/dist/test` | 71 | | `webdriver.ts` | Installs the Selenium webdriver used for the Protractor e2e specs | 72 | 73 | ## Utilities 74 | 75 | The `utils` folder contains utilities provided by the seed (`/utils/seed`) and project specific utilities (`/utils/project`). As for the project specific utilities there is a sample provided (`/utils/project/sample_util.ts`) to help you get started. 76 | 77 | The utilities are exported by the barrel files `project.utils.ts` (for the project specific utilities) and `seed.utils.ts` (for the utilities provided by the seed). 78 | 79 | The seed provides the following utilities: 80 | 81 | | Filename | Description | 82 | | :--------------------- | :---------- | 83 | | `clean.ts` | Provides a utility to clean files and directories | 84 | | `code_change_tools.ts` | Provides utilities to make use of BrowserSync to refresh the browser after a code change | 85 | | `server.ts` | Provides utilities to start `express` servers for the application, the documentation and the unit test coverage | 86 | | `task_tools.ts` | Provides utilities to start tasks (matching task names as string input parameters from the `gulpfile.ts` to the corresponding files) | 87 | | `template_locals.ts` | Provides a utility for template locals | 88 | | `tsproject.ts` | Provides a utility to configure the TypeScript transpilation | 89 | | `watch.ts` | Provides a utility to watch for file changes and notify live reloads | 90 | 91 | -------------------------------------------------------------------------------- /tools/config/seed.config.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import * as slash from 'slash'; 3 | import { argv } from 'yargs'; 4 | 5 | import { Environments, InjectableDependency } from './seed.config.interfaces'; 6 | 7 | /************************* DO NOT CHANGE ************************ 8 | * 9 | * DO NOT make any changes in this file because it will 10 | * make your migration to newer versions of the seed harder. 11 | * 12 | * Your application-specific configurations should be 13 | * in project.config.ts. If you need to change any tasks 14 | * from "./tasks" overwrite them by creating a task with the 15 | * same name in "./projects". For further information take a 16 | * look at the documentation: 17 | * 18 | * 1) https://github.com/mgechev/angular2-seed/tree/master/tools 19 | * 2) https://github.com/mgechev/angular2-seed/wiki 20 | * 21 | *****************************************************************/ 22 | 23 | /** 24 | * The enumeration of available environments. 25 | * @type {Environments} 26 | */ 27 | export const ENVIRONMENTS: Environments = { 28 | DEVELOPMENT: 'dev', 29 | PRODUCTION: 'prod' 30 | }; 31 | 32 | /** 33 | * This class represents the basic configuration of the seed. 34 | * It provides the following: 35 | * - Constants for directories, ports, versions etc. 36 | * - Injectable NPM dependencies 37 | * - Injectable application assets 38 | * - Temporary editor files to be ignored by the watcher and asset builder 39 | * - SystemJS configuration 40 | * - Autoprefixer configuration 41 | * - BrowserSync configuration 42 | * - Utilities 43 | */ 44 | export class SeedConfig { 45 | 46 | /** 47 | * The port where the application will run. 48 | * The default port is `5555`, which can be overriden by the `--port` flag when running `npm start`. 49 | * @type {number} 50 | */ 51 | PORT = argv['port'] || 5555; 52 | 53 | /** 54 | * The root folder of the project (up two levels from the current directory). 55 | */ 56 | PROJECT_ROOT = join(__dirname, '../..'); 57 | 58 | /** 59 | * The current environment. 60 | * The default environment is `dev`, which can be overriden by the `--config-env ENV_NAME` flag when running `npm start`. 61 | */ 62 | ENV = getEnvironment(); 63 | 64 | /** 65 | * The flag for the debug option of the application. 66 | * The default value is `false`, which can be overriden by the `--debug` flag when running `npm start`. 67 | * @type {boolean} 68 | */ 69 | DEBUG = argv['debug'] || false; 70 | 71 | /** 72 | * The port where the documentation application will run. 73 | * The default docs port is `4003`, which can be overriden by the `--docs-port` flag when running `npm start`. 74 | * @type {number} 75 | */ 76 | DOCS_PORT = argv['docs-port'] || 4003; 77 | 78 | /** 79 | * The port where the unit test coverage report application will run. 80 | * The default coverage port is `4004`, which can by overriden by the `--coverage-port` flag when running `npm start`. 81 | * @type {number} 82 | */ 83 | COVERAGE_PORT = argv['coverage-port'] || 4004; 84 | 85 | /** 86 | * The path to the coverage output 87 | * NB: this must match what is configured in ./karma.conf.js 88 | */ 89 | COVERAGE_DIR = 'coverage'; 90 | 91 | /** 92 | * Karma reporter configuration 93 | */ 94 | KARMA_REPORTERS: any = { 95 | preprocessors: { 96 | 'dist/**/!(*spec).js': ['coverage'] 97 | }, 98 | reporters: ['mocha', 'coverage'], 99 | coverageReporter: { 100 | dir: this.COVERAGE_DIR + '/', 101 | reporters: [ 102 | {type: 'json', subdir: '.', file: 'coverage-final.json'} 103 | ] 104 | } 105 | }; 106 | 107 | /** 108 | * The path for the base of the application at runtime. 109 | * The default path is based on the environment '/', 110 | * which can be overriden by the `--base` flag when running `npm start`. 111 | * @type {string} 112 | */ 113 | APP_BASE = argv['base'] || '/'; 114 | 115 | /** 116 | * The base path of node modules. 117 | * @type {string} 118 | */ 119 | NPM_BASE = slash(join(this.APP_BASE, 'node_modules/')); 120 | 121 | /** 122 | * The flag for the hot-loader option of the application. 123 | * Per default the option is not set, but can be set by the `--hot-loader` flag when running `npm start`. 124 | * @type {boolean} 125 | */ 126 | ENABLE_HOT_LOADING = argv['hot-loader']; 127 | 128 | /** 129 | * The port where the application will run, if the `hot-loader` option mode is used. 130 | * The default hot-loader port is `5578`. 131 | * @type {number} 132 | */ 133 | HOT_LOADER_PORT = 5578; 134 | 135 | /** 136 | * The build interval which will force the TypeScript compiler to perform a typed compile run. 137 | * Between the typed runs, a typeless compile is run, which is typically much faster. 138 | * For example, if set to 5, the initial compile will be typed, followed by 5 typeless runs, 139 | * then another typed run, and so on. 140 | * If a compile error is encountered, the build will use typed compilation until the error is resolved. 141 | * The default value is `0`, meaning typed compilation will always be performed. 142 | * @type {number} 143 | */ 144 | TYPED_COMPILE_INTERVAL = 0; 145 | 146 | /** 147 | * The directory where the bootstrap file is located. 148 | * The default directory is `app`. 149 | * @type {string} 150 | */ 151 | BOOTSTRAP_DIR = argv['app'] || 'app'; 152 | 153 | /** 154 | * The directory where the client files are located. 155 | * The default directory is `client`. 156 | * @type {string} 157 | */ 158 | APP_CLIENT = argv['client'] || 'client'; 159 | 160 | /** 161 | * The bootstrap file to be used to boot the application. The file to be used is dependent if the hot-loader option is 162 | * used or not. 163 | * Per default (non hot-loader mode) the `main.ts` file will be used, with the hot-loader option enabled, the 164 | * `hot_loader_main.ts` file will be used. 165 | * @type {string} 166 | */ 167 | BOOTSTRAP_MODULE = `${this.BOOTSTRAP_DIR}/` + (this.ENABLE_HOT_LOADING ? 'hot_loader_main' : 'main'); 168 | 169 | BOOTSTRAP_PROD_MODULE = `${this.BOOTSTRAP_DIR}/` + 'main'; 170 | 171 | NG_FACTORY_FILE = 'main-prod'; 172 | 173 | BOOTSTRAP_FACTORY_PROD_MODULE = `${this.BOOTSTRAP_DIR}/${this.NG_FACTORY_FILE}`; 174 | /** 175 | * The default title of the application as used in the `` tag of the 176 | * `index.html`. 177 | * @type {string} 178 | */ 179 | APP_TITLE = 'Welcome to angular2-seed!'; 180 | 181 | /** 182 | * The base folder of the applications source files. 183 | * @type {string} 184 | */ 185 | APP_SRC = `src/${this.APP_CLIENT}`; 186 | 187 | /** 188 | * The folder of the applications asset files. 189 | * @type {string} 190 | */ 191 | ASSETS_SRC = `${this.APP_SRC}/assets`; 192 | 193 | /** 194 | * The folder of the applications css files. 195 | * @type {string} 196 | */ 197 | CSS_SRC = `${this.APP_SRC}/css`; 198 | 199 | /** 200 | * The directory of the applications tools 201 | * @type {string} 202 | */ 203 | TOOLS_DIR = 'tools'; 204 | 205 | /** 206 | * The directory of the tasks provided by the seed. 207 | */ 208 | SEED_TASKS_DIR = join(process.cwd(), this.TOOLS_DIR, 'tasks', 'seed'); 209 | 210 | /** 211 | * The destination folder for the generated documentation. 212 | * @type {string} 213 | */ 214 | DOCS_DEST = 'docs'; 215 | 216 | /** 217 | * The base folder for built files. 218 | * @type {string} 219 | */ 220 | DIST_DIR = 'dist'; 221 | 222 | /** 223 | * The folder for built files in the `dev` environment. 224 | * @type {string} 225 | */ 226 | DEV_DEST = `${this.DIST_DIR}/dev`; 227 | 228 | /** 229 | * The folder for the built files in the `prod` environment. 230 | * @type {string} 231 | */ 232 | PROD_DEST = `${this.DIST_DIR}/prod`; 233 | 234 | /** 235 | * The folder for temporary files. 236 | * @type {string} 237 | */ 238 | TMP_DIR = `${this.DIST_DIR}/tmp`; 239 | 240 | /** 241 | * The folder for the built files, corresponding to the current environment. 242 | * @type {string} 243 | */ 244 | APP_DEST = this.ENV === ENVIRONMENTS.DEVELOPMENT ? this.DEV_DEST : this.PROD_DEST; 245 | 246 | /** 247 | * The folder for the built CSS files. 248 | * @type {strings} 249 | */ 250 | CSS_DEST = `${this.APP_DEST}/css`; 251 | 252 | /** 253 | * The folder for the built JavaScript files. 254 | * @type {string} 255 | */ 256 | JS_DEST = `${this.APP_DEST}/js`; 257 | 258 | /** 259 | * The version of the application as defined in the `package.json`. 260 | */ 261 | VERSION = appVersion(); 262 | 263 | /** 264 | * The name of the bundle file to includes all CSS files. 265 | * @type {string} 266 | */ 267 | CSS_PROD_BUNDLE = 'main.css'; 268 | 269 | /** 270 | * The name of the bundle file to include all JavaScript shims. 271 | * @type {string} 272 | */ 273 | JS_PROD_SHIMS_BUNDLE = 'shims.js'; 274 | 275 | /** 276 | * The name of the bundle file to include all JavaScript application files. 277 | * @type {string} 278 | */ 279 | JS_PROD_APP_BUNDLE = 'app.js'; 280 | 281 | /** 282 | * The required NPM version to run the application. 283 | * @type {string} 284 | */ 285 | VERSION_NPM = '2.14.2'; 286 | 287 | /** 288 | * The required NodeJS version to run the application. 289 | * @type {string} 290 | */ 291 | VERSION_NODE = '4.0.0'; 292 | 293 | /** 294 | * The flag to enable handling of SCSS files 295 | * The default value is false. Override with the '--scss' flag. 296 | * @type {boolean} 297 | */ 298 | ENABLE_SCSS = argv['scss'] || false; 299 | 300 | /** 301 | * The list of NPM dependcies to be injected in the `index.html`. 302 | * @type {InjectableDependency[]} 303 | */ 304 | NPM_DEPENDENCIES: InjectableDependency[] = [ 305 | { src: 'zone.js/dist/zone.js', inject: 'libs' }, 306 | { src: 'core-js/client/shim.min.js', inject: 'shims' }, 307 | { src: 'systemjs/dist/system.src.js', inject: 'shims', env: ENVIRONMENTS.DEVELOPMENT }, 308 | // Temporary fix. See https://github.com/angular/angular/issues/9359 309 | { src: '.tmp/Rx.min.js', inject: 'libs', env: ENVIRONMENTS.DEVELOPMENT }, 310 | ]; 311 | 312 | /** 313 | * The list of local files to be injected in the `index.html`. 314 | * @type {InjectableDependency[]} 315 | */ 316 | APP_ASSETS: InjectableDependency[] = [ 317 | { src: `${this.CSS_SRC}/main.${this.getInjectableStyleExtension()}`, inject: true, vendor: false }, 318 | ]; 319 | 320 | /** 321 | * The list of editor temporary files to ignore in watcher and asset builder. 322 | * @type {string[]} 323 | */ 324 | TEMP_FILES: string[] = [ 325 | '**/*___jb_tmp___', 326 | '**/*~', 327 | ]; 328 | 329 | /** 330 | * Returns the array of injectable dependencies (npm dependencies and assets). 331 | * @return {InjectableDependency[]} The array of npm dependencies and assets. 332 | */ 333 | get DEPENDENCIES(): InjectableDependency[] { 334 | return normalizeDependencies(this.NPM_DEPENDENCIES.filter(filterDependency.bind(null, this.ENV))) 335 | .concat(this.APP_ASSETS.filter(filterDependency.bind(null, this.ENV))); 336 | } 337 | 338 | /** 339 | * The configuration of SystemJS for the `dev` environment. 340 | * @type {any} 341 | */ 342 | SYSTEM_CONFIG_DEV: any = { 343 | defaultJSExtensions: true, 344 | packageConfigPaths: [ 345 | `/node_modules/*/package.json`, 346 | `/node_modules/**/package.json`, 347 | `/node_modules/@angular/*/package.json` 348 | ], 349 | paths: { 350 | [this.BOOTSTRAP_MODULE]: `${this.APP_BASE}${this.BOOTSTRAP_MODULE}`, 351 | '@angular/common': 'node_modules/@angular/common/bundles/common.umd.js', 352 | '@angular/compiler': 'node_modules/@angular/compiler/bundles/compiler.umd.js', 353 | '@angular/core': 'node_modules/@angular/core/bundles/core.umd.js', 354 | '@angular/forms': 'node_modules/@angular/forms/bundles/forms.umd.js', 355 | '@angular/http': 'node_modules/@angular/http/bundles/http.umd.js', 356 | '@angular/platform-browser': 'node_modules/@angular/platform-browser/bundles/platform-browser.umd.js', 357 | '@angular/platform-browser-dynamic': 'node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 358 | '@angular/router': 'node_modules/@angular/router/bundles/router.umd.js', 359 | 360 | '@angular/common/testing': 'node_modules/@angular/common/bundles/common-testing.umd.js', 361 | '@angular/compiler/testing': 'node_modules/@angular/compiler/bundles/compiler-testing.umd.js', 362 | '@angular/core/testing': 'node_modules/@angular/core/bundles/core-testing.umd.js', 363 | '@angular/http/testing': 'node_modules/@angular/http/bundles/http-testing.umd.js', 364 | '@angular/platform-browser/testing': 365 | 'node_modules/@angular/platform-browser/bundles/platform-browser-testing.umd.js', 366 | '@angular/platform-browser-dynamic/testing': 367 | 'node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', 368 | '@angular/router/testing': 'node_modules/@angular/router/bundles/router-testing.umd.js', 369 | 370 | 'app/*': '/app/*', 371 | // For test config 372 | 'dist/dev/*': '/base/dist/dev/*', 373 | '*': 'node_modules/*' 374 | }, 375 | packages: { 376 | } 377 | }; 378 | 379 | /** 380 | * The configuration of SystemJS of the application. 381 | * Per default, the configuration of the `dev` environment will be used. 382 | * @type {any} 383 | */ 384 | SYSTEM_CONFIG: any = this.SYSTEM_CONFIG_DEV; 385 | 386 | /** 387 | * The system builder configuration of the application. 388 | * @type {any} 389 | */ 390 | SYSTEM_BUILDER_CONFIG: any = { 391 | defaultJSExtensions: true, 392 | base: this.PROJECT_ROOT, 393 | packageConfigPaths: [ 394 | join('node_modules', '*', 'package.json'), 395 | join('node_modules', '@angular', '*', 'package.json') 396 | ], 397 | paths: { 398 | [join(this.TMP_DIR, this.BOOTSTRAP_DIR, '*')]: `${this.TMP_DIR}/${this.BOOTSTRAP_DIR}/*`, 399 | 'node_modules/*': 'node_modules/*', 400 | '*': 'node_modules/*' 401 | }, 402 | packages: { 403 | '@angular/common': { 404 | main: 'index.js', 405 | defaultExtension: 'js' 406 | }, 407 | '@angular/compiler': { 408 | main: 'index.js', 409 | defaultExtension: 'js' 410 | }, 411 | '@angular/core/testing': { 412 | main: 'index.js', 413 | defaultExtension: 'js' 414 | }, 415 | '@angular/core': { 416 | main: 'index.js', 417 | defaultExtension: 'js' 418 | }, 419 | '@angular/forms': { 420 | main: 'index.js', 421 | defaultExtension: 'js' 422 | }, 423 | '@angular/http': { 424 | main: 'index.js', 425 | defaultExtension: 'js' 426 | }, 427 | '@angular/platform-browser': { 428 | main: 'index.js', 429 | defaultExtension: 'js' 430 | }, 431 | '@angular/platform-browser-dynamic': { 432 | main: 'index.js', 433 | defaultExtension: 'js' 434 | }, 435 | '@angular/router': { 436 | main: 'index.js', 437 | defaultExtension: 'js' 438 | }, 439 | 'rxjs': { 440 | main: 'Rx.js', 441 | defaultExtension: 'js' 442 | } 443 | } 444 | }; 445 | 446 | /** 447 | * The Autoprefixer configuration for the application. 448 | * @type {Array} 449 | */ 450 | BROWSER_LIST = [ 451 | 'ie >= 10', 452 | 'ie_mob >= 10', 453 | 'ff >= 30', 454 | 'chrome >= 34', 455 | 'safari >= 7', 456 | 'opera >= 23', 457 | 'ios >= 7', 458 | 'android >= 4.4', 459 | 'bb >= 10' 460 | ]; 461 | 462 | /** 463 | * White list for CSS color guard 464 | * @type {[string, string][]} 465 | */ 466 | COLOR_GUARD_WHITE_LIST: [string, string][] = [ 467 | ]; 468 | 469 | /** 470 | * Configurations for NPM module configurations. Add to or override in project.config.ts. 471 | * If you like, use the mergeObject() method to assist with this. 472 | */ 473 | PLUGIN_CONFIGS: any = { 474 | /** 475 | * The BrowserSync configuration of the application. 476 | * The default open behavior is to open the browser. To prevent the browser from opening use the `--b` flag when 477 | * running `npm start` (tested with serve.dev). 478 | * Example: `npm start -- --b` 479 | * @type {any} 480 | */ 481 | 'browser-sync': { 482 | middleware: [require('connect-history-api-fallback')({ 483 | index: `${this.APP_BASE}index.html` 484 | })], 485 | port: this.PORT, 486 | startPath: this.APP_BASE, 487 | open: argv['b'] ? false : true, 488 | injectChanges: false, 489 | server: { 490 | baseDir: `${this.DIST_DIR}/empty/`, 491 | routes: { 492 | [`${this.APP_BASE}${this.APP_SRC}`]: this.APP_SRC, 493 | [`${this.APP_BASE}${this.APP_DEST}`]: this.APP_DEST, 494 | [`${this.APP_BASE}node_modules`]: 'node_modules', 495 | [`${this.APP_BASE.replace(/\/$/, '')}`]: this.APP_DEST 496 | } 497 | } 498 | }, 499 | 500 | // Note: you can customize the location of the file 501 | 'environment-config': join(this.PROJECT_ROOT, this.TOOLS_DIR, 'env'), 502 | 503 | /** 504 | * The options to pass to gulp-sass (and then to node-sass). 505 | * Reference: https://github.com/sass/node-sass#options 506 | * @type {object} 507 | */ 508 | 'gulp-sass': { 509 | includePaths: ['./node_modules/'] 510 | }, 511 | 512 | /** 513 | * The options to pass to gulp-concat-css 514 | * Reference: https://github.com/mariocasciaro/gulp-concat-css 515 | * @type {object} 516 | */ 517 | 'gulp-concat-css': { 518 | targetFile: this.CSS_PROD_BUNDLE, 519 | options: { 520 | rebaseUrls: false 521 | } 522 | } 523 | }; 524 | 525 | /** 526 | * Recursively merge source onto target. 527 | * @param {any} target The target object (to receive values from source) 528 | * @param {any} source The source object (to be merged onto target) 529 | */ 530 | mergeObject(target: any, source: any) { 531 | const deepExtend = require('deep-extend'); 532 | deepExtend(target, source); 533 | } 534 | 535 | /** 536 | * Locate a plugin configuration object by plugin key. 537 | * @param {any} pluginKey The object key to look up in PLUGIN_CONFIGS. 538 | */ 539 | getPluginConfig(pluginKey: string): any { 540 | if (this.PLUGIN_CONFIGS[pluginKey]) { 541 | return this.PLUGIN_CONFIGS[pluginKey]; 542 | } 543 | return null; 544 | } 545 | 546 | getInjectableStyleExtension() { 547 | return this.ENV === ENVIRONMENTS.PRODUCTION && this.ENABLE_SCSS ? 'scss' : 'css'; 548 | } 549 | 550 | } 551 | 552 | /** 553 | * Normalizes the given `deps` to skip globs. 554 | * @param {InjectableDependency[]} deps - The dependencies to be normalized. 555 | */ 556 | export function normalizeDependencies(deps: InjectableDependency[]) { 557 | deps 558 | .filter((d: InjectableDependency) => !/\*/.test(d.src)) // Skip globs 559 | .forEach((d: InjectableDependency) => d.src = require.resolve(d.src)); 560 | return deps; 561 | } 562 | 563 | /** 564 | * Returns if the given dependency is used in the given environment. 565 | * @param {string} env - The environment to be filtered for. 566 | * @param {InjectableDependency} d - The dependency to check. 567 | * @return {boolean} `true` if the dependency is used in this environment, `false` otherwise. 568 | */ 569 | function filterDependency(env: string, d: InjectableDependency): boolean { 570 | if (!d.env) { 571 | d.env = Object.keys(ENVIRONMENTS).map(k => ENVIRONMENTS[k]); 572 | } 573 | if (!(d.env instanceof Array)) { 574 | (<any>d).env = [d.env]; 575 | } 576 | return d.env.indexOf(env) >= 0; 577 | } 578 | 579 | /** 580 | * Returns the applications version as defined in the `package.json`. 581 | * @return {number} The applications version. 582 | */ 583 | function appVersion(): number | string { 584 | var pkg = require('../../package.json'); 585 | return pkg.version; 586 | } 587 | 588 | /** 589 | * Returns the environment of the application. 590 | */ 591 | function getEnvironment() { 592 | let base: string[] = argv['_']; 593 | let prodKeyword = !!base.filter(o => o.indexOf(ENVIRONMENTS.PRODUCTION) >= 0).pop(); 594 | let env = (argv['env'] || '').toLowerCase(); 595 | if ((base && prodKeyword) || env === ENVIRONMENTS.PRODUCTION) { 596 | return ENVIRONMENTS.PRODUCTION; 597 | } else { 598 | return ENVIRONMENTS.DEVELOPMENT; 599 | } 600 | } 601 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [![Angular Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://angular.io/styleguide) 4 | [![Build Status](https://travis-ci.org/mgechev/angular-seed.svg?branch=master)](https://travis-ci.org/mgechev/angular-seed) 5 | [![Build Status](https://ci.appveyor.com/api/projects/status/jg5vg36w0klpa00e?svg=true)](https://ci.appveyor.com/project/mgechev/angular2-seed) 6 | [![Join the chat at https://gitter.im/mgechev/angular2-seed](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mgechev/angular2-seed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) 8 | [![Dependency Status](https://david-dm.org/mgechev/angular-seed.svg)](https://david-dm.org/mgechev/angular-seed) 9 | [![devDependency Status](https://david-dm.org/mgechev/angular-seed/dev-status.svg)](https://david-dm.org/mgechev/angular-seed#info=devDependencies) 10 | 11 | Provides fast, reliable and extensible starter for the development of Angular projects. 12 | 13 | `angular-seed` provides the following features: 14 | 15 | - Allows you to painlessly update the seed tasks of your already existing project. 16 | - Supports multiple Angular applications with shared codebase in a single instance of the seed. 17 | - Official Angular i18n support. 18 | - Ready to go, statically typed build system using gulp for working with TypeScript. 19 | - Production and development builds. 20 | - **Ahead-of-Time** compilation support. 21 | - Sample unit tests with Jasmine and Karma including code coverage via [istanbul](https://gotwarlost.github.io/istanbul/). 22 | - End-to-end tests with Protractor. 23 | - Development server with Livereload. 24 | - Following the [best practices](https://angular.io/styleguide). 25 | - Manager of your type definitions using @types. 26 | - Has autoprefixer and css-lint support. 27 | 28 | # How to start 29 | 30 | **Note** that this seed project requires node v4.x.x or higher and npm 2.14.7. 31 | 32 | **Here is how to [speed-up the build on Windows](https://github.com/mgechev/angular-seed/wiki/Speed-up-the-build-on-Windows)**. 33 | 34 | In order to start the seed use: 35 | 36 | 37 | ```bash 38 | git clone --depth 1 https://github.com/mgechev/angular-seed.git 39 | cd angular-seed 40 | # install the project's dependencies 41 | npm install 42 | # watches your files and uses livereload by default 43 | npm start 44 | # api document for the app 45 | # npm run build.docs 46 | 47 | # to start deving with livereload site and coverage as well as continuous testing 48 | npm run start.deving 49 | 50 | # dev build 51 | npm run build.dev 52 | # prod build 53 | npm run build.prod 54 | # prod build with AoT compilation 55 | npm run build.prod.exp 56 | 57 | # dev build of multiple applications (by default the value of --app is "app") 58 | npm start -- --app baz 59 | npm start -- --app foo 60 | npm start -- --app bar 61 | ``` 62 | 63 | _Does not rely on any global dependencies._ 64 | 65 | # Table of Contents 66 | 67 | - [Introduction](#introduction) 68 | - [How to start](#how-to-start) 69 | - [Table of Content](#table-of-content) 70 | - [Configuration](#configuration) 71 | - [Environment Configuration](#environment-configuration) 72 | - [Tools documentation](#tools-documentation) 73 | - [How to extend?](#how-to-extend) 74 | - [Running tests](#running-tests) 75 | <!--- [Progressive Web Apps](#progressive-web-apps) --> 76 | - [Contributing](#contributing) 77 | - [Advanced Seed Option](#advanced-seed-option) 78 | - [Examples](#examples) 79 | - [Directory Structure](#directory-structure) 80 | - [Contributors](#contributors) 81 | - [Wiki Contributors](#wiki-contributors) 82 | - [Change Log](#change-log) 83 | - [License](#license) 84 | 85 | # Configuration 86 | 87 | Default application server configuration 88 | 89 | ```js 90 | var PORT = 5555; 91 | var LIVE_RELOAD_PORT = 4002; 92 | var DOCS_PORT = 4003; 93 | var APP_BASE = '/'; 94 | ``` 95 | 96 | Configure at runtime 97 | 98 | ```bash 99 | npm start -- --port 8080 --reload-port 4000 --base /my-app/ 100 | ``` 101 | 102 | ## Environment configuration 103 | 104 | If you have different environments and you need to configure them to use different end points, settings, etc. you can use the files `dev.ts` or `prod.ts` in`./tools/env/`. The name of the file is environment you want to use. 105 | 106 | The environment can be specified by using: 107 | 108 | ```bash 109 | npm start -- --config-env ENV_NAME 110 | ``` 111 | 112 | Currently the `ENV_NAME`s are `dev`, `prod`, `staging`, but you can simply add a different file `"ENV_NAME.ts".` file in order to alter extra such environments. 113 | 114 | # Tools documentation 115 | 116 | A documentation of the provided tools can be found in [tools/README.md](tools/README.md). 117 | 118 | # How to extend? 119 | 120 | Visit the [Wiki page](https://github.com/mgechev/angular-seed/wiki) of the project. 121 | 122 | # Running tests 123 | 124 | ```bash 125 | npm test 126 | 127 | # Development. Your app will be watched by karma 128 | # on each change all your specs will be executed. 129 | npm run test.watch 130 | # NB: The command above might fail with a "EMFILE: too many open files" error. 131 | # Some OS have a small limit of opened file descriptors (256) by default 132 | # and will result in the EMFILE error. 133 | # You can raise the maximum of file descriptors by running the command below: 134 | ulimit -n 10480 135 | 136 | 137 | # code coverage (istanbul) 138 | # auto-generated at the end of `npm test` 139 | # view coverage report: 140 | npm run serve.coverage 141 | 142 | # e2e (aka. end-to-end, integration) - In three different shell windows 143 | # Make sure you don't have a global instance of Protractor 144 | # Make sure you do have Java in your PATH (required for webdriver) 145 | 146 | # npm install webdriver-manager <- Install this first for e2e testing 147 | # npm run webdriver-update <- You will need to run this the first time 148 | npm run webdriver-start 149 | npm run serve.e2e 150 | npm run e2e 151 | 152 | # e2e live mode - Protractor interactive mode 153 | # Instead of last command above, you can use: 154 | npm run e2e.live 155 | ``` 156 | You can learn more about [Protractor Interactive Mode here](https://github.com/angular/protractor/blob/master/docs/debugging.md#testing-out-protractor-interactively) 157 | 158 | <!-- # Progressive Web Apps 159 | 160 | `angular-seed` supports progressive web apps with [angular/mobile-toolkit](https://github.com/angular/mobile-toolkit). 161 | 162 | The seed can generate a file `manifest.appcache` which lists all files included in a project's output, along with SHA1 hashes of all file contents. This file can be used directly as an AppCache manifest (for now, `index.html` must be manually edited to set this up). 163 | 164 | The manifest is also annotated for use with `angular-service-worker`. Some manual operations are currently required to enable this usage. The package must be installed, and `worker.js` manually copied into the project src directory: 165 | 166 | ```bash 167 | cp node_modules/angular-service-worker/dist/worker.js src/client 168 | ``` 169 | 170 | In order to generate the manifest file run: 171 | 172 | ```bash 173 | # ENV can be both prod or dev 174 | npm run generate.manifest -- --env ENV 175 | ``` 176 | 177 | Then, the commented snippet in `main.ts` must be uncommented to register the worker script as a service worker. --> 178 | 179 | # Contributing 180 | 181 | Please see the [CONTRIBUTING](https://github.com/mgechev/angular-seed/blob/master/.github/CONTRIBUTING.md) file for guidelines. 182 | 183 | # Advanced Seed Option 184 | 185 | An [advanced option to this seed exists here](https://github.com/NathanWalker/angular2-seed-advanced) which mirrors the latest changes here but adds core support for: 186 | 187 | - [ngrx/store](https://github.com/ngrx/store) RxJS powered state management, inspired by **Redux** 188 | - [ng2-translate](https://github.com/ocombe/ng2-translate) for i18n 189 | - Usage is optional but on by default 190 | - Up to you and your team how you want to utilize it. It can be easily removed if not needed. 191 | - [angulartics2](https://github.com/angulartics/angulartics2) Vendor-agnostic analytics for Angular applications. 192 | - Out of box support for [Segment](https://segment.com/) 193 | - When using the seed, be sure to change your `write_key` [here](https://github.com/NathanWalker/angular2-seed-advanced/blob/master/src/client/index.html#L24) 194 | - Can be changed to any vendor, [learn more here](https://github.com/angulartics/angulartics2#supported-providers) 195 | - [lodash](https://lodash.com/) Helps reduce blocks of code down to single lines and enhances readability 196 | - [NativeScript](https://www.nativescript.org/) cross platform mobile (w/ native UI) apps. [Setup instructions here](#nativescript-app). 197 | - [Electron](http://electron.atom.io/) cross platform desktop apps (Mac, Windows and Linux). [Setup instructions here](#electron-app). 198 | 199 | You may use it to learn how to extend this seed for your own use cases or use the advanced seed if your project needs those features. 200 | 201 | # Examples 202 | 203 | Forks of this project demonstrate how to extend and integrate with other libraries: 204 | 205 | - https://github.com/mgechev/switching-to-angular2 - code samples for the book ["Switching to Angular 2"](https://www.packtpub.com/web-development/switching-angular-2). 206 | - https://github.com/DeviantJS/angular2-seed-postcss - Extending PostCSS with precss / cssnext for Sass-like features. 207 | - https://github.com/DeviantJS/angular2-seed-material2 - integration with [Angular2-Material](https://github.com/angular/material2). 208 | - https://github.com/AngularShowcase/angular2-sample-app - sample Angular application. 209 | - https://github.com/AngularShowcase/ng2-bootstrap-sbadmin - ng2-bootstrap-sbadmin. 210 | - https://github.com/AngularShowcase/angular2-seed-ng2-highcharts - Simple application including a [Highcharts](http://www.highcharts.com) graph. 211 | - https://github.com/tarlepp/angular-sailsjs-boilerplate-frontend-angular2 - Example application for [Sails.js](http://sailsjs.org/) integration. 212 | - https://github.com/ludohenin/ng2-wp-blog - Angular application using Wordpress [JSON-API](http://v2.wp-api.org) backend.. 213 | - https://github.com/AngularShowcase/angular2-seed-example-mashup - Angular application demonstrating the use of [Redux](http://redux.js.org/), [D3](https://github.com/mbostock/d3), [socket io](https://github.com/socketio), [Google Charts](https://developers.google.com/chart/), and [RxJs](https://github.com/Reactive-Extensions/RxJS). 214 | - https://github.com/tiagomapmarques/angular2-seed-phaser/tree/releases - integration with [Phaser](http://phaser.io/). 215 | - https://github.com/vyakymenko/angular2-seed-express - integration with [Express](https://expressjs.com/) full-stack development. 216 | - https://github.com/UIUXEngineering/angular2-jspm-typescript-seed - integration with [JSPM](http://jspm.io/). 217 | 218 | # Directory Structure 219 | 220 | ``` 221 | . 222 | ├── LICENSE 223 | ├── README.md 224 | ├── gulpfile.ts <- configuration of the gulp tasks 225 | ├── karma.conf.js <- configuration of the test runner 226 | ├── package.json <- dependencies of the project 227 | ├── protractor.conf.js <- e2e tests configuration 228 | ├── src <- source code of the application 229 | │   └── client 230 | │   ├── app 231 | │   │   ├── +about 232 | │   │   │   ├── about.component.css 233 | │   │   │   ├── about.component.e2e-spec.ts 234 | │   │   │   ├── about.component.html 235 | │   │   │   ├── about.component.spec.ts 236 | │   │   │   ├── about.component.ts 237 | │   │   │   ├── about.module.ts 238 | │   │   │   ├── about.routes.ts 239 | │   │   │   └── index.ts 240 | │   │   ├── +home 241 | │   │   │   ├── home.component.css 242 | │   │   │   ├── home.component.e2e-spec.ts 243 | │   │   │   ├── home.component.html 244 | │   │   │   ├── home.component.spec.ts 245 | │   │   │   ├── home.component.ts 246 | │   │   │   ├── home.module.ts 247 | │   │   │   ├── home.routes.ts 248 | │   │   │   └── index.ts 249 | │   │   ├── app.component.e2e-spec.ts 250 | │   │   ├── app.component.html 251 | │   │   ├── app.component.spec.ts 252 | │   │   ├── app.component.ts 253 | │   │   ├── app.module.ts 254 | │   │   ├── app.routes.ts 255 | │   │   ├── hot_loader_main.ts 256 | │   │   ├── main.ts 257 | │   │   └── shared 258 | │   │   ├── config 259 | │   │   │   └── env.config.ts 260 | │   │   ├── index.ts 261 | │   │   ├── shared.module.ts 262 | │   │   ├── name-list 263 | │   │   │   ├── index.ts 264 | │   │   │   ├── name-list.service.spec.ts 265 | │   │   │   └── name-list.service.ts 266 | │   │   ├── navbar 267 | │   │   │   ├── index.ts 268 | │   │   │   ├── navbar.component.css 269 | │   │   │   ├── navbar.component.html 270 | │   │   │   └── navbar.component.ts 271 | │   │   └── toolbar 272 | │   │   ├── index.ts 273 | │   │   ├── toolbar.component.css 274 | │   │   ├── toolbar.component.html 275 | │   │   └── toolbar.component.ts 276 | │   ├── assets 277 | │   │   ├── data.json 278 | │   │   └── svg 279 | │   │   └── more.svg 280 | │   ├── css 281 | │   │   └── main.css 282 | │   ├── index.html 283 | │   ├── testing 284 | │   │   └── router 285 | │   │   ├── mock-location-strategy.ts 286 | │   │   └── router-testing-providers.ts 287 | │   └── tsconfig.json 288 | ├── test-main.js <- testing configuration 289 | ├── tools 290 | │   ├── README.md <- build documentation 291 | │   ├── config 292 | │   │   ├── project.config.ts <- configuration of the specific project 293 | │   │   ├── seed.config.interfaces.ts 294 | │   │   └── seed.config.ts <- generic configuration of the seed project 295 | │   │   └── seed.tslint.json <- generic tslint configuration of the seed project 296 | │   ├── config.ts <- exported configuration (merge both seed.config and project.config, project.config overrides seed.config) 297 | │   ├── debug.ts 298 | │   ├── env <- environment configuration 299 | │   │   ├── base.ts 300 | │   │   ├── dev.ts 301 | │   │   └── prod.ts 302 | │   ├── manual_typings 303 | │   │   ├── project <- manual ambient typings for the project 304 | │   │   │   └── sample.package.d.ts 305 | │   │   └── seed <- seed manual ambient typings 306 | │   │   ├── autoprefixer.d.ts 307 | │   │   ├── colorguard.d.ts 308 | │   │   ├── connect-livereload.d.ts 309 | │   │   ├── cssnano.d.ts 310 | │   │   ├── doiuse.d.ts 311 | │   │   ├── express-history-api-fallback.d.ts 312 | │   │   ├── istream.d.ts 313 | │   │   ├── karma.d.ts 314 | │   │   ├── merge-stream.d.ts 315 | │   │   ├── open.d.ts 316 | │   │   ├── postcss-reporter.d.ts 317 | │   │   ├── slash.d.ts 318 | │   │   ├── stylelint.d.ts 319 | │   │   ├── systemjs-builder.d.ts 320 | │   │   ├── tildify.d.ts 321 | │   │   ├── tiny-lr.d.ts 322 | │   │   └── walk.d.ts 323 | │   ├── tasks <- gulp tasks 324 | │   │   ├── project <- project specific gulp tasks 325 | │   │   │   └── sample.task.ts 326 | │   │   └── seed <- seed generic gulp tasks. They can be overriden by the project specific gulp tasks 327 | │   │   ├── build.assets.dev.ts 328 | │   │   ├── build.assets.prod.ts 329 | │   │   ├── build.bundles.app.ts 330 | │   │   ├── build.bundles.ts 331 | │   │   ├── build.docs.ts 332 | │   │   ├── build.html_css.ts 333 | │   │   ├── build.index.dev.ts 334 | │   │   ├── build.index.prod.ts 335 | │   │   ├── build.js.dev.ts 336 | │   │   ├── build.js.e2e.ts 337 | │   │   ├── build.js.prod.ts 338 | │   │   ├── build.js.test.ts 339 | │   │   ├── build.js.tools.ts 340 | │   │   ├── check.versions.ts 341 | │   │   ├── clean.all.ts 342 | │   │   ├── clean.coverage.ts 343 | │   │   ├── clean.dev.ts 344 | │   │   ├── clean.prod.ts 345 | │   │   ├── clean.tools.ts 346 | │   │   ├── copy.js.prod.ts 347 | │   │   ├── css-lint.ts 348 | │   │   ├── e2e.ts 349 | │   │   ├── generate.manifest.ts 350 | │   │   ├── karma.start.ts 351 | │   │   ├── serve.coverage.ts 352 | │   │   ├── serve.docs.ts 353 | │   │   ├── server.prod.ts 354 | │   │   ├── server.start.ts 355 | │   │   ├── tslint.ts 356 | │   │   ├── watch.dev.ts 357 | │   │   ├── watch.e2e.ts 358 | │   │   ├── watch.test.ts 359 | │   │   └── webdriver.ts 360 | │   ├── utils <- build utils 361 | │   │   ├── project <- project specific gulp utils 362 | │   │   │   └── sample_util.ts 363 | │   │   ├── project.utils.ts 364 | │   │   ├── seed <- seed specific gulp utils 365 | │   │   │   ├── clean.ts 366 | │   │   │   ├── code_change_tools.ts 367 | │   │   │   ├── server.ts 368 | │   │   │   ├── tasks_tools.ts 369 | │   │   │   ├── template_locals.ts 370 | │   │   │   ├── tsproject.ts 371 | │   │   │   └── watch.ts 372 | │   │   └── seed.utils.ts 373 | │   └── utils.ts 374 | ├── tsconfig.json <- configuration of the typescript project (ts-node, which runs the tasks defined in gulpfile.ts) 375 | ├── tslint.json <- tslint configuration 376 | ├── typings <- typings directory. Contains all the external typing definitions defined with typings 377 | ├── typings.json 378 | └── appveyor.yml 379 | ``` 380 | 381 | # Contributors 382 | 383 | [<img alt="mgechev" src="https://avatars.githubusercontent.com/u/455023?v=3&s=117" width="117">](https://github.com/mgechev) |[<img alt="ludohenin" src="https://avatars.githubusercontent.com/u/1011516?v=3&s=117" width="117">](https://github.com/ludohenin) |[<img alt="d3viant0ne" src="https://avatars.githubusercontent.com/u/8420490?v=3&s=117" width="117">](https://github.com/d3viant0ne) |[<img alt="Shyam-Chen" src="https://avatars.githubusercontent.com/u/13535256?v=3&s=117" width="117">](https://github.com/Shyam-Chen) |[<img alt="tarlepp" src="https://avatars.githubusercontent.com/u/595561?v=3&s=117" width="117">](https://github.com/tarlepp) |[<img alt="NathanWalker" src="https://avatars.githubusercontent.com/u/457187?v=3&s=117" width="117">](https://github.com/NathanWalker) | 384 | :---: |:---: |:---: |:---: |:---: |:---: | 385 | [mgechev](https://github.com/mgechev) |[ludohenin](https://github.com/ludohenin) |[d3viant0ne](https://github.com/d3viant0ne) |[Shyam-Chen](https://github.com/Shyam-Chen) |[tarlepp](https://github.com/tarlepp) |[NathanWalker](https://github.com/NathanWalker) | 386 | 387 | [<img alt="Nightapes" src="https://avatars.githubusercontent.com/u/15911153?v=3&s=117" width="117">](https://github.com/Nightapes) |[<img alt="TheDonDope" src="https://avatars.githubusercontent.com/u/1188033?v=3&s=117" width="117">](https://github.com/TheDonDope) |[<img alt="nareshbhatia" src="https://avatars.githubusercontent.com/u/1220198?v=3&s=117" width="117">](https://github.com/nareshbhatia) |[<img alt="hank-ehly" src="https://avatars.githubusercontent.com/u/11639738?v=3&s=117" width="117">](https://github.com/hank-ehly) |[<img alt="kiuka" src="https://avatars.githubusercontent.com/u/11283191?v=3&s=117" width="117">](https://github.com/kiuka) |[<img alt="daniru" src="https://avatars.githubusercontent.com/u/2070853?v=3&s=117" width="117">](https://github.com/daniru) | 388 | :---: |:---: |:---: |:---: |:---: |:---: | 389 | [Nightapes](https://github.com/Nightapes) |[TheDonDope](https://github.com/TheDonDope) |[nareshbhatia](https://github.com/nareshbhatia) |[hank-ehly](https://github.com/hank-ehly) |[kiuka](https://github.com/kiuka) |[daniru](https://github.com/daniru) | 390 | 391 | [<img alt="vyakymenko" src="https://avatars.githubusercontent.com/u/7300673?v=3&s=117" width="117">](https://github.com/vyakymenko) |[<img alt="jesperronn" src="https://avatars.githubusercontent.com/u/6267?v=3&s=117" width="117">](https://github.com/jesperronn) |[<img alt="njs50" src="https://avatars.githubusercontent.com/u/55112?v=3&s=117" width="117">](https://github.com/njs50) |[<img alt="aboeglin" src="https://avatars.githubusercontent.com/u/8297302?v=3&s=117" width="117">](https://github.com/aboeglin) |[<img alt="robstoll" src="https://avatars.githubusercontent.com/u/5557885?v=3&s=117" width="117">](https://github.com/robstoll) |[<img alt="sasikumardr" src="https://avatars.githubusercontent.com/u/1760104?v=3&s=117" width="117">](https://github.com/sasikumardr) | 392 | :---: |:---: |:---: |:---: |:---: |:---: | 393 | [vyakymenko](https://github.com/vyakymenko) |[jesperronn](https://github.com/jesperronn) |[njs50](https://github.com/njs50) |[aboeglin](https://github.com/aboeglin) |[robstoll](https://github.com/robstoll) |[sasikumardr](https://github.com/sasikumardr) | 394 | 395 | [<img alt="gkalpak" src="https://avatars.githubusercontent.com/u/8604205?v=3&s=117" width="117">](https://github.com/gkalpak) |[<img alt="ryzy" src="https://avatars.githubusercontent.com/u/994940?v=3&s=117" width="117">](https://github.com/ryzy) |[<img alt="markwhitfeld" src="https://avatars.githubusercontent.com/u/1948265?v=3&s=117" width="117">](https://github.com/markwhitfeld) |[<img alt="sfabriece" src="https://avatars.githubusercontent.com/u/3108592?v=3&s=117" width="117">](https://github.com/sfabriece) |[<img alt="jerryorta-dev" src="https://avatars.githubusercontent.com/u/341155?v=3&s=117" width="117">](https://github.com/jerryorta-dev) |[<img alt="pgrzeszczak" src="https://avatars.githubusercontent.com/u/3300099?v=3&s=117" width="117">](https://github.com/pgrzeszczak) | 396 | :---: |:---: |:---: |:---: |:---: |:---: | 397 | [gkalpak](https://github.com/gkalpak) |[ryzy](https://github.com/ryzy) |[markwhitfeld](https://github.com/markwhitfeld) |[sfabriece](https://github.com/sfabriece) |[jerryorta-dev](https://github.com/jerryorta-dev) |[pgrzeszczak](https://github.com/pgrzeszczak) | 398 | 399 | [<img alt="eppsilon" src="https://avatars.githubusercontent.com/u/5643?v=3&s=117" width="117">](https://github.com/eppsilon) |[<img alt="e-oz" src="https://avatars.githubusercontent.com/u/526352?v=3&s=117" width="117">](https://github.com/e-oz) |[<img alt="natarajanmca11" src="https://avatars.githubusercontent.com/u/9244766?v=3&s=117" width="117">](https://github.com/natarajanmca11) |[<img alt="domfarolino" src="https://avatars.githubusercontent.com/u/9669289?v=3&s=117" width="117">](https://github.com/domfarolino) |[<img alt="JayKan" src="https://avatars.githubusercontent.com/u/1400300?v=3&s=117" width="117">](https://github.com/JayKan) |[<img alt="larsthorup" src="https://avatars.githubusercontent.com/u/1202959?v=3&s=117" width="117">](https://github.com/larsthorup) | 400 | :---: |:---: |:---: |:---: |:---: |:---: | 401 | [eppsilon](https://github.com/eppsilon) |[e-oz](https://github.com/e-oz) |[natarajanmca11](https://github.com/natarajanmca11) |[domfarolino](https://github.com/domfarolino) |[JayKan](https://github.com/JayKan) |[larsthorup](https://github.com/larsthorup) | 402 | 403 | [<img alt="JakePartusch" src="https://avatars.githubusercontent.com/u/6424140?v=3&s=117" width="117">](https://github.com/JakePartusch) |[<img alt="LuxDie" src="https://avatars.githubusercontent.com/u/12536671?v=3&s=117" width="117">](https://github.com/LuxDie) |[<img alt="amedinavalencia" src="https://avatars.githubusercontent.com/u/21317797?v=3&s=117" width="117">](https://github.com/amedinavalencia) |[<img alt="tsm91" src="https://avatars.githubusercontent.com/u/4459551?v=3&s=117" width="117">](https://github.com/tsm91) |[<img alt="jvitor83" src="https://avatars.githubusercontent.com/u/3493339?v=3&s=117" width="117">](https://github.com/jvitor83) |[<img alt="juristr" src="https://avatars.githubusercontent.com/u/542458?v=3&s=117" width="117">](https://github.com/juristr) | 404 | :---: |:---: |:---: |:---: |:---: |:---: | 405 | [JakePartusch](https://github.com/JakePartusch) |[LuxDie](https://github.com/LuxDie) |[amedinavalencia](https://github.com/amedinavalencia) |[tsm91](https://github.com/tsm91) |[jvitor83](https://github.com/jvitor83) |[juristr](https://github.com/juristr) | 406 | 407 | [<img alt="JohnCashmore" src="https://avatars.githubusercontent.com/u/2050794?v=3&s=117" width="117">](https://github.com/JohnCashmore) |[<img alt="ouq77" src="https://avatars.githubusercontent.com/u/1796191?v=3&s=117" width="117">](https://github.com/ouq77) |[<img alt="devanp92" src="https://avatars.githubusercontent.com/u/4533277?v=3&s=117" width="117">](https://github.com/devanp92) |[<img alt="hAWKdv" src="https://avatars.githubusercontent.com/u/4449497?v=3&s=117" width="117">](https://github.com/hAWKdv) |[<img alt="JunaidZA" src="https://avatars.githubusercontent.com/u/16782593?v=3&s=117" width="117">](https://github.com/JunaidZA) |[<img alt="c-ice" src="https://avatars.githubusercontent.com/u/347238?v=3&s=117" width="117">](https://github.com/c-ice) | 408 | :---: |:---: |:---: |:---: |:---: |:---: | 409 | [JohnCashmore](https://github.com/JohnCashmore) |[ouq77](https://github.com/ouq77) |[devanp92](https://github.com/devanp92) |[hAWKdv](https://github.com/hAWKdv) |[JunaidZA](https://github.com/JunaidZA) |[c-ice](https://github.com/c-ice) | 410 | 411 | [<img alt="markharding" src="https://avatars.githubusercontent.com/u/851436?v=3&s=117" width="117">](https://github.com/markharding) |[<img alt="ojacquemart" src="https://avatars.githubusercontent.com/u/1189345?v=3&s=117" width="117">](https://github.com/ojacquemart) |[<img alt="tiagomapmarques" src="https://avatars.githubusercontent.com/u/704002?v=3&s=117" width="117">](https://github.com/tiagomapmarques) |[<img alt="TuiKiken" src="https://avatars.githubusercontent.com/u/959821?v=3&s=117" width="117">](https://github.com/TuiKiken) |[<img alt="evanplaice" src="https://avatars.githubusercontent.com/u/303159?v=3&s=117" width="117">](https://github.com/evanplaice) |[<img alt="gotenxds" src="https://avatars.githubusercontent.com/u/3519520?v=3&s=117" width="117">](https://github.com/gotenxds) | 412 | :---: |:---: |:---: |:---: |:---: |:---: | 413 | [markharding](https://github.com/markharding) |[ojacquemart](https://github.com/ojacquemart) |[tiagomapmarques](https://github.com/tiagomapmarques) |[TuiKiken](https://github.com/TuiKiken) |[evanplaice](https://github.com/evanplaice) |[gotenxds](https://github.com/gotenxds) | 414 | 415 | [<img alt="turbohappy" src="https://avatars.githubusercontent.com/u/437299?v=3&s=117" width="117">](https://github.com/turbohappy) |[<img alt="karlhaas" src="https://avatars.githubusercontent.com/u/7677394?v=3&s=117" width="117">](https://github.com/karlhaas) |[<img alt="troyanskiy" src="https://avatars.githubusercontent.com/u/1538862?v=3&s=117" width="117">](https://github.com/troyanskiy) |[<img alt="Bigous" src="https://avatars.githubusercontent.com/u/6886560?v=3&s=117" width="117">](https://github.com/Bigous) |[<img alt="ip512" src="https://avatars.githubusercontent.com/u/1699735?v=3&s=117" width="117">](https://github.com/ip512) |[<img alt="Green-Cat" src="https://avatars.githubusercontent.com/u/3328823?v=3&s=117" width="117">](https://github.com/Green-Cat) | 416 | :---: |:---: |:---: |:---: |:---: |:---: | 417 | [turbohappy](https://github.com/turbohappy) |[karlhaas](https://github.com/karlhaas) |[troyanskiy](https://github.com/troyanskiy) |[Bigous](https://github.com/Bigous) |[ip512](https://github.com/ip512) |[Green-Cat](https://github.com/Green-Cat) | 418 | 419 | [<img alt="Yonet" src="https://avatars.githubusercontent.com/u/3523671?v=3&s=117" width="117">](https://github.com/Yonet) |[<img alt="edud69" src="https://avatars.githubusercontent.com/u/1514745?v=3&s=117" width="117">](https://github.com/edud69) |[<img alt="inkidotcom" src="https://avatars.githubusercontent.com/u/100466?v=3&s=117" width="117">](https://github.com/inkidotcom) |[<img alt="yassirh" src="https://avatars.githubusercontent.com/u/4649139?v=3&s=117" width="117">](https://github.com/yassirh) |[<img alt="taguan" src="https://avatars.githubusercontent.com/u/1026937?v=3&s=117" width="117">](https://github.com/taguan) |[<img alt="bbarry" src="https://avatars.githubusercontent.com/u/84951?v=3&s=117" width="117">](https://github.com/bbarry) | 420 | :---: |:---: |:---: |:---: |:---: |:---: | 421 | [Yonet](https://github.com/Yonet) |[edud69](https://github.com/edud69) |[inkidotcom](https://github.com/inkidotcom) |[yassirh](https://github.com/yassirh) |[taguan](https://github.com/taguan) |[bbarry](https://github.com/bbarry) | 422 | 423 | [<img alt="sonicparke" src="https://avatars.githubusercontent.com/u/1139721?v=3&s=117" width="117">](https://github.com/sonicparke) |[<img alt="brendanbenson" src="https://avatars.githubusercontent.com/u/866866?v=3&s=117" width="117">](https://github.com/brendanbenson) |[<img alt="brian428" src="https://avatars.githubusercontent.com/u/140338?v=3&s=117" width="117">](https://github.com/brian428) |[<img alt="briantopping" src="https://avatars.githubusercontent.com/u/158115?v=3&s=117" width="117">](https://github.com/briantopping) |[<img alt="ckapilla" src="https://avatars.githubusercontent.com/u/451875?v=3&s=117" width="117">](https://github.com/ckapilla) |[<img alt="cadriel" src="https://avatars.githubusercontent.com/u/205520?v=3&s=117" width="117">](https://github.com/cadriel) | 424 | :---: |:---: |:---: |:---: |:---: |:---: | 425 | [sonicparke](https://github.com/sonicparke) |[brendanbenson](https://github.com/brendanbenson) |[brian428](https://github.com/brian428) |[briantopping](https://github.com/briantopping) |[ckapilla](https://github.com/ckapilla) |[cadriel](https://github.com/cadriel) | 426 | 427 | [<img alt="dszymczuk" src="https://avatars.githubusercontent.com/u/539352?v=3&s=117" width="117">](https://github.com/dszymczuk) |[<img alt="dmurat" src="https://avatars.githubusercontent.com/u/470930?v=3&s=117" width="117">](https://github.com/dmurat) |[<img alt="peah90" src="https://avatars.githubusercontent.com/u/4435255?v=3&s=117" width="117">](https://github.com/peah90) |[<img alt="dstockhammer" src="https://avatars.githubusercontent.com/u/1156637?v=3&s=117" width="117">](https://github.com/dstockhammer) |[<img alt="dwido" src="https://avatars.githubusercontent.com/u/154235?v=3&s=117" width="117">](https://github.com/dwido) |[<img alt="totev" src="https://avatars.githubusercontent.com/u/4454638?v=3&s=117" width="117">](https://github.com/totev) | 428 | :---: |:---: |:---: |:---: |:---: |:---: | 429 | [dszymczuk](https://github.com/dszymczuk) |[dmurat](https://github.com/dmurat) |[peah90](https://github.com/peah90) |[dstockhammer](https://github.com/dstockhammer) |[dwido](https://github.com/dwido) |[totev](https://github.com/totev) | 430 | 431 | [<img alt="nosachamos" src="https://avatars.githubusercontent.com/u/1261686?v=3&s=117" width="117">](https://github.com/nosachamos) |[<img alt="koodikindral" src="https://avatars.githubusercontent.com/u/6285484?v=3&s=117" width="117">](https://github.com/koodikindral) |[<img alt="Falinor" src="https://avatars.githubusercontent.com/u/9626158?v=3&s=117" width="117">](https://github.com/Falinor) |[<img alt="allenhwkim" src="https://avatars.githubusercontent.com/u/1437734?v=3&s=117" width="117">](https://github.com/allenhwkim) |[<img alt="hpinsley" src="https://avatars.githubusercontent.com/u/750098?v=3&s=117" width="117">](https://github.com/hpinsley) |[<img alt="NN77" src="https://avatars.githubusercontent.com/u/3319904?v=3&s=117" width="117">](https://github.com/NN77) | 432 | :---: |:---: |:---: |:---: |:---: |:---: | 433 | [nosachamos](https://github.com/nosachamos) |[koodikindral](https://github.com/koodikindral) |[Falinor](https://github.com/Falinor) |[allenhwkim](https://github.com/allenhwkim) |[hpinsley](https://github.com/hpinsley) |[NN77](https://github.com/NN77) | 434 | 435 | [<img alt="isidroamv" src="https://avatars.githubusercontent.com/u/4197621?v=3&s=117" width="117">](https://github.com/isidroamv) |[<img alt="jeffbcross" src="https://avatars.githubusercontent.com/u/463703?v=3&s=117" width="117">](https://github.com/jeffbcross) |[<img alt="Drane" src="https://avatars.githubusercontent.com/u/389499?v=3&s=117" width="117">](https://github.com/Drane) |[<img alt="johnjelinek" src="https://avatars.githubusercontent.com/u/873610?v=3&s=117" width="117">](https://github.com/johnjelinek) |[<img alt="JunusErgin" src="https://avatars.githubusercontent.com/u/7281463?v=3&s=117" width="117">](https://github.com/JunusErgin) |[<img alt="justindujardin" src="https://avatars.githubusercontent.com/u/101493?v=3&s=117" width="117">](https://github.com/justindujardin) | 436 | :---: |:---: |:---: |:---: |:---: |:---: | 437 | [isidroamv](https://github.com/isidroamv) |[jeffbcross](https://github.com/jeffbcross) |[Drane](https://github.com/Drane) |[johnjelinek](https://github.com/johnjelinek) |[JunusErgin](https://github.com/JunusErgin) |[justindujardin](https://github.com/justindujardin) | 438 | 439 | [<img alt="lihaibh" src="https://avatars.githubusercontent.com/u/4681233?v=3&s=117" width="117">](https://github.com/lihaibh) |[<img alt="Brooooooklyn" src="https://avatars.githubusercontent.com/u/3468483?v=3&s=117" width="117">](https://github.com/Brooooooklyn) |[<img alt="tandu" src="https://avatars.githubusercontent.com/u/273313?v=3&s=117" width="117">](https://github.com/tandu) |[<img alt="nulldev07" src="https://avatars.githubusercontent.com/u/2115712?v=3&s=117" width="117">](https://github.com/nulldev07) |[<img alt="daixtrose" src="https://avatars.githubusercontent.com/u/5588692?v=3&s=117" width="117">](https://github.com/daixtrose) |[<img alt="mjwwit" src="https://avatars.githubusercontent.com/u/4455124?v=3&s=117" width="117">](https://github.com/mjwwit) | 440 | :---: |:---: |:---: |:---: |:---: |:---: | 441 | [lihaibh](https://github.com/lihaibh) |[Brooooooklyn](https://github.com/Brooooooklyn) |[tandu](https://github.com/tandu) |[nulldev07](https://github.com/nulldev07) |[daixtrose](https://github.com/daixtrose) |[mjwwit](https://github.com/mjwwit) | 442 | 443 | [<img alt="ocombe" src="https://avatars.githubusercontent.com/u/265378?v=3&s=117" width="117">](https://github.com/ocombe) |[<img alt="gdi2290" src="https://avatars.githubusercontent.com/u/1016365?v=3&s=117" width="117">](https://github.com/gdi2290) |[<img alt="typekpb" src="https://avatars.githubusercontent.com/u/499820?v=3&s=117" width="117">](https://github.com/typekpb) |[<img alt="philipooo" src="https://avatars.githubusercontent.com/u/1702399?v=3&s=117" width="117">](https://github.com/philipooo) |[<img alt="redian" src="https://avatars.githubusercontent.com/u/816941?v=3&s=117" width="117">](https://github.com/redian) |[<img alt="alexweber" src="https://avatars.githubusercontent.com/u/14409?v=3&s=117" width="117">](https://github.com/alexweber) | 444 | :---: |:---: |:---: |:---: |:---: |:---: | 445 | [ocombe](https://github.com/ocombe) |[gdi2290](https://github.com/gdi2290) |[typekpb](https://github.com/typekpb) |[philipooo](https://github.com/philipooo) |[redian](https://github.com/redian) |[alexweber](https://github.com/alexweber) | 446 | 447 | [<img alt="robbatt" src="https://avatars.githubusercontent.com/u/1379424?v=3&s=117" width="117">](https://github.com/robbatt) |[<img alt="robertpenner" src="https://avatars.githubusercontent.com/u/79827?v=3&s=117" width="117">](https://github.com/robertpenner) |[<img alt="Sjiep" src="https://avatars.githubusercontent.com/u/5003111?v=3&s=117" width="117">](https://github.com/Sjiep) |[<img alt="sclausen" src="https://avatars.githubusercontent.com/u/916076?v=3&s=117" width="117">](https://github.com/sclausen) |[<img alt="heavymery" src="https://avatars.githubusercontent.com/u/3417123?v=3&s=117" width="117">](https://github.com/heavymery) |[<img alt="tapas4java" src="https://avatars.githubusercontent.com/u/2254963?v=3&s=117" width="117">](https://github.com/tapas4java) | 448 | :---: |:---: |:---: |:---: |:---: |:---: | 449 | [robbatt](https://github.com/robbatt) |[robertpenner](https://github.com/robertpenner) |[Sjiep](https://github.com/Sjiep) |[sclausen](https://github.com/sclausen) |[heavymery](https://github.com/heavymery) |[tapas4java](https://github.com/tapas4java) | 450 | 451 | [<img alt="vincentpalita" src="https://avatars.githubusercontent.com/u/2738822?v=3&s=117" width="117">](https://github.com/vincentpalita) |[<img alt="Yalrafih" src="https://avatars.githubusercontent.com/u/7460011?v=3&s=117" width="117">](https://github.com/Yalrafih) |[<img alt="billsworld" src="https://avatars.githubusercontent.com/u/16911647?v=3&s=117" width="117">](https://github.com/billsworld) |[<img alt="blackheart01" src="https://avatars.githubusercontent.com/u/1414277?v=3&s=117" width="117">](https://github.com/blackheart01) |[<img alt="butterfieldcons" src="https://avatars.githubusercontent.com/u/12204784?v=3&s=117" width="117">](https://github.com/butterfieldcons) |[<img alt="danielcrisp" src="https://avatars.githubusercontent.com/u/1104814?v=3&s=117" width="117">](https://github.com/danielcrisp) | 452 | :---: |:---: |:---: |:---: |:---: |:---: | 453 | [vincentpalita](https://github.com/vincentpalita) |[Yalrafih](https://github.com/Yalrafih) |[billsworld](https://github.com/billsworld) |[blackheart01](https://github.com/blackheart01) |[butterfieldcons](https://github.com/butterfieldcons) |[danielcrisp](https://github.com/danielcrisp) | 454 | 455 | [<img alt="jgolla" src="https://avatars.githubusercontent.com/u/1542447?v=3&s=117" width="117">](https://github.com/jgolla) |[<img alt="omerfarukyilmaz" src="https://avatars.githubusercontent.com/u/5538485?v=3&s=117" width="117">](https://github.com/omerfarukyilmaz) |[<img alt="pbazurin-softheme" src="https://avatars.githubusercontent.com/u/4518922?v=3&s=117" width="117">](https://github.com/pbazurin-softheme) |[<img alt="rossedfort" src="https://avatars.githubusercontent.com/u/11775628?v=3&s=117" width="117">](https://github.com/rossedfort) |[<img alt="savcha" src="https://avatars.githubusercontent.com/u/879542?v=3&s=117" width="117">](https://github.com/savcha) |[<img alt="ultrasonicsoft" src="https://avatars.githubusercontent.com/u/4145169?v=3&s=117" width="117">](https://github.com/ultrasonicsoft) | 456 | :---: |:---: |:---: |:---: |:---: |:---: | 457 | [jgolla](https://github.com/jgolla) |[omerfarukyilmaz](https://github.com/omerfarukyilmaz) |[pbazurin-softheme](https://github.com/pbazurin-softheme) |[rossedfort](https://github.com/rossedfort) |[savcha](https://github.com/savcha) |[ultrasonicsoft](https://github.com/ultrasonicsoft) | 458 | 459 | [<img alt="amaltsev" src="https://avatars.githubusercontent.com/u/2480962?v=3&s=117" width="117">](https://github.com/amaltsev) | 460 | :---: | 461 | [amaltsev](https://github.com/amaltsev) | 462 | 463 | ## Wiki Contributors 464 | 465 | Here are all the awesome guys who are helping to make the project's wiki even better! 466 | 467 | ``` 468 | 40 Minko Gechev 469 | 22 Clayton K. N. Passos 470 | 15 Shyam-Chen 471 | 14 Vincent van Proosdij 472 | 8 matthew harwood 473 | 8 Christian Dobert 474 | 8 Robert van Kints 475 | 6 Ludovic HENIN 476 | 5 Attila Egyed 477 | 4 davidgfolch 478 | 4 Chris Kapilla 479 | 3 Stefan Schüller 480 | 3 Patrick Hillert 481 | 3 Ezequiel Cicala 482 | 3 Brian Kotek 483 | 2 Nathan Walker 484 | 2 Dinsitro 485 | 2 Drake Wilson 486 | 2 Simon Hampton 487 | 2 Yannick Koehler 488 | 2 Giovanni Candido da Silva 489 | 2 hhubik 490 | 2 Joshua Wiens 491 | 2 Cy Klassen 492 | 1 zcsongor 493 | 1 Ameer Nuri 494 | 1 Ankit Kamboj 495 | 1 BouncingBit 496 | 1 Dang Tung 497 | 1 Eddie Sun 498 | 1 Enrico Secondulfo 499 | 1 Eugene Serkin 500 | 1 Ishara Samantha 501 | 1 Myrmex 502 | 1 Pol Stafford 503 | 1 Raphael Schmitt 504 | 1 Robert Stoll 505 | 1 Sebastian Fuss 506 | 1 Sebastien de Salvador 507 | 1 The Ult 508 | 1 Yonet 509 | 1 graham 510 | 1 kiuka 511 | 1 silicakes 512 | 1 Adam Johannesmeyer 513 | ``` 514 | 515 | # Change Log 516 | 517 | You can follow the [Angular change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md). 518 | 519 | # License 520 | 521 | MIT 522 | --------------------------------------------------------------------------------