上個月Angular
釋出了4.0.0
版本,少年們,趕快學起來吧,這篇文章帶領大家搭建一個簡單的Angular
應用,會盡量詳細的把每個點都解釋到。
首先我選擇了用webpack2
來作為打包工具,選擇wenpack2
的理由不言而喻。這裡假設你已經瞭解webpack2
的一些原理,下面開始來學習吧~
詳細程式碼可以看我的git專案
一、配置 webpack
首先新建一個專案資料夾
mkdir angular-dream
cd angular-dream複製程式碼
在控制檯中輸入命令 npm init
,建立 package.json
檔案。如圖:
在控制檯中可以一路回車。當然,這裡我命名了專案的名稱為 angular-dream
,還有一些其他的資訊。
建立好之後用編輯器(我使用的是webstorm)開啟這個專案。
package.json 檔案的配置
關於 package.json
檔案裡面的一些引數的含義,可以參考阮一峰老師寫的這篇文章 。
{
"name": "angular2-dream",
"version": "1.0.0",
"description": "Hello Angular2",
"scripts": {
"start": "webpack-dev-server --config config/webpack.dev.js --progress",
"test": "karma start",
"build": "webpack --config config/webpack.dev.js --progress --profile --bail",
"webpack": "webpack",
"rimraf": "rimraf"
},
"keywords": [
"angular2",
"webpack"
],
"author": "yanmeng@hujiang.com",
"license": "MIT",
"dependencies": {
"@angular/animations": "~4.0.1",
"@angular/common": "~4.0.0",
"@angular/compiler": "~4.0.0",
"@angular/core": "^4.0.1",
"@angular/forms": "~4.0.1",
"@angular/http": "~4.0.1",
"core-js": "^2.4.1",
"rxjs": "5.2.0",
"zone.js": "^0.8.5"
},
"devDependencies": {
"reflect-metadata": "^0.1.10",
"html-webpack-plugin": "^2.28.0",
"@angular/compiler-cli": "~4.0.1",
"@angular/platform-browser": "~4.0.1",
"@angular/platform-browser-dynamic": "~4.0.1",
"@angular/platform-server": "~4.0.1",
"@angular/router": "~4.0.1",
"@angularclass/hmr": "^1.2.2",
"@angularclass/hmr-loader": "^3.0.2",
"@types/jasmine": "^2.5.43",
"@types/node": "^6.0.45",
"angular2-template-loader": "^0.6.0",
"awesome-typescript-loader": "^3.0.4",
"bootstrap": "^4.0.0-alpha.6",
"bootstrap-sass": "^3.3.7",
"css-loader": "^0.26.1",
"extract-text-webpack-plugin": "2.0.0-beta.5",
"file-loader": "^0.9.0",
"font-awesome": "^4.7.0",
"html-loader": "^0.4.3",
"postcss-loader": "^1.3.1",
"raw-loader": "^0.5.1",
"style-loader": "^0.13.1",
"to-string-loader": "^1.1.5",
"ts-helpers": "^1.1.2",
"url-loader": "^0.5.7",
"webpack": "2.2.0",
"webpack-dev-server": "2.2.0-rc.0",
"webpack-merge": "^2.4.0",
"typescript": "^2.2.2"
}
}複製程式碼
@angular/compiler
- Angular的模板編譯器。 它會理解模板,並且把模板轉化成程式碼,以供應用程式執行和渲染。 開發人員通常不會直接跟這個編譯器打交道,而是通過platform-browser-dynamic或離線模板編譯器間接使用它。@angular/platform-browser
- 與DOM和瀏覽器相關的每樣東西,特別是幫助往DOM中渲染的那部分。 這個包還包含bootstrapStatic方法,用來引導那些在產品構建時需要離線預編譯模板的應用程式@angular/platform-browser-dynamic
- 為應用程式提供一些提供商和bootstrap方法,以便在客戶端編譯模板。不要用於離線編譯。 我們使用這個包在開發期間引導應用,以及引導plunker中的範例。core-js
- 為全域性上下文(window)打的補丁,提供了ES2015(ES6)的很多基礎特性。 我們也可以把它換成提供了相同核心API的其它填充庫。 一旦所有的“主流瀏覽器”都實現了這些API,這個依賴就可以去掉了。reflect-metadata
- 一個由Angular和TypeScript編譯器共享的依賴包。
tsconfig.json 檔案的配置
在專案的根目錄下建立 tsconfig.json
檔案。
瀏覽器不能直接執行 TypeScript
,需要用編譯器轉譯成JavaScript,而且編譯器需要進行一些配置。 tsconfig.json
的配置就是指導編譯器如何生成JavaScript檔案。
{
"compilerOptions": {
"declaration": false,
"module": "commonjs", // 組織程式碼的方式
"target": "es5", // 編譯目標平臺
"moduleResolution": "node",
"sourceMap": true, // 把ts檔案變異成js檔案時,是否生成對應的SourceMap檔案
"emitDecoratorMetadata": true, // 讓TypeScript支援為帶有裝飾器的宣告生成後設資料
"experimentalDecorators": true, // 是否啟用實驗性裝飾器特性
"noImplicitAny": true,
"lib": ["dom", "es6"],
"suppressImplicitAnyIndexErrors": true
},
"exclude": [
"node_modules",
"dist"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useWebpackText": true
},
"compileOnSave": false,
"buildOnSave": false
}複製程式碼
當 noImplicitAny
標誌是 true
並且TypeScript編譯器無法推斷出型別時,它仍然會生成JavaScript檔案。 但是它也會報告一個錯誤。 很多飽經滄桑的程式設計師更喜歡這種嚴格的設定,因為型別檢查能在編譯期間捕獲更多意外錯誤。
建立 webpack.config.js檔案
在根目錄下建立 webpack.config.js
檔案
module.exports = require('./config/webpack.dev.js');複製程式碼
現在在控制檯中執行 npm install
命令,安裝專案的依賴。
二、Polyfills
配置好上述的幾個檔案之後呢,我們在專案中的根目錄下建立一個 src
資料夾。
在 src
資料夾的下面新建一個 polyfills.ts
檔案。
polyfills.ts
檔案裡引入了執行Angular應用時所需的一些標準js。
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';
/** Evergreen browsers require these. **/
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
/***************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone';
import 'ts-helpers';
if (process.env.ENV === 'production') {
// Production
} else {
// Development and test
Error['stackTraceLimit'] = Infinity;
require('zone.js/dist/long-stack-trace-zone');
}複製程式碼
三、Vendor
在 src
資料夾的下面新建一個 vendor.ts
檔案。
vendor.ts
檔案裡面引入了一些第三方的依賴。
// Angular
//包含所有提供商依賴
import '@angular/platform-browser';
import '@angular/platform-browser-dynamic';
import '@angular/compiler';
import '@angular/core'; // 存放核心程式碼,如變化監測機制,依賴注入機制,渲染,裝飾器等。
import '@angular/common';
import '@angular/http';
import '@angular/router';
// RxJS
import 'rxjs/Observable';
import 'rxjs/Subscription';
import 'rxjs/Subject';
import 'rxjs/BehaviorSubject';
// Bootsctrap
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';複製程式碼
四、Main
在 src
資料夾的下面新建一個 main.ts
檔案。
在 main.ts
檔案中,我們指定了專案的根模組為 AppModule
import {AppModule} from './app/app.module';
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
platformBrowserDynamic().bootstrapModule(AppModule);
// platformBrowserDynamic().bootstrapModule()方法來編譯啟用AppModule模組
// 根據當前的執行環境,如作業系統、瀏覽器,來初始化一個執行環境,然後從這個環境裡面執行AppModule。複製程式碼
五、config
在根目錄下建立一個 config
資料夾
helpers.js
在 config
資料夾下面建立一個 helpers.js
檔案。
在這裡請注意入口 polyfills
,vendor
和 app
的先後順序。
var path = require('path');
var _root = path.resolve(__dirname, '..');
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [_root].concat(args));
}
exports.root = root;複製程式碼
webpack.common.js
在 config
資料夾下面建立一個 webpack.common.js
檔案。
const helpers = require('./helpers');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts', // 執行Angular時所需的一些標準js
'vendor': './src/vendor.ts', // Angular、Lodash、bootstrap.css......
'app': './src/main.ts' // 應用程式碼
},
resolve: { // 解析模組路徑時的配置
extensions: ['.ts', '.js'] // 制定模組的字尾,在引入模組時就會自動補全
},
module: {
rules: [ // 告訴webpack每一類檔案需要使用什麼載入器來處理
{
test : /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader']
//awesome-typescript-loader - 一個用於把TypeScript程式碼轉譯成ES5的載入器,它會由tsconfig.json檔案提供指導
//angular2-template-loader - 用於載入Angular元件的模板和樣式
}, {
test: /\.json$/,
use : 'json-loader'
}, {
test: /\.styl$/,
loader: 'css-loader!stylus-loader'
}, {
test : /\.css$/,
loaders: ['to-string-loader', 'css-loader']
}, {
test: /\.html$/,
use: 'raw-loader',
exclude: [helpers.root('src/index.html')]
//html - 為元件模板準備的載入器
}, {
test:/\.(jpg|png|gif)$/,
use:"file-loader"
}, {
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use : "url-loader?limit=10000&minetype=application/font-woff"
}, {
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use : "file-loader"
}
]
},
plugins: [
//熱替換
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'polyfills']
//多個html共用一個js檔案,提取公共程式碼
}),
new HtmlWebpackPlugin({
template: './src/index.html'
// 自動向目標.html檔案注入script和link標籤
})
]
};複製程式碼
webpack.dev.js
在 config
資料夾下面建立一個 webpack.dev.js
檔案。
var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.common.js');
const helpers = require('./helpers');
module.exports = webpackMerge(commonConfig, {
output : {
path : helpers.root('dist'),
publicPath: '/',
filename : '[name].js'
},
devServer: {
port : 8080,
historyApiFallback: true
}
});複製程式碼
至此,現在的目錄結構就如下圖所示:
因為我們還沒有建立 AppModule
,所以 main.ts
檔案會被標紅。
六、根模組 AppModule
基本的配置已經完成啦,現在我們來建立根模組~
在 src
檔案下面新建一個 app
資料夾,
建立 app.component.ts
在app
資料夾下面新建 app.component.ts
檔案
import { Component } from "@angular/core";
@Component({
selector : 'root-app',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor() {}
}複製程式碼
建立 app.component.html
在 app
資料夾下面新建 app.component.html
檔案
<h1 class="title">Hello Angular2</h1>
<router-outlet></router-outlet>複製程式碼
建立 app.routes.ts
這裡我們用一下路由來完成頁面之間的跳轉
import { Routes } from '@angular/router';
import { AppComponent } from "./app.component";
export const routes: Routes = [ // Routes型別的陣列
{
path : 'index',
component : AppComponent
},{
path : '',
redirectTo: 'index',
pathMatch : 'full'
}
];複製程式碼
建立 app.module.ts
在 app
資料夾下面新建 app.module.ts
檔案
import { AppComponent } from './app.component';
import { routes } from './app.routes';
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { RouterModule } from "@angular/router";
import { NgModule } from "@angular/core";
//@NgModule裝飾器用來為模組定義後設資料
@NgModule({ // @NgModule 用來定義模組用的裝飾器
declarations: [AppComponent], // 匯入模組所依賴的元件、指令等,用於指定這個模組的檢視類
imports: [
BrowserModule, //包含了commonModule和applicationModule模組,封裝在瀏覽器平臺執行時的一些工具庫
FormsModule, // 表單相關的元件指令等,包含了[(ngModel)]
RouterModule.forRoot(routes,{useHash: false}), // RouterModule.forRoot()方法來建立根路由模組
], // 匯入當前模組所需要的其他模組
bootstrap: [AppComponent], // 標記出引導元件
//把這個AppComponent標記為引導 (bootstrap) 元件。當Angular引導應用時,它會在DOM中渲
//染AppComponent,並把結果放進index.html的元素內部。
})
export class AppModule { }複製程式碼
六、宿主頁面
在 src
資料夾下面新建 index.html
檔案
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Angular2 Hello Word</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<root-app>Loading...</root-app>
</body>
</html>複製程式碼
好啦,此時的專案目錄結構就是下圖所示:
接下來執行 npm start
開始你的 Angular
之旅吧~
參考: