從零開始搭建口袋妖怪管理系統(5)-藉助webpack4.6工程化項目(下)

一. 分析

上一章咱們使用webpack對項目進行了工程化改造,實現了從簡單系統到多模塊系統的打包升級,你可能覺得如今就完成了webpack的配置,可是實際上如今項目仍是處於webpack入門級配置的程度。調試一下代碼就會發現,除了比原先項目變得稍微整潔以及完成了app.js模塊引入以外,仍然有不少不足:css

1. 程序被打包到一個文件中,致使調試日誌全都指向了bundle.js文件,沒法追蹤錯誤和警告;
2. 打包以後的dist目錄應包含項目全部功能,如今缺乏index.html;
3. 每次修改完代碼想要運行的時候都須要輸入*npm run build*從新打包項目;

應該明確一點,打包項目是爲了方便咱們的開發調試而不是增長開發複雜度,因此爲了使讓咱們的開發變得更加舒服,這些問題須要立刻解決。html

2、問題處理

2.1 日誌追蹤

爲了更容易地追蹤錯誤和警告,應將編譯後的代碼bundle.js映射回原始代碼。打包工具的開發者確定早就考慮到了打包致使的日誌追蹤問題,因此咱們在webpack的文檔中很容易就找到這個:使用source map,也就是使用source-map功能實現編譯後代碼到源代碼的映射。因而在項目的webpack.config.js文件中加入:webpack

devtool: 'inline-source-map',

從新編譯結果以下:
source-map 編譯結果git

咱們發現bundle.js文件變大了,下面的編譯提示也告訴咱們文件過大將影響性能,因此當咱們將代碼打包發佈到生產環境的時候應該關閉掉source-map或者使用其餘配置(劃重點)。source-map除了咱們用到的配置以外還有其餘不一樣選項,若是想要更深刻學習就閱讀這裏:source-map 指南- Devtoolgithub

修改以後從新運行代碼,日誌打印結果以下:web

加入source-map 後的日誌

ok如今能夠成功映射源代碼輸出日誌了。npm

2.2 將index.html加入dist

dist中如今只有bundle.js文件,index.html仍在根目錄,咱們想要成功運行程序,則每次編譯都應清除dist目錄下文件,再把最新的index.html複製到dist中,與bundle.js配合運行。json

2.2.1 index.html生成

首先考慮如何往dist加入html文件,參考文檔設定 HtmlWebpackPlugin,閱讀以後發現大概意思是:在webpack.config.js中加入插件htmlwebpackplugin,而後就能夠自動生成一個全新的index.html。segmentfault

那咱們原來的html咋辦呢,裏面有meta、title、對js和css的引用,還有一些其餘代碼,難道只能拋棄他們嗎?固然是不可能的,htmlwebpackplugin做爲一個插件,是爲讓咱們在編譯打包過程當中得到更好的體驗,特別是自動爲index.html添加生成後文件引用而不用手動修改這一功能。想要更好地使用它就先閱讀一下htmlwebpackplugin的Readme,看完大概知道經過在webpack.config.js配置htmlwebpackplugin,使其在目標目錄生成一個原來index.html類似的html,話有點多如今立刻開始,先安裝html-webpack-plugin:數組

yarn add html-webpack-plugin --save-dev

而後模仿設定 HtmlWebpackPlugin,在webpack.config.js中完成基礎index.html生成配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/app.js',
  devtool: 'inline-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      title: '口袋妖怪'
    })
  ],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

上面配置中咱們作了兩件事:

1. 加入html-webpack-plugin插件的引用;
2. 在plugins數組中建立了HtmlWebpackPlugin的對象(最終webpack將根據該插件對象的配置造成咱們的新index.html);

npm run build一下,如今咱們看看生成的index.html和本來的index.html有什麼不同:
插件生成(左)和本來index(右)的對比

看來還有點差距,咱們還須要對新index.html的<body>插入 ng-controller="AppController",而後再在<body>中加入導航&ngView的html。官方沒說怎麼配置,因此咱們參考了Github-html-webpack-plugin的Readme,在Options中找到一個簡單的配置參數template,並瞭解到咱們只須要建立並引用一個html做爲模板,便可以輕鬆生成想要的index.html,故在根目錄建立index.tpl.html以下:

<!DOCTYPE html>
<html lang="en" ng-app="pokemon-app">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body ng-controller="AppController">
    <h1>口袋妖怪管理系統</h1>
    <div>
      <h2>快速導航:</h2>
      <a href="/#!/pokemons">口袋妖怪</a>
      <a href="/#!/skills">技能</a>
      <a href="/#!/hagberrys">樹果</a>
      <a href="/#!/props">道具</a>
      <a href="/#!/games">遊戲</a>
    </div>
    <div ng-view></div>
  </body>
</html>

再修改webpack.config.js中的插件:

plugins: [
    new HtmlWebpackPlugin({
        title: '口袋妖怪',
        template: 'index.tpl.html'
    })
]

執行編譯npm run build,看到dist/index.html以下:
基於index.tpl.html生成新index.html

使用命令行進入dist目錄,開啓http-server,而後打開對應url:
新生成index.html後運行失敗.png

失敗緣由是"沒法加載pm-list.html",這裏暴露了咱們打包過程的一個問題,即當前項目只是打包了全部js,可是對於每一個模塊的html模板文件(list & detail)卻仍然是用相對路徑引用的。正式上線的話只會將dist文件夾放到服務器上,而list & detail是讀不到的,因此咱們須要使用webpack將這兩個html也一塊兒打包進bundle.js中。

這時很明顯的,咱們不能再用相對路徑引用html模板了,應該把list & detail的html看成字符串加載進bundle.js,因而修改pokemon.js以下:

import angular from 'angular';
import ngRoute from 'angular-route';
import pmlist from './pm-list.html';
import pmdetail from './pm-detail.html';

export default angular.module('pokemon-app.pokemon', [ngRoute])
    .config(['$routeProvider', function ($routeProvider) {
      $routeProvider
        .when('/pokemons', {
          template: pmlist,
          controller: 'PMListController'
        })
        .when ('/pokemon/:no', {
          template: pmdetail,
          controller: 'PMDetailController'
        })
    }])
    .controller('PMListController', PMListController)
    .controller('PMDetailController', PMDetailController)
    .name;

上面咱們作了兩件事:

1. 用import引入兩個html模板;
2. 將原來的templateUrl改成template並賦予其引用的html模板文件;

通過修改,模塊html的內容文本應該也會被打包到bundle.js中。完成編輯以後運行npm run build,發現:
解析失敗

如上圖高亮處所示,list文件和detail文件的錯誤都是"解析失敗,須要對應類型的loader"。查閱Loader文檔可知,webpack使用loader來預處理各類文件,那咱們如今須要解析html內容,天然是使用用來加載文件原始內容的raw-loader,參考文檔中的使用方法,先安裝:

yarn add raw-loader --save-dev

再在webpack.config.js的module.exports={}的大括號中加入:

module: {
    rules: [{
      test: /\.html$/,
      loader: 'raw-loader'
    }]
  },

完成以後運行npm run build,發現編譯打包成功,再嘗試運行http-server dist,發現管理系統的口袋妖怪部分已經可以正常使用了!快速將其餘模塊按照pokemon的修改方式進行修改,完成編譯以後,該項目的dist文件應該是可以直接部署在服務器上運行的了,也就是說咱們已經成功實現了項目打包工做的基礎功能了~

2.2.2 清除dist目錄文件

完成了上一小結的實踐以後項目的打包上線應該是沒什麼問題了,不過若是項目在上線前出現了重大修改或者回撤,dist目錄下可能殘留有一些冗餘文件。官方文檔說每次編譯打包前先清除dist目錄文件是比較推薦的作法。那麼如今就來考慮下如何每次構建都清除dist中的文件了,參考文檔清理 /dist 文件夾,先安裝clean-webpack-plugin插件:

yarn add clean-webpack-plugin --save-dev

再在webpack.config.js插入引用並建立清空實例:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');    //插入引用

module.exports = {
  entry: './src/app.js',
  devtool: 'inline-source-map',
  plugins: [
    new CleanWebpackPlugin(['dist']),        //建立清空實例
    new HtmlWebpackPlugin({
      title: '口袋妖怪',
      template: 'index.tpl.html'
    })
  ],
  module: {
    rules: [{
      test: /\.html$/,
      loader: 'raw-loader'
    }]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

如今執行 npm run build,再檢查 /dist 文件夾。若是一切順利,你如今應該不會再看到舊的文件,只有構建後生成的文件!

至此,咱們每次使用npm run build以後都能生成無遺留及冗餘文件的、完成代碼壓縮的index.html 及 bundle.js,也就是能夠直接將dist部署到服務器運行咱們的網站了(記得關閉或修改source-map)。

2.3 自動編譯打包

用過Vue2或者React官方CLI搭建過項目的同窗都知道,這些項目都具備實時重載頁面功能,即修改文件後自動從新加載網頁來展現修改效果。咱們引入webpack構建項目的目的天然也是可以這樣方便地進行開發。爲了解決每次編寫完成代碼後都要從新輸入編譯命令的問題,咱們查閱webpack文檔找到了這個:選擇一個開發工具,對比一下官方提供的三種自動編譯方式:

按照KISS原則,咱們確定選擇一個符合咱們需求的最簡單的東西,因此接下來咱們將使用webpack-dev-server來達到咱們的目的,首先安裝webpack-dev-server插件:

yarn add webpack-dev-server --save-dev

安裝完成以後,在webpack.config.js中加入服務器開啓位置配置:

module.exports = {
  entry: './src/app.js',
  devtool: 'inline-source-map',
  devServer: {                        // 服務器開啓位置配置
      contentBase: './dist'
  },
  ...,
  ...
};

完成配置後,在webpack-dev-server運行過程當中,該文件夾將做爲可訪問文件以供訪問。接下來咱們在package.json文件中加入一行'start'腳本以運行webpack-dev-server:

"scripts": {
    "start": "webpack-dev-server --open",            // 新增
    "build": "webpack"
}

如今只須要簡單運行npm start,就會看到瀏覽器自動加載頁面。若是咱們修改代碼並保存,頁面將會自動重載。

至此咱們已經完成了項目的實時重載功能。在開發以前運行npm start,等待初始化打包完成以後,每次咱們完成代碼修改並保存,頁面都會自動重載以展現新頁面。

3、源碼

口袋妖怪SPA系統源碼地址:https://github.com/Nodreame/p...

本章基本功能提交:build(webpack): add source-map & auto bulid & finish dist & merge Readme

4、總結

至此,咱們系統已經基本完成了項目的工程化,項目當前支持自動實時重載、日誌映射,以及支持將編譯打包後的dist文件夾部署到服務器直接運行。既然已經完成開發環境的構建那麼接下來天然要繼續開發項目啦!繼續設計接下來的功能和樣式,讓它越發豐富起來吧!請看下章~

系列文章

從零開始搭建口袋妖怪管理系統(1)-從Angular1.x開始

從零開始搭建口袋妖怪管理系統(2)-藉助ngRoute實現詳情頁面跳轉

從零開始搭建口袋妖怪管理系統(3)-實現一個簡單的SPA管理系統

從零開始搭建口袋妖怪管理系統(4)-藉助webpack4.6工程化項目(上)

To be continue...

相關文章
相關標籤/搜索