Angular之路–帶你來搭建Webpack 2 + Angular 4專案

position_柚子發表於2019-03-03

上個月Angular釋出了4.0.0版本,少年們,趕快學起來吧,這篇文章帶領大家搭建一個簡單的Angular應用,會盡量詳細的把每個點都解釋到。

首先我選擇了用webpack2來作為打包工具,選擇wenpack2的理由不言而喻。這裡假設你已經瞭解webpack2的一些原理,下面開始來學習吧~

詳細程式碼可以看我的git專案

一、配置 webpack

首先新建一個專案資料夾

mkdir angular-dream
cd angular-dream複製程式碼

在控制檯中輸入命令 npm init ,建立 package.json 檔案。如圖:

Angular之路–帶你來搭建Webpack 2 + Angular 4專案
建立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,vendorapp 的先後順序。

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
  }
});複製程式碼

至此,現在的目錄結構就如下圖所示:

Angular之路–帶你來搭建Webpack 2 + Angular 4專案

因為我們還沒有建立 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>複製程式碼

好啦,此時的專案目錄結構就是下圖所示:

Angular之路–帶你來搭建Webpack 2 + Angular 4專案

接下來執行 npm start 開始你的 Angular 之旅吧~

參考:

相關文章