如何利用webpack來提升前端開發效率(一)?

B2D1發表於2019-01-15

業務場景分析

隨著Vue、React生態的蓬勃發展,我們在開發單頁應用時,一般已離不開利用腳手架自動生成專案模板,熟悉的有 create-react-app project vue create project等命令。 但在很多應用場景下,我們往往需要走出前端框架的“溫室”來進行開發,常見的有:

  • H5單頁面製作
  • 傳統網頁開發(以JQueryBootstrap為代表,以適應低版本瀏覽器如 IE)
  • 展示為主導的靜態頁面
  • ...

優化點

可能大家在遇到上述開發場景時,可能就二話不說,直接開啟編輯器,擼起袖子就是“程式碼一把梭”。
不妨靜下心來,仔細剖析,一般流程我們有以下幾個優化點:

  • 程式碼變更,頁面自動重新整理(不必再瘋狂蹂躪F5)
  • 自動處理靜態資源的優化,快取,打包,壓縮(減少資源載入時間,減少資源HTTP請求)
  • 用上ES6,ES7,Sass,PostCSS...(什麼瀏覽器廠商字首,import載入,輕鬆實現)
  • 開發和生產兩套配置(開發和生產職責分明,易於維護)

解決方案

webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(module bundler)。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle
通俗的來說,webpack就像一個大廚,HTML是原料,而圖片、CSS、JS則是調味料,我們只需提供原料和調味料,webpack就會以“高超的廚藝”幫我們,烹飪出一道佳餚,也就是構建我們的Web應用程式

初嘗webpack

下面讓我們從一個例子入手,利用webpack4.x逐步構建一個高複用,功能俱全,模組清晰的前端腳手架。

在命令列輸入以下命令

mkdir my-webpack && cd my-webpack
npm init -y // 可以 npm i nrm 下載 nrm 使用 nrm use taobeo 切換淘寶映象,提升下載速度,nrm ls 檢視當前使用的npm源
npm i webpack webpack-cli -g // 先全域性安裝,為了可以使用webpack命令
npm i webpack webpack-cli -D // 再專案本地安裝,因為專案所需webpack版本是固定的,而全域性webpack版本會隨時更新,為了防止版本衝突
複製程式碼

建立webpack.config.js、src/index.js、dist/index.html 目錄如下圖所示

如何利用webpack來提升前端開發效率(一)?
分別輸入以下程式碼

<!-- dist/index.html -->
<!DOCTYPE html>
<html lang="en">

<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>My Webpack</title>
</head>

<body>
  <script src="bundle.js"></script>
</body>

</html>
複製程式碼
// src/index.js
console.log('hello webpack!');
複製程式碼
// webpack.config.js
const path = require('path');
const pathResolve = targetPath => path.resolve(__dirname, targetPath)

module.exports = {
  entry: { 
    index: pathResolve('src/index.js') // 入口檔案,即要打包的js檔案
  },
  output: {
    path: pathResolve('dist'), // 打包檔案的位置
    filename: 'bundle.js' // 打包檔案的名稱
  },
}
複製程式碼

然後在當前目錄下,在命令列輸入webpack 可以看到

Hash: c949bc1db5e801df578d
Version: webpack 4.28.4
Time: 377ms
Built at: 2019-01-15 20:57:39
    Asset       Size  Chunks             Chunk Names
bundle.js  959 bytes       0  [emitted]  index
Entrypoint index = bundle.js
[0] ./src/index.js 47 bytes {0} [built]

WARNING in configuration // 通過設定mode的值('development' or 'production')即可解除警告
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
複製程式碼

這表明我們打包成功,dist資料夾生成了bundle.jsindex.html使用。開啟dist/index.html,如圖所示:

如何利用webpack來提升前端開發效率(一)?
有人不禁要問,這webpack也不過如此,只不過把js檔案換了個名字(index -> bundle),反而更麻煩,還不如按部就班敲程式碼。No,這才是第一步,接來下可要坐穩了。

新增loader和plugin

我們發現,dist/index.html還要手寫<script>指令碼引入,實在麻煩,何不由webpack自動生成,再來加點佐料(CSS,圖片),豈不是更完美!我們刪除dist資料夾,在src路徑下新增一張你喜歡的圖片。

在命令列執行以下命令。

npm i html-webpack-plugin style-loader css-loader url-loader file-loader -D
複製程式碼

修改以下檔案

/* src/index.css */
body {
  background: #ff4040;
}
複製程式碼
// src/index.js
import './index.css'; // 匯入css檔案
import icon from './leaf.png'; 匯入圖片url

console.log('hello webpack!');

// 建立img標籤給src賦值,並插入html文件
const img = document.createElement('img');
img.setAttribute('src', icon);
document.body.appendChild(img);
複製程式碼
// webpack.config.js
const path = require('path');
const pathResolve = (targetPath) => path.resolve(__dirname, targetPath);
const htmlWebpackPlugin = require('html-webpack-plugin'); // 匯入‘html-webpack-plugin’外掛
module.exports = {
  entry: {
    index: pathResolve('src/index.js'),
  },
  output: {
    path: pathResolve('dist'),
    filename: '[name].js',
  },
  module: {  // loader專注於處理制定格式的檔案,來載入各種各樣的資源
    rules: [
      {
        test: /\.css$/, // 正則匹配以.css結尾的檔案
        use: ['style-loader', 'css-loader'], // loader從右向左執行 先使用css-loader提取css資源,然後使用style-laoder通過<style>標籤插入<head>
      },
      {
        test: /\.(png|jpg|jpeg|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
                limit: 8192, // 小於8kb的檔案則轉為dataURL:Base64形式,大於8kb則交由file-loader處理,生成新圖片並打包
                name: '[name].[hash:7].[ext]', // hash值對應本次build的hash值,每次打包都不相同
                outputPath: 'img', // 輸出路徑,即dist/img
            },
          },
        ],
      },
    ],
  },
  plugins: [ // 外掛專注於處理webpack在編譯過程中某個特定的任務
    new htmlWebpackPlugin({ // 該外掛可以自動生成HTML檔案,並匯入靜態資源
      filename: pathResolve('dist/index.html'), // 生成HTML檔名稱
      title: 'my-webpack' // 文件名稱
    }),
  ],
};

複製程式碼

在命令列執行webpack,可以看到自動生成了dist資料夾,開啟dist資料夾下的index.html,可以看到:

如何利用webpack來提升前端開發效率(一)?

新增devServer和熱更新

當我們每次修改程式碼時,都要輸入webpack命令重新構建,令人頭痛,有沒有簡單的辦法呢?當然有! 我們可以利用webpack-dev-server來為我們搭建一個本地伺服器,提供及時瀏覽和熱更新。

在命令列輸入以下命令

npm i webpack-dev-server -D
複製程式碼

修改以下檔案

// package.json
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
  + "dev" : "webpack-dev-server --mode development",
  + "build": "webpack --mode production"
  },
複製程式碼
// webpack.config.js
+   const webpack = require('webpack');
    module.exports = {
    +   devServer: {
            contentBase: pathResolve('dist'), // 本地伺服器所載入檔案的目錄
            port: '8080', // 設定埠號為8080
            inline: true, // 檔案修改後實時重新整理(瀏覽器重新整理)
            historyApiFallback: true, // 使用HTML5 History API時,對於任何404響應,返回index.html
            hot: true // 熱更新(瀏覽器不重新整理)
        },
        plugins: [
        +    new webpack.HotModuleReplacementPlugin(), // 熱更新外掛 
        +    new webpack.NamedModulesPlugin()
      ]
 }
複製程式碼
// src/index.js
// ...
if (module.hot) {
  module.hot.accept() // 如果存在熱更新,則啟用
}
複製程式碼

執行npm run dev

如何利用webpack來提升前端開發效率(一)?
修改src/index.js

// src/index.js
+ console.log('hot replacement!');
複製程式碼

可以立刻看到:

如何利用webpack來提升前端開發效率(一)?
很明顯,此處網頁並未重新整理,而是發生了熱更新。

使用Sass,postCSS,分離CSS

回過頭看dist下的檔案,並沒有任何css相關檔案,html檔案中頁沒有style標籤,原來經過打包後,css被整合在js中。

如何利用webpack來提升前端開發效率(一)?
顯然這並不是我們想要的,我們下一步的任務是將CSS從中分離出來,並且嘗試使用Sass(一種CSS前處理器語言)和postCSS來新增瀏覽器廠商字首 。

在命令列輸入以下命令

npm i mini-css-extract-plugin node-sass sass-loader postcss-loader autoprefixer -D
複製程式碼

新增src/index.scss

/* src/index.scss */
$link-color: #f1f1f1;

body {
  background: $link_color;
}

#avatar {
  width: 200px;
  height: 200px;
  background: url('./packet.png'); // 準備一張大於8kb的圖片
  border-radius: 50%;
}
複製程式碼

新增src/index.html

<!DOCTYPE html>
<html lang="en">

<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>my-webpack</title>
</head>

<body>
  <img id="avatar"></img>
</body>

</html>
複製程式碼

新增postcss.config.js

module.exports = {
  plugins: [
    require('autoprefixer')({ // 自動管理瀏覽器字首的外掛
      browsers: ['last 10 versions', 'Firefox >= 20', 'Android >= 4.0', 'iOS >= 8']
    })
  ]
}
複製程式碼

修改以下檔案

// src/index.js
- import './index.css';
+ import './index.scss';
複製程式碼
// webpack.config.js
+   const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module.exports = {
        module:{
            rules:[
        +       {
                    test: /\.(sa|sc|c)ss$/,
                    use: [{
                    loader: MiniCssExtractPlugin.loader,
                    options: {
                        publicPath: '../' // CSS中最終路徑 = publicPath + background: url,設定publicPath確保圖片取得到
                        }
                    },
                        'css-loader',
                        'postcss-loader',
                        'sass-loader',
                    ],
                },
            ]
        },
        plugins: [
        +    new MiniCssExtractPlugin({
                filename: 'css/[name].[contenthash:7].css', // contenthash 根據css檔案內容生成hash值
            }),
            new htmlWebpackPlugin({
            -    title: 'my-webpack', 
            +    template: pathResolve('src/index.html'), // HTML模板
            }),
        ],
    },
  ],
複製程式碼

執行npm run build,可以看到,CSS檔案已被分離成獨立檔案,在head頭部以link方式引入,並且自動新增了webkit moz ms等相容性廠商字首。

如何利用webpack來提升前端開發效率(一)?

如何利用webpack來提升前端開發效率(一)?

結語

第一篇主要研究了什麼是webpack以及loader、plugin的用法,這樣我們的前端腳手架已經可以處理基本的業務需求。
第二篇將對我們的前端腳手架做進一步的優化,包括但不限於程式碼分割,壓縮,快取處理,多頁面
本人水平有限,不足之處還希望大家在評論區提出,???再次感謝大家的閱讀!!!

已更新 如何利用webpack來提升前端開發效率(二)?

相關文章