├── src ├── index.ts ├── components │ ├── index.ts │ └── hello-world │ │ ├── HelloWorld.component.html │ │ ├── HelloWorld.component.scss │ │ ├── index.ts │ │ ├── HelloWorld.component.ts │ │ ├── README.md │ │ ├── HelloWorld.module.ts │ │ └── HelloWorld.spec.ts ├── polyfills.ts ├── vendor.ts └── tsconfig.aot.json ├── .editorconfig ├── typedoc.json ├── tsconfig.json ├── CHANGELOG.md ├── README.md ├── gulpfile.js ├── .gitignore ├── protractor.conf.js ├── LICENSE ├── karma-shim.js ├── karma.conf.js ├── package.json ├── tslint.json ├── scripts └── gulp │ └── inline-resources.js └── webpack.config.js /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hello-world'; -------------------------------------------------------------------------------- /src/components/hello-world/HelloWorld.component.html: -------------------------------------------------------------------------------- 1 |

Hello World

-------------------------------------------------------------------------------- /src/components/hello-world/HelloWorld.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | h1 { 3 | color: red; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/components/hello-world/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Export all module and components 3 | */ 4 | export {HelloWorldModule} from './HelloWorld.module'; 5 | export {HelloWorldComponent} from './HelloWorld.component'; 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/client/shim'; 2 | import 'reflect-metadata'; 3 | require('zone.js/dist/zone'); 4 | 5 | import 'ts-helpers'; 6 | 7 | if (process.env.ENV === 'build') { 8 | // Production 9 | 10 | } else { 11 | // Development 12 | 13 | Error['stackTraceLimit'] = Infinity; 14 | 15 | require('zone.js/dist/long-stack-trace-zone'); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/hello-world/HelloWorld.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * example of component 3 | * 4 | * @author Daniele Zurico 5 | */ 6 | import {Component} from '@angular/core'; 7 | @Component({ 8 | selector: 'hello-world', 9 | templateUrl: './HelloWorld.component.html', 10 | styleUrls: ['./HelloWorld.component.scss'] 11 | }) 12 | 13 | export class HelloWorldComponent { 14 | 15 | } -------------------------------------------------------------------------------- /src/vendor.ts: -------------------------------------------------------------------------------- 1 | // Angular 2 2 | import '@angular/platform-browser'; 3 | import '@angular/platform-browser-dynamic'; 4 | import '@angular/core'; 5 | import '@angular/common'; 6 | import '@angular/http'; 7 | import '@angular/router'; 8 | 9 | import 'rxjs'; 10 | import '@angularclass/hmr'; 11 | 12 | // Other vendors for example jQuery, Lodash or Bootstrap 13 | // You can import js, ts, css, sass, ... 14 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "modules", 3 | "out": "doc", 4 | "theme": "default", 5 | "ignoreCompilerErrors": "true", 6 | "experimentalDecorators": "true", 7 | "emitDecoratorMetadata": "true", 8 | "target": "ES5", 9 | "moduleResolution": "node", 10 | "preserveConstEnums": "true", 11 | "stripInternal": "true", 12 | "suppressExcessPropertyErrors": "true", 13 | "suppressImplicitAnyIndexErrors": "true", 14 | "module": "commonjs" 15 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "module": "commonjs", 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "sourceMap": true, 8 | "noEmitHelpers": true, 9 | "lib": [ 10 | "es6", 11 | "es2015", 12 | "dom" 13 | ] 14 | }, 15 | "compileOnSave": false, 16 | "buildOnSave": false, 17 | "awesomeTypescriptLoaderOptions": { 18 | "forkChecker": true, 19 | "useWebpackText": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/hello-world/README.md: -------------------------------------------------------------------------------- 1 | #Hello World 2 | 3 | It is an example how to write components in the correct way. It display the message **Hello world**. 4 | 5 | To include Hello World in your project you have to: 6 | 1) In your Module include HelloWorldModule: 7 | ```javascript 8 | @NgModule({ 9 | imports: [HelloWorldModule], 10 | declarations: [], 11 | exports: [] 12 | }) 13 | ``` 14 | 15 | 2) In your html add: 16 | ```html 17 | 18 | ``` -------------------------------------------------------------------------------- /src/components/hello-world/HelloWorld.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule, ModuleWithProviders} from '@angular/core'; 2 | import {HelloWorldComponent} from './HelloWorld.component'; 3 | /** 4 | * The Hello World component is an example how to write components in the correct way. 5 | * 6 | * @author Daniele Zurico 7 | */ 8 | @NgModule({ 9 | declarations: [HelloWorldComponent], 10 | exports: [HelloWorldComponent] 11 | }) 12 | 13 | export class HelloWorldModule { 14 | static forRoot(): ModuleWithProviders { 15 | return {ngModule: HelloWorldModule, providers: []}; 16 | } 17 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # 04 October 2016 4 | 5 | - Migrate to webpack 2 6 | 7 | # 18 September 2016 8 | 9 | - Using `awesome-typescript-loader` instead of `ts-loader`. 10 | 11 | # 5 September 2016 12 | 13 | - Migration to TS2 and @types 14 | 15 | ## 1 September 2016 16 | 17 | - Using RC6. 18 | 19 | ## 28 August 2016 20 | 21 | - Adding webpack-dashboard. 22 | 23 | ## 23 August 2016 24 | 25 | - Adding HMR support. 26 | 27 | ## 3 July 2016 28 | 29 | - Use html5mode instead of hash navigation. 30 | 31 | ## 24 June 2016 32 | 33 | - Be able to import Component's templates and styles without using require. 34 | -------------------------------------------------------------------------------- /src/tsconfig.aot.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "lib": [ 7 | "es6", 8 | "es2015", 9 | "dom" 10 | ], 11 | "noImplicitAny": false, 12 | "target": "es5", 13 | "module": "es2015", 14 | "moduleResolution": "node", 15 | "sourceMap": true, 16 | "mapRoot": "", 17 | "outDir": "./../dist", 18 | "skipLibCheck": true, 19 | "baseUrl": "" 20 | }, 21 | "exclude": [ 22 | "**/*.spec.ts", 23 | "./vendor.ts", 24 | "./polyfills.ts" 25 | ], 26 | "angularCompilerOptions": { 27 | "skipTemplateCodegen": true, 28 | "debug": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/hello-world/HelloWorld.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | async, 3 | TestBed 4 | } from '@angular/core/testing'; 5 | 6 | import {HelloWorldComponent} from './HelloWorldComponent'; 7 | 8 | describe('Testing Hello World Component', () => { 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | providers: [], 12 | declarations: [HelloWorldComponent] 13 | }); 14 | }); 15 | 16 | it('Should contain hello world text', async(() => { 17 | const fixture = TestBed.createComponent(HelloWorldComponent); 18 | fixture.detectChanges(); 19 | 20 | let compiled = fixture.debugElement.nativeElement; 21 | 22 | expect(compiled.querySelector('h1').textContent).toContain('Hello World'); 23 | })); 24 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #angular2-library 2 | 3 | this project show how to package a library using ngc. 4 | 5 | For more information please visit: http://www.dzurico.com/how-to-create-an-angular-library/ 6 | 7 | ###how to install 8 | npm install 9 | 10 | ###how to package the library 11 | npm run build 12 | 13 | ###how to use the package in your project 14 | npm install ../angular2-library (specify the correct path) 15 | 16 | in your module include: 17 | ``` 18 | import {HelloWorldModule} from 'angular2-sdk/dist'; 19 | 20 | @NgModule({ 21 | imports: [ 22 | ... 23 | HelloWorldModule 24 | ], 25 | declarations: [ 26 | ... 27 | ], 28 | providers: [ 29 | ... 30 | ], 31 | bootstrap: [...] 32 | }) 33 | ``` 34 | 35 | in your view (html) 36 | ``` 37 | 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var inlineResources = require('./scripts/gulp/inline-resources'); 3 | var sass = require('gulp-sass'); 4 | 5 | 6 | gulp.task('copy-and-inline-resource', copyHtml); 7 | 8 | function copyHtml() { 9 | gulp.src('src/components/**/*.html') 10 | .pipe(gulp.dest('./dist/components')).on('end', copyAssets); 11 | } 12 | 13 | function copyAssets () { 14 | gulp.src('./src/assets/**/*') 15 | .pipe(gulp.dest('./dist/assets')).on('end', copyScss); 16 | } 17 | function copyScss () { 18 | gulp.src('./src/components/**/*.scss') 19 | .pipe(gulp.dest('./dist/components')).on('end', inlineResource); 20 | } 21 | 22 | function inlineResource() { 23 | inlineResources('./dist/components'); 24 | } 25 | 26 | gulp.task('default', ['copy-and-inline-resource']); -------------------------------------------------------------------------------- /.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 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Users Environment Variables 23 | .lock-wscript 24 | 25 | # OS generated files # 26 | .DS_Store 27 | ehthumbs.db 28 | Icon? 29 | Thumbs.db 30 | 31 | # Node Files # 32 | /node_modules 33 | /bower_components 34 | 35 | # Coverage # 36 | /coverage/ 37 | 38 | # Typing # 39 | /src/typings/tsd/ 40 | /typings/ 41 | /tsd_typings/ 42 | 43 | # Dist # 44 | /dist 45 | /public/__build__/ 46 | /src/*/__build__/ 47 | __build__/** 48 | .webpack.json 49 | 50 | # Doc # 51 | /doc/ 52 | 53 | # IDE # 54 | .idea/ 55 | *.swp 56 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | baseUrl: 'http://localhost:8080/', 3 | 4 | specs: [ 5 | 'src/**/*.e2e-spec.js' 6 | ], 7 | exclude: [], 8 | 9 | framework: 'jasmine2', 10 | 11 | allScriptsTimeout: 110000, 12 | 13 | jasmineNodeOpts: { 14 | showTiming: true, 15 | showColors: true, 16 | isVerbose: false, 17 | includeStackTrace: false, 18 | defaultTimeoutInterval: 400000 19 | }, 20 | directConnect: true, 21 | 22 | capabilities: { 23 | 'browserName': 'chrome' 24 | }, 25 | 26 | onPrepare: function () { 27 | var SpecReporter = require('jasmine-spec-reporter'); 28 | // add jasmine spec reporter 29 | jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: true})); 30 | 31 | browser.ignoreSynchronization = true; 32 | }, 33 | 34 | 35 | /** 36 | * Angular 2 configuration 37 | * 38 | * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching 39 | * `rootEl` 40 | * 41 | */ 42 | useAllAngular2AppRoots: true 43 | }; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Preboot team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /karma-shim.js: -------------------------------------------------------------------------------- 1 | Error.stackTraceLimit = Infinity; 2 | 3 | require('core-js/client/shim'); 4 | require('reflect-metadata'); 5 | 6 | require('ts-helpers'); 7 | 8 | require('zone.js/dist/zone'); 9 | require('zone.js/dist/long-stack-trace-zone'); 10 | require('zone.js/dist/proxy'); 11 | require('zone.js/dist/sync-test'); 12 | require('zone.js/dist/jasmine-patch'); 13 | require('zone.js/dist/async-test'); 14 | require('zone.js/dist/fake-async-test'); 15 | 16 | /* 17 | Ok, this is kinda crazy. We can use the the context method on 18 | require that webpack created in order to tell webpack 19 | what files we actually want to require or import. 20 | Below, context will be a function/object with file names as keys. 21 | using that regex we are saying look in client/app and find 22 | any file that ends with '.spec.ts' and get its path. By passing in true 23 | we say do this recursively 24 | */ 25 | var appContext = require.context('./src', true, /\.spec\.ts/); 26 | 27 | // get all the files, for each file, call the context function 28 | // that will require the file and load it up here. Context will 29 | // loop and require those spec files here 30 | appContext.keys().forEach(appContext); 31 | 32 | // Select BrowserDomAdapter. 33 | // see https://github.com/AngularClass/angular2-webpack-starter/issues/124 34 | // Somewhere in the test setup 35 | var testing = require('@angular/core/testing'); 36 | var browser = require('@angular/platform-browser-dynamic/testing'); 37 | 38 | testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting()); 39 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var webpackConfig = require('./webpack.config'); 4 | 5 | var ENV = process.env.npm_lifecycle_event; 6 | var isTestWatch = ENV === 'test-watch'; 7 | 8 | module.exports = function (config) { 9 | var _config = { 10 | 11 | // base path that will be used to resolve all patterns (eg. files, exclude) 12 | basePath: '', 13 | 14 | // frameworks to use 15 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 16 | frameworks: ['jasmine'], 17 | 18 | // list of files / patterns to load in the browser 19 | files: [ 20 | { pattern: './karma-shim.js', watched: false } 21 | ], 22 | 23 | // list of files to exclude 24 | exclude: [], 25 | 26 | // preprocess matching files before serving them to the browser 27 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 28 | preprocessors: { 29 | './karma-shim.js': ['webpack', 'sourcemap'] 30 | }, 31 | 32 | webpack: webpackConfig, 33 | 34 | webpackMiddleware: { 35 | // webpack-dev-middleware configuration 36 | // i. e. 37 | stats: 'errors-only' 38 | }, 39 | 40 | webpackServer: { 41 | noInfo: true // please don't spam the console when running in karma! 42 | }, 43 | 44 | // test results reporter to use 45 | // possible values: 'dots', 'progress', 'mocha' 46 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 47 | reporters: ["mocha"], 48 | 49 | // web server port 50 | port: 9876, 51 | 52 | // enable / disable colors in the output (reporters and logs) 53 | colors: true, 54 | 55 | // level of logging 56 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 57 | logLevel: config.LOG_INFO, 58 | 59 | // enable / disable watching file and executing tests whenever any file changes 60 | autoWatch: false, 61 | 62 | // start these browsers 63 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 64 | browsers: isTestWatch ? ['Chrome'] : ['PhantomJS'], 65 | 66 | // Continuous Integration mode 67 | // if true, Karma captures browsers, runs the tests and exits 68 | singleRun: true 69 | }; 70 | 71 | if (!isTestWatch) { 72 | _config.reporters.push("coverage"); 73 | 74 | _config.coverageReporter = { 75 | dir: 'coverage/', 76 | reporters: [{ 77 | type: 'json', 78 | dir: 'coverage', 79 | subdir: 'json', 80 | file: 'coverage-final.json' 81 | }] 82 | }; 83 | } 84 | 85 | config.set(_config); 86 | 87 | }; 88 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-sdk", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "lint": "tslint --force \"src/**/*.ts\"", 7 | "pretest": "npm run lint", 8 | "test": "karma start", 9 | "posttest": "remap-istanbul -i coverage/json/coverage-final.json -o coverage/html -t html", 10 | "test-watch": "karma start --no-single-run --auto-watch", 11 | "build": "rimraf dist && ngc -p src/tsconfig.aot.json && gulp" 12 | }, 13 | "dependencies": { 14 | "@angular/common": "2.3.0", 15 | "@angular/compiler": "2.2.4", 16 | "@angular/compiler-cli": "2.3.0", 17 | "@angular/core": "2.3.0", 18 | "@angular/forms": "2.3.0", 19 | "@angular/http": "2.3.0", 20 | "@angular/platform-browser": "2.3.0", 21 | "@angular/platform-browser-dynamic": "2.3.0", 22 | "@angular/router": "3.2.4", 23 | "angular-router-loader": "^0.4.0", 24 | "core-js": "^2.4.1", 25 | "reflect-metadata": "^0.1.3", 26 | "rxjs": "5.0.0-rc.4", 27 | "zone.js": "^0.7.2" 28 | }, 29 | "devDependencies": { 30 | "@angular-cli/ast-tools": "^1.0.9", 31 | "@angularclass/hmr": "^1.0.1", 32 | "@angularclass/hmr-loader": "^3.0.2", 33 | "@ngtools/webpack": "^1.1.6", 34 | "@types/jasmine": "^2.2.29", 35 | "@types/node": "^6.0.38", 36 | "@types/selenium-webdriver": "2.53.33", 37 | "angular2-template-loader": "^0.6.0", 38 | "autoprefixer": "^6.3.2", 39 | "awesome-typescript-loader": "^2.2.4", 40 | "codelyzer": "1.0.0-beta.3", 41 | "copy-webpack-plugin": "^4.0.0", 42 | "css-loader": "^0.25.0", 43 | "extract-text-webpack-plugin": "^2.0.0-beta.4", 44 | "file-loader": "^0.9.0", 45 | "gulp": "^3.9.1", 46 | "gulp-sass": "^2.3.2", 47 | "html-loader": "^0.4.0", 48 | "html-webpack-plugin": "^2.8.1", 49 | "istanbul-instrumenter-loader": "^0.2.0", 50 | "jasmine-core": "^2.3.4", 51 | "jasmine-spec-reporter": "^2.4.0", 52 | "json-loader": "^0.5.3", 53 | "karma": "1.3.0", 54 | "karma-chrome-launcher": "^2.0.0", 55 | "karma-coverage": "^1.0.0", 56 | "karma-jasmine": "^1.0.2", 57 | "karma-mocha-reporter": "^2.0.3", 58 | "karma-phantomjs-launcher": "^1.0.0", 59 | "karma-remap-istanbul": "0.2.1", 60 | "karma-sourcemap-loader": "^0.3.7", 61 | "karma-webpack": "1.8.0", 62 | "node-sass": "^3.4.2", 63 | "null-loader": "0.1.1", 64 | "phantomjs-prebuilt": "^2.1.4", 65 | "postcss-loader": "^1.1.0", 66 | "protractor": "^4.0.10", 67 | "raw-loader": "0.5.1", 68 | "remap-istanbul": "^0.6.4", 69 | "rimraf": "^2.5.1", 70 | "sass-loader": "^4.0.0", 71 | "shelljs": "^0.7.0", 72 | "style-loader": "^0.13.0", 73 | "ts-helpers": "^1.1.1", 74 | "tslint": "^3.4.0", 75 | "tslint-loader": "^2.1.0", 76 | "typedoc": "^0.5.1", 77 | "typescript": "2.0.6", 78 | "url-loader": "^0.5.6", 79 | "webpack": "^2.1.0-beta.28", 80 | "webpack-dev-server": "2.1.0-beta.9" 81 | }, 82 | "files": [ 83 | "dist" 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "class-name": true, 7 | "comment-format": [ 8 | true, 9 | "check-space" 10 | ], 11 | "curly": true, 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [ 15 | true, 16 | "spaces" 17 | ], 18 | "label-position": true, 19 | "label-undefined": true, 20 | "max-line-length": [ 21 | true, 22 | 140 23 | ], 24 | "member-access": false, 25 | "member-ordering": [ 26 | true, 27 | "static-before-instance", 28 | "variables-before-functions" 29 | ], 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-console": [ 33 | true, 34 | "debug", 35 | "info", 36 | "time", 37 | "timeEnd", 38 | "trace" 39 | ], 40 | "no-construct": true, 41 | "no-debugger": true, 42 | "no-duplicate-key": true, 43 | "no-duplicate-variable": true, 44 | "no-empty": false, 45 | "no-eval": true, 46 | "no-inferrable-types": true, 47 | "no-shadowed-variable": true, 48 | "no-string-literal": false, 49 | "no-switch-case-fall-through": true, 50 | "no-trailing-whitespace": true, 51 | "no-unused-expression": true, 52 | "no-unused-variable": true, 53 | "no-unreachable": true, 54 | "no-use-before-declare": true, 55 | "no-var-keyword": true, 56 | "object-literal-sort-keys": false, 57 | "one-line": [ 58 | true, 59 | "check-open-brace", 60 | "check-catch", 61 | "check-else", 62 | "check-whitespace" 63 | ], 64 | "quotemark": [ 65 | true, 66 | "single" 67 | ], 68 | "radix": true, 69 | "semicolon": [ 70 | "always" 71 | ], 72 | "triple-equals": [ 73 | true, 74 | "allow-null-check" 75 | ], 76 | "typedef-whitespace": [ 77 | true, 78 | { 79 | "call-signature": "nospace", 80 | "index-signature": "nospace", 81 | "parameter": "nospace", 82 | "property-declaration": "nospace", 83 | "variable-declaration": "nospace" 84 | } 85 | ], 86 | "variable-name": false, 87 | "whitespace": [ 88 | true, 89 | "check-branch", 90 | "check-decl", 91 | "check-operator", 92 | "check-separator", 93 | "check-type" 94 | ], 95 | 96 | "directive-selector-name": [true, "camelCase"], 97 | "component-selector-name": [true, "kebab-case"], 98 | "directive-selector-type": [true, "attribute"], 99 | "component-selector-type": [true, "element"], 100 | "use-input-property-decorator": true, 101 | "use-output-property-decorator": true, 102 | "use-host-property-decorator": true, 103 | "no-input-rename": true, 104 | "no-output-rename": true, 105 | "use-life-cycle-interface": true, 106 | "use-pipe-transform-interface": true, 107 | "component-class-suffix": true, 108 | "directive-class-suffix": true, 109 | "directive-selector-prefix": [true, "my"], 110 | "component-selector-prefix": [true, "my"], 111 | "pipe-naming": [true, "camelCase", "my"] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /scripts/gulp/inline-resources.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const glob = require('glob'); 6 | /** 7 | * Simple Promiseify function that takes a Node API and return a version that supports promises. 8 | * We use promises instead of synchronized functions to make the process less I/O bound and 9 | * faster. It also simplify the code. 10 | */ 11 | function promiseify(fn) { 12 | return function() { 13 | const args = [].slice.call(arguments, 0); 14 | return new Promise((resolve, reject) => { 15 | fn.apply(this, args.concat([function (err, value) { 16 | if (err) { 17 | reject(err); 18 | } else { 19 | resolve(value); 20 | } 21 | }])); 22 | }); 23 | }; 24 | } 25 | const readFile = promiseify(fs.readFile); 26 | const writeFile = promiseify(fs.writeFile); 27 | function inlineResources(globs) { 28 | if (typeof globs == 'string') { 29 | globs = [globs]; 30 | } 31 | /** 32 | * For every argument, inline the templates and styles under it and write the new file. 33 | */ 34 | return Promise.all(globs.map(pattern => { 35 | if (pattern.indexOf('*') < 0) { 36 | // Argument is a directory target, add glob patterns to include every files. 37 | pattern = path.join(pattern, '**', '*'); 38 | } 39 | const files = glob.sync(pattern, {}) 40 | .filter(name => /\.js$/.test(name)); // Matches only JavaScript files. 41 | // Generate all files content with inlined templates. 42 | return Promise.all(files.map(filePath => { 43 | return readFile(filePath, 'utf-8') 44 | .then(content => inlineResourcesFromString(content, url => { 45 | return path.join(path.dirname(filePath), url); 46 | })) 47 | .then(content => writeFile(filePath, content)) 48 | .catch(err => { 49 | console.error('An error occured: ', err); 50 | }); 51 | })); 52 | })); 53 | } 54 | /** 55 | * Inline resources from a string content. 56 | * @param content {string} The source file's content. 57 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 58 | * @returns {string} The content with resources inlined. 59 | */ 60 | function inlineResourcesFromString(content, urlResolver) { 61 | // Curry through the inlining functions. 62 | return [ 63 | inlineTemplate, 64 | inlineStyle, 65 | removeModuleId 66 | ].reduce((content, fn) => fn(content, urlResolver), content); 67 | } 68 | if (require.main === module) { 69 | inlineResources(process.argv.slice(2)); 70 | } 71 | /** 72 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and 73 | * replace with `template: ...` (with the content of the file included). 74 | * @param content {string} The source file's content. 75 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 76 | * @return {string} The content with all templates inlined. 77 | */ 78 | function inlineTemplate(content, urlResolver) { 79 | return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function(m, templateUrl) { 80 | const templateFile = urlResolver(templateUrl); 81 | const templateContent = fs.readFileSync(templateFile, 'utf-8'); 82 | const shortenedTemplate = templateContent 83 | .replace(/([\n\r]\s*)+/gm, ' ') 84 | .replace(/"/g, '\\"'); 85 | return `template: "${shortenedTemplate}"`; 86 | }); 87 | } 88 | /** 89 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and 90 | * replace with `styles: [...]` (with the content of the file included). 91 | * @param urlResolver {Function} A resolver that takes a URL and return a path. 92 | * @param content {string} The source file's content. 93 | * @return {string} The content with all styles inlined. 94 | */ 95 | function inlineStyle(content, urlResolver) { 96 | return content.replace(/styleUrls:\s*(\[[\s\S]*?\])/gm, function(m, styleUrls) { 97 | const urls = eval(styleUrls); 98 | return 'styles: [' 99 | + urls.map(styleUrl => { 100 | const styleFile = urlResolver(styleUrl); 101 | const styleContent = fs.readFileSync(styleFile, 'utf-8'); 102 | const shortenedStyle = styleContent 103 | .replace(/([\n\r]\s*)+/gm, ' ') 104 | .replace(/"/g, '\\"'); 105 | return `"${shortenedStyle}"`; 106 | }) 107 | .join(',\n') 108 | + ']'; 109 | }); 110 | } 111 | /** 112 | * Remove every mention of `moduleId: module.id`. 113 | * @param content {string} The source file's content. 114 | * @returns {string} The content with all moduleId: mentions removed. 115 | */ 116 | function removeModuleId(content) { 117 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, ''); 118 | } 119 | module.exports = inlineResources; 120 | module.exports.inlineResourcesFromString = inlineResourcesFromString; -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Helper: root() is defined at the bottom 2 | var path = require('path'); 3 | var webpack = require('webpack'); 4 | 5 | // Webpack Plugins 6 | var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; 7 | var autoprefixer = require('autoprefixer'); 8 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 10 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 11 | var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin; 12 | 13 | /** 14 | * Env 15 | * Get npm lifecycle event to identify the environment 16 | */ 17 | var ENV = process.env.npm_lifecycle_event; 18 | var isTestWatch = ENV === 'test-watch'; 19 | var isTest = ENV === 'test' || isTestWatch; 20 | var isProd = ENV === 'build'; 21 | 22 | module.exports = function makeWebpackConfig() { 23 | /** 24 | * Config 25 | * Reference: http://webpack.github.io/docs/configuration.html 26 | * This is the object where all configuration gets set 27 | */ 28 | var config = {}; 29 | 30 | /** 31 | * Devtool 32 | * Reference: http://webpack.github.io/docs/configuration.html#devtool 33 | * Type of sourcemap to use per build type 34 | */ 35 | if (isProd) { 36 | config.devtool = 'source-map'; 37 | } 38 | else if (isTest) { 39 | config.devtool = 'inline-source-map'; 40 | } 41 | else { 42 | config.devtool = 'eval-source-map'; 43 | } 44 | 45 | /** 46 | * Entry 47 | * Reference: http://webpack.github.io/docs/configuration.html#entry 48 | */ 49 | config.entry = isTest ? {} : { 50 | 'polyfills': './src/polyfills.ts', 51 | 'vendor': './src/vendor.ts', 52 | 'app': './src/main.ts' // our angular app 53 | }; 54 | 55 | /** 56 | * Output 57 | * Reference: http://webpack.github.io/docs/configuration.html#output 58 | */ 59 | config.output = isTest ? {} : { 60 | path: root('dist'), 61 | publicPath: isProd ? '/' : 'http://localhost:8080/', 62 | filename: isProd ? 'js/[name].[hash].js' : 'js/[name].js', 63 | chunkFilename: isProd ? '[id].[hash].chunk.js' : '[id].chunk.js' 64 | }; 65 | 66 | /** 67 | * Resolve 68 | * Reference: http://webpack.github.io/docs/configuration.html#resolve 69 | */ 70 | config.resolve = { 71 | // only discover files that have those extensions 72 | extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html'], 73 | }; 74 | 75 | var atlOptions = ''; 76 | if (isTest && !isTestWatch) { 77 | // awesome-typescript-loader needs to output inlineSourceMap for code coverage to work with source maps. 78 | atlOptions = 'inlineSourceMap=true&sourceMap=false'; 79 | } 80 | 81 | /** 82 | * Loaders 83 | * Reference: http://webpack.github.io/docs/configuration.html#module-loaders 84 | * List: http://webpack.github.io/docs/list-of-loaders.html 85 | * This handles most of the magic responsible for converting modules 86 | */ 87 | config.module = { 88 | rules: [ 89 | // Support for .ts files. 90 | { 91 | test: /\.ts$/, 92 | loaders: ['awesome-typescript-loader?' + atlOptions, 'angular2-template-loader', '@angularclass/hmr-loader', 'angular-router-loader'], 93 | exclude: [isTest ? /\.(e2e)\.ts$/ : /\.(spec|e2e)\.ts$/, /node_modules\/(?!(ng2-.+))/] 94 | }, 95 | 96 | // copy those assets to output 97 | { 98 | test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 99 | loader: 'file-loader?name=fonts/[name].[hash].[ext]?' 100 | }, 101 | 102 | // Support for *.json files. 103 | {test: /\.json$/, loader: 'json-loader'}, 104 | 105 | // Support for CSS as raw text 106 | // use 'null' loader in test mode (https://github.com/webpack/null-loader) 107 | // all css in src/style will be bundled in an external css file 108 | { 109 | test: /\.css$/, 110 | exclude: root('src', 'app'), 111 | loader: isTest ? 'null-loader' : ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: ['css-loader', 'postcss-loader']}) 112 | }, 113 | // all css required in src/app files will be merged in js files 114 | {test: /\.css$/, include: root('src', 'app'), loader: 'raw-loader!postcss-loader'}, 115 | 116 | // support for .scss files 117 | // use 'null' loader in test mode (https://github.com/webpack/null-loader) 118 | // all css in src/style will be bundled in an external css file 119 | { 120 | test: /\.(scss|sass)$/, 121 | exclude: root('src', 'app'), 122 | loader: isTest ? 'null-loader' : ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: ['css-loader', 'postcss-loader', 'sass-loader']}) 123 | }, 124 | // all css required in src/app files will be merged in js files 125 | {test: /\.(scss|sass)$/, exclude: root('src', 'style'), loader: 'raw-loader!postcss-loader!sass-loader'}, 126 | 127 | // support for .html as raw text 128 | // todo: change the loader to something that adds a hash to images 129 | {test: /\.html$/, loader: 'raw-loader', exclude: root('src', 'public')} 130 | ] 131 | }; 132 | 133 | if (isTest && !isTestWatch) { 134 | // instrument only testing sources with Istanbul, covers ts files 135 | config.module.rules.push({ 136 | test: /\.ts$/, 137 | enforce: 'post', 138 | include: path.resolve('src'), 139 | loader: 'istanbul-instrumenter-loader', 140 | exclude: [/\.spec\.ts$/, /\.e2e\.ts$/, /node_modules/] 141 | }); 142 | } 143 | 144 | if (!isTest || !isTestWatch) { 145 | // tslint support 146 | config.module.rules.push({ 147 | test: /\.ts$/, 148 | enforce: 'pre', 149 | loader: 'tslint-loader' 150 | }); 151 | } 152 | 153 | /** 154 | * Plugins 155 | * Reference: http://webpack.github.io/docs/configuration.html#plugins 156 | * List: http://webpack.github.io/docs/list-of-plugins.html 157 | */ 158 | config.plugins = [ 159 | // Define env variables to help with builds 160 | // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 161 | new webpack.DefinePlugin({ 162 | // Environment helpers 163 | 'process.env': { 164 | ENV: JSON.stringify(ENV) 165 | } 166 | }), 167 | 168 | // Workaround needed for angular 2 angular/angular#11580 169 | new webpack.ContextReplacementPlugin( 170 | // The (\\|\/) piece accounts for path separators in *nix and Windows 171 | /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, 172 | root('./src') // location of your src 173 | ), 174 | 175 | // Tslint configuration for webpack 2 176 | new webpack.LoaderOptionsPlugin({ 177 | options: { 178 | /** 179 | * Apply the tslint loader as pre/postLoader 180 | * Reference: https://github.com/wbuchwalter/tslint-loader 181 | */ 182 | tslint: { 183 | emitErrors: false, 184 | failOnHint: false 185 | }, 186 | /** 187 | * Sass 188 | * Reference: https://github.com/jtangelder/sass-loader 189 | * Transforms .scss files to .css 190 | */ 191 | sassLoader: { 192 | //includePaths: [path.resolve(__dirname, "node_modules/foundation-sites/scss")] 193 | }, 194 | /** 195 | * PostCSS 196 | * Reference: https://github.com/postcss/autoprefixer-core 197 | * Add vendor prefixes to your css 198 | */ 199 | postcss: [ 200 | autoprefixer({ 201 | browsers: ['last 2 version'] 202 | }) 203 | ] 204 | } 205 | }) 206 | ]; 207 | 208 | if (!isTest && !isTestWatch) { 209 | config.plugins.push( 210 | new ForkCheckerPlugin(), 211 | 212 | // Generate common chunks if necessary 213 | // Reference: https://webpack.github.io/docs/code-splitting.html 214 | // Reference: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin 215 | new CommonsChunkPlugin({ 216 | name: ['vendor', 'polyfills'] 217 | }), 218 | 219 | // Inject script and link tags into html files 220 | // Reference: https://github.com/ampedandwired/html-webpack-plugin 221 | new HtmlWebpackPlugin({ 222 | template: './src/public/index.html', 223 | chunksSortMode: 'dependency' 224 | }), 225 | 226 | // Extract css files 227 | // Reference: https://github.com/webpack/extract-text-webpack-plugin 228 | // Disabled when in test mode or not in build mode 229 | new ExtractTextPlugin({filename: 'css/[name].[hash].css', disable: !isProd}) 230 | ); 231 | } 232 | 233 | // Add build specific plugins 234 | if (isProd) { 235 | config.plugins.push( 236 | // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin 237 | // Only emit files when there are no errors 238 | new webpack.NoErrorsPlugin(), 239 | 240 | // // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin 241 | // // Dedupe modules in the output 242 | // new webpack.optimize.DedupePlugin(), 243 | 244 | // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 245 | // Minify all javascript, switch loaders to minimizing mode 246 | new webpack.optimize.UglifyJsPlugin({sourceMap: true, mangle: { keep_fnames: true }}), 247 | 248 | // Copy assets from the public folder 249 | // Reference: https://github.com/kevlened/copy-webpack-plugin 250 | new CopyWebpackPlugin([{ 251 | from: root('src/public') 252 | }]) 253 | ); 254 | } 255 | 256 | /** 257 | * Dev server configuration 258 | * Reference: http://webpack.github.io/docs/configuration.html#devserver 259 | * Reference: http://webpack.github.io/docs/webpack-dev-server.html 260 | */ 261 | config.devServer = { 262 | contentBase: './src/public', 263 | historyApiFallback: true, 264 | quiet: true, 265 | stats: 'minimal' // none (or false), errors-only, minimal, normal (or true) and verbose 266 | }; 267 | 268 | return config; 269 | }(); 270 | 271 | // Helper functions 272 | function root(args) { 273 | args = Array.prototype.slice.call(arguments, 0); 274 | return path.join.apply(path, [__dirname].concat(args)); 275 | } 276 | --------------------------------------------------------------------------------