-# Angular2 Webpack Starter [](https://angularclass.com/slack-join) [](https://gitter.im/angularclass/angular2-webpack-starter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# Angular Webpack Starter [](https://gitter.im/angularclass/angular2-webpack-starter?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-> An Angular 2 starter kit featuring [Angular 2](https://angular.io) ([Router](https://angular.io/docs/js/latest/api/router/), [Forms](https://angular.io/docs/js/latest/api/forms/),
-[Http](https://angular.io/docs/js/latest/api/http/),
+> An Angular starter kit featuring [Angular 6](https://angular.io), [Ahead of Time Compile](https://angular.io/docs/ts/latest/cookbook/aot-compiler.html), [Router](https://angular.io/docs/ts/latest/guide/router.html), [Forms](https://angular.io/docs/ts/latest/guide/forms.html),
+[Http](https://angular.io/docs/ts/latest/guide/server-communication.html),
[Services](https://gist.github.com/gdi2290/634101fec1671ee12b3e#_follow_@AngularClass_on_twitter),
-[Tests](https://angular.io/docs/js/latest/api/test/), [E2E](https://angular.github.io/protractor/#/faq#what-s-the-difference-between-karma-and-protractor-when-do-i-use-which-)), [Material](https://github.com/angular/material2), [Karma](https://karma-runner.github.io/), [Protractor](https://angular.github.io/protractor/), [Jasmine](https://github.com/jasmine/jasmine), [Istanbul](https://github.com/gotwarlost/istanbul), [TypeScript](http://www.typescriptlang.org/), [@types](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0ahUKEwjgjdrR7u_NAhUQ7GMKHXgpC4EQFggnMAI&url=https%3A%2F%2Fwww.npmjs.com%2F~types&usg=AFQjCNG2PFhwEo88JKo12mrw_4d0w1oNiA&sig2=N69zbO0yN8ET7v4KVCUOKA), [TsLint](http://palantir.github.io/tslint/), [Codelyzer](https://github.com/mgechev/codelyzer), [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement-with-webpack.html), and [Webpack 2](http://webpack.github.io/) by [AngularClass](https://angularclass.com).
+[Tests](https://angular.io/docs/ts/latest/guide/testing.html), [E2E](https://angular.github.io/protractor/#/faq#what-s-the-difference-between-karma-and-protractor-when-do-i-use-which-)), [Karma](https://karma-runner.github.io/), [Protractor](https://angular.github.io/protractor/), [Jasmine](https://github.com/jasmine/jasmine), [Istanbul](https://github.com/gotwarlost/istanbul), [TypeScript](http://www.typescriptlang.org/), [@types](https://www.npmjs.com/~types), [TsLint](http://palantir.github.io/tslint/), [Codelyzer](https://github.com/mgechev/codelyzer), [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement-with-webpack.html), and [Webpack](http://webpack.github.io/).
-> If you're looking for Angular 1.x please use [NG6-starter](https://github.com/angularclass/NG6-starter)
+> If you're looking for Angular 1.x please use [NG6-starter](https://github.com/gdi2290/NG6-starter)
> If you're looking to learn about Webpack and ES6 Build Tools check out [ES6-build-tools](https://github.com/AngularClass/ES6-build-tools)
> If you're looking to learn TypeScript see [TypeStrong/learn-typescript](https://github.com/TypeStrong/learn-typescript)
-> If you're looking for something easier to get started with then see the angular2-seed that I also maintain [angular/angular2-seed](https://github.com/AngularClass/angular2-seed)
-> If you're looking to add Angular 2 Material Design we have a branch [material2](https://github.com/AngularClass/angular2-webpack-starter/tree/material2)
+> If you're looking for something easier to get started with then see the angular-seed that I also maintain [gdi2290/angular-seed](https://github.com/gdi2290/angular-seed)
-This seed repo serves as an Angular 2 starter for anyone looking to get up and running with Angular 2 and TypeScript fast. Using a [Webpack 2](http://webpack.github.io/) for building our files and assisting with boilerplate. We're also using Protractor for our end-to-end story and Karma for our unit tests.
-* Best practices in file and application organization for Angular 2.
+This seed repo serves as an Angular starter for anyone looking to get up and running with Angular and TypeScript fast. Using a [Webpack 4](https://webpack.js.org) for building our files and assisting with boilerplate. We're also using Protractor for our end-to-end story and Karma for our unit tests.
+* Best practices in file and application organization for Angular.
* Ready to go build system using Webpack for working with TypeScript.
-* Angular 2 examples that are ready to go when experimenting with Angular 2.
-* A great Angular 2 seed repo for anyone who wants to start their project.
-* Testing Angular 2 code with Jasmine and Karma.
+* Angular examples that are ready to go when experimenting with Angular.
+* A great Angular seed repo for anyone who wants to start their project.
+* Ahead of Time (AoT) compile for rapid page loads of your production builds.
+* Tree shaking to automatically remove unused code from your production bundle.
+* Testing Angular code with Jasmine and Karma.
* Coverage with Istanbul and Karma
-* End-to-end Angular 2 code using Protractor.
+* End-to-end Angular app testing using Protractor.
* Type manager with @types
-* Hot Module Replacement with Webpack and [@angularclass/hmr](https://github.com/angularclass/angular2-hmr) and [@angularclass/hmr-loader](https://github.com/angularclass/angular2-hmr-loader)
-* Material Design with [angular/material2](https://github.com/angular/material2)
+* Hot Module Replacement with Webpack and [@gdi2290/hmr](https://github.com/gdi2290/angular-hmr) and [@gdi2290/hmr-loader](https://github.com/PatrickJS/angular-hmr-loader)
### Quick start
-**Make sure you have Node version >= 5.0 and NPM >= 3**
-> Clone/Download the repo then edit `app.ts` inside [`/src/app/app.ts`](/src/app/app.ts)
+**Make sure you have Node version >= 8.0 and (NPM >= 5 or [Yarn](https://yarnpkg.com) )**
+> Clone/Download the repo then edit `app.component.ts` inside [`/src/app/app.component.ts`](/src/app/app.component.ts)
```bash
# clone our repo
# --depth 1 removes all but one .git commit history
-git clone --depth 1 https://github.com/angularclass/angular2-webpack-starter.git
+git clone --depth 1 https://github.com/gdi2290/angular-starter.git
# change directory to our repo
-cd angular2-webpack-starter
+cd angular-starter
# install the repo with npm
npm install
@@ -77,53 +72,61 @@ go to [http://0.0.0.0:3000](http://0.0.0.0:3000) or [http://localhost:3000](http
* [Installing](#installing)
* [Running the app](#running-the-app)
* [Configuration](#configuration)
+* [AoT Don'ts](#aot-donts)
+* [External Stylesheets](#external-stylesheets)
* [Contributing](#contributing)
* [TypeScript](#typescript)
* [@Types](#types)
* [Frequently asked questions](#frequently-asked-questions)
* [Support, Questions, or Feedback](#support-questions-or-feedback)
+* [Deployment](#deployment)
* [License](#license)
## File Structure
We use the component approach in our starter. This is the new standard for developing Angular apps and a great way to ensure maintainable code by encapsulation of our behavior logic. A component is basically a self contained app usually in a single file or a folder with each concern as a file: style, template, specs, e2e, and component class. Here's how it looks:
```
-angular2-webpack-starter/
- ├──config/ * our configuration
- | ├──helpers.js * helper functions for our configuration files
- | ├──spec-bundle.js * ignore this magic that sets up our angular 2 testing environment
- | ├──karma.conf.js * karma config for our unit tests
- | ├──protractor.conf.js * protractor config for our end-to-end tests
- │ ├──webpack.dev.js * our development webpack config
- │ ├──webpack.prod.js * our production webpack config
- │ └──webpack.test.js * our testing webpack config
+angular-starter/
+ ├──config/ * our configuration
+ | ├──build-utils.js * common config and shared functions for prod and dev
+ | ├──config.common.json * config for both environments prod and dev such title and description of index.html
+ | ├──config.dev.json * config for development environment
+ | ├──config.prod.json * config for production environment
+ │ │ (note: you can load your own config file, just set the evn ANGULAR_CONF_FILE with the path of your own file)
+ | ├──helpers.js * helper functions for our configuration files
+ | ├──spec-bundle.js * ignore this magic that sets up our Angular testing environment
+ | ├──karma.conf.js * karma config for our unit tests
+ | ├──protractor.conf.js * protractor config for our end-to-end tests
+ │ ├──webpack.common.js * common tasks for webpack build process shared for dev and prod
+ │ ├──webpack.dev.js * our development webpack config
+ │ ├──webpack.prod.js * our production webpack config
+ │ └──webpack.test.js * our testing webpack config
│
- ├──src/ * our source files that will be compiled to javascript
- | ├──main.browser.ts * our entry file for our browser environment
+ ├──src/ * our source files that will be compiled to javascript
+ | ├──main.browser.ts * our entry file for our browser environment
│ │
- | ├──index.html * Index.html: where we generate our index page
+ | ├──index.html * Index.html: where we generate our index page
│ │
- | ├──polyfills.ts * our polyfills file
+ | ├──polyfills.ts * our polyfills file
│ │
- | ├──vendor.ts * our vendor file
+ │ ├──app/ * WebApp: folder
+ │ │ ├──app.component.spec.ts * a simple test of components in app.component.ts
+ │ │ ├──app.e2e.ts * a simple end-to-end test for /
+ │ │ └──app.component.ts * a simple version of our App component components
│ │
- │ ├──app/ * WebApp: folder
- │ │ ├──app.spec.ts * a simple test of components in app.ts
- │ │ ├──app.e2e.ts * a simple end-to-end test for /
- │ │ └──app.ts * App.ts: a simple version of our App component components
- │ │
- │ └──assets/ * static assets are served here
- │ ├──icon/ * our list of icons from www.favicon-generator.org
- │ ├──service-worker.js * ignore this. Web App service worker that's not complete yet
- │ ├──robots.txt * for search engines to crawl your website
- │ └──humans.txt * for humans to know who the developers are
+ │ └──assets/ * static assets are served here
+ │ ├──icon/ * our list of icons from www.favicon-generator.org
+ │ ├──service-worker.js * ignore this. Web App service worker that's not complete yet
+ │ ├──robots.txt * for search engines to crawl your website
+ │ └──humans.txt * for humans to know who the developers are
│
│
- ├──tslint.json * typescript lint config
- ├──typedoc.json * typescript documentation generator
- ├──tsconfig.json * config that webpack uses for typescript
- ├──package.json * what npm uses to manage it's dependencies
- └──webpack.config.js * webpack main configuration file
+ ├──tslint.json * typescript lint config
+ ├──typedoc.json * typescript documentation generator
+ ├──tsconfig.json * typescript config used outside webpack
+ ├──tsconfig.webpack.json * config that webpack uses for typescript
+ ├──package.json * what npm uses to manage its dependencies
+ └──webpack.config.js * webpack main configuration file
```
@@ -131,9 +134,9 @@ angular2-webpack-starter/
## Dependencies
What you need to run this app:
* `node` and `npm` (`brew install node`)
-* Ensure you're running the latest versions Node `v4.x.x`+ (or `v5.x.x`) and NPM `3.x.x`+
+* Ensure you're running the latest versions Node `v8.x.x`+ (or `v9.x.x`) and NPM `5.x.x`+
-> If you have `nvm` installed, which is highly recommended (`brew install nvm`) you can do a `nvm install --lts && nvm use` in `$` to run with the latest Node LTS. You can also have this `zsh` done for you [automatically](https://github.com/creationix/nvm#calling-nvm-use-automatically-in-a-directory-with-a-nvmrc-file)
+> If you have `nvm` installed, which is highly recommended (`brew install nvm`) you can do a `nvm install --lts && nvm use` in `$` to run with the latest Node LTS. You can also have this `zsh` done for you [automatically](https://github.com/creationix/nvm#calling-nvm-use-automatically-in-a-directory-with-a-nvmrc-file)
Once you have those, you should install these globals with `npm install --global`:
* `webpack` (`npm install --global webpack`)
@@ -141,12 +144,13 @@ Once you have those, you should install these globals with `npm install --global
* `karma` (`npm install --global karma-cli`)
* `protractor` (`npm install --global protractor`)
* `typescript` (`npm install --global typescript`)
+* `tslint` (`npm install --global tslint@4.5.1`)
## Installing
* `fork` this repo
* `clone` your fork
* `npm install webpack-dev-server rimraf webpack -g` to install required global dependencies
-* `npm install` to install all dependencies
+* `npm install` to install all dependencies or `yarn`
* `npm run server` to start the dev server in another tab
## Running the app
@@ -162,13 +166,16 @@ npm run server:prod
```
## Other commands
+## the following commands with npm can be used with yarn as well
### build files
```bash
# development
npm run build:dev
-# production
+# production (jit)
npm run build:prod
+# AoT
+npm run build:aot
```
### hot module replacement
@@ -181,7 +188,7 @@ npm run server:dev:hmr
npm run watch
```
-### run tests
+### run unit tests
```bash
npm run test
```
@@ -193,20 +200,20 @@ npm run watch:test
### run end-to-end tests
```bash
-# make sure you have your server running in another terminal
+# update Webdriver (optional, done automatically by postinstall script)
+npm run webdriver:update
+# this will start a test server and launch Protractor
npm run e2e
```
-### run webdriver (for end-to-end)
+### continuous integration (run unit tests and e2e tests together)
```bash
-npm run webdriver:update
-npm run webdriver:start
+# this will test both your JIT and AoT builds
+npm run ci
```
### run Protractor's elementExplorer (for end-to-end)
```bash
-npm run webdriver:start
-# in another terminal
npm run e2e:live
```
@@ -218,6 +225,27 @@ npm run build:docker
# Configuration
Configuration files live in `config/` we are currently using webpack, karma, and protractor for different stages of your application
+# AoT Don'ts
+The following are some things that will make AoT compile fail.
+
+- Don’t use require statements for your templates or styles, use styleUrls and templateUrls, the angular2-template-loader plugin will change it to require at build time.
+- Don’t use default exports.
+- Don’t use `form.controls.controlName`, use `form.get(‘controlName’)`
+- Don’t use `control.errors?.someError`, use `control.hasError(‘someError’)`
+- Don’t use functions in your providers, routes or declarations, export a function and then reference that function name
+- @Inputs, @Outputs, View or Content Child(ren), Hostbindings, and any field you use from the template or annotate for Angular should be public
+
+For more detailed guide on AoT's Do's and Don'ts refer to https://github.com/rangle/angular-2-aot-sandbox
+
+# External Stylesheets
+Any stylesheets (Sass or CSS) placed in the `src/styles` directory and imported into your project will automatically be compiled into an external `.css` and embedded in your production builds.
+
+For example to use Bootstrap as an external stylesheet:
+1) Create a `styles.scss` file (name doesn't matter) in the `src/styles` directory.
+2) `npm install` the version of Bootstrap you want.
+3) In `styles.scss` add `@import '~bootstrap/scss/bootstrap.scss';`
+4) In `src/app/app.module.ts` add underneath the other import statements: `import '../styles/styles.scss';`
+
# Contributing
You can include more examples as components but they must introduce a new concept such as `Home` component (separate folders), and Todo (services). I'll accept pretty much everything so feel free to open a Pull-Request
@@ -225,7 +253,7 @@ You can include more examples as components but they must introduce a new concep
> To take full advantage of TypeScript with autocomplete you would have to install it globally and use an editor with the correct TypeScript plugins.
## Use latest TypeScript compiler
-TypeScript 1.7.x includes everything you need. Make sure to upgrade, even if you installed TypeScript previously.
+TypeScript 2.7.x includes everything you need. Make sure to upgrade, even if you installed TypeScript previously.
```
npm install --global typescript
@@ -235,23 +263,23 @@ npm install --global typescript
We have good experience using these editors:
* [Visual Studio Code](https://code.visualstudio.com/)
-* [Webstorm 10](https://www.jetbrains.com/webstorm/download/)
+* [Webstorm 2018.1](https://www.jetbrains.com/webstorm/download/)
* [Atom](https://atom.io/) with [TypeScript plugin](https://atom.io/packages/atom-typescript)
* [Sublime Text](http://www.sublimetext.com/3) with [Typescript-Sublime-Plugin](https://github.com/Microsoft/Typescript-Sublime-plugin#installation)
### Visual Studio Code + Debugger for Chrome
-> Install [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) and see docs for instructions to launch Chrome
+> Install [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) and see docs for instructions to launch Chrome
The included `.vscode` automatically connects to the webpack development server on port `3000`.
# Types
> When you include a module that doesn't include Type Definitions inside of the module you can include external Type Definitions with @types
-i.e, to have youtube api support, run this command in terminal:
+i.e, to have youtube api support, run this command in terminal:
```shell
npm i @types/youtube @types/gapi @types/gapi.youtube
-```
-In some cases where your code editor doesn't support Typescript 2 yet or these types weren't listed in ```tsconfig.json```, add these to **"src/custom-typings.d.ts"** to make peace with the compile check:
+```
+In some cases where your code editor doesn't support Typescript 2 yet or these types weren't listed in ```tsconfig.json```, add these to **"src/custom-typings.d.ts"** to make peace with the compile check:
```es6
import '@types/gapi.youtube';
import '@types/gapi';
@@ -293,89 +321,185 @@ import * as _ from 'lodash';
# Frequently asked questions
-* What's the current browser support for Angular 2 Beta?
- * Please view the updated list of [browser support for Angular 2](https://github.com/angularclass/awesome-angular2#current-browser-support-for-angular-2)
+* What's the current browser support for Angular?
+ * Please view the updated list of [browser support for Angular](https://github.com/gdi2290/awesome-angular#current-browser-support-for-angular)
* Why is my service, aka provider, is not injecting parameter correctly?
* Please use `@Injectable()` for your service for typescript to correctly attach the metadata (this is a TypeScript problem)
-* How do I run protractor with node 0.12.x?
- * please check out this repo to use the old version of protractor [#146](https://github.com/AngularClass/angular2-webpack-starter/pull/146/files)
* Where do I write my tests?
- * You can write your tests next to your component files. See [`/src/app/home/home.spec.ts`](/src/app/home/home.spec.ts)
+ * You can write your tests next to your component files. See [`/src/app/home/home.component.spec.ts`](/src/app/home/home.component.spec.ts)
* How do I start the app when I get `EACCES` and `EADDRINUSE` errors?
* The `EADDRINUSE` error means the port `3000` is currently being used and `EACCES` is lack of permission for webpack to build files to `./dist/`
* How to use `sass` for css?
- * `loaders: ['raw-loader','sass-loader']` and `@Component({ styleUrls: ['./filename.scss'] })` see issue [#136](https://github.com/AngularClass/angular2-webpack-starter/issues/136)
-* How do I test a Service?
- * See issue [#130](https://github.com/AngularClass/angular2-webpack-starter/issues/130#issuecomment-158872648)
+ * * `loaders: ['raw-loader','sass-loader']` and `@Component({ styleUrls: ['./filename.scss'] })` see Wiki page [How to include SCSS in components](https://github.com/gdi2290/angular-starter/wiki/How-to-include-SCSS-in-components), or issue [#136](https://github.com/gdi2290/angular-starter/issues/136) for more information.
+* How do I test a Service?
+ * See issue [#130](https://github.com/gdi2290/angular-starter/issues/130#issuecomment-158872648)
* How do I add `vscode-chrome-debug` support?
- * The VS Code chrome debug extension support can be done via `launch.json` see issue [#144](https://github.com/AngularClass/angular2-webpack-starter/issues/144#issuecomment-164063790)
+ * The VS Code chrome debug extension support can be done via `launch.json` see issue [#144](https://github.com/gdi2290/angular-starter/issues/144#issuecomment-164063790)
* How do I make the repo work in a virtual machine?
- * You need to use `0.0.0.0` so revert these changes [#205](https://github.com/AngularClass/angular2-webpack-starter/pull/205/files)
-* What are the naming conventions for Angular 2?
- * please see issue [#185](https://github.com/AngularClass/angular2-webpack-starter/issues/185) and PR [196](https://github.com/AngularClass/angular2-webpack-starter/pull/196)
+ * You need to use `0.0.0.0` so revert these changes [#205](https://github.com/gdi2290/angular-starter/pull/205/files)
+* What are the naming conventions for Angular?
+ * please see issue [#185](https://github.com/gdi2290/angular-starter/issues/185) and PR [196](https://github.com/gdi2290/angular-starter/pull/196)
* How do I include bootstrap or jQuery?
- * please see issue [#215](https://github.com/AngularClass/angular2-webpack-starter/issues/215) and [#214](https://github.com/AngularClass/angular2-webpack-starter/issues/214#event-511768416)
+ * please see issue [#215](https://github.com/gdi2290/angular-starter/issues/215) and [#214](https://github.com/gdi2290/angular-starter/issues/214#event-511768416)
* How do I async load a component?
- * see wiki [How-do-I-async-load-a-component-with-AsyncRoute](https://github.com/AngularClass/angular2-webpack-starter/wiki/How-do-I-async-load-a-component-with-AsyncRoute)
+ * see wiki [How-do-I-async-load-a-component-with-AsyncRoute](https://github.com/gdi2290/angular-starter/wiki/How-do-I-async-load-a-component-with-AsyncRoute)
* Error: Cannot find module 'tapable'
- * Remove `node_modules/` and run `npm cache clean` then `npm install`
-* What about Webpack 2?
- * If you're looking for Webpack 2 version then see the [experimental version](https://github.com/gdi2290/angular2-webpack2-starter) that will be merged soon.
+ * Remove `node_modules/` and run `npm cache clean` then `npm install`
* How do I turn on Hot Module Replacement
- * Run `npm run server:dev:hmr`
+ * Run `npm run server:dev:hmr`
* `RangeError: Maximum call stack size exceeded`
- * This is a problem with minifying Angular 2 and it's recent JIT templates. If you set `mangle` to `false` then you should be good.
+ * This is a problem with minifying Angular and it's recent JIT templates. If you set `mangle` to `false` then you should be good.
* Why is the size of my app larger in development?
- * We are using inline source-maps and hot module replacement which will increase the bundle size.
+ * We are using inline source-maps and hot module replacement which will increase the bundle size.
* If you're in China
- * check out https://github.com/cnpm/cnpm
-* If you're looking to add Angular 2 Material Design
- * check out the [material2](https://github.com/AngularClass/angular2-webpack-starter/tree/material2) branch
+ * check out https://github.com/cnpm/cnpm
* node-pre-gyp ERR in npm install (Windows)
- * install Python x86 version between 2.5 and 3.0 on windows see issue [#626](https://github.com/AngularClass/angular2-webpack-starter/issues/626)
+ * often happens when you're behind proxy and proxy wasn't configured in the npm as it tries to download binary package from the github and if it fails to do so, it will try to compile node-sass from the source codes
+ * install Python3 x86
* `Error:Error: Parse tsconfig error [{"messageText":"Unknown compiler option 'lib'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'strictNullChecks'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'baseUrl'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'paths'.","category":1,"code":5023},{"messageText":"Unknown compiler option 'types'.","category":1,"code":5023}]`
- * remove `node_modules/typescript` and run `npm install typescript@beta`. This repo now uses ts 2.0
+ * remove `node_modules/typescript` and run `npm install typescript@beta`. This repo now uses ts 2.0
* "There are multiple modules with names that only differ in casing"
- * change `c:\[path to angular2-webpack-starter]` to `C:\[path to angular2-webpack-starter]` see [926#issuecomment-245223547](https://github.com/AngularClass/angular2-webpack-starter/issues/926#issuecomment-245223547)
+ * change `c:\[path to angular-starter]` to `C:\[path to angular-starter]` see [926#issuecomment-245223547](https://github.com/gdi2290/angular-starter/issues/926#issuecomment-245223547)
# Support, Questions, or Feedback
-> Contact us anytime for anything about this repo or Angular 2
+> Contact us anytime for anything about this repo or Angular
-* [Chat: AngularClass.slack](http://angularclass.com/member-join/)
-* [Twitter: @AngularClass](https://twitter.com/AngularClass)
-* [Gitter: AngularClass/angular2-webpack-starter](https://gitter.im/angularclass/angular2-webpack-starter)
+`@PatrickJS__` on twitter
-# Quick Start Guides
+# Deployment
-## Nitrous
+## Docker
-You can quickly create a free development environment to get started using this
-starter kit in the cloud on [Nitrous](https://www.nitrous.io/):
+To run project you only need host machine with **operating system** with installed **git** (to clone this repo)
+and [docker](https://www.docker.com/) and thats all - any other software is not needed
+(other software like node.js etc. will be automatically downloaded and installed inside docker container during build step based on dockerfile).
-
-
-
+### Install docker
-Simply run `HOST=0.0.0.0 npm start` from the terminal inside of
-`~/code/angular2-webpack-starter` and access your site via the "Preview > 3000"
-link in the IDE.
+#### MacOS:
-
+`brew cask install docker`
-___
+And run docker by Mac bottom menu> launchpad > docker (on first run docker will ask you about password)
+
+#### Ubuntu:
+
+```
+sudo apt-get update
+sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
+sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'
+sudo apt-get update
+apt-cache policy docker-engine
+sudo apt-get install -y docker-engine
+sudo systemctl status docker # test: should be ‘active’
+```
+And add your user to docker group (to avoid `sudo` before using `docker` command in future):
+```
+sudo usermod -aG docker $(whoami)
+```
+and logout and login again.
+
+### Build image
+
+Because *node.js* is big memory consumer you need 1-2GB RAM or virtual memory to build docker image
+(it was successfully tested on machine with 512MB RAM + 2GB virtual memory - building process take 7min)
+
+Go to main project folder. To build image type:
+
+`docker build -t angular-starter .`
+
+The **angular-starter** name used in above commands is only example image name.
+To remove intermediate images created by docker on build process, type:
+
+`docker rmi -f $(docker images -f "dangling=true" -q)`
+
+### Run image
-enjoy — **AngularClass**
+To run created docker image on [localhost:8080](localhost:8080) type (parameter `-p 8080:80` is host:container port mapping)
-
+`docker run --name angular-starter -p 8080:80 angular-starter &`
+
+And that's all, you can open browser and go to [localhost:8080](localhost:8080).
+
+### Build and Run image using docker-compose
+
+To create and run docker image on [localhost:8080](localhost:8080) as part of large project you may use **docker-compose**. Type
+
+`docker-compose up`
+
+And that's all, you can open browser and go to [localhost:8080](localhost:8080).
+
+
+### Run image on sub-domain
+
+If you want to run image as virtual-host on sub-domain you must setup [proxy](https://github.com/jwilder/nginx-proxy). You should install proxy and set sub-domain in this way:
+
+ ```
+ docker run -d -p 80:80 --name nginx-proxy -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy:alpine
+ ```
+
+ And in your `/etc/hosts` file (linux) add line: `127.0.0.1 angular-starter.your-domain.com` or in yor hosting add
+ following DNS record (wildchar `*` is handy because when you add new sub-domain in future, you don't need to touch/add any DNS record)
+
+ ```
+ Type: CNAME
+ Hostname: *.your-domain.com
+ Direct to: your-domain.com
+ TTL(sec): 43200
+ ```
+
+And now you are ready to run image on subdomain by:
+
+```
+docker run -e VIRTUAL_HOST=angular-starter.your-domain.com --name angular-starter angular-starter &
+```
+
+### Login into docker container
+
+`docker exec -t -i angular-starter /bin/bash`
+
+## Netlify
+
+You can quickly create a free site to get started using this
+starter kit in production on [Netlify](https://www.netlify.com/):
+
+[](https://app.netlify.com/start/deploy?repository=https://github.com/AngularClass/angular-starter)
+
+### Optional Integration with SonarQube (for continous code quality)
+Assuming you have SonarQube 5.5.6 (LTS) installed
+* Setup SonarQube with the [Sonar Typescript plugin](https://github.com/Pablissimo/SonarTsPlugin#installation) and the Generic Test Coverage plugin https://docs.sonarqube.org/display/PLUG/Generic+Test+Coverage
+* Install sonar-scanner globally
+```bash
+npm install --global sonar-scanner
+```
+* Install the [Karma plugin for sonarqube](https://www.npmjs.com/package/karma-sonarqube-unit-reporter) as a dev dependency
+```bash
+npm install karma-sonarqube-unit-reporter --save-dev
+```
+* Sonar Host URL configuration:
+Update [`sonar-project.properties`](sonar-project.properties) file for the property `sonar.host.url` to point to your SonarQube server. By default this assumes that the SonarQube server is running locally using the default port
+```
+sonar.host.url=
+```
+* Run the unit tests with sonar reporter enabled
+```bash
+npm run test:sonar
+```
+* The test results collected in the results folder in the sonar compatible format
+* Push results to SonarCube
+```bash
+sonar-scanner
+```
+* If working with SonarQube 6.x it supports [Generic Test Data](https://docs.sonarqube.org/display/SONAR/Generic+Test+Data)
+* Modify the [karma.conf.js](config/karma.config.js) to set the appropriate version of the sonarQube
+```es6
+sonarQubeUnitReporter: {
+ sonarQubeVersion: '6.x',
+}
+```
+___
-[](https://angularclass.com)
-##[AngularClass](https://angularclass.com)
-> Learn AngularJS, Angular 2, and Modern Web Development from the best.
-> Looking for corporate Angular training, want to host us, or Angular consulting? patrick@angularclass.com
+enjoy — [**PatrickJS**](https://patrickjs.com)
___
diff --git a/config/build-utils.js b/config/build-utils.js
new file mode 100644
index 0000000000..6e94e92ff9
--- /dev/null
+++ b/config/build-utils.js
@@ -0,0 +1,131 @@
+const ts = require('typescript');
+const path = require('path');
+const fs = require('fs');
+const helpers = require('./helpers');
+
+const APP_COMMON_CONFIG = require('./config.common.json');
+
+const DEFAULT_METADATA = {
+ title: APP_COMMON_CONFIG.title,
+ description: APP_COMMON_CONFIG.description,
+ baseUrl: '/',
+ isDevServer: helpers.isWebpackDevServer(),
+ HMR: helpers.hasProcessFlag('hot'),
+ AOT: process.env.BUILD_AOT || helpers.hasNpmFlag('aot'),
+ E2E: !!process.env.BUILD_E2E,
+ WATCH: helpers.hasProcessFlag('watch'),
+ tsConfigPath: 'tsconfig.webpack.json',
+
+ /**
+ * This suffix is added to the environment.ts file, if not set the default environment file is loaded (development)
+ * To disable environment files set this to null
+ */
+ envFileSuffix: ''
+};
+
+function supportES2015(tsConfigPath) {
+ if (!supportES2015.hasOwnProperty('supportES2015')) {
+ const tsTarget = readTsConfig(tsConfigPath).options.target;
+ supportES2015['supportES2015'] = tsTarget !== ts.ScriptTarget.ES3 && tsTarget !== ts.ScriptTarget.ES5;
+ }
+ return supportES2015['supportES2015'];
+}
+
+function readTsConfig(tsConfigPath) {
+ const configResult = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
+ return ts.parseJsonConfigFileContent(configResult.config, ts.sys,
+ path.dirname(tsConfigPath), undefined, tsConfigPath);
+}
+
+function getEnvFile(suffix) {
+ if (suffix && suffix[0] !== '.') {
+ suffix = '.' + suffix;
+ }
+
+ if (suffix === null) {
+ return;
+ }
+
+ let fileName = helpers.root(`src/environments/environment${suffix}.ts`);
+ if (fs.existsSync(fileName)) {
+ return fileName;
+ } else if (fs.existsSync(fileName = helpers.root('src/environments/environment.ts'))) {
+ console.warn(`Could not find environment file with suffix ${suffix}, loading default environment file`);
+ return fileName;
+ } else {
+ throw new Error('Environment file not found.')
+ }
+}
+
+/**
+ * Read the tsconfig to determine if we should prefer ES2015 modules.
+ * Load rxjs path aliases.
+ * https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking
+ * @param supportES2015 Set to true when the output of typescript is >= ES6
+ */
+function rxjsAlias(supportES2015) {
+ try {
+ const rxjsPathMappingImport = supportES2015 ? 'rxjs/_esm2015/path-mapping' : 'rxjs/_esm5/path-mapping';
+ const rxPaths = require(rxjsPathMappingImport);
+ return rxPaths(helpers.root('node_modules'));
+ } catch (e) {
+ return {};
+ }
+}
+
+function ngcWebpackSetup(prod, metadata) {
+ if (!metadata) {
+ metadata = DEFAULT_METADATA;
+ }
+
+ const buildOptimizer = prod && metadata.AOT;
+ const sourceMap = true; // TODO: apply based on tsconfig value?
+ const ngcWebpackPluginOptions = {
+ skipCodeGeneration: !metadata.AOT,
+ sourceMap
+ };
+
+ const environment = getEnvFile(metadata.envFileSuffix);
+ if (environment) {
+ ngcWebpackPluginOptions.hostReplacementPaths = {
+ [helpers.root('src/environments/environment.ts')]: environment
+ }
+ }
+
+ if (!prod && metadata.WATCH) {
+ // Force commonjs module format for TS on dev watch builds.
+ ngcWebpackPluginOptions.compilerOptions = {
+ module: 'commonjs'
+ };
+ }
+
+ const buildOptimizerLoader = {
+ loader: '@angular-devkit/build-optimizer/webpack-loader',
+ options: {
+ sourceMap
+ }
+ };
+
+ const loaders = [
+ {
+ test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
+ use: buildOptimizer ? [ buildOptimizerLoader, '@ngtools/webpack' ] : [ '@ngtools/webpack' ]
+ },
+ ...buildOptimizer
+ ? [ { test: /\.js$/, use: [ buildOptimizerLoader ] } ]
+ : []
+ ];
+
+ return {
+ loaders,
+ plugin: ngcWebpackPluginOptions
+ };
+}
+
+
+exports.DEFAULT_METADATA = DEFAULT_METADATA;
+exports.supportES2015 = supportES2015;
+exports.readTsConfig = readTsConfig;
+exports.getEnvFile = getEnvFile;
+exports.rxjsAlias = rxjsAlias;
+exports.ngcWebpackSetup = ngcWebpackSetup;
diff --git a/config/config.common.json b/config/config.common.json
new file mode 100644
index 0000000000..5ab0d19606
--- /dev/null
+++ b/config/config.common.json
@@ -0,0 +1,4 @@
+{
+ "title": "Angular Starter by @gdi2290 from @TipeIO",
+ "description": "An Angular starter kit featuring Angular 5, Ahead of Time Compile, Router, Forms, Http, Services, Tests, E2E), Karma, Protractor, Jasmine, Istanbul, TypeScript, @types, TsLint, Codelyzer, Hot Module Replacement, and Webpack by Tipe.io"
+}
diff --git a/config/config.dev.json b/config/config.dev.json
new file mode 100644
index 0000000000..2f8218edd0
--- /dev/null
+++ b/config/config.dev.json
@@ -0,0 +1,10 @@
+{
+ "firebase": {
+ "apiKey": "",
+ "authDomain": "XXXXXX.firebaseapp.com",
+ "databaseURL": "https://XXXXXX.firebaseio.com",
+ "projectId": "XXXXXX",
+ "storageBucket": "XXXXXX.appspot.com",
+ "messagingSenderId": "000000000000"
+ }
+}
diff --git a/config/config.prod.json b/config/config.prod.json
new file mode 100644
index 0000000000..1ac6fc2768
--- /dev/null
+++ b/config/config.prod.json
@@ -0,0 +1,11 @@
+{
+ "firebase": {
+ "apiKey": "",
+ "authDomain": "XXXXXX.firebaseapp.com",
+ "databaseURL": "https://XXXXXX.firebaseio.com",
+ "projectId": "XXXXXX",
+ "storageBucket": "XXXXXX.appspot.com",
+ "messagingSenderId": "000000000000"
+ },
+ "gtmKey" : "GTM-XXXXXXX"
+}
diff --git a/config/empty.js b/config/empty.js
new file mode 100644
index 0000000000..6bc5423e97
--- /dev/null
+++ b/config/empty.js
@@ -0,0 +1,11 @@
+module.exports = {
+ hmrModule: function(ngmodule) {
+ return ngmodule;
+ },
+ NgProbeToken: {},
+ HmrState: function() {},
+ _createConditionalRootRenderer: function(rootRenderer, extraTokens, coreTokens) {
+ return rootRenderer;
+ },
+ __platform_browser_private__: {}
+};
diff --git a/config/github-deploy/index.js b/config/github-deploy/index.js
index e03899bed0..0367f712d6 100644
--- a/config/github-deploy/index.js
+++ b/config/github-deploy/index.js
@@ -1,12 +1,17 @@
-const helpers = require('../helpers');
const execSync = require('child_process').execSync;
+/**
+ * Used to merge webpack configs.
+ */
+const webpackMerge = require('webpack-merge'); // used to merge webpack configs
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const helpers = require('../helpers');
-const REPO_NAME_RE = /Push {2}URL: https:\/\/github\.com\/.*\/(.*)\.git/;
+const REPO_NAME_RE = /Push {2}URL: ((git@github\.com:)|(https:\/\/github\.com\/)).+\/(.+)\.git/;
-function getWebpackConfigModule() {
- if (helpers.hasProcessFlag('github-dev')) {
+function getWebpackConfigModule(options) {
+ if (options.githubDev) {
return require('../webpack.dev.js');
- } else if (helpers.hasProcessFlag('github-prod')) {
+ } else if (options.githubProd) {
return require('../webpack.prod.js');
} else {
throw new Error('Invalid compile option.');
@@ -22,7 +27,7 @@ function getRepoName(remoteName) {
if (!match) {
throw new Error('Could not find a repository on remote ' + remoteName);
} else {
- return match[1];
+ return match[4];
}
}
@@ -54,6 +59,37 @@ function safeUrl(url) {
return stripped ? stripped + '/' : '';
}
+function replaceHtmlWebpackPlugin(plugins, ghRepoName) {
+ for (var i=0; i tags for 'apple-touch-icon' (AKA Web Clips). **/
+ /**
+ * tags for 'apple-touch-icon' (AKA Web Clips).
+ */
{ rel: 'apple-touch-icon', sizes: '57x57', href: '/assets/icon/apple-icon-57x57.png' },
{ rel: 'apple-touch-icon', sizes: '60x60', href: '/assets/icon/apple-icon-60x60.png' },
{ rel: 'apple-touch-icon', sizes: '72x72', href: '/assets/icon/apple-icon-72x72.png' },
@@ -26,15 +28,21 @@ module.exports = {
{ rel: 'apple-touch-icon', sizes: '152x152', href: '/assets/icon/apple-icon-152x152.png' },
{ rel: 'apple-touch-icon', sizes: '180x180', href: '/assets/icon/apple-icon-180x180.png' },
- /** tags for android web app icons **/
+ /**
+ * tags for android web app icons
+ */
{ rel: 'icon', type: 'image/png', sizes: '192x192', href: '/assets/icon/android-icon-192x192.png' },
- /** tags for favicons **/
+ /**
+ * tags for favicons
+ */
{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/assets/icon/favicon-32x32.png' },
{ rel: 'icon', type: 'image/png', sizes: '96x96', href: '/assets/icon/favicon-96x96.png' },
{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '/assets/icon/favicon-16x16.png' },
- /** tags for a Web App Manifest **/
+ /**
+ * tags for a Web App Manifest
+ */
{ rel: 'manifest', href: '/assets/manifest.json' }
],
meta: [
diff --git a/config/helpers.js b/config/helpers.js
index 41c9c7741b..aae072eafc 100644
--- a/config/helpers.js
+++ b/config/helpers.js
@@ -1,24 +1,31 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-var path = require('path');
+const path = require('path');
-// Helper functions
+const EVENT = process.env.npm_lifecycle_event || '';
+
+/**
+ * Helper functions.
+ */
var ROOT = path.resolve(__dirname, '..');
function hasProcessFlag(flag) {
return process.argv.join('').indexOf(flag) > -1;
}
+function hasNpmFlag(flag) {
+ return EVENT.includes(flag);
+}
+
function isWebpackDevServer() {
return process.argv[1] && !! (/webpack-dev-server/.exec(process.argv[1]));
}
-function root(args) {
- args = Array.prototype.slice.call(arguments, 0);
- return path.join.apply(path, [ROOT].concat(args));
-}
+
+var root = path.join.bind(path, ROOT);
exports.hasProcessFlag = hasProcessFlag;
+exports.hasNpmFlag = hasNpmFlag;
exports.isWebpackDevServer = isWebpackDevServer;
exports.root = root;
diff --git a/config/html-elements-plugin/index.js b/config/html-elements-plugin/index.js
index 5766a2fdbb..c4be4909eb 100644
--- a/config/html-elements-plugin/index.js
+++ b/config/html-elements-plugin/index.js
@@ -1,31 +1,3 @@
-
-function HtmlElementsPlugin(locations) {
- this.locations = locations;
-}
-
-HtmlElementsPlugin.prototype.apply = function(compiler) {
- var self = this;
- compiler.plugin('compilation', function(compilation) {
- compilation.options.htmlElements = compilation.options.htmlElements || {};
-
- compilation.plugin('html-webpack-plugin-before-html-generation', function(htmlPluginData, callback) {
- const locations = self.locations;
-
- if (locations) {
- const publicPath = htmlPluginData.assets.publicPath;
-
- Object.getOwnPropertyNames(locations).forEach(function(loc) {
- compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath);
- });
- }
-
-
- callback(null, htmlPluginData);
- });
- });
-
-};
-
const RE_ENDS_WITH_BS = /\/$/;
/**
@@ -42,31 +14,41 @@ const RE_ENDS_WITH_BS = /\/$/;
function createTag(tagName, attrMap, publicPath) {
publicPath = publicPath || '';
- // add trailing slash if we have a publicPath and it doesn't have one.
+ /**
+ * Add trailing slash if we have a publicPath and it doesn't have one.
+ */
if (publicPath && !RE_ENDS_WITH_BS.test(publicPath)) {
publicPath += '/';
}
const attributes = Object.getOwnPropertyNames(attrMap)
- .filter(function(name) { return name[0] !== '='; } )
- .map(function(name) {
+ .filter(function (name) {
+ return name[0] !== '=';
+ })
+ .map(function (name) {
var value = attrMap[name];
if (publicPath) {
- // check if we have explicit instruction, use it if so (e.g: =herf: false)
- // if no instruction, use public path if it's href attribute.
+ /**
+ * Check if we have explicit instruction, use it if so (e.g: =herf: false)
+ * if no instruction, use public path if it's href attribute.
+ */
const usePublicPath = attrMap.hasOwnProperty('=' + name) ? !!attrMap['=' + name] : name === 'href';
if (usePublicPath) {
- // remove a starting trailing slash if the value has one so we wont have //
+ /**
+ * Remove a starting trailing slash if the value has one so we wont have //
+ */
value = publicPath + (value[0] === '/' ? value.substr(1) : value);
}
}
- return name + '="' + value + '"';
+ return `${name}="${value}"`;
});
- return '<' + tagName + ' ' + attributes.join(' ') + '>';
+ const closingTag = tagName === 'script' ? '' : '';
+
+ return `<${tagName} ${attributes.join(' ')}>${closingTag}`;
}
/**
@@ -91,16 +73,50 @@ function createTag(tagName, attrMap, publicPath) {
*/
function getHtmlElementString(dataSource, publicPath) {
return Object.getOwnPropertyNames(dataSource)
- .map(function(name) {
+ .map(function (name) {
if (Array.isArray(dataSource[name])) {
- return dataSource[name].map(function(attrs) { return createTag(name, attrs, publicPath); } );
+ return dataSource[name].map(function (attrs) {
+ return createTag(name, attrs, publicPath);
+ });
} else {
- return [ createTag(name, dataSource[name], publicPath) ];
+ return [createTag(name, dataSource[name], publicPath)];
}
})
- .reduce(function(arr, curr) {
+ .reduce(function (arr, curr) {
return arr.concat(curr);
}, [])
.join('\n\t');
}
+
+class HtmlElementsPlugin {
+ constructor(locations) {
+ this.locations = locations;
+ }
+
+ /* istanbul ignore next: this would be integration tests */
+ apply(compiler) {
+ compiler.hooks.compilation.tap('HtmlElementsPlugin', compilation => {
+ compilation.options.htmlElements = compilation.options.htmlElements || {};
+ compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync('HtmlElementsPlugin',
+ (htmlPluginData, callback) => {
+
+ const locations = this.locations;
+ if (locations) {
+ const publicPath = htmlPluginData.assets.publicPath;
+
+ Object.getOwnPropertyNames(locations).forEach(function (loc) {
+
+ compilation.options.htmlElements[loc] = getHtmlElementString(locations[loc], publicPath);
+ });
+ }
+
+ // return htmlPluginData;
+ callback(null, htmlPluginData);
+ }
+ );
+ });
+ }
+}
+
module.exports = HtmlElementsPlugin;
+
diff --git a/config/karma.conf.js b/config/karma.conf.js
index d2e2956858..f83c39b604 100644
--- a/config/karma.conf.js
+++ b/config/karma.conf.js
@@ -1,39 +1,59 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-module.exports = function(config) {
- var testWebpackConfig = require('./webpack.test.js')({env: 'test'});
+module.exports = function (config) {
+ const testWebpackConfig = require('./webpack.test.js')({ env: 'test' });
- var configuration = {
+ const configuration = {
- // base path that will be used to resolve all patterns (e.g. files, exclude)
+ /**
+ * Base path that will be used to resolve all patterns (e.g. files, exclude).
+ */
basePath: '',
- /*
+ /**
* Frameworks to use
*
* available frameworks: https://npmjs.org/browse/keyword/karma-adapter
*/
frameworks: ['jasmine'],
- // list of files to exclude
- exclude: [ ],
+ /**
+ * List of files to exclude.
+ */
+ exclude: [],
- /*
- * list of files / patterns to load in the browser
+ client: {
+ captureConsole: false
+ },
+
+ /**
+ * List of files / patterns to load in the browser
*
* we are building the test environment in ./spec-bundle.js
*/
- files: [ { pattern: './config/spec-bundle.js', watched: false } ],
+ files: [
+ { pattern: './config/spec-bundle.js', watched: false },
+ { pattern: './src/assets/**/*', watched: false, included: false, served: true, nocache: false }
+ ],
+
+ /**
+ * By default all assets are served at http://localhost:[PORT]/base/
+ */
+ proxies: {
+ "/assets/": "/base/src/assets/"
+ },
- /*
- * preprocess matching files before serving them to the browser
+ /**
+ * Preprocess matching files before serving them to the browser
* available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
*/
preprocessors: { './config/spec-bundle.js': ['coverage', 'webpack', 'sourcemap'] },
- // Webpack Config at ./webpack.test.js
+ /**
+ * Webpack Config at ./webpack.test.js
+ */
webpack: testWebpackConfig,
coverageReporter: {
@@ -46,58 +66,111 @@ module.exports = function(config) {
html: './coverage/html'
},
- // Webpack please don't spam the console when running in karma!
- webpackMiddleware: { stats: 'errors-only'},
+ /**
+ * Webpack please don't spam the console when running in karma!
+ */
+ webpackMiddleware: {
+ /**
+ * webpack-dev-middleware configuration
+ * i.e.
+ */
+ logLevel: 'warn',
+ /**
+ * and use stats to turn off verbose output
+ */
+ stats: {
+ /**
+ * options i.e.
+ */
+ chunks: false
+ }
+ },
- /*
- * test results reporter to use
+ /**
+ * Test results reporter to use
*
* possible values: 'dots', 'progress'
* available reporters: https://npmjs.org/browse/keyword/karma-reporter
*/
- reporters: [ 'mocha', 'coverage', 'remap-coverage' ],
+ reporters: ['mocha', 'coverage', 'remap-coverage'],
- // web server port
+ /**
+ * Web server port.
+ */
port: 9876,
- // enable / disable colors in the output (reporters and logs)
+ /**
+ * enable / disable colors in the output (reporters and logs)
+ */
colors: true,
- /*
- * level of logging
+ /**
+ * Level of logging
* possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
*/
- logLevel: config.LOG_INFO,
+ logLevel: config.LOG_WARN,
- // enable / disable watching file and executing tests whenever any file changes
- autoWatch: false,
+ /**
+ * enable / disable watching file and executing tests whenever any file changes
+ */
+ autoWatch: true,
- /*
+ /**
* start these browsers
* available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
*/
browsers: [
- 'Chrome'
+ 'ChromeTravisCi'
],
customLaunchers: {
ChromeTravisCi: {
- base: 'Chrome',
- flags: ['--no-sandbox']
+ base: 'ChromeHeadless',
+ flags: ['--no-sandbox', '--disable-gpu']
}
},
- /*
+ /**
* Continuous Integration mode
* if true, Karma captures browsers, runs the tests and exits
*/
- singleRun: true
+ singleRun: false,
+
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+
+ /**
+ * For slower machines you may need to have a longer browser
+ * wait time . Uncomment the line below if required.
+ */
+ // browserNoActivityTimeout: 30000
+
};
- if (process.env.TRAVIS){
+ // Optional Sonar Qube Reporter
+ if (process.env.SONAR_QUBE) {
+
+ // SonarQube reporter plugin configuration
+ configuration.sonarQubeUnitReporter = {
+ sonarQubeVersion: '5.x',
+ outputFile: 'reports/ut_report.xml',
+ overrideTestDescription: true,
+ testPath: 'src/app',
+ testFilePattern: '.spec.ts',
+ useBrowserName: false
+ };
+
+ // Additional lcov format required for
+ // sonarqube
+ configuration.remapCoverageReporter.lcovonly = './coverage/coverage.lcov';
+
+ configuration.reporters.push('sonarqubeUnit');
+ }
+
+ if (process.env.TRAVIS) {
configuration.browsers = [
- 'ChromeTravisCi',
- 'PhantomJS'
+ 'ChromeTravisCi'
];
}
diff --git a/config/modules/angular2-hmr-prod.js b/config/modules/angular2-hmr-prod.js
deleted file mode 100644
index 26fce4699f..0000000000
--- a/config/modules/angular2-hmr-prod.js
+++ /dev/null
@@ -1,3 +0,0 @@
-exports.HmrState = function() {
-
-};
diff --git a/config/nginx-custom.conf b/config/nginx-custom.conf
new file mode 100644
index 0000000000..8e1dbe59d9
--- /dev/null
+++ b/config/nginx-custom.conf
@@ -0,0 +1,19 @@
+server {
+ listen 80;
+
+ gzip on;
+ gzip_http_version 1.1;
+ gzip_disable "MSIE [1-6]\.";
+ gzip_min_length 1100;
+ gzip_vary on;
+ gzip_proxied expired no-cache no-store private auth;
+ gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
+ gzip_comp_level 5;
+
+ root /usr/share/nginx/html;
+
+ location / {
+ index index.html index.htm;
+ try_files $uri $uri/ /index.html =404;
+ }
+}
diff --git a/config/protractor.conf.js b/config/protractor.conf.js
index 989911d5e7..e3cf3f9d03 100644
--- a/config/protractor.conf.js
+++ b/config/protractor.conf.js
@@ -1,5 +1,5 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
require('ts-node/register');
@@ -8,30 +8,32 @@ var helpers = require('./helpers');
exports.config = {
baseUrl: 'http://localhost:3000/',
- // use `npm run e2e`
+ /**
+ * Use `npm run e2e`
+ */
specs: [
helpers.root('src/**/**.e2e.ts'),
helpers.root('src/**/*.e2e.ts')
],
exclude: [],
- framework: 'jasmine2',
+ framework: 'jasmine',
- allScriptsTimeout: 110000,
+ allScriptsTimeout: 11000,
jasmineNodeOpts: {
showTiming: true,
showColors: true,
isVerbose: false,
includeStackTrace: false,
- defaultTimeoutInterval: 400000
+ defaultTimeoutInterval: 40000
},
- directConnect: true,
+ directConnect: true,
capabilities: {
- 'browserName': 'chrome',
- 'chromeOptions': {
- 'args': ['show-fps-counter=true']
+ browserName: 'chrome',
+ chromeOptions: {
+ args: [ "--headless", "--disable-gpu", "--window-size=800x600", "--no-sandbox" ]
}
},
@@ -45,5 +47,7 @@ exports.config = {
* useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
* `rootEl`
*/
- useAllAngular2AppRoots: true
+ useAllAngular2AppRoots: true,
+
+ SELENIUM_PROMISE_MANAGER: false,
};
diff --git a/config/resource-override.js b/config/resource-override.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/config/spec-bundle.js b/config/spec-bundle.js
index 63a0f14a31..9906c2179e 100644
--- a/config/spec-bundle.js
+++ b/config/spec-bundle.js
@@ -1,8 +1,8 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-/*
+/**
* When testing with webpack and ES6, we have to do some extra
* things to get testing to work right. Because we are gonna write tests
* in ES6 too, we have to compile those as well. That's handled in
@@ -16,9 +16,6 @@ Error.stackTraceLimit = Infinity;
require('core-js/es6');
require('core-js/es7/reflect');
-// Typescript emit helpers polyfill
-require('ts-helpers');
-
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy'); // since zone.js 0.6.15
@@ -27,9 +24,6 @@ require('zone.js/dist/jasmine-patch'); // put here since zone.js 0.6.14
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
-// RxJS
-require('rxjs/Rx');
-
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
@@ -38,7 +32,7 @@ testing.TestBed.initTestEnvironment(
browser.platformBrowserDynamicTesting()
);
-/*
+/**
* Ok, this is kinda crazy. We can use the context method on
* require that webpack created in order to tell webpack
* what files we actually want to require or import.
@@ -49,8 +43,8 @@ testing.TestBed.initTestEnvironment(
*/
var testContext = require.context('../src', true, /\.spec\.ts/);
-/*
- * get all the files, for each file, call the context function
+/**
+ * Get all the files, for each file, call the context function
* that will require the file and load it up here. Context will
* loop and require those spec files here
*/
@@ -58,5 +52,7 @@ function requireAll(requireContext) {
return requireContext.keys().map(requireContext);
}
-// requires and returns all modules that match
+/**
+ * Requires and returns all modules that match
+ */
var modules = requireAll(testContext);
diff --git a/config/webpack.common.js b/config/webpack.common.js
index e454bc5e71..23d6648a0a 100644
--- a/config/webpack.common.js
+++ b/config/webpack.common.js
@@ -1,198 +1,187 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-const webpack = require('webpack');
const helpers = require('./helpers');
-/*
+/**
* Webpack Plugins
+ *
+ * problem with copy-webpack-plugin
*/
-// problem with copy-webpack-plugin
-const AssetsPlugin = require('assets-webpack-plugin');
-const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
-const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
+const DefinePlugin = require('webpack/lib/DefinePlugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
-const ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;
const HtmlElementsPlugin = require('./html-elements-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
-const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
+const WebpackInlineManifestPlugin = require('webpack-inline-manifest-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
+const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin;
-/*
- * Webpack Constants
- */
-const HMR = helpers.hasProcessFlag('hot');
-const METADATA = {
- title: 'Angular2 Webpack Starter by @gdi2290 from @AngularClass',
- baseUrl: '/',
- isDevServer: helpers.isWebpackDevServer()
-};
+const buildUtils = require('./build-utils');
-/*
+/**
* Webpack configuration
*
- * See: http://webpack.github.io/docs/configuration.html#cli
+ * See: https://webpack.js.org/configuration/
*/
-module.exports = function (options) {
- isProd = options.env === 'production';
- return {
+module.exports = function(options) {
+ const isProd = options.env === 'production';
+ const APP_CONFIG = require(process.env.ANGULAR_CONF_FILE || (isProd ? './config.prod.json' : './config.dev.json'));
- /*
- * Cache generated modules and chunks to improve performance for multiple incremental builds.
- * This is enabled by default in watch mode.
- * You can pass false to disable it.
- *
- * See: http://webpack.github.io/docs/configuration.html#cache
- */
- //cache: false,
+ const METADATA = Object.assign({}, buildUtils.DEFAULT_METADATA, options.metadata || {});
+ const GTM_API_KEY = process.env.GTM_API_KEY || APP_CONFIG.gtmKey;
- /*
+ const ngcWebpackConfig = buildUtils.ngcWebpackSetup(isProd, METADATA);
+ const supportES2015 = buildUtils.supportES2015(METADATA.tsConfigPath);
+
+ const entry = {
+ polyfills: './src/polyfills.browser.ts',
+ main: './src/main.browser.ts'
+ };
+
+ Object.assign(ngcWebpackConfig.plugin, {
+ tsConfigPath: METADATA.tsConfigPath,
+ mainPath: entry.main
+ });
+
+ return {
+ /**
* The entry point for the bundle
* Our Angular.js app
*
- * See: http://webpack.github.io/docs/configuration.html#entry
+ * See: https://webpack.js.org/configuration/entry-context/#entry
*/
- entry: {
-
- 'polyfills': './src/polyfills.browser.ts',
- 'vendor': './src/vendor.browser.ts',
- 'main': './src/main.browser.ts'
-
- },
+ entry: entry,
- /*
+ /**
* Options affecting the resolving of modules.
*
- * See: http://webpack.github.io/docs/configuration.html#resolve
+ * See: https://webpack.js.org/configuration/resolve/
*/
resolve: {
+ mainFields: [...(supportES2015 ? ['es2015'] : []), 'browser', 'module', 'main'],
- /*
+ /**
* An array of extensions that should be used to resolve modules.
*
- * See: http://webpack.github.io/docs/configuration.html#resolve-extensions
+ * See: https://webpack.js.org/configuration/resolve/#resolve-extensions
*/
extensions: ['.ts', '.js', '.json'],
- // An array of directory names to be resolved to the current directory
- modules: [helpers.root('src'), 'node_modules'],
+ /**
+ * An array of directory names to be resolved to the current directory
+ */
+ modules: [helpers.root('src'), helpers.root('node_modules')],
+ /**
+ * Add support for lettable operators.
+ *
+ * For existing codebase a refactor is required.
+ * All rxjs operator imports (e.g. `import 'rxjs/add/operator/map'` or `import { map } from `rxjs/operator/map'`
+ * must change to `import { map } from 'rxjs/operators'` (note that all operators are now under that import.
+ * Additionally some operators have changed to to JS keyword constraints (do => tap, catch => catchError)
+ *
+ * Remember to use the `pipe()` method to chain operators, this functinoally makes lettable operators similar to
+ * the old operators usage paradigm.
+ *
+ * For more details see:
+ * https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking
+ *
+ * If you are not planning on refactoring your codebase (or not planning on using imports from `rxjs/operators`
+ * comment out this line.
+ *
+ * BE AWARE that not using lettable operators will probably result in significant payload added to your bundle.
+ */
+ alias: buildUtils.rxjsAlias(supportES2015)
},
- /*
+ /**
* Options affecting the normal modules.
*
- * See: http://webpack.github.io/docs/configuration.html#module
+ * See: https://webpack.js.org/configuration/module/
*/
module: {
-
rules: [
+ ...ngcWebpackConfig.loaders,
- /*
- * Typescript loader support for .ts and Angular 2 async routes via .async.ts
- * Replace templateUrl and stylesUrl with require()
- *
- * See: https://github.com/s-panferov/awesome-typescript-loader
- * See: https://github.com/TheLarkInn/angular2-template-loader
- */
- {
- test: /\.ts$/,
- loaders: [
- '@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd,
- 'awesome-typescript-loader',
- 'angular2-template-loader'
- ],
- exclude: [/\.(spec|e2e)\.ts$/]
- },
-
- /*
- * Json loader support for *.json files.
+ /**
+ * To string and css loader support for *.css files (from Angular components)
+ * Returns file content as string
*
- * See: https://github.com/webpack/json-loader
*/
{
- test: /\.json$/,
- loader: 'json-loader'
+ test: /\.css$/,
+ use: ['to-string-loader', 'css-loader'],
+ exclude: [helpers.root('src', 'styles')]
},
- /*
- * to string and css loader support for *.css files
- * Returns file content as string
+ /**
+ * To string and sass loader support for *.scss files (from Angular components)
+ * Returns compiled css content as string
*
*/
{
- test: /\.css$/,
- loaders: ['to-string-loader', 'css-loader']
+ test: /\.scss$/,
+ use: ['to-string-loader', 'css-loader', 'sass-loader'],
+ exclude: [helpers.root('src', 'styles')]
},
- /* Raw loader support for *.html
+ /**
+ * Raw loader support for *.html
* Returns file content as string
*
* See: https://github.com/webpack/raw-loader
*/
{
test: /\.html$/,
- loader: 'raw-loader',
+ use: 'raw-loader',
exclude: [helpers.root('src/index.html')]
},
- /* File loader for supporting images, for example, in CSS files.
+ /**
+ * File loader for supporting images, for example, in CSS files.
*/
{
test: /\.(jpg|png|gif)$/,
- loader: 'file'
+ use: 'file-loader'
},
- ],
-
+ /* File loader for supporting fonts, for example, in CSS files.
+ */
+ {
+ test: /\.(eot|woff2?|svg|ttf)([\?]?.*)$/,
+ use: 'file-loader'
+ }
+ ]
},
- /*
+ /**
* Add additional plugins to the compiler.
*
- * See: http://webpack.github.io/docs/configuration.html#plugins
+ * See: https://webpack.js.org/configuration/plugins/
*/
plugins: [
- new AssetsPlugin({
- path: helpers.root('dist'),
- filename: 'webpack-assets.json',
- prettyPrint: true
- }),
-
- /*
- * Plugin: ForkCheckerPlugin
- * Description: Do type checking in a separate process, so webpack don't need to wait.
+ /**
+ * Plugin: DefinePlugin
+ * Description: Define free variables.
+ * Useful for having development builds with debug logging or adding global constants.
*
- * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
- */
- new ForkCheckerPlugin(),
- /*
- * Plugin: CommonsChunkPlugin
- * Description: Shares common code between the pages.
- * It identifies common modules and put them into a commons chunk.
+ * Environment helpers
*
- * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
- * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app
+ * See: https://webpack.js.org/plugins/define-plugin/
*/
- new CommonsChunkPlugin({
- name: ['polyfills', 'vendor'].reverse()
+ // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
+ new DefinePlugin({
+ ENV: JSON.stringify(METADATA.ENV),
+ HMR: METADATA.HMR,
+ AOT: METADATA.AOT,
+ 'process.env.ENV': JSON.stringify(METADATA.ENV),
+ 'process.env.NODE_ENV': JSON.stringify(METADATA.ENV),
+ 'process.env.HMR': METADATA.HMR
+ // 'FIREBASE_CONFIG': JSON.stringify(APP_CONFIG.firebase),
}),
/**
- * Plugin: ContextReplacementPlugin
- * Description: Provides context to Angular's use of System.import
- *
- * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin
- * See: https://github.com/angular/angular/issues/11580
- */
- new ContextReplacementPlugin(
- // The (\\|\/) piece accounts for path separators in *nix and Windows
- /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
- helpers.root('src') // location of your src
- ),
-
- /*
* Plugin: CopyWebpackPlugin
* Description: Copy files and directories in webpack.
*
@@ -200,31 +189,40 @@ module.exports = function (options) {
*
* See: https://www.npmjs.com/package/copy-webpack-plugin
*/
- new CopyWebpackPlugin([{
- from: 'src/assets',
- to: 'assets',
- }, {
- from: 'src/meta',
- }, ]),
-
+ new CopyWebpackPlugin(
+ [{ from: 'src/assets', to: 'assets' }, { from: 'src/meta' }],
+ isProd ? { ignore: ['mock-data/**/*'] } : undefined
+ ),
/*
- * Plugin: HtmlWebpackPlugin
- * Description: Simplifies creation of HTML files to serve your webpack bundles.
- * This is especially useful for webpack bundles that include a hash in the filename
- * which changes every compilation.
- *
- * See: https://github.com/ampedandwired/html-webpack-plugin
- */
+ * Plugin: HtmlWebpackPlugin
+ * Description: Simplifies creation of HTML files to serve your webpack bundles.
+ * This is especially useful for webpack bundles that include a hash in the filename
+ * which changes every compilation.
+ *
+ * See: https://github.com/ampedandwired/html-webpack-plugin
+ */
new HtmlWebpackPlugin({
template: 'src/index.html',
title: METADATA.title,
- chunksSortMode: 'dependency',
+ chunksSortMode: function(a, b) {
+ const entryPoints = ['inline', 'polyfills', 'sw-register', 'styles', 'vendor', 'main'];
+ return entryPoints.indexOf(a.names[0]) - entryPoints.indexOf(b.names[0]);
+ },
metadata: METADATA,
- inject: 'head'
+ gtmKey: GTM_API_KEY,
+ inject: 'body',
+ xhtml: true,
+ minify: isProd
+ ? {
+ caseSensitive: true,
+ collapseWhitespace: true,
+ keepClosingSlash: true
+ }
+ : false
}),
- /*
+ /**
* Plugin: ScriptExtHtmlWebpackPlugin
* Description: Enhances html-webpack-plugin functionality
* with different deployment options for your scripts including:
@@ -232,11 +230,14 @@ module.exports = function (options) {
* See: https://github.com/numical/script-ext-html-webpack-plugin
*/
new ScriptExtHtmlWebpackPlugin({
- defaultAttribute: 'defer'
+ sync: /inline|polyfills|vendor/,
+ defaultAttribute: 'async',
+ preload: [/polyfills|vendor|main/],
+ prefetch: [/chunk/]
}),
- /*
- * Plugin: HtmlHeadConfigPlugin
+ /**
+ * Plugin: HtmlElementsPlugin
* Description: Generate html tags based on javascript maps.
*
* If a publicPath is set in the webpack output configuration, it will be automatically added to
@@ -261,20 +262,22 @@ module.exports = function (options) {
headTags: require('./head-config.common')
}),
+ new AngularCompilerPlugin(ngcWebpackConfig.plugin),
+
/**
- * Plugin LoaderOptionsPlugin (experimental)
+ * Plugin: WebpackInlineManifestPlugin
+ * Inline Webpack's manifest.js in index.html
*
- * See: https://gist.github.com/sokra/27b24881210b56bbaff7
+ * https://github.com/almothafar/webpack-inline-manifest-plugin
*/
- new LoaderOptionsPlugin({}),
-
+ new WebpackInlineManifestPlugin()
],
- /*
+ /**
* Include polyfills or mocks for various node stuff
* Description: Node configuration
*
- * See: https://webpack.github.io/docs/configuration.html#node
+ * See: https://webpack.js.org/configuration/node/
*/
node: {
global: true,
@@ -284,6 +287,5 @@ module.exports = function (options) {
clearImmediate: false,
setImmediate: false
}
-
};
-}
+};
diff --git a/config/webpack.dev.js b/config/webpack.dev.js
old mode 100644
new mode 100755
index d0680a3bd4..ecabb3a16f
--- a/config/webpack.dev.js
+++ b/config/webpack.dev.js
@@ -1,59 +1,49 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
const helpers = require('./helpers');
+const buildUtils = require('./build-utils');
const webpackMerge = require('webpack-merge'); // used to merge webpack configs
const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev
/**
* Webpack Plugins
*/
-const DefinePlugin = require('webpack/lib/DefinePlugin');
-const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
-/**
- * Webpack Constants
- */
-const ENV = process.env.ENV = process.env.NODE_ENV = 'development';
-const HOST = process.env.HOST || 'localhost';
-const PORT = process.env.PORT || 3000;
-const HMR = helpers.hasProcessFlag('hot');
-const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
- host: HOST,
- port: PORT,
- ENV: ENV,
- HMR: HMR
-});
-
/**
* Webpack configuration
*
- * See: http://webpack.github.io/docs/configuration.html#cli
+ * See: https://webpack.js.org/configuration/
*/
-module.exports = function (options) {
- return webpackMerge(commonConfig({env: ENV}), {
+module.exports = function(options) {
+ const ENV = (process.env.ENV = process.env.NODE_ENV = 'development');
+ const HOST = process.env.HOST || 'localhost';
+ const PORT = process.env.PORT || 3000;
+
+ const METADATA = Object.assign({}, buildUtils.DEFAULT_METADATA, {
+ host: HOST,
+ port: PORT,
+ ENV: ENV,
+ HMR: helpers.hasProcessFlag('hot'),
+ PUBLIC: process.env.PUBLIC_DEV || HOST + ':' + PORT
+ });
- /**
- * Developer tool to enhance debugging
- *
- * See: http://webpack.github.io/docs/configuration.html#devtool
- * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
- */
- devtool: 'cheap-module-source-map',
+ return webpackMerge(commonConfig({ env: ENV, metadata: METADATA }), {
+ mode: 'development',
+ devtool: 'inline-source-map',
/**
* Options affecting the output of the compilation.
*
- * See: http://webpack.github.io/docs/configuration.html#output
+ * See: https://webpack.js.org/configuration/output/
*/
output: {
-
/**
* The output directory as absolute path (required).
*
- * See: http://webpack.github.io/docs/configuration.html#output-path
+ * See: https://webpack.js.org/configuration/output/#output-path
*/
path: helpers.root('dist'),
@@ -61,7 +51,7 @@ module.exports = function (options) {
* Specifies the name of each output file on disk.
* IMPORTANT: You must not specify an absolute path here!
*
- * See: http://webpack.github.io/docs/configuration.html#output-filename
+ * See: https://webpack.js.org/configuration/output/#output-filename
*/
filename: '[name].bundle.js',
@@ -69,51 +59,48 @@ module.exports = function (options) {
* The filename of the SourceMaps for the JavaScript files.
* They are inside the output.path directory.
*
- * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
+ * See: https://webpack.js.org/configuration/output/#output-sourcemapfilename
*/
- sourceMapFilename: '[name].map',
+ sourceMapFilename: '[file].map',
/** The filename of non-entry chunks as relative path
* inside the output.path directory.
*
- * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
+ * See: https://webpack.js.org/configuration/output/#output-chunkfilename
*/
chunkFilename: '[id].chunk.js',
library: 'ac_[name]',
- libraryTarget: 'var',
+ libraryTarget: 'var'
},
- plugins: [
-
- /**
- * Plugin: DefinePlugin
- * Description: Define free variables.
- * Useful for having development builds with debug logging or adding global constants.
- *
- * Environment helpers
- *
- * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
- */
- // NOTE: when adding more properties, make sure you include them in custom-typings.d.ts
- new DefinePlugin({
- 'ENV': JSON.stringify(METADATA.ENV),
- 'HMR': METADATA.HMR,
- 'process.env': {
- 'ENV': JSON.stringify(METADATA.ENV),
- 'NODE_ENV': JSON.stringify(METADATA.ENV),
- 'HMR': METADATA.HMR,
+ module: {
+ rules: [
+ /**
+ * Css loader support for *.css files (styles directory only)
+ * Loads external css styles into the DOM, supports HMR
+ *
+ */
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader'],
+ include: [helpers.root('src', 'styles')]
+ },
+
+ /**
+ * Sass loader support for *.scss files (styles directory only)
+ * Loads external sass styles into the DOM, supports HMR
+ *
+ */
+ {
+ test: /\.scss$/,
+ use: ['style-loader', 'css-loader', 'sass-loader'],
+ include: [helpers.root('src', 'styles')]
}
- }),
-
- /**
- * Plugin: NamedModulesPlugin (experimental)
- * Description: Uses file names as module name.
- *
- * See: https://github.com/webpack/webpack/commit/a04ffb928365b19feb75087c63f13cadfc08e1eb
- */
- new NamedModulesPlugin(),
+ ]
+ },
+ plugins: [
/**
* Plugin LoaderOptionsPlugin (experimental)
*
@@ -121,23 +108,8 @@ module.exports = function (options) {
*/
new LoaderOptionsPlugin({
debug: true,
- options: {
-
- /**
- * Static analysis linter for TypeScript advanced options configuration
- * Description: An extensible linter for the TypeScript language.
- *
- * See: https://github.com/wbuchwalter/tslint-loader
- */
- tslint: {
- emitErrors: false,
- failOnHint: false,
- resourcePath: 'src'
- },
-
- }
- }),
-
+ options: {}
+ })
],
/**
@@ -146,24 +118,38 @@ module.exports = function (options) {
* The server emits information about the compilation state to the client,
* which reacts to those events.
*
- * See: https://webpack.github.io/docs/webpack-dev-server.html
+ * See: https://webpack.js.org/configuration/dev-server/
*/
devServer: {
port: METADATA.port,
host: METADATA.host,
+ hot: METADATA.HMR,
+ public: METADATA.PUBLIC,
historyApiFallback: true,
watchOptions: {
- aggregateTimeout: 300,
- poll: 1000
+ // if you're using Docker you may need this
+ // aggregateTimeout: 300,
+ // poll: 1000,
+ ignored: /node_modules/
},
- outputPath: helpers.root('dist')
+ /**
+ * Here you can access the Express app object and add your own custom middleware to it.
+ *
+ * See: https://webpack.js.org/configuration/dev-server/
+ */
+ setup: function(app) {
+ // For example, to define custom handlers for some paths:
+ // app.get('/some/path', function(req, res) {
+ // res.json({ custom: 'response' });
+ // });
+ }
},
- /*
+ /**
* Include polyfills or mocks for various node stuff
* Description: Node configuration
*
- * See: https://webpack.github.io/docs/configuration.html#node
+ * See: https://webpack.js.org/configuration/node/
*/
node: {
global: true,
@@ -171,8 +157,8 @@ module.exports = function (options) {
process: true,
module: false,
clearImmediate: false,
- setImmediate: false
+ setImmediate: false,
+ fs: 'empty'
}
-
});
-}
+};
diff --git a/config/webpack.github-deploy.js b/config/webpack.github-deploy.js
index 5ad45191b0..7211e2b866 100644
--- a/config/webpack.github-deploy.js
+++ b/config/webpack.github-deploy.js
@@ -1,12 +1,11 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
+const fs = require('fs');
+const path = require('path');
const helpers = require('./helpers');
const ghDeploy = require('./github-deploy');
const webpackMerge = require('webpack-merge'); // used to merge webpack configs
-const ghpages = require('gh-pages');
-const webpackConfig = ghDeploy.getWebpackConfigModule(); // the settings that are common to prod and dev
-
/**
* Webpack Constants
@@ -15,65 +14,68 @@ const GIT_REMOTE_NAME = 'origin';
const COMMIT_MESSAGE = 'Updates';
const GH_REPO_NAME = ghDeploy.getRepoName(GIT_REMOTE_NAME);
-const METADATA = webpackMerge(webpackConfig.metadata, {
- /**
- * Prefixing the REPO name to the baseUrl for router support.
- * This also means all resource URIs (CSS/Images/JS) will have this prefix added by the browser
- * unless they are absolute (start with '/'). We will handle it via `output.publicPath`
- */
- baseUrl: '/' + GH_REPO_NAME + '/' + ghDeploy.safeUrl(webpackConfig.metadata.baseUrl)
-});
+module.exports = function(options) {
+ const webpackConfigFactory = ghDeploy.getWebpackConfigModule(options); // the settings that are common to prod and dev
+ const webpackConfig = webpackConfigFactory(options);
-module.exports = webpackMerge(webpackConfig, {
/**
- * Merged metadata from webpack.common.js for index.html
- *
- * See: (custom attribute)
+ * Replace the instance of HtmlWebpackPlugin with an updated one.
*/
- metadata: METADATA,
+ ghDeploy.replaceHtmlWebpackPlugin(webpackConfig.plugins, GH_REPO_NAME);
+ return webpackMerge(webpackConfig, {
- output: {
- /**
- * The public path is set to the REPO name.
- *
- * `HtmlElementsPlugin` will add it to all resources url's created by it.
- * `HtmlWebpackPlugin` will add it to all webpack bundels/chunks.
- *
- * In theory publicPath shouldn't be used since the browser should automatically prefix the
- * `baseUrl` into all URLs, however this is not the case when the URL is absolute (start with /)
- *
- * It's important to prefix & suffix the repo name with a slash (/).
- * Prefixing so every resource will be absolute (otherwise it will be url.com/repoName/repoName...
- * Suffixing since chunks will not do it automatically (testes against about page)
- */
- publicPath: '/' + GH_REPO_NAME + '/' + ghDeploy.safeUrl(webpackConfig.output.publicPath)
- },
+ output: {
+ /**
+ * The public path is set to the REPO name.
+ *
+ * `HtmlElementsPlugin` will add it to all resources url's created by it.
+ * `HtmlWebpackPlugin` will add it to all webpack bundels/chunks.
+ *
+ * In theory publicPath shouldn't be used since the browser should automatically prefix the
+ * `baseUrl` into all URLs, however this is not the case when the URL is absolute (start with /)
+ *
+ * It's important to prefix & suffix the repo name with a slash (/).
+ * Prefixing so every resource will be absolute (otherwise it will be url.com/repoName/repoName...
+ * Suffixing since chunks will not do it automatically (testes against about page)
+ */
+ publicPath: '/' + GH_REPO_NAME + '/' + ghDeploy.safeUrl(webpackConfig.output.publicPath)
+ },
- plugins: [
- function() {
- this.plugin('done', function(stats) {
- console.log('Starting deployment to GitHub.');
+ plugins: [
+ function() {
+ this.plugin('done', function(stats) {
+ console.log('Starting deployment to GitHub.');
- const logger = function (msg) {
- console.log(msg);
- };
+ const logger = function(msg) {
+ console.log(msg);
+ };
- const options = {
- logger: logger,
- remote: GIT_REMOTE_NAME,
- message: COMMIT_MESSAGE
- };
+ const options = {
+ logger: logger,
+ remote: GIT_REMOTE_NAME,
+ message: COMMIT_MESSAGE,
+ dotfiles: true // for .nojekyll
+ };
+ /**
+ * Since GitHub moved to Jekyll 3.3, their server ignores the "node_modules" and "vendors" folder by default.
+ * but, as of now, it also ignores "vendors*" files.
+ * This means vendor.bundle.js or vendor.[chunk].bundle.js will return 404.
+ * this is the fix for now.
+ */
+ fs.writeFileSync(path.join(webpackConfig.output.path, '.nojekyll'), '');
- ghpages.publish(webpackConfig.output.path, options, function(err) {
- if (err) {
- console.log('GitHub deployment done. STATUS: ERROR.');
- throw err;
- } else {
- console.log('GitHub deployment done. STATUS: SUCCESS.');
- }
+ const ghpages = require('gh-pages');
+ ghpages.publish(webpackConfig.output.path, options, function(err) {
+ if (err) {
+ console.log('GitHub deployment done. STATUS: ERROR.');
+ throw err;
+ } else {
+ console.log('GitHub deployment done. STATUS: SUCCESS.');
+ }
+ });
});
- });
- }
- ]
-});
+ }
+ ]
+ });
+};
diff --git a/config/webpack.prod.js b/config/webpack.prod.js
index 64d3845211..99c4cc947b 100644
--- a/config/webpack.prod.js
+++ b/config/webpack.prod.js
@@ -1,58 +1,83 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-
const helpers = require('./helpers');
-const webpackMerge = require('webpack-merge'); // used to merge webpack configs
-const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev
+const buildUtils = require('./build-utils');
/**
- * Webpack Plugins
+ * Used to merge webpack configs
*/
-const DedupePlugin = require('webpack/lib/optimize/DedupePlugin');
-const DefinePlugin = require('webpack/lib/DefinePlugin');
-const IgnorePlugin = require('webpack/lib/IgnorePlugin');
-const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
-const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
-const ProvidePlugin = require('webpack/lib/ProvidePlugin');
-const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
-const WebpackMd5Hash = require('webpack-md5-hash');
+const webpackMerge = require('webpack-merge');
/**
- * Webpack Constants
+ * The settings that are common to prod and dev
*/
-const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
-const HOST = process.env.HOST || 'localhost';
-const PORT = process.env.PORT || 8080;
-const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
- host: HOST,
- port: PORT,
- ENV: ENV,
- HMR: false
-});
+const commonConfig = require('./webpack.common.js');
-module.exports = function (env) {
- return webpackMerge(commonConfig({env: ENV}), {
+/**
+ * Webpack Plugins
+ */
+
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const HashedModuleIdsPlugin = require('webpack/lib/HashedModuleIdsPlugin');
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
+
+/***
+ * Ref: https://github.com/mishoo/UglifyJS2/tree/harmony#minify-options
+ * @param supportES2015
+ * @param enableCompress disabling compress could improve the performance, see https://github.com/webpack/webpack/issues/4558#issuecomment-352255789
+ * @returns {{ecma: number, warnings: boolean, ie8: boolean, mangle: boolean, compress: {pure_getters: boolean, passes: number}, output: {ascii_only: boolean, comments: boolean}}}
+ */
+function getUglifyOptions(supportES2015, enableCompress) {
+ const uglifyCompressOptions = {
+ pure_getters: true /* buildOptimizer */,
+ // PURE comments work best with 3 passes.
+ // See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
+ passes: 2 /* buildOptimizer */
+ };
+
+ return {
+ ecma: supportES2015 ? 6 : 5,
+ warnings: false, // TODO verbose based on option?
+ ie8: false,
+ mangle: true,
+ compress: enableCompress ? uglifyCompressOptions : false,
+ output: {
+ ascii_only: true,
+ comments: false
+ }
+ };
+}
+
+module.exports = function(env) {
+ const ENV = (process.env.NODE_ENV = process.env.ENV = 'production');
+ const supportES2015 = buildUtils.supportES2015(buildUtils.DEFAULT_METADATA.tsConfigPath);
+ const sourceMapEnabled = process.env.SOURCE_MAP === '1';
+ const METADATA = Object.assign({}, buildUtils.DEFAULT_METADATA, {
+ host: process.env.HOST || 'localhost',
+ port: process.env.PORT || 8080,
+ ENV: ENV,
+ HMR: false
+ });
+
+ // set environment suffix so these environments are loaded.
+ METADATA.envFileSuffix = METADATA.E2E ? 'e2e.prod' : 'prod';
+
+ return webpackMerge(commonConfig({ env: ENV, metadata: METADATA }), {
+ mode: 'production',
- /**
- * Developer tool to enhance debugging
- *
- * See: http://webpack.github.io/docs/configuration.html#devtool
- * See: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
- */
devtool: 'source-map',
/**
* Options affecting the output of the compilation.
*
- * See: http://webpack.github.io/docs/configuration.html#output
+ * See: https://webpack.js.org/configuration/output/
*/
output: {
-
/**
* The output directory as absolute path (required).
*
- * See: http://webpack.github.io/docs/configuration.html#output-path
+ * See: https://webpack.js.org/configuration/output/#output-path
*/
path: helpers.root('dist'),
@@ -60,7 +85,7 @@ module.exports = function (env) {
* Specifies the name of each output file on disk.
* IMPORTANT: You must not specify an absolute path here!
*
- * See: http://webpack.github.io/docs/configuration.html#output-filename
+ * See: https://webpack.js.org/configuration/output/#output-filename
*/
filename: '[name].[chunkhash].bundle.js',
@@ -68,184 +93,79 @@ module.exports = function (env) {
* The filename of the SourceMaps for the JavaScript files.
* They are inside the output.path directory.
*
- * See: http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
+ * See: https://webpack.js.org/configuration/output/#output-sourcemapfilename
*/
- sourceMapFilename: '[name].[chunkhash].bundle.map',
+ sourceMapFilename: '[file].map',
/**
* The filename of non-entry chunks as relative path
* inside the output.path directory.
*
- * See: http://webpack.github.io/docs/configuration.html#output-chunkfilename
+ * See: https://webpack.js.org/configuration/output/#output-chunkfilename
*/
- chunkFilename: '[id].[chunkhash].chunk.js'
+ chunkFilename: '[name].[chunkhash].chunk.js'
+ },
+
+ module: {
+ rules: [
+ /**
+ * Extract CSS files from .src/styles directory to external CSS file
+ */
+ {
+ test: /\.css$/,
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ include: [helpers.root('src', 'styles')]
+ },
+
+ /**
+ * Extract and compile SCSS files from .src/styles directory to external CSS file
+ */
+ {
+ test: /\.scss$/,
+ use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
+ include: [helpers.root('src', 'styles')]
+ }
+ ]
+ },
+ optimization: {
+ minimizer: [
+ /**
+ * Plugin: UglifyJsPlugin
+ * Description: Minimize all JavaScript output of chunks.
+ * Loaders are switched into minimizing mode.
+ *
+ * See: https://webpack.js.org/plugins/uglifyjs-webpack-plugin/
+ *
+ * NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
+ */
+ new UglifyJsPlugin({
+ sourceMap: sourceMapEnabled,
+ parallel: true,
+ cache: helpers.root('webpack-cache/uglify-cache'),
+ uglifyOptions: getUglifyOptions(supportES2015, true)
+ })
+ ],
+ splitChunks: {
+ chunks: 'all'
+ }
},
/**
* Add additional plugins to the compiler.
*
- * See: http://webpack.github.io/docs/configuration.html#plugins
+ * See: https://webpack.js.org/configuration/plugins/
*/
plugins: [
-
- /**
- * Plugin: WebpackMd5Hash
- * Description: Plugin to replace a standard webpack chunkhash with md5.
- *
- * See: https://www.npmjs.com/package/webpack-md5-hash
- */
- new WebpackMd5Hash(),
-
- /**
- * Plugin: DedupePlugin
- * Description: Prevents the inclusion of duplicate code into your bundle
- * and instead applies a copy of the function at runtime.
- *
- * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
- * See: https://github.com/webpack/docs/wiki/optimization#deduplication
- */
- // new DedupePlugin(), // see: https://github.com/angular/angular-cli/issues/1587
-
- /**
- * Plugin: DefinePlugin
- * Description: Define free variables.
- * Useful for having development builds with debug logging or adding global constants.
- *
- * Environment helpers
- *
- * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
- */
- // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
- new DefinePlugin({
- 'ENV': JSON.stringify(METADATA.ENV),
- 'HMR': METADATA.HMR,
- 'process.env': {
- 'ENV': JSON.stringify(METADATA.ENV),
- 'NODE_ENV': JSON.stringify(METADATA.ENV),
- 'HMR': METADATA.HMR,
- }
- }),
-
- /**
- * Plugin: UglifyJsPlugin
- * Description: Minimize all JavaScript output of chunks.
- * Loaders are switched into minimizing mode.
- *
- * See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
- */
- // NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
- new UglifyJsPlugin({
- // beautify: true, //debug
- // mangle: false, //debug
- // dead_code: false, //debug
- // unused: false, //debug
- // deadCode: false, //debug
- // compress: {
- // screw_ie8: true,
- // keep_fnames: true,
- // drop_debugger: false,
- // dead_code: false,
- // unused: false
- // }, // debug
- // comments: true, //debug
-
-
- beautify: false, //prod
- mangle: {
- screw_ie8: true,
- keep_fnames: true
- }, //prod
- compress: {
- screw_ie8: true
- }, //prod
- comments: false //prod
- }),
-
- /**
- * Plugin: NormalModuleReplacementPlugin
- * Description: Replace resources that matches resourceRegExp with newResource
- *
- * See: http://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
- */
-
- new NormalModuleReplacementPlugin(
- /angular2-hmr/,
- helpers.root('config/modules/angular2-hmr-prod.js')
- ),
-
- /**
- * Plugin: IgnorePlugin
- * Description: Don’t generate modules for requests matching the provided RegExp.
- *
- * See: http://webpack.github.io/docs/list-of-plugins.html#ignoreplugin
- */
-
- // new IgnorePlugin(/angular2-hmr/),
-
- /**
- * Plugin: CompressionPlugin
- * Description: Prepares compressed versions of assets to serve
- * them with Content-Encoding
- *
- * See: https://github.com/webpack/compression-webpack-plugin
- */
- // install compression-webpack-plugin
- // new CompressionPlugin({
- // regExp: /\.css$|\.html$|\.js$|\.map$/,
- // threshold: 2 * 1024
- // })
-
- /**
- * Plugin LoaderOptionsPlugin (experimental)
- *
- * See: https://gist.github.com/sokra/27b24881210b56bbaff7
- */
- new LoaderOptionsPlugin({
- debug: false,
- options: {
-
- /**
- * Static analysis linter for TypeScript advanced options configuration
- * Description: An extensible linter for the TypeScript language.
- *
- * See: https://github.com/wbuchwalter/tslint-loader
- */
- tslint: {
- emitErrors: true,
- failOnHint: true,
- resourcePath: 'src'
- },
-
-
- /**
- * Html loader advanced options
- *
- * See: https://github.com/webpack/html-loader#advanced-options
- */
- // TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor
- htmlLoader: {
- minimize: true,
- removeAttributeQuotes: false,
- caseSensitive: true,
- customAttrSurround: [
- [/#/, /(?:)/],
- [/\*/, /(?:)/],
- [/\[?\(?/, /(?:)/]
- ],
- customAttrAssign: [/\)?\]?=/]
- },
-
- }
- }),
-
+ new MiniCssExtractPlugin({ filename: '[name]-[hash].css', chunkFilename: '[name]-[chunkhash].css' }),
+ new HashedModuleIdsPlugin()
],
- /*
+ /**
* Include polyfills or mocks for various node stuff
* Description: Node configuration
*
- * See: https://webpack.github.io/docs/configuration.html#node
+ * See: https://webpack.js.org/configuration/node/
*/
node: {
global: true,
@@ -253,8 +173,8 @@ module.exports = function (env) {
process: false,
module: false,
clearImmediate: false,
- setImmediate: false
+ setImmediate: false,
+ fs: 'empty'
}
-
});
-}
+};
diff --git a/config/webpack.test.js b/config/webpack.test.js
index 416df68e3b..6d08c7fd3d 100644
--- a/config/webpack.test.js
+++ b/config/webpack.test.js
@@ -1,9 +1,8 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
const helpers = require('./helpers');
-const path = require('path');
/**
* Webpack Plugins
@@ -16,16 +15,16 @@ const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin')
/**
* Webpack Constants
*/
-const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
+const ENV = (process.env.ENV = process.env.NODE_ENV = 'test');
/**
* Webpack configuration
*
- * See: http://webpack.github.io/docs/configuration.html#cli
+ * See: https://webpack.js.org/configuration/
*/
-module.exports = function (options) {
+module.exports = function(options) {
return {
-
+ mode: 'development',
/**
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack
*
@@ -37,45 +36,32 @@ module.exports = function (options) {
/**
* Options affecting the resolving of modules.
*
- * See: http://webpack.github.io/docs/configuration.html#resolve
+ * See: https://webpack.js.org/configuration/resolve/
*/
resolve: {
-
/**
* An array of extensions that should be used to resolve modules.
*
- * See: http://webpack.github.io/docs/configuration.html#resolve-extensions
+ * See: https://webpack.js.org/configuration/resolve/#resolve-extensions
*/
extensions: ['.ts', '.js'],
/**
* Make sure root is src
*/
- modules: [ path.resolve(__dirname, 'src'), 'node_modules' ]
-
+ modules: [helpers.root('src'), 'node_modules']
},
/**
* Options affecting the normal modules.
*
- * See: http://webpack.github.io/docs/configuration.html#module
+ * See: https://webpack.js.org/configuration/module/
+ *
+ * 'use:' revered back to 'loader:' as a temp. workaround for #1188
+ * See: https://github.com/gdi2290/angular-starter/issues/1188#issuecomment-262872034
*/
module: {
-
rules: [
-
- /**
- * Tslint loader support for *.ts files
- *
- * See: https://github.com/wbuchwalter/tslint-loader
- */
- {
- enforce: 'pre',
- test: /\.ts$/,
- loader: 'tslint-loader',
- exclude: [helpers.root('node_modules')]
- },
-
/**
* Source map loader support for *.js files
* Extracts SourceMaps for source files that as added as sourceMappingURL comment.
@@ -87,8 +73,9 @@ module.exports = function (options) {
test: /\.js$/,
loader: 'source-map-loader',
exclude: [
- // these packages have problems with their sourcemaps
- helpers.root('node_modules/rxjs'),
+ /**
+ * These packages have problems with their sourcemaps
+ */
helpers.root('node_modules/@angular')
]
},
@@ -100,42 +87,49 @@ module.exports = function (options) {
*/
{
test: /\.ts$/,
- loader: 'awesome-typescript-loader',
- query: {
- // use inline sourcemaps for "karma-remap-coverage" reporter
- sourceMap: false,
- inlineSourceMap: true,
- compilerOptions: {
-
- // Remove TypeScript helpers to be injected
- // below by DefinePlugin
- removeComments: true
-
- }
- },
+ use: [
+ {
+ loader: 'awesome-typescript-loader',
+ query: {
+ /**
+ * Use inline sourcemaps for "karma-remap-coverage" reporter
+ */
+ sourceMap: false,
+ inlineSourceMap: true,
+ compilerOptions: {
+ /**
+ * Remove TypeScript helpers to be injected
+ * below by DefinePlugin
+ */
+ removeComments: true
+ }
+ }
+ },
+ 'angular2-template-loader'
+ ],
exclude: [/\.e2e\.ts$/]
},
/**
- * Json loader support for *.json files.
+ * Raw loader support for *.css files
+ * Returns file content as string
*
- * See: https://github.com/webpack/json-loader
+ * See: https://github.com/webpack/raw-loader
*/
{
- test: /\.json$/,
- loader: 'json-loader',
+ test: /\.css$/,
+ loader: ['to-string-loader', { loader: 'css-loader', options: { url: false } }],
exclude: [helpers.root('src/index.html')]
},
/**
- * Raw loader support for *.css files
- * Returns file content as string
+ * Raw loader support for *.scss files
*
* See: https://github.com/webpack/raw-loader
*/
{
- test: /\.css$/,
- loaders: ['to-string-loader', 'css-loader'],
+ test: /\.scss$/,
+ loader: ['raw-loader', 'sass-loader'],
exclude: [helpers.root('src/index.html')]
},
@@ -162,22 +156,17 @@ module.exports = function (options) {
test: /\.(js|ts)$/,
loader: 'istanbul-instrumenter-loader',
include: helpers.root('src'),
- exclude: [
- /\.(e2e|spec)\.ts$/,
- /node_modules/
- ]
+ exclude: [/\.(e2e|spec)\.ts$/, /node_modules/]
}
-
]
},
/**
* Add additional plugins to the compiler.
*
- * See: http://webpack.github.io/docs/configuration.html#plugins
+ * See: https://webpack.js.org/configuration/plugins/
*/
plugins: [
-
/**
* Plugin: DefinePlugin
* Description: Define free variables.
@@ -185,16 +174,17 @@ module.exports = function (options) {
*
* Environment helpers
*
- * See: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
+ * See: https://webpack.js.org/plugins/define-plugin/
+ *
+ * NOTE: when adding more properties make sure you include them in custom-typings.d.ts
*/
- // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
new DefinePlugin({
- 'ENV': JSON.stringify(ENV),
- 'HMR': false,
+ ENV: JSON.stringify(ENV),
+ HMR: false,
'process.env': {
- 'ENV': JSON.stringify(ENV),
- 'NODE_ENV': JSON.stringify(ENV),
- 'HMR': false,
+ ENV: JSON.stringify(ENV),
+ NODE_ENV: JSON.stringify(ENV),
+ HMR: false
}
}),
@@ -202,55 +192,60 @@ module.exports = function (options) {
* Plugin: ContextReplacementPlugin
* Description: Provides context to Angular's use of System.import
*
- * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin
+ * See: https://webpack.js.org/plugins/context-replacement-plugin/
* See: https://github.com/angular/angular/issues/11580
*/
new ContextReplacementPlugin(
- // The (\\|\/) piece accounts for path separators in *nix and Windows
- /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
- helpers.root('src') // location of your src
+ /**
+ * The (\\|\/) piece accounts for path separators in *nix and Windows
+ */
+ /\@angular(\\|\/)core(\\|\/)esm5/,
+ helpers.root('src'), // location of your src
+ {
+ /**
+ * your Angular Async Route paths relative to this root directory
+ */
+ }
),
- /**
+ /**
* Plugin LoaderOptionsPlugin (experimental)
*
* See: https://gist.github.com/sokra/27b24881210b56bbaff7
*/
new LoaderOptionsPlugin({
- debug: true,
+ debug: false,
options: {
-
/**
- * Static analysis linter for TypeScript advanced options configuration
- * Description: An extensible linter for the TypeScript language.
- *
- * See: https://github.com/wbuchwalter/tslint-loader
+ * legacy options go here
*/
- tslint: {
- emitErrors: false,
- failOnHint: false,
- resourcePath: 'src'
- },
-
}
- }),
-
+ })
],
+ /**
+ * Disable performance hints
+ *
+ * See: https://github.com/a-tarasyuk/rr-boilerplate/blob/master/webpack/dev.config.babel.js#L41
+ */
+ performance: {
+ hints: false
+ },
+
/**
* Include polyfills or mocks for various node stuff
* Description: Node configuration
*
- * See: https://webpack.github.io/docs/configuration.html#node
+ * See: https://webpack.js.org/configuration/node/
*/
node: {
global: true,
- process: false,
crypto: 'empty',
+ process: false,
module: false,
clearImmediate: false,
- setImmediate: false
+ setImmediate: false,
+ fs: 'empty'
}
-
};
-}
+};
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000..7f61f3725c
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+version: '3'
+services:
+ angular-starter:
+ build:
+ context: .
+ dockerfile: Dockerfile-dev
+ container_name: angular-starter
+ networks:
+ - angular-starter
+ ports:
+ - '3000:3000'
+ environment:
+ - HOST=0.0.0.0
+ command: npm run start
+networks:
+ angular-starter:
+ driver: bridge
diff --git a/firebase.json b/firebase.json
new file mode 100644
index 0000000000..80e83f98d9
--- /dev/null
+++ b/firebase.json
@@ -0,0 +1,16 @@
+{
+ "hosting": {
+ "public": "dist",
+ "rewrites": [
+ {
+ "source": "**",
+ "destination": "/index.html"
+ }
+ ],
+ "ignore": [
+ "firebase.json",
+ "**/.*",
+ "**/node_modules/**"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/karma.conf.js b/karma.conf.js
index 27c49adca0..79ce74d23a 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -1,6 +1,8 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-// Look in ./config for karma.conf.js
+/**
+ * Look in ./config for karma.conf.js
+ */
module.exports = require('./config/karma.conf.js');
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 0000000000..dc8e367d34
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,3 @@
+[build]
+ command = "npm run build:prod"
+ publish = "dist"
diff --git a/package.json b/package.json
index 8d2ceb49bc..40135678b8 100644
--- a/package.json
+++ b/package.json
@@ -1,144 +1,183 @@
{
- "name": "angular2-webpack-starter",
- "version": "5.0.5",
- "description": "An Angular 2 Webpack Starter kit featuring Angular 2 (Router, Http, Forms, Services, Tests, E2E, Coverage), Karma, Protractor, Jasmine, Istanbul, TypeScript, and Webpack by AngularClass",
+ "name": "angular-starter",
+ "version": "7.5.0",
+ "description": "An Angular Webpack Starter kit featuring Angular (Router, Http, Forms, Services, Tests, E2E, Coverage), Karma, Protractor, Jasmine, Istanbul, TypeScript, and Webpack by Tipe.io",
"keywords": [
+ "angular",
"angular2",
+ "angular4",
+ "angular5",
"webpack",
- "typescript"
+ "typescript",
+ "tipe",
+ "tipe.io"
],
- "author": "Patrick Stapleton ",
- "homepage": "https://github.com/angularclass/angular2-webpack-starter",
+ "author": "Patrick Stapleton ",
+ "homepage": "https://github.com/gdi2290/angular-starter",
"license": "MIT",
"scripts": {
- "build:dev": "webpack --config config/webpack.dev.js --progress --profile",
- "build:docker": "npm run build:prod && docker build -t angular2-webpack-start:latest .",
- "build:prod": "webpack --config config/webpack.prod.js --progress --profile --bail",
+ "build:aot:prod": "rimraf dist compiled && cross-env BUILD_AOT=1 SOURCE_MAP=0 npm run webpack -- --config config/webpack.prod.js --progress --profile --bail",
+ "build:aot": "npm run build:aot:prod",
+ "build:aot:dev": "cross-env BUILD_AOT=1 npm run build:dev",
+ "build:dev": "rimraf dist && npm run webpack -- --config config/webpack.dev.js --mode development --progress --profile --trace-deprecation",
+ "build:docker": "npm run build:prod && docker build -t angular-webpack-starter:latest .",
+ "build:prod": "rimraf dist && npm run webpack -- --config config/webpack.prod.js --progress --profile --bail",
"build": "npm run build:dev",
- "ci": "npm run lint && npm test && npm run e2e",
+ "ci:aot": "cross-env BUILD_E2E=1 npm run lint && npm run test:ci && npm run build:aot && npm run e2e",
+ "ci:jit": "cross-env BUILD_E2E=1 npm run lint && npm run test:ci && npm run build:prod && npm run e2e",
+ "ci:nobuild": "npm run lint && npm test:ci && npm run e2e",
+ "ci:testall": "cross-env BUILD_E2E=1 npm run lint && npm run test:ci && npm run build:prod && npm run e2e && npm run build:aot && npm run e2e",
+ "ci:travis": "cross-env BUILD_E2E=1 npm run lint && npm run test:ci && npm run build:aot && npm run e2e:travis",
+ "ci": "npm run ci:testall",
+ "clean:all": "npm run rimraf -- doc coverage dist compiled webpack-cache",
+ "clean:cache": "npm run rimraf -- webpack-cache",
+ "clean:aot": "npm run rimraf -- compiled",
"clean:dist": "npm run rimraf -- dist",
"clean:install": "npm set progress=false && npm install",
- "clean:start": "npm start",
- "clean": "npm cache clean && npm run rimraf -- node_modules doc coverage dist",
+ "clean": "npm cache verify && npm run rimraf -- node_modules doc coverage dist compiled webpack-cache",
"docker": "docker",
"docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./src/",
- "e2e:live": "npm run e2e -- --elementExplorer",
- "e2e": "npm run protractor",
- "github-deploy:dev": "webpack --config config/webpack.github-deploy.js --progress --profile --github-dev",
- "github-deploy:prod": "webpack --config config/webpack.github-deploy.js --progress --profile --github-prod",
+ "docs:compodoc": "compodoc -p tsconfig.json",
+ "docs:compodoc:serve": "compodoc -p tsconfig.json -s",
+ "docs:compodoc:serve:watch": "compodoc -p tsconfig.json -s -w",
+ "e2e:live": "npm-run-all -p -r server:prod:ci protractor:live",
+ "e2e:travis": "npm-run-all -p -r server:prod:ci protractor:delay",
+ "e2e": "npm-run-all -p -r server:prod:ci protractor",
+ "github-deploy:dev": "npm run webpack -- --config config/webpack.github-deploy.js --mode development --progress --profile --env.githubDev",
+ "github-deploy:prod": "npm run webpack -- --config config/webpack.github-deploy.js --mode production --progress --profile --env.githubProd",
"github-deploy": "npm run github-deploy:dev",
"lint": "npm run tslint \"src/**/*.ts\"",
+ "node": "node",
+ "postinstall": "npm run webdriver:update",
"postversion": "git push && git push --tags",
- "prebuild:dev": "npm run clean:dist",
- "prebuild:prod": "npm run clean:dist",
"preclean:install": "npm run clean",
- "preclean:start": "npm run clean",
- "pree2e": "npm run webdriver:update -- --standalone",
"preversion": "npm test",
"protractor": "protractor",
+ "protractor:delay": "sleep 3 && npm run protractor",
+ "protractor:live": "protractor --elementExplorer",
"rimraf": "rimraf",
- "server:dev:hmr": "npm run server:dev -- --inline --hot",
- "server:dev": "webpack-dev-server --config config/webpack.dev.js --progress --profile --watch --content-base src/",
- "server:prod": "http-server dist --cors",
+ "server:dev:hmr": "npm run server:dev -- --hot --hotOnly",
+ "server:aot:dev": "cross-env BUILD_AOT=1 npm run server:dev",
+ "server:dev": "npm run webpack-dev-server -- --config config/webpack.dev.js --open --progress --profile --watch --content-base src/",
+ "server:prod": "http-server dist -c-1 --cors",
+ "server:prod:ci": "http-server dist -p 3000 -c-1 --cors",
"server": "npm run server:dev",
+ "start:prod:hmr": "cross-env ANGULAR_CONF_FILE=./config.prod.json npm run server:dev:hmr",
"start:hmr": "npm run server:dev:hmr",
"start": "npm run server:dev",
+ "start:aot": "npm run server:aot:dev",
"test": "karma start",
- "tslint": "tslint",
+ "test:sonar": "npm run lint && cross-env SONAR_QUBE=1 karma start",
+ "test:ci": "karma start --single-run --browsers ChromeTravisCi",
+ "tslint": "tslint \"src/**/*.ts\" --project tsconfig.json",
"typedoc": "typedoc",
"version": "npm run build",
"watch:dev:hmr": "npm run watch:dev -- --hot",
"watch:dev": "npm run build:dev -- --watch",
+ "watch:aot:dev": "npm run build:aot:dev -- --watch",
"watch:prod": "npm run build:prod -- --watch",
+ "watch:aot:prod": "npm run build:aot:prod -- --watch",
"watch:test": "npm run test -- --auto-watch --no-single-run",
"watch": "npm run watch:dev",
- "webdriver-manager": "webdriver-manager",
- "webdriver:start": "npm run webdriver-manager start",
- "webdriver:update": "npm run webdriver-manager update",
- "webpack-dev-server": "webpack-dev-server",
- "webpack": "webpack"
+ "webdriver-manager": "node ./node_modules/protractor/bin/webdriver-manager",
+ "webdriver:start": "node ./node_modules/protractor/bin/webdriver-manager start",
+ "webdriver:update": "node ./node_modules/protractor/bin/webdriver-manager update",
+ "webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
+ "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js"
},
"dependencies": {
- "@angular/common": "2.1.0",
- "@angular/compiler": "2.1.0",
- "@angular/core": "2.1.0",
- "@angular/forms": "^2.1.0",
- "@angular/http": "2.1.0",
- "@angular/platform-browser": "2.1.0",
- "@angular/platform-browser-dynamic": "2.1.0",
- "@angular/platform-server": "2.1.0",
- "@angular/router": "3.1.0",
- "@angularclass/conventions-loader": "^1.0.2",
- "@angularclass/hmr": "~1.2.0",
- "@angularclass/hmr-loader": "~3.0.2",
- "assets-webpack-plugin": "^3.4.0",
- "core-js": "^2.4.1",
- "http-server": "^0.9.0",
+ "@angular/animations": "^6.0.6",
+ "@angular/common": "^6.0.6",
+ "@angular/compiler": "^6.0.6",
+ "@angular/core": "^6.0.6",
+ "@angular/forms": "^6.0.6",
+ "@angular/platform-browser": "^6.0.6",
+ "@angular/platform-browser-dynamic": "^6.0.6",
+ "@angular/platform-server": "^6.0.6",
+ "@angular/router": "^6.0.6",
+ "core-js": "^2.5.7",
+ "http-server": "^0.11.1",
"ie-shim": "^0.1.0",
- "rxjs": "^5.0.0-rc.1",
- "zone.js": "~0.6.17"
+ "reflect-metadata": "^0.1.12",
+ "rxjs": "^6.2.1",
+ "zone.js": "^0.8.26"
},
"devDependencies": {
- "@types/hammerjs": "^2.0.33",
- "@types/jasmine": "^2.2.34",
- "@types/node": "^6.0.38",
- "@types/protractor": "^1.5.20",
- "@types/selenium-webdriver": "2.44.29",
- "@types/source-map": "^0.1.27",
- "@types/uglify-js": "^2.0.27",
- "@types/webpack": "^1.12.34",
- "angular2-template-loader": "^0.5.0",
- "awesome-typescript-loader": "^2.2.1",
- "codelyzer": "~1.0.0-beta.2",
- "copy-webpack-plugin": "^3.0.1",
- "css-loader": "^0.25.0",
- "exports-loader": "^0.6.3",
- "expose-loader": "^0.7.1",
- "file-loader": "^0.9.0",
- "gh-pages": "^0.11.0",
- "html-webpack-plugin": "^2.21.0",
- "imports-loader": "^0.6.5",
- "istanbul-instrumenter-loader": "^1.0.0",
- "json-loader": "^0.5.4",
- "karma": "^1.2.0",
- "karma-chrome-launcher": "^2.0.0",
- "karma-coverage": "^1.1.1",
- "karma-jasmine": "^1.0.2",
- "karma-mocha-reporter": "^2.0.0",
- "karma-remap-coverage": "^0.1.1",
+ "@angular-devkit/build-optimizer": "^0.6.8",
+ "@angular/cli": "^6.0.8",
+ "@angular/compiler-cli": "^6.0.6",
+ "@angular/language-service": "^6.0.6",
+ "@compodoc/compodoc": "^1.1.3",
+ "@ngtools/webpack": "^6.0.8",
+ "@types/hammerjs": "^2.0.35",
+ "@types/jasmine": "^2.8.8",
+ "@types/node": "^10.3.5",
+ "@types/uglify-js": "^3.0.2",
+ "@types/webpack": "^4.4.2",
+ "add-asset-html-webpack-plugin": "^2.1.3",
+ "angular2-template-loader": "^0.6.2",
+ "assets-webpack-plugin": "^3.8.4",
+ "awesome-typescript-loader": "^5.2.0",
+ "codelyzer": "^4.3.0",
+ "copy-webpack-plugin": "^4.5.1",
+ "cross-env": "^5.2.0",
+ "css-loader": "^0.28.11",
+ "exports-loader": "^0.7.0",
+ "expose-loader": "^0.7.5",
+ "file-loader": "^1.1.11",
+ "find-root": "^1.1.0",
+ "gh-pages": "^1.2.0",
+ "html-webpack-plugin": "^3.2.0",
+ "imports-loader": "^0.8.0",
+ "istanbul-instrumenter-loader": "^3.0.1",
+ "jasmine-core": "^3.1.0",
+ "karma": "^2.0.4",
+ "karma-chrome-launcher": "^2.2.0",
+ "karma-coverage": "^1.1.2",
+ "karma-jasmine": "^1.1.2",
+ "karma-mocha-reporter": "^2.2.5",
+ "karma-remap-coverage": "^0.1.5",
"karma-sourcemap-loader": "^0.3.7",
- "karma-webpack": "1.8.0",
- "parse5": "^2.2.2",
- "protractor": "^4.0.9",
- "raw-loader": "0.5.1",
- "rimraf": "^2.5.2",
- "script-ext-html-webpack-plugin": "^1.3.2",
- "source-map-loader": "^0.1.5",
- "string-replace-loader": "1.0.5",
- "style-loader": "^0.13.1",
- "to-string-loader": "^1.1.4",
- "ts-helpers": "1.1.2",
- "ts-node": "^1.3.0",
- "tslint": "^4.0.0-dev.0",
- "tslint-loader": "^2.1.3",
- "typedoc": "^0.5.0",
- "typescript": "^2.0.3",
- "url-loader": "^0.5.7",
- "webpack": "2.1.0-beta.25",
- "webpack-dev-middleware": "^1.6.1",
- "webpack-dev-server": "^2.1.0-beta.9",
- "webpack-md5-hash": "^0.0.5",
- "webpack-merge": "^0.14.1"
+ "karma-webpack": "^3.0.0",
+ "mini-css-extract-plugin": "^0.4.0",
+ "node-sass": "^4.9.0",
+ "npm-run-all": "^4.1.3",
+ "optimize-js-plugin": "^0.0.4",
+ "parse5": "^5.0.0",
+ "protractor": "^5.3.2",
+ "raw-loader": "^0.5.1",
+ "rimraf": "^2.6.2",
+ "rxjs-tslint": "^0.1.5",
+ "sass-loader": "^7.0.3",
+ "script-ext-html-webpack-plugin": "^2.0.1",
+ "source-map-loader": "^0.2.3",
+ "string-replace-loader": "^2.1.1",
+ "style-loader": "^0.21.0",
+ "to-string-loader": "^1.1.5",
+ "ts-node": "^7.0.0",
+ "tslib": "^1.9.3",
+ "tslint": "^5.10.0",
+ "tslint-loader": "^3.6.0",
+ "typedoc": "^0.11.1",
+ "typescript": "~2.7.2",
+ "uglifyjs-webpack-plugin": "^1.2.6",
+ "url-loader": "^1.0.1",
+ "webpack": "^4.12.0",
+ "webpack-cli": "^3.0.8",
+ "webpack-dev-middleware": "^3.1.3",
+ "webpack-dev-server": "^3.1.4",
+ "webpack-inline-manifest-plugin": "^4.0.1",
+ "webpack-merge": "^4.1.3"
},
"repository": {
"type": "git",
- "url": "https://github.com/angularclass/angular2-webpack-starter.git"
+ "url": "https://github.com/gdi2290/angular-starter.git"
},
"bugs": {
- "url": "https://github.com/angularclass/angular2-webpack-starter/issues"
+ "url": "https://github.com/gdi2290/angular-starter/issues"
},
"engines": {
- "node": ">= 4.2.1",
- "npm": ">= 3"
+ "node": ">= 8.0.0",
+ "npm": ">= 5"
}
}
diff --git a/protractor.conf.js b/protractor.conf.js
index b3f7738ffb..7e93e836e1 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -1,6 +1,8 @@
/**
- * @author: @AngularClass
+ * @author: tipe.io
*/
-// look in ./config for protractor.conf.js
+/**
+ * look in ./config for protractor.conf.js
+ */
exports.config = require('./config/protractor.conf.js').config;
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000000..6dbf1798c3
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,18 @@
+sonar.projectKey=angular:angular-starter
+sonar.projectName=angular-starter
+sonar.projectVersion=6.0.0
+sonar.sourceEncoding=UTF-8
+sonar.sources=src
+sonar.exclusions=**/node_modules/**,**/*.spec.ts
+sonar.tests=src/app
+sonar.test.inclusions=**/*.spec.ts
+
+sonar.ts.tslint.configPath=tslint.json
+sonar.ts.coverage.lcovReportPath=coverage/coverage.lcov
+# if using local tslint then enable the line below
+# sonar.ts.tslint.outputPath=reports/lint_issues.json
+sonar.genericcoverage.unitTestReportPaths=reports/ut_report.xml
+
+# Change the host.url to point to the
+# sonarcube server (default localhost)
+sonar.host.url=http://localhost:9000
\ No newline at end of file
diff --git a/src/app/+barrel/+child-barrel/child-barrel.component.ts b/src/app/+barrel/+child-barrel/child-barrel.component.ts
new file mode 100644
index 0000000000..ad41402046
--- /dev/null
+++ b/src/app/+barrel/+child-barrel/child-barrel.component.ts
@@ -0,0 +1,25 @@
+import {
+ Component,
+ OnInit,
+} from '@angular/core';
+/**
+ * We're loading this component asynchronously
+ * We are using some magic with es6-promise-loader that will wrap the module with a Promise
+ * see https://github.com/gdi2290/es6-promise-loader for more info
+ */
+
+console.log('`ChildBarrel` component loaded asynchronously');
+
+@Component({
+ selector: 'child-barrel',
+ template: `
+
Hello from Child Barrel
+ `,
+})
+export class ChildBarrelComponent implements OnInit {
+
+ public ngOnInit() {
+ console.log('hello `ChildBarrel` component');
+ }
+
+}
diff --git a/src/app/+barrel/+child-barrel/child-barrel.module.ts b/src/app/+barrel/+child-barrel/child-barrel.module.ts
new file mode 100644
index 0000000000..afefb5720d
--- /dev/null
+++ b/src/app/+barrel/+child-barrel/child-barrel.module.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { routes } from './child-barrel.routes';
+import { ChildBarrelComponent } from './child-barrel.component';
+
+console.log('`ChildBarrel` bundle loaded asynchronously');
+
+@NgModule({
+ declarations: [
+ /**
+ * Components / Directives/ Pipes
+ */
+ ChildBarrelComponent,
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ RouterModule.forChild(routes),
+ ],
+})
+export class ChildBarrelModule {
+ public static routes = routes;
+}
diff --git a/src/app/+barrel/+child-barrel/child-barrel.routes.ts b/src/app/+barrel/+child-barrel/child-barrel.routes.ts
new file mode 100644
index 0000000000..43e250dbd4
--- /dev/null
+++ b/src/app/+barrel/+child-barrel/child-barrel.routes.ts
@@ -0,0 +1,5 @@
+import { ChildBarrelComponent } from './child-barrel.component';
+
+export const routes = [
+ { path: '', component: ChildBarrelComponent, pathMatch: 'full' },
+];
diff --git a/src/app/+barrel/+child-barrel/index.ts b/src/app/+barrel/+child-barrel/index.ts
new file mode 100644
index 0000000000..8621b2f988
--- /dev/null
+++ b/src/app/+barrel/+child-barrel/index.ts
@@ -0,0 +1 @@
+export { ChildBarrelModule } from './child-barrel.module';
diff --git a/src/app/+barrel/barrel.component.ts b/src/app/+barrel/barrel.component.ts
new file mode 100644
index 0000000000..5fa3983996
--- /dev/null
+++ b/src/app/+barrel/barrel.component.ts
@@ -0,0 +1,31 @@
+import {
+ Component,
+ OnInit,
+} from '@angular/core';
+/**
+ * We're loading this component asynchronously
+ * We are using some magic with es6-promise-loader that will wrap the module with a Promise
+ * see https://github.com/gdi2290/es6-promise-loader for more info
+ */
+
+console.log('`Barrel` component loaded asynchronously');
+
+@Component({
+ selector: 'barrel',
+ template: `
+
Hello from Barrel
+
+
+ Child Barrel
+
+
+
+ `,
+})
+export class BarrelComponent implements OnInit {
+
+ public ngOnInit() {
+ console.log('hello `Barrel` component');
+ }
+
+}
diff --git a/src/app/+barrel/barrel.module.ts b/src/app/+barrel/barrel.module.ts
new file mode 100644
index 0000000000..c4e917d0e6
--- /dev/null
+++ b/src/app/+barrel/barrel.module.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { routes } from './barrel.routes';
+import { BarrelComponent } from './barrel.component';
+
+console.log('`Barrel` bundle loaded asynchronously');
+
+@NgModule({
+ declarations: [
+ /**
+ * Components / Directives/ Pipes
+ */
+ BarrelComponent,
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ RouterModule.forChild(routes),
+ ],
+})
+export class BarrelModule {
+ public static routes = routes;
+}
diff --git a/src/app/+barrel/barrel.routes.ts b/src/app/+barrel/barrel.routes.ts
new file mode 100644
index 0000000000..8c937065fb
--- /dev/null
+++ b/src/app/+barrel/barrel.routes.ts
@@ -0,0 +1,8 @@
+import { BarrelComponent } from './barrel.component';
+
+export const routes = [
+ { path: '', children: [
+ { path: '', component: BarrelComponent },
+ { path: 'child-barrel', loadChildren: './+child-barrel#ChildBarrelModule' }
+ ]},
+];
diff --git a/src/app/+barrel/index.ts b/src/app/+barrel/index.ts
new file mode 100644
index 0000000000..3f87dff82d
--- /dev/null
+++ b/src/app/+barrel/index.ts
@@ -0,0 +1 @@
+export { BarrelModule } from './barrel.module';
diff --git a/src/app/+detail/+child-detail/child-detail.component.ts b/src/app/+detail/+child-detail/child-detail.component.ts
new file mode 100644
index 0000000000..235f2911dc
--- /dev/null
+++ b/src/app/+detail/+child-detail/child-detail.component.ts
@@ -0,0 +1,25 @@
+import {
+ Component,
+ OnInit,
+} from '@angular/core';
+/**
+ * We're loading this component asynchronously
+ * We are using some magic with es6-promise-loader that will wrap the module with a Promise
+ * see https://github.com/gdi2290/es6-promise-loader for more info
+ */
+
+console.log('`ChildDetail` component loaded asynchronously');
+
+@Component({
+ selector: 'child-detail',
+ template: `
+
Hello from Child Detail
+ `,
+})
+export class ChildDetailComponent implements OnInit {
+
+ public ngOnInit() {
+ console.log('hello `ChildDetail` component');
+ }
+
+}
diff --git a/src/app/+detail/+child-detail/child-detail.module.ts b/src/app/+detail/+child-detail/child-detail.module.ts
new file mode 100644
index 0000000000..02553e1378
--- /dev/null
+++ b/src/app/+detail/+child-detail/child-detail.module.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { routes } from './child-detail.routes';
+import { ChildDetailComponent } from './child-detail.component';
+
+console.log('`ChildDetail` bundle loaded asynchronously');
+
+@NgModule({
+ declarations: [
+ /**
+ * Components / Directives/ Pipes
+ */
+ ChildDetailComponent,
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ RouterModule.forChild(routes),
+ ],
+})
+export class ChildDetailModule {
+ public static routes = routes;
+}
diff --git a/src/app/+detail/+child-detail/child-detail.routes.ts b/src/app/+detail/+child-detail/child-detail.routes.ts
new file mode 100644
index 0000000000..dc94cac3d2
--- /dev/null
+++ b/src/app/+detail/+child-detail/child-detail.routes.ts
@@ -0,0 +1,5 @@
+import { ChildDetailComponent } from './child-detail.component';
+
+export const routes = [
+ { path: '', component: ChildDetailComponent, pathMatch: 'full' },
+];
diff --git a/src/app/+detail/+child-detail/index.ts b/src/app/+detail/+child-detail/index.ts
new file mode 100644
index 0000000000..c23f15ff60
--- /dev/null
+++ b/src/app/+detail/+child-detail/index.ts
@@ -0,0 +1 @@
+export { ChildDetailModule } from './child-detail.module';
diff --git a/src/app/+detail/detail.component.ts b/src/app/+detail/detail.component.ts
index 8209f7fe57..0fa814658e 100644
--- a/src/app/+detail/detail.component.ts
+++ b/src/app/+detail/detail.component.ts
@@ -1,18 +1,30 @@
-import { Component } from '@angular/core';
+import {
+ Component,
+ OnInit,
+} from '@angular/core';
+/**
+ * We're loading this component asynchronously
+ * We are using some magic with es6-promise-loader that will wrap the module with a Promise
+ * see https://github.com/gdi2290/es6-promise-loader for more info
+ */
+
+console.log('`Detail` component loaded asynchronously');
@Component({
selector: 'detail',
template: `