The goal of this repo is introduce how to setup an empty, prue clean angular 2 project using webpack 2. The reason why we need an empty angular2+webpack project. Because the offical seed project is build up by angularcli, its disadvanage is lower configurable than webpack. The other hand, setup a seed project is a good practise to understand modules dependency of angular2, and good understand to webpack configuration
- Create an empty npm package
mkdir angular2-webpack-seed
cd angular2-webpack-seed
# Create package.json
npm init
package.json
is generated, remove some properies like below
{
"name": "ng2demo",
"version": "1.0.0",
"description": "",
"scripts": {
},
"author": ""
}
- Init Git repo
git init
- Install webpack 2
npm install webpack@beta --save-dev
webpack is a dev tool, it is not used in product souce code, so we use --save-dev
option
- Create
.gitignore
file for ignore some careless files
node_modules\
- Create file and folder structure for angular 2
│ .gitignore
│ package.json
│
└───src
│ index.html
│ main.ts
│
└───app
app.component.html
app.component.less
app.component.ts
app.module.ts
- Enrich content for entry html, index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
- Add simple html in app/app.component.html
<h1>
{{title}}
</h1>
- Add simple style in app/app.component.less
h1 {
color: red;
}
- Add component content in app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: require('./app.component.html'),
styles: [require('./app.component.less')]
})
export class AppComponent {
title = 'app works!';
}
require will extend refernce file's content to here, if don't use require, we can use templateUrl
and styleUrls
templateUrl: 'src/app/app.component.html',
styleUrls: ['src/app/app.component.less']
- Add component in module, app.module.ts
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- Add content for root module main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
Now we have imported these stuff
import { Component } from '@angular/core'; //in app.component.ts
import { NgModule } from '@angular/core'; //in app.module.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; //in main.ts
- These imports depend on
@angular/core
and@angular/platform-browser-dynamic
, let's install it
npm install @angular/core @angular/platform-browser-dynamic --save
@angular/core
and ``@angular/platform-browser-dynamicis used in souce code, it is not a dev tool, so we use
--save` option, not `--save-dev`
@angular/core
also depends on rxjs
and zone.js
ng2demo@1.0.0 F:\dev\ng2demo
+-- @angular/core@2.4.3
+-- UNMET PEER DEPENDENCY rxjs@^5.0.1
`-- UNMET PEER DEPENDENCY zone.js@^0.7.2
- Let's install
rxjs
,zone.js
npm install rxjs zone.js --save
@angular/platform-browser-dynamic
also depends on @angular/common
, @angular/compiler
and @angular/platform-browser
+-- UNMET PEER DEPENDENCY @angular/common@2.4.3
+-- UNMET PEER DEPENDENCY @angular/compiler@2.4.3
+-- UNMET PEER DEPENDENCY @angular/platform-browser@2.4.3
`-- @angular/platform-browser-dynamic@2.4.3
- Install
@angular/common
,@angular/compiler
and@angular/platform-browser
npm install @angular/common @angular/compiler @angular/platform-browser --save
- Create
webpack.config.js
in root folder, add configuartion
module.exports = {
entry: './src/main.ts',
output: {
filename: '[name].js',
path: 'dist'
}
}
We just write a very simple webpack config file, we will meet many problems, let's fix them one by one. Running webpack
, or runing webpack --config webpack.config.js
. Due to ues default filename webpack.config.js, --config is optional.
Errors
ERROR in ./src/main.ts
Module not found: Error: Can't resolve './app/app.module' in 'F:\dev\ng2demo\src'
@ ./src/main.ts 3:0-45
ERROR in ./src/main.ts
Module not found: Error: Can't resolve '@angular/platform-browser-dynamic' in 'F:\dev\ng2demo\src'
@ ./src/main.ts 1:0-75
- According to the message, need to add
resolve
property in webpack.config.js
empty '' is removed from webpack2, in webpack1 need to add it, looks like extensions: ['', '.js', '.ts']
resolve: {
extensions: ['.js', '.ts']
}
Run webpack, still have errors
ERROR in ./src/app/app.module.ts
Module parse failed: F:\dev\ng2demo\src\app\app.module.ts Unexpected character '@' (5:0)
You may need an appropriate loader to handle this file type.
| import { AppComponent } from './app.component';
|
| @NgModule({
| declarations: [
| AppComponent
@ ./src/main.ts 3:0-45
@NgModule
is not recognized, maybe typescript is not recogrnized, let's us add ts-loader
to have a try.
npm install ts-loader --save-dev
- Add content in
webpack.config.js
module: {
rules: [
{
exclude: /node_modules/,
loader: 'ts-loader',
test: /\.ts$/,
}
]
}
Run webpack, still have errors
ERROR in ./src/main.ts
Module build failed: Could not load TypeScript. Try installing with `npm install typescript`. If TypeScript is installed globally, try using `npm link typescript`.
- Install typescript
npm install typescript --save-dev
Run webpack, still have errors
ERROR in error TS18002: The 'files' list in config file 'tsconfig.json' is empty.
ERROR in ./src/main.ts
Module build failed: error while parsing tsconfig.json
- New add tsconfig.json, can refer to tsconfig.json page
{
"compilerOptions": {
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"removeComments": false,
"sourceMap": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5"
},
"exclude": [
"node_modules"
]
}
Run webpack, still have many errors
ERROR in F:\dev\ng2demo\node_modules\@angular\compiler\src\i18n\extractor.d.ts
(14,33): error TS2304: Cannot find name 'Promise'.
ERROR in F:\dev\ng2demo\node_modules\@angular\compiler\src\output\output_ast.d.ts
(433,63): error TS2304: Cannot find name 'Set'.
ERROR in F:\dev\ng2demo\node_modules\@angular\core\src\di\reflective_provider.d.ts
(88,165): error TS2304: Cannot find name 'Map'.
ERROR in ./src/app/app.component.ts
(5,13): error TS2304: Cannot find name 'require'.
They are caused by no import typescript definition files, we can import a tool typings, it is a typescript definition manager. Use typings to generate .d.ts
files
- Install typings
npm install typings --save-dev
require
is keyword of node, so we need to import typescript definition .d.ts
file. I don't know where can be imported Promise
, Set
, Map
. But refer to other project, it's imported from core-js
.
- Search
node
typescript definition file
typings search --name node
Search result
Viewing 2 of 2
NAME SOURCE HOMEPAGE DESCRIPTION VERSIONS UPDATED
node dt http://nodejs.org/ 2 2017-01-10T23:30:17.000Z
node env 4 2017-01-02T17:57:25.000Z
- Search
core-js
typescript definition file
typings search --name core-js
Search result
Viewing 1 of 1
NAME SOURCE HOMEPAGE DESCRIPTION VERSIONS UPDATED
core-js dt https://github.com/zloirock/core-js/ 2 2016-11-30T13:37:42.000Z
- Install
node
andcore-js
ts definition file
typings install dt~node dt~core-js --global --save
This will generate typings.json
file. It stored configuration so we only need to typings install without more options next time. typings install
will create a typings
folder which has a index.d.ts
file, the file recored its dependency.
typings.json content
{
"globalDependencies": {
"core-js": "registry:dt/core-js#0.9.7+20161130133742",
"node": "registry:dt/node#7.0.0+20170110233017"
}
}
- Add
typings install
topackage.json
, asbuild
command
"scripts": {
"build": "npm install && typings install"
}
Continue run webpack, still found errors
ERROR in ./src/app/app.component.html
Module parse failed: F:\dev\ng2demo\src\app\app.component.html Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <h1>
| {{title}}
| </h1>
@ ./src/app/app.component.ts 18:18-49
@ ./src/app/app.module.ts
@ ./src/main.ts
- According to error message, we know webpack need a loader for html parsing, add
raw-loader
for html
npm install raw-loader --save-dev
- Add html loader in module->rules of
webpack.config.js
{
exclude: /node_modules/,
loader: 'raw-loader',
test: /\.html$/,
},
Running webpack, found that no errors. Actually we should meet less parse error, but now less file has no content.
- Add content in
app.component.less
h1 {
color: red;
}
Errors showing for webpack running
ERROR in ./src/app/app.component.less
Module parse failed: F:\dev\ng2demo\src\app\app.component.less Unexpected token (1:3)
You may need an appropriate loader to handle this file type.
| h1 {
| color: red;
| }
@ ./src/app/app.component.ts 19:17-48
@ ./src/app/app.module.ts
@ ./src/main.ts
- Introduce
less-loader
npm install less-loader --save-dev
Less-loader has dependency with less
+-- UNMET PEER DEPENDENCY less@^2.3.1
`-- less-loader@2.2.3
- Install
less
npm install less --save-dev
- Add less-loader configuration in webpack.config.js
{
exclude: /node_modules/,
loader: 'less-loader',
test: /\.less$/,
},
Only add less-loader
can't fix less file parse error. Need to introduce raw-loader
, raw-loader is for loading file as string.
- Install raw-loader
npm install raw-loader --save-dev
- Add raw-loader configuration in webpack.config.js
{
exclude: /node_modules/,
loaders: ['raw-loader', 'less-loader'],
test: /\.less$/,
},
Now all webpack executing errors are fixed. webpack command running successfully. Next step we will see what's result the simple web app running in browser. Firstly install a tool for running http service. We will use webpack-dev-server
webpack generated dist folder and some files etc bundles
├───dist
│ │ main.js
│ │
│ └───src
│ │ main.d.ts
│ │
│ └───app
│ app.component.d.ts
│ app.module.d.ts
- Install webpack-dev-server
npm install webpack-dev-server --save-dev
- Add webpack-dev-server to package.json as npm start script
"scripts": {
"start": "webpack-dev-server --inline --progress --port 8080"
},
- Execute
npm start
command
npm start
webpack-dev-server hosts http service on port 8080, open browser, access "http://localhost:8080", only list some file structure, this is because http service doesn't find entry index html. Let's introduce a new tool html-webpack-plugin, it creates htmls to serve webpack bundles
- Install html-webpack-plugin
npm install html-webpack-plugin --save-dev
- Configure html-webpack-plugin in webpack.config.js
// Add before module.exports
var HtmlWebpackPlugin = require('html-webpack-plugin');
// Add plugins property in module.exports
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
Show these errors in chrome browser running npm start
to start webpack-dev-server
Uncaught reflect-metadata shim is required when using class decorators
This error denotes reflect-metadata is lost in our product source code. Here you can introduce reflect-metadata
, add it to package.json. But we will use core-js
, because we already used it's typescript definition file in typings.json
- Install core-js
npm install core-js --save
- New add a file in src folder, ployfills.ts
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
- Import ployfills in main.ts, add one line in main.ts
import './ployfills'
The next error is
Uncaught (in promise) Error: Angular requires Zone.js prolyfill.
at new NgZone (main.js:24049)
at PlatformRef_._bootstrapModuleFactoryWithZone (main.js:30419)
- Add zone.js in ployfills.ts
import 'zone.js/dist/zone';
Next errors
Unhandled Promise rejection: No ErrorHandler. Is platform module (BrowserModule) included? ; Zone: <root> ; Task: Promise.then ; Value: ZoneAwareError {stack: "Error: No ErrorHandler. Is platform module (Browse…(http://localhost:8080/main.js:72809:35) [<root>]", message: "No ErrorHandler. Is platform module (BrowserModule) included?", originalStack: "Error: No ErrorHandler. Is platform module (Browse…askQueue (http://localhost:8080/main.js:72809:35)", zoneAwareStack: "Error: No ErrorHandler. Is platform module (Browse…(http://localhost:8080/main.js:72809:35) [<root>]", name: "Error"} Error: No ErrorHandler. Is platform module (BrowserModule) included?
at http://localhost:8080/main.js:30427:23 [angular]
at Object.onInvoke (http://localhost:8080/main.js:24226:37) [angular]
at Zone.run (http://localhost:8080/main.js:72489:43) [<root> => angular]
at NgZone.run (http://localhost:8080/main.js:24095:62) [<root>]
at PlatformRef_._bootstrapModuleFactoryWithZone (http://localhost:8080/main.js:30422:23) [<root>]
at http://localhost:8080/main.js:30473:59 [<root>]
at Zone.run (http://localhost:8080/main.js:72489:43) [<root> => <root>]
at http://localhost:8080/main.js:72911:57 [<root>]
at Zone.runTask (http://localhost:8080/main.js:72527:47) [<root> => <root>]
at drainMicroTaskQueue (http://localhost:8080/main.js:72809:35) [<root>]
Seem lost BrowserModule, Angular2 needs it.
- Import BrowserModule in app.module.ts
import { BrowserModule } from '@angular/platform-browser';
// Add it to @NgModule
imports: [BrowserModule],
Now web page is showing successfully. You can have a try running the two commands npm run build
and npm start
. Next step, we will introduce tslint
and tslint-loader
for code style checking
- Install tslint and tslint-loader
npm install tslint tslint-loader --save-dev
- Init a tsling.json
tslint --init
- Add tslint-loader configuration in webpack.config.js
{
enforce: 'pre',
exclude: /node_modules/,
loader: 'tslint-loader',
test: /\.ts$/,
},