diff --git a/.editorconfig b/.editorconfig index 5760be5..869ff6c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,16 @@ +# @AngularClass # http://editorconfig.org + root = true [*] +charset = utf-8 indent_style = space indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true +end_of_line = lf insert_final_newline = true +trim_trailing_whitespace = true [*.md] +insert_final_newline = false trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index b38db2f..12d2915 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,62 @@ -node_modules/ -build/ +# @AngularClass + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Users Environment Variables +.lock-wscript + +# OS generated files # +.DS_Store +ehthumbs.db +Icon? +Thumbs.db + +# Node Files # +/node_modules +/bower_components +npm-debug.log + +# Coverage # +/coverage/ + +# Typing # +/src/typings/tsd/ +/typings/ +/tsd_typings/ + +# Dist # +/dist +/public/__build__/ +/src/*/__build__/ +/__build__/** +/public/dist/ +/src/*/dist/ +/dist/** +/.awcache +.webpack.json + +# Doc # +/doc/ + +# IDE # +.idea/ +*.swp diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..b009dfb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7a1f206 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: node_js +node_js: + - "4" + - "5" + - "6" + - "node" +services: + - docker +before_install: + - export CHROME_BIN=chromium-browser + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + # Repo for yarn + - sudo apt-key adv --keyserver pgp.mit.edu --recv D101F7899D41F3C3 + - echo "deb http://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + - sudo apt-get update -qq + - sudo apt-get install -y -qq yarn + - sleep 3 + # Updating NPM to relevant version >= 3 on Node.JS LTS + - npm i -g npm@^3 +install: + - yarn +script: + - npm test + - npm run build:docker +cache: + directories: + - $HOME/.yarn-cache +sudo: required diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cb51733 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +# Builds a Docker to deliver dist/ +FROM nginx:latest +COPY dist/ /usr/share/nginx/html \ No newline at end of file diff --git a/LICENSE b/LICENSE index c545e32..88bd8b8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,22 @@ -Copyright <greg.fun@gmail.com> +The MIT License (MIT) -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Copyright (c) 2015-2016 AngularClass LLC - http://www.apache.org/licenses/LICENSE-2.0 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/README.md b/README.md index fe272f8..e68160f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,383 @@ -# webpack-test +

+ + Angular 2 Fundamentals + +

+___ + +[![taylor swift](https://img.shields.io/badge/secured%20by-taylor%20swift-brightgreen.svg)](https://twitter.com/SwiftOnSecurity) +[![volkswagen status](https://auchenberg.github.io/volkswagen/volkswargen_ci.svg?v=1)](https://github.com/auchenberg/volkswagen) [![GitHub version](https://badge.fury.io/gh/angularclass%2Fangular2-webpack-starter.svg)](https://badge.fury.io/gh/angularclass%2Fangular2-webpack-starter) [![Dependency Status](https://david-dm.org/angularclass/angular2-webpack-starter.svg)](https://david-dm.org/angularclass/angular2-webpack-starter) +[![Stack Share](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](http://stackshare.io/angularclass/angular-2-webpack-starter) + +

+ + Webpack and Angular 2 + +

+ +# Angular2 Webpack Starter [![Join Slack](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://angularclass.com/slack-join) [![Join the chat at https://gitter.im/angularclass/angular2-webpack-starter](https://badges.gitter.im/Join%20Chat.svg)](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/), +[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). + +> If you're looking for Angular 1.x please use [NG6-starter](https://github.com/angularclass/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) + +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. +* 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. +* Coverage with Istanbul and Karma +* End-to-end Angular 2 code 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) + +### 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) + +```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 + +# change directory to our repo +cd angular2-webpack-starter + +# install the repo with npm +npm install + +# start the server +npm start + +# use Hot Module Replacement +npm run server:dev:hmr + +# if you're in China use cnpm +# https://github.com/cnpm/cnpm +``` +go to [http://0.0.0.0:3000](http://0.0.0.0:3000) or [http://localhost:3000](http://localhost:3000) in your browser + +# Table of Contents +* [File Structure](#file-structure) +* [Getting Started](#getting-started) + * [Dependencies](#dependencies) + * [Installing](#installing) + * [Running the app](#running-the-app) +* [Configuration](#configuration) +* [Contributing](#contributing) +* [TypeScript](#typescript) +* [@Types](#types) +* [Frequently asked questions](#frequently-asked-questions) +* [Support, Questions, or Feedback](#support-questions-or-feedback) +* [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 + │ + ├──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 + │ │ + | ├──polyfills.ts * our polyfills file + │ │ + | ├──vendor.ts * our vendor file + │ │ + │ ├──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 + │ + │ + ├──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 + +``` + +# Getting Started +## 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`+ + +> 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`) +* `webpack-dev-server` (`npm install --global webpack-dev-server`) +* `karma` (`npm install --global karma-cli`) +* `protractor` (`npm install --global protractor`) +* `typescript` (`npm install --global typescript`) + +## 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 or `yarn` +* `npm run server` to start the dev server in another tab + +## Running the app +After you have installed all dependencies you can now run the app. Run `npm run server` to start a local server using `webpack-dev-server` which will watch, build (in-memory), and reload for you. The port will be displayed to you as `http://0.0.0.0:3000` (or if you prefer IPv6, if you're using `express` server, then it's `http://[::1]:3000/`). + +### server +```bash +# development +npm run server +# production +npm run build:prod +npm run server:prod +``` + +## Other commands + +### build files +```bash +# development +npm run build:dev +# production +npm run build:prod +``` + +### hot module replacement +```bash +npm run server:dev:hmr +``` + +### watch and build files +```bash +npm run watch +``` + +### run tests +```bash +npm run test +``` + +### watch and run our tests +```bash +npm run watch:test +``` + +### run end-to-end tests +```bash +# make sure you have your server running in another terminal +npm run e2e +``` + +### run webdriver (for end-to-end) +```bash +npm run webdriver:update +npm run webdriver:start +``` + +### run Protractor's elementExplorer (for end-to-end) +```bash +npm run webdriver:start +# in another terminal +npm run e2e:live +``` + +### build Docker +```bash +npm run build:docker +``` + +# Configuration +Configuration files live in `config/` we are currently using webpack, karma, and protractor for different stages of your application + +# 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 + +# TypeScript +> 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. + +``` +npm install --global typescript +``` + +## Use a TypeScript-aware editor +We have good experience using these editors: + +* [Visual Studio Code](https://code.visualstudio.com/) +* [Webstorm 10](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 + +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: +```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: +```es6 +import '@types/gapi.youtube'; +import '@types/gapi'; +import '@types/youtube'; +``` + +## Custom Type Definitions +When including 3rd party modules you also need to include the type definition for the module +if they don't provide one within the module. You can try to install it with @types + +``` +npm install @types/node +npm install @types/lodash +``` + +If you can't find the type definition in the registry we can make an ambient definition in +this file for now. For example + +```typescript +declare module "my-module" { + export function doesSomething(value: string): string; +} +``` + + +If you're prototyping and you will fix the types later you can also declare it as type any + +```typescript +declare var assert: any; +declare var _: any; +declare var $: any; +``` + +If you're importing a module that uses Node.js modules which are CommonJS you need to import as + +```typescript +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) +* 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) +* 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) +* 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) +* 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) +* 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) +* 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) +* 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. +* How do I turn on Hot Module Replacement + * 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. +* 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. +* 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 +* 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) +* `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 +* "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) + +# Support, Questions, or Feedback +> Contact us anytime for anything about this repo or Angular 2 + +* [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) + +# Quick Start Guides + +## Nitrous + +You can quickly create a free development environment to get started using this +starter kit in the cloud on [Nitrous](https://www.nitrous.io/): + + + Nitrous Quickstart + + +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. + +

+ + Angular 2 Fundamentals + +

+ +___ + +enjoy — **AngularClass** + +

+ +[![AngularClass](https://cloud.githubusercontent.com/assets/1016365/9863770/cb0620fc-5af7-11e5-89df-d4b0b2cdfc43.png "Angular Class")](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 + +___ + # License -[Apache-2.0](/LICENSE) + [MIT](/LICENSE) diff --git a/config/github-deploy/index.js b/config/github-deploy/index.js new file mode 100644 index 0000000..e03899b --- /dev/null +++ b/config/github-deploy/index.js @@ -0,0 +1,59 @@ +const helpers = require('../helpers'); +const execSync = require('child_process').execSync; + +const REPO_NAME_RE = /Push {2}URL: https:\/\/github\.com\/.*\/(.*)\.git/; + +function getWebpackConfigModule() { + if (helpers.hasProcessFlag('github-dev')) { + return require('../webpack.dev.js'); + } else if (helpers.hasProcessFlag('github-prod')) { + return require('../webpack.prod.js'); + } else { + throw new Error('Invalid compile option.'); + } +} + +function getRepoName(remoteName) { + remoteName = remoteName || 'origin'; + + var stdout = execSync('git remote show ' + remoteName), + match = REPO_NAME_RE.exec(stdout); + + if (!match) { + throw new Error('Could not find a repository on remote ' + remoteName); + } else { + return match[1]; + } +} + +function stripTrailing(str, char) { + + if (str[0] === char) { + str = str.substr(1); + } + + if (str.substr(-1) === char) { + str = str.substr(0, str.length - 1); + } + + return str; +} + +/** + * Given a string remove trailing slashes and adds 1 slash at the end of the string. + * + * Example: + * safeUrl('/value/') + * // 'value/' + * + * @param url + * @returns {string} + */ +function safeUrl(url) { + const stripped = stripTrailing(url || '', '/'); + return stripped ? stripped + '/' : ''; +} + +exports.getWebpackConfigModule = getWebpackConfigModule; +exports.getRepoName = getRepoName; +exports.safeUrl = safeUrl; diff --git a/config/head-config.common.js b/config/head-config.common.js new file mode 100644 index 0000000..ce6dec9 --- /dev/null +++ b/config/head-config.common.js @@ -0,0 +1,45 @@ +/** + * Configuration for head elements added during the creation of index.html. + * + * All href attributes are added the publicPath (if exists) by default. + * You can explicitly hint to prefix a publicPath by setting a boolean value to a key that has + * the same name as the attribute you want to operate on, but prefix with = + * + * Example: + * { name: 'msapplication-TileImage', content: '/assets/icon/ms-icon-144x144.png', '=content': true }, + * Will prefix the publicPath to content. + * + * { rel: 'apple-touch-icon', sizes: '57x57', href: '/assets/icon/apple-icon-57x57.png', '=href': false }, + * Will not prefix the publicPath on href (href attributes are added by default + * + */ +module.exports = { + link: [ + /** 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' }, + { rel: 'apple-touch-icon', sizes: '76x76', href: '/assets/icon/apple-icon-76x76.png' }, + { rel: 'apple-touch-icon', sizes: '114x114', href: '/assets/icon/apple-icon-114x114.png' }, + { rel: 'apple-touch-icon', sizes: '120x120', href: '/assets/icon/apple-icon-120x120.png' }, + { rel: 'apple-touch-icon', sizes: '144x144', href: '/assets/icon/apple-icon-144x144.png' }, + { 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 **/ + { rel: 'icon', type: 'image/png', sizes: '192x192', href: '/assets/icon/android-icon-192x192.png' }, + + /** 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 **/ + { rel: 'manifest', href: '/assets/manifest.json' } + ], + meta: [ + { name: 'msapplication-TileColor', content: '#00bcd4' }, + { name: 'msapplication-TileImage', content: '/assets/icon/ms-icon-144x144.png', '=content': true }, + { name: 'theme-color', content: '#00bcd4' } + ] +}; diff --git a/config/helpers.js b/config/helpers.js new file mode 100644 index 0000000..41c9c77 --- /dev/null +++ b/config/helpers.js @@ -0,0 +1,24 @@ +/** + * @author: @AngularClass + */ +var path = require('path'); + +// Helper functions +var ROOT = path.resolve(__dirname, '..'); + +function hasProcessFlag(flag) { + return process.argv.join('').indexOf(flag) > -1; +} + +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)); +} + +exports.hasProcessFlag = hasProcessFlag; +exports.isWebpackDevServer = isWebpackDevServer; +exports.root = root; diff --git a/config/html-elements-plugin/index.js b/config/html-elements-plugin/index.js new file mode 100644 index 0000000..5766a2f --- /dev/null +++ b/config/html-elements-plugin/index.js @@ -0,0 +1,106 @@ + +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 = /\/$/; + +/** + * Create an HTML tag with attributes from a map. + * + * Example: + * createTag('link', { rel: "manifest", href: "/assets/manifest.json" }) + * // + * @param tagName The name of the tag + * @param attrMap A Map of attribute names (keys) and their values. + * @param publicPath a path to add to eh start of static asset url + * @returns {string} + */ +function createTag(tagName, attrMap, publicPath) { + publicPath = publicPath || ''; + + // 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) { + 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. + 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 // + value = publicPath + (value[0] === '/' ? value.substr(1) : value); + } + } + + return name + '="' + value + '"'; + }); + + return '<' + tagName + ' ' + attributes.join(' ') + '>'; +} + +/** + * Returns a string representing all html elements defined in a data source. + * + * Example: + * + * const ds = { + * link: [ + * { rel: "apple-touch-icon", sizes: "57x57", href: "/assets/icon/apple-icon-57x57.png" } + * ], + * meta: [ + * { name: "msapplication-TileColor", content: "#00bcd4" } + * ] + * } + * + * getHeadTags(ds); + * // "" + * "" + * + * @returns {string} + */ +function getHtmlElementString(dataSource, publicPath) { + return Object.getOwnPropertyNames(dataSource) + .map(function(name) { + if (Array.isArray(dataSource[name])) { + return dataSource[name].map(function(attrs) { return createTag(name, attrs, publicPath); } ); + } else { + return [ createTag(name, dataSource[name], publicPath) ]; + } + }) + .reduce(function(arr, curr) { + return arr.concat(curr); + }, []) + .join('\n\t'); +} +module.exports = HtmlElementsPlugin; diff --git a/config/karma.conf.js b/config/karma.conf.js new file mode 100644 index 0000000..1f35c87 --- /dev/null +++ b/config/karma.conf.js @@ -0,0 +1,104 @@ +/** + * @author: @AngularClass + */ + +module.exports = function(config) { + var testWebpackConfig = require('./webpack.test.js')({env: 'test'}); + + var configuration = { + + // 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 / patterns to load in the browser + * + * we are building the test environment in ./spec-bundle.js + */ + files: [ { pattern: './config/spec-bundle.js', watched: false } ], + + /* + * 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: testWebpackConfig, + + coverageReporter: { + type: 'in-memory' + }, + + remapCoverageReporter: { + 'text-summary': null, + json: './coverage/coverage.json', + html: './coverage/html' + }, + + // Webpack please don't spam the console when running in karma! + webpackMiddleware: { stats: 'errors-only'}, + + /* + * test results reporter to use + * + * possible values: 'dots', 'progress' + * available reporters: https://npmjs.org/browse/keyword/karma-reporter + */ + reporters: [ 'mocha', 'coverage', 'remap-coverage' ], + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + /* + * level of logging + * possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + */ + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + /* + * start these browsers + * available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + */ + browsers: [ + 'Chrome' + ], + + customLaunchers: { + ChromeTravisCi: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, + + /* + * Continuous Integration mode + * if true, Karma captures browsers, runs the tests and exits + */ + singleRun: true + }; + + if (process.env.TRAVIS){ + configuration.browsers = [ + 'ChromeTravisCi' + ]; + } + + config.set(configuration); +}; diff --git a/config/modules/angular2-hmr-prod.js b/config/modules/angular2-hmr-prod.js new file mode 100644 index 0000000..26fce46 --- /dev/null +++ b/config/modules/angular2-hmr-prod.js @@ -0,0 +1,3 @@ +exports.HmrState = function() { + +}; diff --git a/config/protractor.conf.js b/config/protractor.conf.js new file mode 100644 index 0000000..989911d --- /dev/null +++ b/config/protractor.conf.js @@ -0,0 +1,49 @@ +/** + * @author: @AngularClass + */ + +require('ts-node/register'); +var helpers = require('./helpers'); + +exports.config = { + baseUrl: 'http://localhost:3000/', + + // use `npm run e2e` + specs: [ + helpers.root('src/**/**.e2e.ts'), + helpers.root('src/**/*.e2e.ts') + ], + exclude: [], + + framework: 'jasmine2', + + allScriptsTimeout: 110000, + + jasmineNodeOpts: { + showTiming: true, + showColors: true, + isVerbose: false, + includeStackTrace: false, + defaultTimeoutInterval: 400000 + }, + directConnect: true, + + capabilities: { + 'browserName': 'chrome', + 'chromeOptions': { + 'args': ['show-fps-counter=true'] + } + }, + + onPrepare: function() { + browser.ignoreSynchronization = true; + }, + + /** + * Angular 2 configuration + * + * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching + * `rootEl` + */ + useAllAngular2AppRoots: true +}; diff --git a/config/spec-bundle.js b/config/spec-bundle.js new file mode 100644 index 0000000..63a0f14 --- /dev/null +++ b/config/spec-bundle.js @@ -0,0 +1,62 @@ +/** + * @author: @AngularClass + */ + +/* + * 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 + * karma.conf.js with the karma-webpack plugin. This is the entry + * file for webpack test. Just like webpack will create a bundle.js + * file for our client, when we run test, it will compile and bundle them + * all here! Crazy huh. So we need to do some setup + */ +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 +require('zone.js/dist/sync-test'); +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'); + +testing.TestBed.initTestEnvironment( + browser.BrowserDynamicTestingModule, + 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. + * Below, context will be a function/object with file names as keys. + * Using that regex we are saying look in ../src then find + * any file that ends with spec.ts and get its path. By passing in true + * we say do this recursively + */ +var testContext = require.context('../src', true, /\.spec\.ts/); + +/* + * 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 + */ +function requireAll(requireContext) { + return requireContext.keys().map(requireContext); +} + +// requires and returns all modules that match +var modules = requireAll(testContext); diff --git a/config/webpack.common.js b/config/webpack.common.js new file mode 100644 index 0000000..6f14980 --- /dev/null +++ b/config/webpack.common.js @@ -0,0 +1,289 @@ +/** + * @author: @AngularClass + */ + +const webpack = require('webpack'); +const helpers = require('./helpers'); + +/* + * Webpack Plugins + */ +// 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 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 ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin'); + +/* + * Webpack Constants + */ +const HMR = helpers.hasProcessFlag('hot'); +const METADATA = { + title: 'Angular2 Webpack Starter by @gdi2290 from @AngularClass', + baseUrl: '/', + isDevServer: helpers.isWebpackDevServer() +}; + +/* + * Webpack configuration + * + * See: http://webpack.github.io/docs/configuration.html#cli + */ +module.exports = function (options) { + isProd = options.env === 'production'; + return { + + /* + * 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, + + /* + * The entry point for the bundle + * Our Angular.js app + * + * See: http://webpack.github.io/docs/configuration.html#entry + */ + entry: { + + 'polyfills': './src/polyfills.browser.ts', + 'vendor': './src/vendor.browser.ts', + 'main': './src/main.browser.ts' + + }, + + /* + * Options affecting the resolving of modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve + */ + resolve: { + + /* + * An array of extensions that should be used to resolve modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve-extensions + */ + extensions: ['.ts', '.js', '.json'], + + // An array of directory names to be resolved to the current directory + modules: [helpers.root('src'), 'node_modules'], + + }, + + /* + * Options affecting the normal modules. + * + * See: http://webpack.github.io/docs/configuration.html#module + */ + module: { + + rules: [ + + /* + * 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. + * + * See: https://github.com/webpack/json-loader + */ + { + test: /\.json$/, + loader: 'json-loader' + }, + + /* + * to string and css loader support for *.css files + * Returns file content as string + * + */ + { + test: /\.css$/, + loaders: ['to-string-loader', 'css-loader'] + }, + + /* Raw loader support for *.html + * Returns file content as string + * + * See: https://github.com/webpack/raw-loader + */ + { + test: /\.html$/, + loader: 'raw-loader', + exclude: [helpers.root('src/index.html')] + }, + + /* File loader for supporting images, for example, in CSS files. + */ + { + test: /\.(jpg|png|gif)$/, + loader: 'file' + }, + + ], + + }, + + /* + * Add additional plugins to the compiler. + * + * See: http://webpack.github.io/docs/configuration.html#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. + * + * 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. + * + * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin + * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app + */ + new CommonsChunkPlugin({ + name: ['polyfills', 'vendor'].reverse() + }), + + /** + * 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. + * + * Copies project static assets. + * + * See: https://www.npmjs.com/package/copy-webpack-plugin + */ + new CopyWebpackPlugin([{ + from: 'src/assets', + to: 'assets', + }, { + from: 'src/meta', + }, ]), + + + /* + * 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', + metadata: METADATA, + inject: 'head' + }), + + /* + * Plugin: ScriptExtHtmlWebpackPlugin + * Description: Enhances html-webpack-plugin functionality + * with different deployment options for your scripts including: + * + * See: https://github.com/numical/script-ext-html-webpack-plugin + */ + new ScriptExtHtmlWebpackPlugin({ + defaultAttribute: 'defer' + }), + + /* + * 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 + * href attributes, you can disable that by adding a "=href": false property. + * You can also enable it to other attribute by settings "=attName": true. + * + * The configuration supplied is map between a location (key) and an element definition object (value) + * The location (key) is then exported to the template under then htmlElements property in webpack configuration. + * + * Example: + * Adding this plugin configuration + * new HtmlElementsPlugin({ + * headTags: { ... } + * }) + * + * Means we can use it in the template like this: + * <%= webpackConfig.htmlElements.headTags %> + * + * Dependencies: HtmlWebpackPlugin + */ + new HtmlElementsPlugin({ + headTags: require('./head-config.common') + }), + + /** + * Plugin LoaderOptionsPlugin (experimental) + * + * See: https://gist.github.com/sokra/27b24881210b56bbaff7 + */ + new LoaderOptionsPlugin({}), + + ], + + /* + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + crypto: 'empty', + process: true, + module: false, + clearImmediate: false, + setImmediate: false + } + + }; +} diff --git a/config/webpack.dev.js b/config/webpack.dev.js new file mode 100644 index 0000000..d0680a3 --- /dev/null +++ b/config/webpack.dev.js @@ -0,0 +1,178 @@ +/** + * @author: @AngularClass + */ + +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 + +/** + * 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 + */ +module.exports = function (options) { + return webpackMerge(commonConfig({env: ENV}), { + + /** + * 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', + + /** + * Options affecting the output of the compilation. + * + * See: http://webpack.github.io/docs/configuration.html#output + */ + output: { + + /** + * The output directory as absolute path (required). + * + * See: http://webpack.github.io/docs/configuration.html#output-path + */ + path: helpers.root('dist'), + + /** + * 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 + */ + filename: '[name].bundle.js', + + /** + * 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 + */ + sourceMapFilename: '[name].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 + */ + chunkFilename: '[id].chunk.js', + + library: 'ac_[name]', + 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, + } + }), + + /** + * Plugin: NamedModulesPlugin (experimental) + * Description: Uses file names as module name. + * + * See: https://github.com/webpack/webpack/commit/a04ffb928365b19feb75087c63f13cadfc08e1eb + */ + new NamedModulesPlugin(), + + /** + * Plugin LoaderOptionsPlugin (experimental) + * + * See: https://gist.github.com/sokra/27b24881210b56bbaff7 + */ + 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' + }, + + } + }), + + ], + + /** + * Webpack Development Server configuration + * Description: The webpack-dev-server is a little node.js Express server. + * 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 + */ + devServer: { + port: METADATA.port, + host: METADATA.host, + historyApiFallback: true, + watchOptions: { + aggregateTimeout: 300, + poll: 1000 + }, + outputPath: helpers.root('dist') + }, + + /* + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + crypto: 'empty', + process: true, + module: false, + clearImmediate: false, + setImmediate: false + } + + }); +} diff --git a/config/webpack.github-deploy.js b/config/webpack.github-deploy.js new file mode 100644 index 0000000..5ad4519 --- /dev/null +++ b/config/webpack.github-deploy.js @@ -0,0 +1,79 @@ +/** + * @author: @AngularClass + */ +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 + */ +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 = webpackMerge(webpackConfig, { + /** + * Merged metadata from webpack.common.js for index.html + * + * See: (custom attribute) + */ + metadata: METADATA, + + + 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.'); + + const logger = function (msg) { + console.log(msg); + }; + + const options = { + logger: logger, + remote: GIT_REMOTE_NAME, + message: COMMIT_MESSAGE + }; + + 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 new file mode 100644 index 0000000..64d3845 --- /dev/null +++ b/config/webpack.prod.js @@ -0,0 +1,260 @@ +/** + * @author: @AngularClass + */ + +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 + +/** + * Webpack Plugins + */ +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'); + +/** + * Webpack Constants + */ +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 +}); + +module.exports = function (env) { + return webpackMerge(commonConfig({env: ENV}), { + + /** + * 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 + */ + output: { + + /** + * The output directory as absolute path (required). + * + * See: http://webpack.github.io/docs/configuration.html#output-path + */ + path: helpers.root('dist'), + + /** + * 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 + */ + filename: '[name].[chunkhash].bundle.js', + + /** + * 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 + */ + sourceMapFilename: '[name].[chunkhash].bundle.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 + */ + chunkFilename: '[id].[chunkhash].chunk.js' + + }, + + /** + * Add additional plugins to the compiler. + * + * See: http://webpack.github.io/docs/configuration.html#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: [/\)?\]?=/] + }, + + } + }), + + ], + + /* + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + crypto: 'empty', + process: false, + module: false, + clearImmediate: false, + setImmediate: false + } + + }); +} diff --git a/config/webpack.test.js b/config/webpack.test.js new file mode 100644 index 0000000..416df68 --- /dev/null +++ b/config/webpack.test.js @@ -0,0 +1,256 @@ +/** + * @author: @AngularClass + */ + +const helpers = require('./helpers'); +const path = require('path'); + +/** + * Webpack Plugins + */ +const ProvidePlugin = require('webpack/lib/ProvidePlugin'); +const DefinePlugin = require('webpack/lib/DefinePlugin'); +const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin'); +const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin'); + +/** + * Webpack Constants + */ +const ENV = process.env.ENV = process.env.NODE_ENV = 'test'; + +/** + * Webpack configuration + * + * See: http://webpack.github.io/docs/configuration.html#cli + */ +module.exports = function (options) { + return { + + /** + * Source map for Karma from the help of karma-sourcemap-loader & karma-webpack + * + * Do not change, leave as is or it wont work. + * See: https://github.com/webpack/karma-webpack#source-maps + */ + devtool: 'inline-source-map', + + /** + * Options affecting the resolving of modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve + */ + resolve: { + + /** + * An array of extensions that should be used to resolve modules. + * + * See: http://webpack.github.io/docs/configuration.html#resolve-extensions + */ + extensions: ['.ts', '.js'], + + /** + * Make sure root is src + */ + modules: [ path.resolve(__dirname, 'src'), 'node_modules' ] + + }, + + /** + * Options affecting the normal modules. + * + * See: http://webpack.github.io/docs/configuration.html#module + */ + 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. + * + * See: https://github.com/webpack/source-map-loader + */ + { + enforce: 'pre', + test: /\.js$/, + loader: 'source-map-loader', + exclude: [ + // these packages have problems with their sourcemaps + helpers.root('node_modules/rxjs'), + helpers.root('node_modules/@angular') + ] + }, + + /** + * Typescript loader support for .ts and Angular 2 async routes via .async.ts + * + * See: https://github.com/s-panferov/awesome-typescript-loader + */ + { + 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 + + } + }, + exclude: [/\.e2e\.ts$/] + }, + + /** + * Json loader support for *.json files. + * + * See: https://github.com/webpack/json-loader + */ + { + test: /\.json$/, + loader: 'json-loader', + exclude: [helpers.root('src/index.html')] + }, + + /** + * Raw loader support for *.css files + * Returns file content as string + * + * See: https://github.com/webpack/raw-loader + */ + { + test: /\.css$/, + loaders: ['to-string-loader', 'css-loader'], + exclude: [helpers.root('src/index.html')] + }, + + /** + * Raw loader support for *.html + * Returns file content as string + * + * See: https://github.com/webpack/raw-loader + */ + { + test: /\.html$/, + loader: 'raw-loader', + exclude: [helpers.root('src/index.html')] + }, + + /** + * Instruments JS files with Istanbul for subsequent code coverage reporting. + * Instrument only testing sources. + * + * See: https://github.com/deepsweet/istanbul-instrumenter-loader + */ + { + enforce: 'post', + test: /\.(js|ts)$/, + loader: 'istanbul-instrumenter-loader', + include: helpers.root('src'), + exclude: [ + /\.(e2e|spec)\.ts$/, + /node_modules/ + ] + } + + ] + }, + + /** + * Add additional plugins to the compiler. + * + * See: http://webpack.github.io/docs/configuration.html#plugins + */ + 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(ENV), + 'HMR': false, + 'process.env': { + 'ENV': JSON.stringify(ENV), + 'NODE_ENV': JSON.stringify(ENV), + 'HMR': false, + } + }), + + /** + * 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 LoaderOptionsPlugin (experimental) + * + * See: https://gist.github.com/sokra/27b24881210b56bbaff7 + */ + 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' + }, + + } + }), + + ], + + /** + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + process: false, + crypto: 'empty', + module: false, + clearImmediate: false, + setImmediate: false + } + + }; +} diff --git a/karma.conf.js b/karma.conf.js index a772e73..27c49ad 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,67 +1,6 @@ -// @AngularClass -var path = require('path'); +/** + * @author: @AngularClass + */ -module.exports = function(config) { - var testWebpackConfig = require('./webpack.test.config.js'); - config.set({ - - // 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 / patterns to load in the browser - // we are building the test environment in ./spec-bundle.js - files: [ { pattern: 'spec-bundle.js', watched: false } ], - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { 'spec-bundle.js': ['webpack', 'sourcemap'] }, - - // Webpack Config at ./webpack.test.config.js - webpack: testWebpackConfig, - - coverageReporter: { - dir : 'coverage/', - reporters: [ - { type: 'text-summary' }, - { type: 'html' } - ], - }, - - // Webpack please don't spam the console when running in karma! - webpackServer: { noInfo: true }, - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: [ 'progress', 'coverage' ], - - // web server port - port: 9876, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: [ 'PhantomJS' ], - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: true - }); - -}; +// Look in ./config for karma.conf.js +module.exports = require('./config/karma.conf.js'); diff --git a/package.json b/package.json index 1a53e83..220fced 100644 --- a/package.json +++ b/package.json @@ -1,85 +1,134 @@ { - "name": "webpack-test", - "version": "0.0.0", - "description": "", - "author": " ", - "homepage": "", - "license": "Apache-2.0", + "name": "angular2-webpack-starter", + "version": "5.1.1", + "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", + "keywords": [ + "angular2", + "webpack", + "typescript" + ], + "author": "Patrick Stapleton ", + "homepage": "https://github.com/angularclass/angular2-webpack-starter", + "license": "MIT", "scripts": { - "clean": "./node_modules/.bin/rimraf node_modules doc typings coverage dist && npm cache clean", - "clean:dist": "./node_modules/.bin/rimraf dist", - "preclean:install": "npm run clean", - "clean:install": "npm install", - "preclean:start": "npm run clean", - "clean:start": "npm start", - "watch": "npm run watch:dev", - "watch:dev": "./node_modules/.bin/webpack --watch --progress --profile --colors --display-error-details --display-cached", - "watch:prod": "./node_modules/.bin/webpack --watch --config webpack.prod.config.js --progress --profile --colors --display-error-details --display-cached", + "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": "npm run build:prod", + "ci": "npm run lint && npm test && npm run e2e", + "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", + "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", + "github-deploy": "npm run github-deploy:dev", + "lint": "npm run tslint \"src/**/*.ts\"", + "postversion": "git push && git push --tags", "prebuild:dev": "npm run clean:dist", - "build:dev": "./node_modules/.bin/webpack --progress --profile --colors --display-error-details --display-cached", "prebuild:prod": "npm run clean:dist", - "build:prod": "./node_modules/.bin/webpack --config webpack.prod.config.js --progress --profile --colors --display-error-details --display-cached", + "preclean:install": "npm run clean", + "preclean:start": "npm run clean", + "pree2e": "npm run webdriver:update -- --standalone", + "preversion": "npm test", + "protractor": "protractor", + "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": "npm run server:dev", - "server:dev": "./node_modules/.bin/webpack-dev-server --progress --profile --colors --display-error-details --display-cached", - "server:prod": "./node_modules/.bin/http-server dist --cors", - "webdriver:update": "./node_modules/.bin/webdriver-manager update", - "webdriver:start": "./node_modules/.bin/webdriver-manager start", - "lint": "./node_modules/.bin/tsconfig-lint", - "e2e": "./node_modules/.bin/protractor", - "test": "./node_modules/.bin/karma start", - "ci": "npm run e2e && npm run test", - "docs": "./node_modules/.bin/typedoc --options typedoc.json src/**/*.ts", + "start:hmr": "npm run server:dev:hmr", "start": "npm run server:dev", - "postinstall": "./node_modules/.bin/typings install" + "test": "karma start", + "tslint": "tslint", + "typedoc": "typedoc", + "version": "npm run build", + "watch:dev:hmr": "npm run watch:dev -- --hot", + "watch:dev": "npm run build:dev -- --watch", + "watch:prod": "npm run build: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" }, "dependencies": { - "angular2": "2.0.0-beta.1", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "es7-reflect-metadata": "^1.4.0", - "github-api": "^0.10.7", - "rxjs": "5.0.0-beta.0", - "zone.js": "0.5.10" + "@angular/common": "2.1.1", + "@angular/compiler": "2.1.1", + "@angular/core": "2.1.1", + "@angular/forms": "^2.1.1", + "@angular/http": "2.1.1", + "@angular/platform-browser": "2.1.1", + "@angular/platform-browser-dynamic": "2.1.1", + "@angular/platform-server": "2.1.1", + "@angular/router": "3.1.1", + "@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", + "ie-shim": "^0.1.0", + "rxjs": "^5.0.0-rc.1", + "zone.js": "~0.6.17" }, "devDependencies": { - "copy-webpack-plugin": "^0.3.3", - "css-loader": "^0.23.0", - "exports-loader": "0.6.2", + "@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": "^4.0.0", + "css-loader": "^0.25.0", + "exports-loader": "^0.6.3", "expose-loader": "^0.7.1", - "file-loader": "^0.8.4", - "html-webpack-plugin": "^1.7.0", - "http-server": "^0.8.5", - "imports-loader": "^0.6.4", - "istanbul-instrumenter-loader": "^0.1.3", - "json-loader": "^0.5.3", - "karma": "^0.13.15", - "karma-chrome-launcher": "^0.2.1", - "karma-coverage": "^0.5.3", - "karma-jasmine": "^0.3.6", - "karma-phantomjs-launcher": "^0.2.1", - "karma-sourcemap-loader": "^0.3.6", - "karma-webpack": "1.7.0", - "phantomjs": "^1.9.18", - "phantomjs-polyfill": "0.0.1", - "protractor": "^3.0.0", + "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", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "1.8.0", + "parse5": "^2.2.2", + "protractor": "^4.0.9", "raw-loader": "0.5.1", - "reflect-metadata": "0.1.2", - "remap-istanbul": "^0.5.1", - "rimraf": "^2.4.4", - "style-loader": "^0.13.0", - "ts-helper": "0.0.1", - "ts-loader": "^0.7.2", - "tsconfig-lint": "^0.4.3", - "tslint": "^3.2.0", - "tslint-loader": "^2.1.0", - "typedoc": "^0.3.12", - "typescript": "^1.7.3", - "typings": "^0.6.1", - "url-loader": "^0.5.6", - "webpack": "^1.12.9", - "webpack-dev-server": "^1.12.1", - "webpack-md5-hash": "0.0.4" + "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.6", + "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.15.0" }, "repository": { "type": "git", @@ -89,10 +138,7 @@ "url": "https://github.com/angularclass/angular2-webpack-starter/issues" }, "engines": { - "node": ">= 4.2.1 <= 5", + "node": ">= 4.2.1", "npm": ">= 3" - }, - "keywords": [ - "" - ] -} \ No newline at end of file + } +} diff --git a/protractor.conf.js b/protractor.conf.js index c70f502..b3f7738 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -1,44 +1,6 @@ -// @AngularClass +/** + * @author: @AngularClass + */ -exports.config = { - baseUrl: 'http://localhost:3000/', - - specs: [ - 'test/**/*.e2e.js' - ], - exclude: [], - - framework: 'jasmine', - - allScriptsTimeout: 110000, - - jasmineNodeOpts: { - showTiming: true, - showColors: true, - isVerbose: false, - includeStackTrace: false, - defaultTimeoutInterval: 400000 - }, - directConnect: true, - - capabilities: { - 'browserName': 'chrome', - 'chromeOptions': { - 'args': ['show-fps-counter=true'] - } - }, - - onPrepare: function() { - browser.ignoreSynchronization = true; - }, - - - /** - * Angular 2 configuration - * - * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching - * `rootEl` - * - */ - useAllAngular2AppRoots: true -}; +// look in ./config for protractor.conf.js +exports.config = require('./config/protractor.conf.js').config; diff --git a/spec-bundle.js b/spec-bundle.js deleted file mode 100644 index 88117ab..0000000 --- a/spec-bundle.js +++ /dev/null @@ -1,43 +0,0 @@ -// @AngularClass -/* - * When testing with webpack and ES6, we have to do some extra - * things get testing to work right. Because we are gonna write test - * in ES6 to, we have to compile those as well. That's handled in - * karma.conf.js with the karma-webpack plugin. This is the entry - * file for webpack test. Just like webpack will create a bundle.js - * file for our client, when we run test, it well compile and bundle them - * all here! Crazy huh. So we need to do some setup -*/ -Error.stackTraceLimit = Infinity; -require('phantomjs-polyfill'); -require('es6-promise'); -require('es6-shim'); -require('es7-reflect-metadata/dist/browser'); - -require('zone.js/lib/browser/zone-microtask.js'); -require('zone.js/lib/browser/long-stack-trace-zone.js'); -require('zone.js/dist/jasmine-patch.js'); - -/* - Ok, this is kinda crazy. We can use the the context method on - require that webpack created in order to tell webpack - what files we actually want to require or import. - Below, context will be an function/object with file names as keys. - using that regex we are saying look in ./src/app and ./test then find - any file that ends with spec.js and get its path. By passing in true - we say do this recursively -*/ -var testContext = require.context('./test', true, /\.spec\.ts/); -var appContext = require.context('./src', true, /\.spec\.ts/); - -// 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 -appContext.keys().forEach(appContext); -testContext.keys().forEach(testContext); - -// Select BrowserDomAdapter. -// see https://github.com/AngularClass/angular2-webpack-starter/issues/124 -var domAdapter = require('angular2/src/platform/browser/browser_adapter'); -domAdapter.BrowserDomAdapter.makeCurrent(); - diff --git a/src/app/+detail/detail.component.ts b/src/app/+detail/detail.component.ts new file mode 100644 index 0000000..8209f7f --- /dev/null +++ b/src/app/+detail/detail.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'detail', + template: ` +

Hello from Detail

+ + ` +}) +export class DetailComponent { + constructor() { + + } + + ngOnInit() { + console.log('hello `Detail` component'); + } + +} diff --git a/src/app/+detail/index.ts b/src/app/+detail/index.ts new file mode 100644 index 0000000..8b92a74 --- /dev/null +++ b/src/app/+detail/index.ts @@ -0,0 +1,27 @@ +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { DetailComponent } from './detail.component'; + +console.log('`Detail` bundle loaded asynchronously'); +// async components must be named routes for WebpackAsyncRoute +export const routes = [ + { path: '', component: DetailComponent, pathMatch: 'full' } +]; + +@NgModule({ + declarations: [ + // Components / Directives/ Pipes + DetailComponent + ], + imports: [ + CommonModule, + FormsModule, + RouterModule.forChild(routes), + ] +}) +export default class AboutModule { + static routes = routes; +} diff --git a/src/app/about/about.component.spec.ts b/src/app/about/about.component.spec.ts new file mode 100644 index 0000000..7caf858 --- /dev/null +++ b/src/app/about/about.component.spec.ts @@ -0,0 +1,35 @@ +import { ActivatedRoute, Data } from '@angular/router'; +import { Component } from '@angular/core'; +import { inject, TestBed } from '@angular/core/testing'; + +// Load the implementations that should be tested +import { AboutComponent } from './about.component'; + +describe('About', () => { + // provide our implementations or mocks to the dependency injector + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + // provide a better mock + { + provide: ActivatedRoute, + useValue: { + data: { + subscribe: (fn: (value: Data) => void) => fn({ + yourData: 'yolo' + }) + } + } + }, + AboutComponent + ] + })); + + it('should log ngOnInit', inject([AboutComponent], (about: AboutComponent) => { + spyOn(console, 'log'); + expect(console.log).not.toHaveBeenCalled(); + + about.ngOnInit(); + expect(console.log).toHaveBeenCalled(); + })); + +}); diff --git a/src/app/about/about.component.ts b/src/app/about/about.component.ts new file mode 100644 index 0000000..f175245 --- /dev/null +++ b/src/app/about/about.component.ts @@ -0,0 +1,65 @@ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +/* + * 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('`About` component loaded asynchronously'); + +@Component({ + selector: 'about', + styles: [` + `], + template: ` +

About

+
+ For hot module reloading run +
npm run start:hmr
+
+
+

+ patrick@AngularClass.com +

+
+
this.localState = {{ localState | json }}
+ ` +}) +export class AboutComponent { + localState: any; + constructor(public route: ActivatedRoute) { + + } + + ngOnInit() { + this.route + .data + .subscribe((data: any) => { + // your resolved data from route + this.localState = data.yourData; + }); + + console.log('hello `About` component'); + // static data that is bundled + // var mockData = require('assets/mock-data/mock-data.json'); + // console.log('mockData', mockData); + // if you're working with mock data you can also use http.get('assets/mock-data/mock-data.json') + this.asyncDataWithWebpack(); + } + asyncDataWithWebpack() { + // you can also async load mock data with 'es6-promise-loader' + // you would do this if you don't want the mock-data bundled + // remember that 'es6-promise-loader' is a promise + setTimeout(() => { + + System.import('../../assets/mock-data/mock-data.json') + .then(json => { + console.log('async mockData', json); + this.localState = json; + }); + + }); + } + +} diff --git a/src/app/about/index.ts b/src/app/about/index.ts new file mode 100644 index 0000000..b7cb92a --- /dev/null +++ b/src/app/about/index.ts @@ -0,0 +1 @@ +export * from './about.component'; diff --git a/src/app/app.component.css b/src/app/app.component.css new file mode 100644 index 0000000..2fc581c --- /dev/null +++ b/src/app/app.component.css @@ -0,0 +1,8 @@ +html, body{ + height: 100%; + font-family: Arial, Helvetica, sans-serif +} + +span.active { + background-color: gray; +} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts new file mode 100644 index 0000000..2809520 --- /dev/null +++ b/src/app/app.component.spec.ts @@ -0,0 +1,22 @@ +import { + inject, + TestBed +} from '@angular/core/testing'; + +// Load the implementations that should be tested +import { AppComponent } from './app.component'; +import { AppState } from './app.service'; + +describe('App', () => { + // provide our implementations or mocks to the dependency injector + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + AppState, + AppComponent + ]})); + + it('should have a url', inject([ AppComponent ], (app: AppComponent) => { + expect(app.url).toEqual('https://twitter.com/AngularClass'); + })); + +}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts new file mode 100644 index 0000000..06c53d6 --- /dev/null +++ b/src/app/app.component.ts @@ -0,0 +1,83 @@ +/* + * Angular 2 decorators and services + */ +import { Component, ViewEncapsulation } from '@angular/core'; + +import { AppState } from './app.service'; + +/* + * App Component + * Top Level Component + */ +@Component({ + selector: 'app', + encapsulation: ViewEncapsulation.None, + styleUrls: [ + './app.component.css' + ], + template: ` + + +
+ +
+ +
this.appState.state = {{ appState.state | json }}
+ + + ` +}) +export class AppComponent { + angularclassLogo = 'assets/img/angularclass-avatar.png'; + name = 'Angular 2 Webpack Starter'; + url = 'https://twitter.com/AngularClass'; + + constructor( + public appState: AppState) { + + } + + ngOnInit() { + console.log('Initial App State', this.appState.state); + } + +} + +/* + * Please review the https://github.com/AngularClass/angular2-examples/ repo for + * more angular app examples that you may copy/paste + * (The examples may not be updated as quickly. Please open an issue on github for us to update it) + * For help or questions please contact us at @AngularClass on twitter + * or our chat on Slack at https://AngularClass.com/slack-join + */ diff --git a/src/app/app.e2e.ts b/src/app/app.e2e.ts new file mode 100644 index 0000000..59cb217 --- /dev/null +++ b/src/app/app.e2e.ts @@ -0,0 +1,32 @@ +describe('App', () => { + + beforeEach(() => { + browser.get('/'); + }); + + + it('should have a title', () => { + let subject = browser.getTitle(); + let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass'; + expect(subject).toEqual(result); + }); + + it('should have header', () => { + let subject = element(by.css('h1')).isPresent(); + let result = true; + expect(subject).toEqual(result); + }); + + it('should have ', () => { + let subject = element(by.css('app home')).isPresent(); + let result = true; + expect(subject).toEqual(result); + }); + + it('should have buttons', () => { + let subject = element(by.css('button')).getText(); + let result = 'Submit Value'; + expect(subject).toEqual(result); + }); + +}); diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..093cc7f --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,96 @@ +import { NgModule, ApplicationRef } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; +import { RouterModule } from '@angular/router'; +import { removeNgStyles, createNewHosts, createInputTransfer } from '@angularclass/hmr'; + +/* + * Platform and Environment providers/directives/pipes + */ +import { ENV_PROVIDERS } from './environment'; +import { ROUTES } from './app.routes'; +// App is our top level component +import { AppComponent } from './app.component'; +import { APP_RESOLVER_PROVIDERS } from './app.resolver'; +import { AppState, InternalStateType } from './app.service'; +import { HomeComponent } from './home'; +import { AboutComponent } from './about'; +import { NoContentComponent } from './no-content'; +import { XLarge } from './home/x-large'; + +// Application wide providers +const APP_PROVIDERS = [ + ...APP_RESOLVER_PROVIDERS, + AppState +]; + +type StoreType = { + state: InternalStateType, + restoreInputValues: () => void, + disposeOldHosts: () => void +}; + +/** + * `AppModule` is the main entry point into Angular2's bootstraping process + */ +@NgModule({ + bootstrap: [ AppComponent ], + declarations: [ + AppComponent, + AboutComponent, + HomeComponent, + NoContentComponent, + XLarge + ], + imports: [ // import Angular's modules + BrowserModule, + FormsModule, + HttpModule, + RouterModule.forRoot(ROUTES, { useHash: true }) + ], + providers: [ // expose our Services and Providers into Angular's dependency injection + ENV_PROVIDERS, + APP_PROVIDERS + ] +}) +export class AppModule { + constructor(public appRef: ApplicationRef, public appState: AppState) {} + + hmrOnInit(store: StoreType) { + if (!store || !store.state) return; + console.log('HMR store', JSON.stringify(store, null, 2)); + // set state + this.appState._state = store.state; + // set input values + if ('restoreInputValues' in store) { + let restoreInputValues = store.restoreInputValues; + setTimeout(restoreInputValues); + } + + this.appRef.tick(); + delete store.state; + delete store.restoreInputValues; + } + + hmrOnDestroy(store: StoreType) { + const cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement); + // save state + const state = this.appState._state; + store.state = state; + // recreate root elements + store.disposeOldHosts = createNewHosts(cmpLocation); + // save input values + store.restoreInputValues = createInputTransfer(); + // remove styles + removeNgStyles(); + } + + hmrAfterDestroy(store: StoreType) { + // display new elements + store.disposeOldHosts(); + delete store.disposeOldHosts; + } + +} + diff --git a/src/app/app.resolver.ts b/src/app/app.resolver.ts new file mode 100644 index 0000000..09cf0fc --- /dev/null +++ b/src/app/app.resolver.ts @@ -0,0 +1,19 @@ +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; + +@Injectable() +export class DataResolver implements Resolve { + constructor() { + + } + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + return Observable.of({ res: 'I am data'}); + } +} + +// an array of services to resolve routes with data +export const APP_RESOLVER_PROVIDERS = [ + DataResolver +]; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 0000000..5b81288 --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,20 @@ +import { Routes, RouterModule } from '@angular/router'; +import { HomeComponent } from './home'; +import { AboutComponent } from './about'; +import { NoContentComponent } from './no-content'; + +import { DataResolver } from './app.resolver'; + + +export const ROUTES: Routes = [ + { path: '', component: HomeComponent }, + { path: 'home', component: HomeComponent }, + { path: 'about', component: AboutComponent }, + { + path: 'detail', loadChildren: () => System.import('./+detail').then((comp: any) => { + return comp.default; + }) + , + }, + { path: '**', component: NoContentComponent }, +]; diff --git a/src/app/app.service.ts b/src/app/app.service.ts new file mode 100644 index 0000000..854db96 --- /dev/null +++ b/src/app/app.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; + +export type InternalStateType = { + [key: string]: any +}; + +@Injectable() +export class AppState { + _state: InternalStateType = { }; + + constructor() { + + } + + // already return a clone of the current state + get state() { + return this._state = this._clone(this._state); + } + // never allow mutation + set state(value) { + throw new Error('do not mutate the `.state` directly'); + } + + + get(prop?: any) { + // use our state getter for the clone + const state = this.state; + return state.hasOwnProperty(prop) ? state[prop] : state; + } + + set(prop: string, value: any) { + // internally mutate our state + return this._state[prop] = value; + } + + + private _clone(object: InternalStateType) { + // simple object clone + return JSON.parse(JSON.stringify( object )); + } +} diff --git a/src/app/app.spec.ts b/src/app/app.spec.ts deleted file mode 100644 index c20da77..0000000 --- a/src/app/app.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { -it, -inject, -injectAsync, -beforeEachProviders, -TestComponentBuilder -} from 'angular2/testing'; - -// Load the implementations that should be tested -import {App} from './app'; - -describe('App', () => { - // provide our implementations or mocks to the dependency injector - beforeEachProviders(() => [ - App - ]); - - it('should have a name', inject([App], (app) => { - expect(app.name).toEqual('webpack-test'); - })); - -}); diff --git a/src/app/app.ts b/src/app/app.ts deleted file mode 100644 index 6a3f7dd..0000000 --- a/src/app/app.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Angular 2 decorators and services - */ -import {Component} from 'angular2/core'; -import {RouteConfig, Router, ROUTER_DIRECTIVES} from 'angular2/router'; -import {FORM_PROVIDERS} from 'angular2/common'; - -import {RouterActive} from './directives/router-active'; -import {Home} from './home/home'; - -/* - * App Component - * Top Level Component - */ -@Component({ - selector: 'app', - providers: [...FORM_PROVIDERS], - directives: [...ROUTER_DIRECTIVES, RouterActive], - pipes: [], - styles: [` - nav ul { - display: inline; - list-style-type: none; - margin: 0; - padding: 0; - width: 60px; - } - nav li { - display: inline; - } - nav li.active { - background-color: lightgray; - } - `], - template: ` -
- -
- -
- Random -
- -
- webpack-test by -
- ` -}) -@RouteConfig([ - { path: '/', component: Home, name: 'Index' }, - { path: '/home', component: Home, name: 'Home' }, - { path: '/**', redirectTo: ['Index'] } -]) -export class App { - name = 'webpack-test'; - constructor() { - - } -} - -/* - * Please review the https://github.com/AngularClass/angular2-examples/ repo for - * more angular app examples that you may copy/paste - * (The examples may not be updated as quickly. Please open an issue on github for us to update it) - * For help or questions please contact us at @AngularClass on twitter - * or our chat on Slack at https://AngularClass.com/slack-join - * or via chat on Gitter at https://gitter.im/AngularClass/angular2-webpack-starter - */ diff --git a/src/app/directives/router-active.ts b/src/app/directives/router-active.ts deleted file mode 100644 index d8e52ae..0000000 --- a/src/app/directives/router-active.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {Router} from 'angular2/router'; -import {isPresent} from 'angular2/src/facade/lang'; -import {Directive, Query, QueryList, Attribute, ElementRef, Renderer} from 'angular2/core'; -import {Instruction, RouterLink} from 'angular2/router'; - -/** - * RouterActive dynamically finds the first element with routerLink and toggles the active class - * - * ## Use - * - * ``` - *
  • Home
  • - *
  • Home
  • - * ``` - */ -@Directive({ - selector: '[router-active]', - inputs: ['routerActive'] -}) -export class RouterActive { - routerActive: string = null; - routerActiveAttr: string = 'active'; - - constructor( - router: Router, - element: ElementRef, - renderer: Renderer, - @Query(RouterLink) routerLink: QueryList, - @Attribute('router-active') routerActiveAttr: string) { - - router.subscribe(() => { - let active = (routerLink).first.isRouteActive; - renderer.setElementClass(element.nativeElement, this._attrOrProp(), active); - }); - } - private _attrOrProp() { - return isPresent(this.routerActive) ? this.routerActive : this.routerActiveAttr; - } -} diff --git a/src/app/environment.ts b/src/app/environment.ts new file mode 100644 index 0000000..8d5288f --- /dev/null +++ b/src/app/environment.ts @@ -0,0 +1,50 @@ + +// Angular 2 +// rc2 workaround +import { enableDebugTools, disableDebugTools } from '@angular/platform-browser'; +import { enableProdMode, ApplicationRef } from '@angular/core'; +// Environment Providers +let PROVIDERS: any[] = [ + // common env directives +]; + +// Angular debug tools in the dev console +// https://github.com/angular/angular/blob/86405345b781a9dc2438c0fbe3e9409245647019/TOOLS_JS.md +let _decorateModuleRef = function identity(value: T): T { return value; }; + +if ('production' === ENV) { + // Production + disableDebugTools(); + enableProdMode(); + + PROVIDERS = [ + ...PROVIDERS, + // custom providers in production + ]; + +} else { + + _decorateModuleRef = (modRef: any) => { + const appRef = modRef.injector.get(ApplicationRef); + const cmpRef = appRef.components[0]; + + let _ng = (window).ng; + enableDebugTools(cmpRef); + (window).ng.probe = _ng.probe; + (window).ng.coreTokens = _ng.coreTokens; + return modRef; + }; + + // Development + PROVIDERS = [ + ...PROVIDERS, + // custom providers in development + ]; + +} + +export const decorateModuleRef = _decorateModuleRef; + +export const ENV_PROVIDERS = [ + ...PROVIDERS +]; diff --git a/src/app/home/directives/x-large.spec.ts b/src/app/home/directives/x-large.spec.ts deleted file mode 100644 index 90a1b6b..0000000 --- a/src/app/home/directives/x-large.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { -it, -inject, -injectAsync, -describe, -beforeEachProviders, -TestComponentBuilder -} from 'angular2/testing'; - -import {Component, provide} from 'angular2/core'; -import {BaseRequestOptions, Http} from 'angular2/http'; -import {MockBackend} from 'angular2/http/testing'; - -// Load the implementations that should be tested -import {XLarge} from './x-large'; - -describe('x-large directive', () => { - // Create a test component to test directives - @Component({ - template: '', - directives: [XLarge] - }) - class TestComponent { } - - it('should sent font-size to x-large', injectAsync([TestComponentBuilder], (tcb) => { - return tcb.overrideTemplate(TestComponent, '
    Content
    ') - .createAsync(TestComponent).then((fixture: any) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement.children[0]; - expect(compiled.style.fontSize).toBe('x-large'); - }); - })); - -}); diff --git a/src/app/home/home.component.css b/src/app/home/home.component.css new file mode 100644 index 0000000..4511e22 --- /dev/null +++ b/src/app/home/home.component.css @@ -0,0 +1 @@ +/*styles for home content only*/ \ No newline at end of file diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html new file mode 100644 index 0000000..dcc5f59 --- /dev/null +++ b/src/app/home/home.component.html @@ -0,0 +1,41 @@ +
    +

    Your Content Here

    + +
    + For material design components use the material2 branch +
    + +
    + +
    + For hot module reloading run +
    npm run start:hmr
    +
    + +
    + +
    +

    Local State

    + +
    + + + + +
    + + +
    this.localState = {{ localState | json }}
    + +
    + +
    diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts new file mode 100644 index 0000000..75d3eb8 --- /dev/null +++ b/src/app/home/home.component.spec.ts @@ -0,0 +1,53 @@ +import { + inject, + TestBed +} from '@angular/core/testing'; +import { Component } from '@angular/core'; +import { + BaseRequestOptions, + ConnectionBackend, + Http +} from '@angular/http'; +import { MockBackend } from '@angular/http/testing'; + +// Load the implementations that should be tested +import { AppState } from '../app.service'; +import { HomeComponent } from './home.component'; +import { Title } from './title'; + +describe('Home', () => { + // provide our implementations or mocks to the dependency injector + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + BaseRequestOptions, + MockBackend, + { + provide: Http, + useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) { + return new Http(backend, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + }, + AppState, + Title, + HomeComponent + ] + })); + + it('should have default data', inject([ HomeComponent ], (home: HomeComponent) => { + expect(home.localState).toEqual({ value: '' }); + })); + + it('should have a title', inject([ HomeComponent ], (home: HomeComponent) => { + expect(!!home.title).toEqual(true); + })); + + it('should log ngOnInit', inject([ HomeComponent ], (home: HomeComponent) => { + spyOn(console, 'log'); + expect(console.log).not.toHaveBeenCalled(); + + home.ngOnInit(); + expect(console.log).toHaveBeenCalled(); + })); + +}); diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts new file mode 100644 index 0000000..47e31a6 --- /dev/null +++ b/src/app/home/home.component.ts @@ -0,0 +1,39 @@ +import { Component } from '@angular/core'; + +import { AppState } from '../app.service'; +import { Title } from './title'; +import { XLarge } from './x-large'; + +@Component({ + // The selector is what angular internally uses + // for `document.querySelectorAll(selector)` in our index.html + // where, in this case, selector is the string 'home' + selector: 'home', // + // We need to tell Angular's Dependency Injection which providers are in our app. + providers: [ + Title + ], + // Our list of styles in our component. We may add more to compose many styles together + styleUrls: [ './home.component.css' ], + // Every Angular template is first compiled by the browser before Angular runs it's compiler + templateUrl: './home.component.html' +}) +export class HomeComponent { + // Set our default values + localState = { value: '' }; + // TypeScript public modifiers + constructor(public appState: AppState, public title: Title) { + + } + + ngOnInit() { + console.log('hello `Home` component'); + // this.title.getData().subscribe(data => this.data = data); + } + + submitState(value: string) { + console.log('submitState', value); + this.appState.set('value', value); + this.localState.value = ''; + } +} diff --git a/src/app/home/home.css b/src/app/home/home.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/home/home.e2e.ts b/src/app/home/home.e2e.ts new file mode 100644 index 0000000..ec1f519 --- /dev/null +++ b/src/app/home/home.e2e.ts @@ -0,0 +1,22 @@ +describe('App', () => { + + beforeEach(() => { + // change hash depending on router LocationStrategy + browser.get('/#/home'); + }); + + + it('should have a title', () => { + let subject = browser.getTitle(); + let result = 'Angular2 Webpack Starter by @gdi2290 from @AngularClass'; + expect(subject).toEqual(result); + }); + + it('should have `your content here` x-large', () => { + let subject = element(by.css('[x-large]')).getText(); + let result = 'Your Content Here'; + expect(subject).toEqual(result); + }); + + +}); diff --git a/src/app/home/home.html b/src/app/home/home.html deleted file mode 100644 index d3ed070..0000000 --- a/src/app/home/home.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - Your Content Here - - - -
    this.title = {{ title | json }}
    -
    diff --git a/src/app/home/home.spec.ts b/src/app/home/home.spec.ts deleted file mode 100644 index 17e267e..0000000 --- a/src/app/home/home.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { -it, -inject, -injectAsync, -describe, -beforeEachProviders, -TestComponentBuilder -} from 'angular2/testing'; - -import {Component, provide} from 'angular2/core'; -import {BaseRequestOptions, Http} from 'angular2/http'; -import {MockBackend} from 'angular2/http/testing'; - -// Load the implementations that should be tested -import {Home} from './home'; -import {Title} from './providers/title'; - -describe('Home', () => { - // provide our implementations or mocks to the dependency injector - beforeEachProviders(() => [ - Title, - Home, - BaseRequestOptions, - MockBackend, - provide(Http, { - useFactory: function(backend, defaultOptions) { - return new Http(backend, defaultOptions); - }, - deps: [MockBackend, BaseRequestOptions] - }) - ]); - - it('should have a title', inject([Home], (home) => { - expect(home.title.value).toEqual('Angular 2'); - })); - - it('should have a http', inject([Home], (home) => { - expect(!!home.http).toEqual(true); - })); - - it('should log ngOnInit', inject([Home], (home) => { - spyOn(console, 'log'); - expect(console.log).not.toHaveBeenCalled(); - - home.ngOnInit(); - expect(console.log).toHaveBeenCalled(); - })); - -}); diff --git a/src/app/home/home.ts b/src/app/home/home.ts deleted file mode 100644 index 67628bd..0000000 --- a/src/app/home/home.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Component} from 'angular2/core'; -import {FORM_DIRECTIVES} from 'angular2/common'; -import {Http} from 'angular2/http'; - -import {Title} from './providers/title'; -import {XLarge} from './directives/x-large'; - -@Component({ - // The selector is what angular internally uses - // for `document.querySelectorAll(selector)` in our index.html - // where, in this case, selector is the string 'app' - selector: 'home', // - // We need to tell Angular's Dependency Injection which providers are in our app. - providers: [ - Title - ], - // We need to tell Angular's compiler which directives are in our template. - // Doing so will allow Angular to attach our behavior to an element - directives: [ - ...FORM_DIRECTIVES, - XLarge - ], - // We need to tell Angular's compiler which custom pipes are in our template. - pipes: [], - // Our list of styles in our component. We may add more to compose many styles together - styles: [require('./home.css')], - // Every Angular template is first compiled by the browser before Angular runs it's compiler - template: require('./home.html') -}) -export class Home { - // TypeScript public modifiers - constructor(public title: Title, public http: Http) { - - } - - ngOnInit() { - console.log('hello Home component'); - } - -} diff --git a/src/app/home/index.ts b/src/app/home/index.ts new file mode 100644 index 0000000..ab5a522 --- /dev/null +++ b/src/app/home/index.ts @@ -0,0 +1 @@ +export * from './home.component'; diff --git a/src/app/home/providers/title.spec.ts b/src/app/home/providers/title.spec.ts deleted file mode 100644 index 7800e98..0000000 --- a/src/app/home/providers/title.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { -it, -inject, -injectAsync, -beforeEachProviders, -TestComponentBuilder -} from 'angular2/testing'; -import {Title} from './title'; - -describe('Title', () => { - let title; - - beforeEach(() => { - title = new Title(); - }); - - it('should return the list of names', () => { - expect(title.value).toEqual('Angular 2'); - }); -}); diff --git a/src/app/home/providers/title.ts b/src/app/home/providers/title.ts deleted file mode 100644 index fad92e9..0000000 --- a/src/app/home/providers/title.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {Injectable} from 'angular2/core'; - -@Injectable() -export class Title { - value = 'Angular 2'; - constructor() { - } -} diff --git a/src/app/home/title/index.ts b/src/app/home/title/index.ts new file mode 100644 index 0000000..1410559 --- /dev/null +++ b/src/app/home/title/index.ts @@ -0,0 +1 @@ +export * from './title.service'; diff --git a/src/app/home/title/title.service.spec.ts b/src/app/home/title/title.service.spec.ts new file mode 100644 index 0000000..8cca3fd --- /dev/null +++ b/src/app/home/title/title.service.spec.ts @@ -0,0 +1,43 @@ +import { + inject, + TestBed +} from '@angular/core/testing'; +import { Component } from '@angular/core'; +import { + BaseRequestOptions, + ConnectionBackend, + Http +} from '@angular/http'; +import { MockBackend } from '@angular/http/testing'; + +import { Title } from './title.service'; + +describe('Title', () => { + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + BaseRequestOptions, + MockBackend, + { + provide: Http, + useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) { + return new Http(backend, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + }, + Title + ]})); + + it('should have http', inject([ Title ], (title: Title) => { + expect(!!title.http).toEqual(true); + })); + + it('should get data from the server', inject([ Title ], (title: Title) => { + spyOn(console, 'log'); + expect(console.log).not.toHaveBeenCalled(); + + title.getData(); + expect(console.log).toHaveBeenCalled(); + expect(title.getData()).toEqual({ value: 'AngularClass' }); + })); + +}); diff --git a/src/app/home/title/title.service.ts b/src/app/home/title/title.service.ts new file mode 100644 index 0000000..599ef56 --- /dev/null +++ b/src/app/home/title/title.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +@Injectable() +export class Title { + value = 'Angular 2'; + constructor(public http: Http) { + + } + + getData() { + console.log('Title#getData(): Get Data'); + // return this.http.get('/assets/data.json') + // .map(res => res.json()); + return { + value: 'AngularClass' + }; + } + +} diff --git a/src/app/home/x-large/index.ts b/src/app/home/x-large/index.ts new file mode 100644 index 0000000..7038da2 --- /dev/null +++ b/src/app/home/x-large/index.ts @@ -0,0 +1 @@ +export * from './x-large.directive'; diff --git a/src/app/home/x-large/x-large.directive.spec.ts b/src/app/home/x-large/x-large.directive.spec.ts new file mode 100644 index 0000000..9f23b2a --- /dev/null +++ b/src/app/home/x-large/x-large.directive.spec.ts @@ -0,0 +1,44 @@ +import { + fakeAsync, + inject, + tick, + TestBed +} from '@angular/core/testing'; +import { Component } from '@angular/core'; +import { BaseRequestOptions, Http } from '@angular/http'; +import { By } from '@angular/platform-browser/src/dom/debug/by'; +import { MockBackend } from '@angular/http/testing'; + +// Load the implementations that should be tested +import { XLarge } from './x-large.directive'; + +describe('x-large directive', () => { + // Create a test component to test directives + @Component({ + template: '
    Content
    ' + }) + class TestComponent { } + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ + XLarge, + TestComponent + ] + }); + }); + + it('should sent font-size to x-large', fakeAsync(() => { + TestBed.compileComponents().then(() => { + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + tick(); + const element = fixture.debugElement.query(By.css('div')); + + expect(element.nativeElement.style.fontSize).toBe('x-large'); + + }); + })); + +}); diff --git a/src/app/home/directives/x-large.ts b/src/app/home/x-large/x-large.directive.ts similarity index 87% rename from src/app/home/directives/x-large.ts rename to src/app/home/x-large/x-large.directive.ts index eaa250c..3719f75 100644 --- a/src/app/home/directives/x-large.ts +++ b/src/app/home/x-large/x-large.directive.ts @@ -1,4 +1,4 @@ -import {Directive, Component, ElementRef, Renderer} from 'angular2/core'; +import { Component, Directive, ElementRef, Renderer } from '@angular/core'; /* * Directive * XLarge is a simple directive to show how one is made diff --git a/src/app/index.ts b/src/app/index.ts new file mode 100644 index 0000000..4d4a9db --- /dev/null +++ b/src/app/index.ts @@ -0,0 +1,2 @@ +// App +export * from './app.module'; diff --git a/src/app/no-content/index.ts b/src/app/no-content/index.ts new file mode 100644 index 0000000..93ea576 --- /dev/null +++ b/src/app/no-content/index.ts @@ -0,0 +1 @@ +export * from './no-content.component'; diff --git a/src/app/no-content/no-content.component.ts b/src/app/no-content/no-content.component.ts new file mode 100644 index 0000000..7aef10e --- /dev/null +++ b/src/app/no-content/no-content.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'no-content', + template: ` +
    +

    404: page missing

    +
    + ` +}) +export class NoContentComponent { + +} diff --git a/src/assets/css/.gitkeep b/src/assets/css/.gitkeep new file mode 100644 index 0000000..857ef8c --- /dev/null +++ b/src/assets/css/.gitkeep @@ -0,0 +1 @@ +@AngularClass diff --git a/src/assets/data.json b/src/assets/data.json new file mode 100644 index 0000000..b566a0b --- /dev/null +++ b/src/assets/data.json @@ -0,0 +1,3 @@ +{ + "value": "AngularClass" +} diff --git a/src/assets/img/angular-logo.png b/src/assets/img/angular-logo.png new file mode 100644 index 0000000..9838bd7 Binary files /dev/null and b/src/assets/img/angular-logo.png differ diff --git a/src/assets/img/angularclass-avatar.png b/src/assets/img/angularclass-avatar.png new file mode 100644 index 0000000..3f5f8bc Binary files /dev/null and b/src/assets/img/angularclass-avatar.png differ diff --git a/src/assets/img/angularclass-logo.png b/src/assets/img/angularclass-logo.png new file mode 100644 index 0000000..4342316 Binary files /dev/null and b/src/assets/img/angularclass-logo.png differ diff --git a/src/assets/manifest.json b/src/assets/manifest.json index b8b45ed..850f16f 100644 --- a/src/assets/manifest.json +++ b/src/assets/manifest.json @@ -1,41 +1,35 @@ { - "name": "webpack-test", + "name": "App", "icons": [ { "src": "/assets/icon/android-icon-36x36.png", "sizes": "36x36", - "type": "image/png", - "density": 0.75 + "type": "image/png" }, { "src": "/assets/icon/android-icon-48x48.png", "sizes": "48x48", - "type": "image/png", - "density": 1.0 + "type": "image/png" }, { "src": "/assets/icon/android-icon-72x72.png", "sizes": "72x72", - "type": "image/png", - "density": 1.5 + "type": "image/png" }, { "src": "/assets/icon/android-icon-96x96.png", "sizes": "96x96", - "type": "image/png", - "density": 2.0 + "type": "image/png" }, { "src": "/assets/icon/android-icon-144x144.png", "sizes": "144x144", - "type": "image/png", - "density": 3.0 + "type": "image/png" }, { "src": "/assets/icon/android-icon-192x192.png", "sizes": "192x192", - "type": "image/png", - "density": 4.0 + "type": "image/png" } ] } diff --git a/src/assets/mock-data/mock-data.json b/src/assets/mock-data/mock-data.json new file mode 100644 index 0000000..d7285e8 --- /dev/null +++ b/src/assets/mock-data/mock-data.json @@ -0,0 +1,3 @@ +[ + {"res": "data"} +] diff --git a/src/custom-typings.d.ts b/src/custom-typings.d.ts new file mode 100644 index 0000000..0ad70d9 --- /dev/null +++ b/src/custom-typings.d.ts @@ -0,0 +1,123 @@ +/* + * Custom Type Definitions + * When including 3rd party modules you also need to include the type definition for the module + * if they don't provide one within the module. You can try to install it with @types + +npm install @types/node +npm install @types/lodash + + * If you can't find the type definition in the registry we can make an ambient/global definition in + * this file for now. For example + +declare module 'my-module' { + export function doesSomething(value: string): string; +} + + * If you are using a CommonJS module that is using module.exports then you will have to write your + * types using export = yourObjectOrFunction with a namespace above it + * notice how we have to create a namespace that is equal to the function we're + * assigning the export to + +declare module 'jwt-decode' { + function jwtDecode(token: string): any; + namespace jwtDecode {} + export = jwtDecode; +} + + * + * If you're prototying and you will fix the types later you can also declare it as type any + * + +declare var assert: any; +declare var _: any; +declare var $: any; + + * + * If you're importing a module that uses Node.js modules which are CommonJS you need to import as + * in the files such as main.browser.ts or any file within app/ + * + +import * as _ from 'lodash' + + * You can include your type definitions in this file until you create one for the @types + * + */ + +// support NodeJS modules without type definitions +declare module '*'; + +// Extra variables that live on Global that will be replaced by webpack DefinePlugin +declare var ENV: string; +declare var HMR: boolean; +declare var System: SystemJS; + +interface SystemJS { + import: (path?: string) => Promise; +} + +interface GlobalEnvironment { + ENV: string; + HMR: boolean; + SystemJS: SystemJS; + System: SystemJS; +} + +interface Es6PromiseLoader { + (id: string): (exportName?: string) => Promise; +} + +type FactoryEs6PromiseLoader = () => Es6PromiseLoader; +type FactoryPromise = () => Promise; + +type AsyncRoutes = { + [component: string]: Es6PromiseLoader | + Function | + FactoryEs6PromiseLoader | + FactoryPromise +}; + + +type IdleCallbacks = Es6PromiseLoader | + Function | + FactoryEs6PromiseLoader | + FactoryPromise ; + +interface WebpackModule { + hot: { + data?: any, + idle: any, + accept(dependencies?: string | string[], callback?: (updatedDependencies?: any) => void): void; + decline(deps?: any | string | string[]): void; + dispose(callback?: (data?: any) => void): void; + addDisposeHandler(callback?: (data?: any) => void): void; + removeDisposeHandler(callback?: (data?: any) => void): void; + check(autoApply?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void; + apply(options?: any, callback?: (err?: Error, outdatedModules?: any[]) => void): void; + status(callback?: (status?: string) => void): void | string; + removeStatusHandler(callback?: (status?: string) => void): void; + }; +} + + +interface WebpackRequire { + (id: string): any; + (paths: string[], callback: (...modules: any[]) => void): void; + ensure(ids: string[], callback: (req: WebpackRequire) => void, chunkName?: string): void; + context(directory: string, useSubDirectories?: boolean, regExp?: RegExp): WebpackContext; +} + +interface WebpackContext extends WebpackRequire { + keys(): string[]; +} + +interface ErrorStackTraceLimit { + stackTraceLimit: number; +} + + +// Extend typings +interface NodeRequire extends WebpackRequire {} +interface ErrorConstructor extends ErrorStackTraceLimit {} +interface NodeRequireFunction extends Es6PromiseLoader {} +interface NodeModule extends WebpackModule {} +interface Global extends GlobalEnvironment {} diff --git a/src/index.html b/src/index.html index 018fdad..c173de8 100644 --- a/src/index.html +++ b/src/index.html @@ -1,41 +1,25 @@ - - {%= o.webpackConfig.metadata.title %} - - + - - - - - - - - - - - - - - - - - - - - + <%= htmlWebpackPlugin.options.title %> + + + + <% if (webpackConfig.htmlElements.headTags) { %> + + <%= webpackConfig.htmlElements.headTags %> + <% } %> - + + - {% for (var css in o.htmlWebpackPlugin.files.css) { %} - - {% } %} + @@ -43,25 +27,21 @@ - - - - - + --> + ga('create', 'UA-71073175-1', 'auto'); + ga('send', 'pageview'); + - {% if (o.webpackConfig.metadata.ENV === 'development') { %} + <% if (htmlWebpackPlugin.options.metadata.isDevServer && htmlWebpackPlugin.options.metadata.HMR !== true) { %> - - {% } %} + + <% } %> - - {% for (var chunk in o.htmlWebpackPlugin.files.chunks) { %} - - {% } %} diff --git a/src/main.browser.ts b/src/main.browser.ts new file mode 100644 index 0000000..6114ae7 --- /dev/null +++ b/src/main.browser.ts @@ -0,0 +1,25 @@ +/* + * Angular bootstraping + */ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { decorateModuleRef } from './app/environment'; +import { bootloader } from '@angularclass/hmr'; +/* + * App Module + * our top level module that holds all of our components + */ +import { AppModule } from './app'; + +/* + * Bootstrap our Angular app with a top level NgModule + */ +export function main(): Promise { + return platformBrowserDynamic() + .bootstrapModule(AppModule) + .then(decorateModuleRef) + .catch(err => console.error(err)); +} + +// needed for hmr +// in prod this is replace for document ready +bootloader(main); diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index 3f7c2b6..0000000 --- a/src/main.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Providers provided by Angular - */ -import {provide} from 'angular2/core'; -import {bootstrap, ELEMENT_PROBE_PROVIDERS} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router'; -import {HTTP_PROVIDERS} from 'angular2/http'; - -/* - * App Component - * our top level component that holds all of our components - */ -import {App} from './app/app'; -/* - * Bootstrap our Angular app with a top level component `App` and inject - * our Services and Providers into Angular's dependency injection - */ -document.addEventListener('DOMContentLoaded', function main() { - bootstrap(App, [ - ...('production' === process.env.ENV ? [] : ELEMENT_PROBE_PROVIDERS), - ...HTTP_PROVIDERS, - ...ROUTER_PROVIDERS, - provide(LocationStrategy, { useClass: HashLocationStrategy }) - ]) - .catch(err => console.error(err)); -}); diff --git a/src/meta/humans.txt b/src/meta/humans.txt new file mode 100644 index 0000000..b2d8794 --- /dev/null +++ b/src/meta/humans.txt @@ -0,0 +1,17 @@ +# humanstxt.org/ +# The humans responsible & technology colophon + +# TEAM + + -- -- + +# THANKS + + + PatrickJS -- @gdi2290 + AngularClass -- @AngularClass + +# TECHNOLOGY COLOPHON + + HTML5, CSS3 + Angular2, TypeScript, Webpack diff --git a/src/meta/robots.txt b/src/meta/robots.txt new file mode 100644 index 0000000..9417495 --- /dev/null +++ b/src/meta/robots.txt @@ -0,0 +1,3 @@ +# robotstxt.org + +User-agent: * diff --git a/src/polyfills.browser.ts b/src/polyfills.browser.ts new file mode 100644 index 0000000..3d0dcd0 --- /dev/null +++ b/src/polyfills.browser.ts @@ -0,0 +1,47 @@ +// TODO(gdi2290): switch to DLLs + +// Polyfills + +// import 'ie-shim'; // Internet Explorer 9 support + + +// import 'core-js/es6'; +// Added parts of es6 which are necessary for your project or your browser support requirements. +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/set'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/weak-set'; +import 'core-js/es6/typed'; +import 'core-js/es6/reflect'; +// see issue https://github.com/AngularClass/angular2-webpack-starter/issues/709 +// import 'core-js/es6/promise'; + +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; + +// Typescript emit helpers polyfill +import 'ts-helpers'; + +if ('production' === ENV) { + // Production + + +} else { + // Development + + Error.stackTraceLimit = Infinity; + + require('zone.js/dist/long-stack-trace-zone'); + +} diff --git a/src/vendor.browser.ts b/src/vendor.browser.ts new file mode 100644 index 0000000..cec2d7d --- /dev/null +++ b/src/vendor.browser.ts @@ -0,0 +1,31 @@ +// For vendors for example jQuery, Lodash, angular2-jwt just import them here unless you plan on +// chunking vendors files for async loading. You would need to import the async loaded vendors +// at the entry point of the async loaded file. Also see custom-typings.d.ts as you also need to +// run `typings install x` where `x` is your module + +// TODO(gdi2290): switch to DLLs + +// Angular 2 +import '@angular/platform-browser'; +import '@angular/platform-browser-dynamic'; +import '@angular/core'; +import '@angular/common'; +import '@angular/forms'; +import '@angular/http'; +import '@angular/router'; + +// AngularClass +import '@angularclass/hmr'; + +// RxJS +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/mergeMap'; + +if ('production' === ENV) { + // Production + + +} else { + // Development + +} diff --git a/src/vendor.ts b/src/vendor.ts deleted file mode 100644 index 711c815..0000000 --- a/src/vendor.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Polyfills -import 'es6-shim'; -// (these modules are what are in 'angular2/bundles/angular2-polyfills' so don't use that here) -import 'es6-promise'; -import 'zone.js/lib/browser/zone-microtask'; - -if ('production' !== process.env.ENV) { - // Reflect Polyfill - require('es7-reflect-metadata/dist/browser'); - Error['stackTraceLimit'] = Infinity; - Zone['longStackTraceZone'] = require('zone.js/lib/zones/long-stack-trace.js'); -} - -if ('production' === process.env.ENV) { - // Reflect with es7-reflect-metadata/reflect-metadata is added - // by webpack.prod.config ProvidePlugin - let ngCore = require('angular2/core'); - ngCore.enableProdMode(); -} -// Angular 2 -import 'angular2/platform/browser'; -import 'angular2/platform/common_dom'; -import 'angular2/router'; -import 'angular2/http'; -import 'angular2/core'; - -// RxJS -import 'rxjs'; - -// Other vendors for example jQuery, Lodash, angular2-jwt -import 'github-api/github'; diff --git a/test/app/app.e2e.js b/test/app/app.e2e.js deleted file mode 100644 index 6562f9d..0000000 --- a/test/app/app.e2e.js +++ /dev/null @@ -1,35 +0,0 @@ - /* - * TODO: ES5 for now until I make a webpack plugin for protractor - */ -describe('App', function() { - - beforeEach(function() { - browser.get('/'); - }); - - - it('should have a title', function() { - var subject = browser.getTitle(); - var result = 'webpack-test'; - expect(subject).toEqual(result); - }); - - it('should have
    ', function() { - var subject = element(by.deepCss('app /deep/ header')).isPresent(); - var result = true; - expect(subject).toEqual(result); - }); - - it('should have
    ', function() { - var subject = element(by.deepCss('app /deep/ main')).isPresent(); - var result = true; - expect(subject).toEqual(result); - }); - - it('should have