【Cute-Webpack】Webpack4 入門手冊(共 18 章)

介紹

1. 背景

最近和部門老大,一塊兒在研究團隊【EFT - 前端新手村】的建設,目的在於:幫助新人快速瞭解和融入公司團隊幫助零基礎新人學習和入門前端開發而且達到公司業務開發水平javascript

本文也是屬於【EFT - 前端新手村】的一部分,用來幫助新人快速入門 Webpack4,內容偏基礎,固然也能夠做爲複習材料~~這裏分享給各位小夥伴啦!css

2. 文章概要

我將從最基礎的【項目初始化】開始介紹,到【處理 CSS / JS / 圖片】,到【熱更新,打包優化】等等,一一介紹和實踐。html

文章共分爲 18 章,關於最基礎的四個核心概念,能夠到我整理的另外一篇文章 《Webpack4 的四個核心概念》 中學習。前端

3. 教程目錄

教程目錄

1、 項目初始化

1. 初始化 demo

新建並進入文件夾 leo:java

mkdir leo
cd leo

而後本地安裝 webpackwebpack-cli在 Webpack 4.0之後須要單獨安裝):node

npm install webpack webpack-cli --save-dev

初始化項目結構:jquery

+ ├─package.json
+ ├─dist          // 存放最終打包的文件
+ │  └─index.html
+ ├─src           // 存放入口文件等開發文件
+ │  └─index.js
+ ├─webpack.config.js  // webpack的配置文件

安裝 lodashwebpack

npm install lodash --save-dev

--save 能夠簡寫爲-S, --save-dev能夠簡寫爲-D.git

開發 index.jsgithub

import _ from 'lodash';

function createElement(){
    let div = document.createElement('div');
    div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
    return div;
}
document.body.appendChild(createElement());

開發 webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',
    mode: 'development',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    }
}

2. 打包測試

開始第一次打包任務:

npx webpack

// 輸出:

Hash: 030b37b6b9a0b4344437
Version: webpack 4.39.1Time: 308ms
Built at: 2019-08-07 08:10:21
  Asset     Size  Chunks             Chunk Names
main.js  552 KiB    main  [emitted]  main
Entrypoint main = main.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 225 bytes {main} [built]
    + 1 hidden module

打包成功後,生成的文件會保存在 dist 目錄中。

如今在 dist/index.html 中引入打包後的 main.js,打開瀏覽器測試:

<script src="./main.js"></script>

2、 webpack 處理 CSS 模塊

這一部分,咱們開始學着使用 webpack 去處理 css 相關的模塊。

1. 修改代碼

在項目 src 目錄中,新建 style 文件夾,並新建 index.css 文件:

├─package.json
  ├─dist          // 存放最終打包的文件
  │  └─index.html
  ├─src           // 存放入口文件等開發文件
  │  ├─index.js
+ │  └─style
+ │     └─index.css
  ├─webpack.config.js  // webpack的配置文件

接着在 index.js 的新建元素方法中,添加 classbox,這樣新建的元素就帶有 boxclass 屬性:

// src/index.js

import _ from 'lodash';
import './style/index.css';// 引入樣式文件

function createElement(){
  let div = document.createElement('div');
  div.innerHTML = _.join(['my', 'name', 'is', 'leo'], '');
+ div.className = 'box';
  return div;
}
document.body.appendChild(createElement());

而後在 index.css 文件爲 box

// src/style/index.css .box{
    color: red;
}

注意:

這裏使用 import './style/index.css'; 引入咱們的樣式文件,是沒辦法解析使用,這時咱們須要在 webpack 中使用到第三方 loader 插件,這裏咱們使用:

  • css-loader : 用於處理 css 文件,使得能在 js 文件中引入使用;
  • style-loader : 用於將 css 文件注入到 index.html 中的 <style> 標籤上;

2. 安裝配置插件

安裝插件:

npm install --save-dev style-loader css-loader

再到 webpack.config.js 中添加 css 解析的 loader 配置:

// webpack.config.js

module: {
  rules: [
    {
      test: /\.css$/,
      use: ["style-loader", "css-loader"]
    }
  ]
}

參數介紹:

test須要匹配的模塊後綴名
use:對應處理的 loader 插件名稱(處理順序是從右往左)。

3. 打包測試

npx webpack

// 輸出:

Hash: 28b3965aa1b6a0047536
Version: webpack 4.39.1
Time: 482msBuilt at: 2019-08-09 07:45:25  Asset     Size  Chunks             Chunk Names
main.js  565 KiB    main  [emitted]  main
Entrypoint main = main.js
[./node_modules/_css-loader@3.2.0@css-loader/dist/cjs.js!./src/style/index.css] 190 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built][./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {main} [built][./src/index.js] 303 bytes {main} [built]
[./src/style/index.css] 447 bytes {main} [built]
    + 3 hidden modules

這時候能夠看見 index.html 中,文本已經變成紅色,而且 css 代碼已經添加到 <style> 標籤上。

webpack01

3、 webpack 模塊介紹和處理 sass

在這一節中,咱們會介紹 webpack 中的模塊,而且介紹如何去處理 sass 文件。

1. webpack 模塊介紹

這裏介紹的模塊(module)是指 webpack.config.js 文件中的 module 配置,它決定了如何處理項目中的不一樣類型模塊。

好比上一節介紹的,使用 style-loadercss-loader 兩個插件去處理 css 文件。

webpack 模塊支持以下語句:

  • ES2015 import 語句;
  • CommonJS require() 語句;
  • AMD definerequire 語句;
  • css/sass/less 文件中 @import 語句;
  • 樣式 (url(...)) 或者 HTML 文件 (<img src=...>) 中的圖片連接 (image url)

這裏建議使用 ES2015 的引入方法,畢竟這是標準。

更多參數介紹,可訪問中文官網的介紹:
《webpack 配置選項》

2. 經常使用模塊

2.1 module.noParse

值的類型:RegExp | [RegExp] | function

防止 webpack 解析那些符合匹配條件的文件,忽略的文件夾中不該該含有 importrequiredefine的調用,或任何其餘導入機制,忽略的 library 能夠提升構建效率

// webpack.config.js

module: {
  noParse: function(content){
    return /jquery|lodash/.test(content);
  }
}

2.2 module.rules

建立模塊時,匹配請求的規則數組。按照規則爲對應模塊使用對應的 loader,或修改解析器(parser)。

// webpack.config.js

module: {
  rules: [
    { test: /\.css$/, use: ['style-loader', 'css-loader']}
  ]
}
  • module.rules 參數有:

use:爲模塊使用指定 loader,而且能夠傳入一個字符串數組,加載順序從右往左

  • module.rules 匹配條件有:

{test : Condition}匹配特定條件,非必傳,支持一個正則表達式正則表達式數組
{include : Condition}匹配特定條件,非必傳,支持一個字符串字符串數組
{exclude : Condition}排除特定條件,非必傳,支持一個字符串字符串數組
{and : [Condition]}:必須匹配數組中的全部條件;
{or : [Condition]}:匹配數組中任一條件;
{not : [Condition]}:必須排除這個條件;

更多參數介紹,可訪問中文官網的介紹:
《Rule》

// webpack.config.js

module: {
  rules: [
    { 
      test: /\.css$/, 
      use: ['style-loader', 'css-loader'],
      include: [
        path.resolve(__dirname, "app/style.css"),
        path.resolve(__dirname, "vendor/style.css")
      ]
    }
  ]
}

3. 加載 Sass 文件

須要使用到 sass-loader 的插件,這裏先安裝:

npm install sass-loader node-sass --save-dev

src/style 目錄下添加 leo.scss 文件,並添加內容:

// leo.scss

$bg-color: #ee3; .box{
    background-color: $bg-color;
}

而後在 src/index.js 中引入 leo.scss 文件:

// src/index.js
import './style/leo.scss';

npx webpack 從新打包,並打開 dist/index.html 能夠看到背景顏色已經添加上去:

[外鏈圖片轉存失敗(img-eHBJzEHn-1565738603711)(https://user-gold-cdn.xitu.io/2019/8/12/16c868881e42f612?w=730&h=553&f=png&s=28540)]

4. 添加快捷打包命令

npx webpack 這個命令咱們須要常用,對於這種命令,咱們能夠把它寫成命令,方便每次使用。

咱們在 package.jsonscripts 中添加一個命令爲 build,之後打包只要執行 npm run build 便可:

"scripts": {
  "build": "npx webpack -c webpack.config.js"
},

這裏的 -c webpack.config.js 中,-c 後面跟着的是 webpack 配置文件的文件名,默承認以不寫。

4、 webpack 開啓 SourceMap 和添加 CSS3 前綴

添加 SourceMap 是爲了方便打包以後,咱們在項目中調試樣式,定位到樣式在源文件的位置。

1. 開啓 SourceMap

css-loadersass-loader 均可以經過設置 options 選項啓用 sourceMap

// webpack.config.js

rules: [
  {
    test: /\.(sc|c|sa)ss$/,
    use: [
      "style-loader", 
      {
        loader:"css-loader",
        options:{ sourceMap: true }
      },
      {
        loader:"sass-loader",
        options:{ sourceMap: true }
      },
    ]
  }
]

再從新打包,看下 index.html 的樣式,樣式已經定位到源文件上了:

[外鏈圖片轉存失敗(img-2LKJpwyu-1565738603712)(https://user-gold-cdn.xitu.io/2019/8/12/16c86888236dd2d8?w=917&h=733&f=png&s=37584)]

這樣咱們在開發過程當中,調試樣式就方便不少了。

2. 爲樣式添加 CSS3 前綴

這裏咱們用到 PostCSS 這個 loader,它是一個 CSS 預處理工具,能夠爲 CSS3 的屬性添加前綴,樣式格式校驗(stylelint),提早使用 CSS 新特性,實現 CSS 模塊化,防止 CSS 樣式衝突。

首先安裝 PostCSS

npm install postcss-loader autoprefixer --save-dev

另外還有:

  • postcss-cssnext 可讓咱們使用 CSS4的樣式,並能配合 autoprefixer 進行瀏覽器部分兼容的補全,還支持嵌套語法。

  • precss 相似 scss 語法,若是咱們只須要使用嵌套,就能夠用它替換 scss

  • postcss-import 讓咱們能夠在@import CSS文件的時 webpack 能監聽並編譯。

更多參數介紹,可訪問中文官網的介紹:
《postcss-loader》

開始添加 postcss-loader 並設置 autoprefixer

// webpack.config.js

rules: [
  {
    test: /\.(sc|c|sa)ss$/,
    use: [
      "style-loader", 
      {
        loader:"css-loader",
        options:{ sourceMap: true }
      },
      {
        loader:"postcss-loader",
        options: {
          ident: "postcss",
          sourceMap: true,
          plugins: loader => [
            require('autoprefixer')(),
            // 這裏可使用更多配置,如上面提到的 postcss-cssnext 等
            // require('postcss-cssnext')()
          ]
        }
      },
      {
        loader:"sass-loader",
        options:{ sourceMap: true }
      },
    ]
  }
]

還須要在 package.json 中添加判斷瀏覽器版本:

// package.json

{
  //...
  "browserslist": [
    "> 1%", // 全球瀏覽器使用率大於1%,最新兩個版本而且是IE8以上的瀏覽器,加前綴 
    "last 2 versions",
    "not ie <= 8"
  ]
}

爲了作測試,咱們修改 src/style/leo.scss.box 的樣式:

// src/style/leo.scss .box{
    background-color: $bg-color;
    display: flex;
}

而後從新打包,能夠看見 CSS3 屬性的前綴已經添加上去了:

webpack05

5、 webpack 將 CSS 抽取成單獨文件

在以前學習中,CSS 樣式代碼都是寫到 index.html<style> 標籤中,這樣樣式代碼多了之後,很不方便。

因而咱們須要將這些樣式打包成單獨的 CSS 文件。

webpack4 開始使用 mini-css-extract-plugin 插件,而在 1-3 版本使用 extract-text-webpack-plugin

注意:抽取樣式之後,就不能使用 style-loader 注入到 html 中。

安裝插件:

npm install mini-css-extract-plugin --save-dev

引入插件:

// webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

而後修改 rules,將 style-loader,替換成 MiniCssExtractPlugin.loader ,而後添加 plugins 配置項:

// webpack.config.js

module: {
  rules: [
    {
      test: /\.(sc|c|sa)ss$/,
      use: [
        MiniCssExtractPlugin.loader, 
        {
          loader:"css-loader",
          options:{ sourceMap: true }
        },
        {
          loader:"postcss-loader",
          options: {
            ident: "postcss",
            sourceMap: true,
            plugins: loader => [require('autoprefixer')()]
          }
        },
        {
          loader:"sass-loader",
          options:{ sourceMap: true }
        },
      ]
    }
  ]
},
plugins: [
  new MiniCssExtractPlugin({
    filename: '[name].css', // 最終輸出的文件名
    chunkFilename: '[id].css'
  })
]

而後從新打包,這時候能夠看到咱們 dist 目錄下就多了個 main.css 文件:

[外鏈圖片轉存失敗(img-3juocHi2-1565738603713)(https://user-gold-cdn.xitu.io/2019/8/12/16c86888174082f4?w=320&h=384&f=png&s=13495)]

由於如今已經將 CSS 都抽取成單獨文件,因此在 dist/index.html 中,咱們須要手動引入 main.css 了:

// index.html

<link rel="stylesheet" href="main.css">

6、 webpack 壓縮 CSS 和 JS

爲了縮小打包後包的體積,咱們常常作優化的時候,將 CSS 和 JS 文件進行壓縮,這裏須要使用到不一樣的插件。

1. 壓縮 CSS

使用 optimize-css-assets-webpack-plugin 壓縮 CSS 的插件。

安裝插件:

npm install optimize-css-assets-webpack-plugin --save-dev

使用插件:

// webpack.config.js

// ... 省略
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
  // ... 省略
  plugins: [
    // ... 省略
    new OptimizeCssAssetsPlugin({})
  ],
}

從新打包,能夠看到 main.css 已經被壓縮成一行代碼,即壓縮成功~

2. 壓縮 JS

使用 uglifyjs-webpack-plugin 壓縮 JS 的插件。

安裝插件:

npm install uglifyjs-webpack-plugin --save-dev

引入插件:

// webpack.config.js

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

使用插件:

// webpack.config.js
// ... 省略
module.exports = {
  // ... 省略
  plugins: [
    // ... 省略
    new OptimizeCssAssetsPlugin({}),
    new UglifyJsPlugin({
      cache: true, parallel: true, sourceMap: true
    })
  ],
}

其中 UglifyJsPlugin 的參數:

cache:當 JS 沒有發生變化則不壓縮;
parallel:是否啓用並行壓縮;
sourceMap:是否啓用 sourceMap;

而後從新打包,查看 main.js,已經被壓縮了:

webpack07

7、webpack 爲文件名添加 hash 值

因爲咱們打包出來的 cssjs 文件是靜態文件,就存在緩存問題,所以咱們能夠給文件名添加 hash 值,防止緩存。

1. 添加 hash 值

直接在 webpack.config.js 中,爲須要添加 hash 值的文件名添加 [hash] 就能夠:

// webpack.config.js

module.exports = {
  // ... 省略其餘
  output: {
    filename: 'main.[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].[hash].css'
    }),
  ],
}

配置完成後,從新打包,就能夠看到文件名中包含了 hash 值了:

webpack08

2. 動態引用打包後的文件

因爲咱們前面給打包的文件名添加了 hash 值,會致使 index.html 引用文件錯誤,因此咱們須要讓它能動態引入打包後的文件。

這裏咱們使用 HtmlWebpackPlugin 插件,它能夠把打包後的 CSS 或者 JS 文件直接引用注入到 HTML 模版中,就不用每次手動修改。

安裝插件:

npm install html-webpack-plugin --save-dev

引入插件:

// webpack.config.js

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

使用插件:

// webpack.config.js

plugins: [
  new HtmlWebpackPlugin({
    title: "leo study!",   // 生成的文件標題
    filename: "main.html", // 最終生成的文件名
    minify: { // 壓縮選項
      collapseWhitespace: true, // 移除空格
      removeComments: true, // 移除註釋
      removeAttributeQuotes: true, // 移除雙引號
    }
  })
],

關於 html-webpack-plugin 更多介紹能夠《查看文檔》https://github.com/jantimon/html-webpack-plugin/。

接着咱們打包之後,能夠看見 dist 目錄下,多了 main.html 的文件,格式化之後,能夠看出,已經動態引入打包後的 CSS 文件和 JS 文件了:

webpack09

8、 webpack 清理目錄插件

在以前,咱們每次打包都會生成新的文件,而且在添加 hash 值之後,文件名不會出現重複的狀況,致使舊文件的冗餘。

爲了解決這個問題,咱們須要在每次打包以前,將 /dist 目錄清空,再進行打包。

這裏咱們使用 clean-webpack-plugin 插件來實現。

安裝插件:

npm install clean-webpack-plugin --save-dev

引入插件:

// webpack.config.js

const CleanWebpackPlugin = require('clean-webpack-plugin');

使用插件:

// webpack.config.js

plugins: [
  new CleanWebpackPlugin()
],

參數 cleanOnceBeforeBuildPatterns 是表示須要清除的文件夾。

這樣咱們每次打包以前,都會先將 /dist 目錄清空一次,再執行打包。

更多參數介紹,可訪問中文官網的介紹:
《clean-webpack-plugin》

9、 webpack 圖片處理和優化

1. 圖片處理

在項目中引入圖片:

// src/style/leo.scss .box{
    background-color: $bg-color;
    display: flex;
    background: url('./../assets/logo.jpg')
}

這時候咱們若是直接打包,會報錯。

咱們須要使用 file-loader 插件來處理文件導入的問題。

安裝插件:

npm install file-loader --save-dev

使用插件:

// webpack.config.js

module: {
  {
    test: /\.(png|svg|jpg|jpeg|gif)$/,
    use: ["file-loader"]
  }]
},

從新打包之後,發現 dist 目錄下多了一個如 373e5e0e214390f8aa9e7abb4c7c635c.jpg 名稱的文件,這就是咱們打包後的圖片。

webpack10

2. 圖片優化

更進一步,咱們能夠對圖片進行壓縮和優化,這裏咱們用到 image-webpack-loader 插件來處理。

安裝插件:

npm install image-webpack-loader --save-dev

使用插件:

// webpack.config.js

module: {
  {
    test: /\.(png|svg|jpg|jpeg|gif)$/,
    include: [path.resolve(__dirname, 'src/')],
    use: ["file-loader",{
        loader: "image-webpack-loader",
        options: {
          mozjpeg: { progressive: true, quality: 65 },
          optipng: { enabled: false },
          pngquant: { quality: '65-90', speed: 4 },
          gifsicle: { interlaced: false },
          webp: { quality: 75 }
        }
      },
    ]
  }]
},

更多參數介紹,可訪問中文官網的介紹:
《image-webpack-loader》

再從新打包,咱們能夠看到圖片打包先後,壓縮了很大:

webpack11

10、 webpack 圖片 base64 和字體處理

1. 圖片 base64 處理

url-loader 功能相似於 file-loader,能夠將 url 地址對應的文件,打包成 base64 的 DataURL,提升訪問效率。

安裝插件:

npm install url-loader --save-dev

使用插件:

注意:這裏須要將前面配置的 image-webpack-loader 先刪除掉,在使用 url-loader

// webpack.config.js

module: {
  {
    test: /\.(png|svg|jpg|jpeg|gif)$/,
    include: [path.resolve(__dirname, 'src/')],
    use: [
      {
        loader: 'url-loader', // 根據圖片大小,把圖片轉換成 base64
          options: { limit: 10000 }, 
      },
      {
        loader: "image-webpack-loader",
        options: {
          mozjpeg: { progressive: true, quality: 65 },
          optipng: { enabled: false },
          pngquant: { quality: '65-90', speed: 4 },
          gifsicle: { interlaced: false },
          webp: { quality: 75 }
        }
      },
    ]
  }]
},

更多參數介紹,可訪問中文官網的介紹:
《url-loader》

2. 字體處理

字體處理的方式和圖片處理方式是同樣的,只是咱們在配置 rules 時的 test 值不相同:

// webpack.config.js

module: {
  {
    test: /\.(woff|woff2|eot|ttf|otf)$/,
    include: [path.resolve(__dirname, 'src/')],
    use: [ 'file-loader' ]
  }
},

11、 webpack 配置合併和提取公共配置

在開發環境(development)和生產環境(production)配置文件有不少不一樣,但也有部分相同,爲了避免每次更換環境的時候都修改配置,咱們就須要將配置文件作合併,和提取公共配置。

咱們使用 webpack-merge 工具,將兩份配置文件合併。

安裝插件:

npm install webpack-merge --save-dev

而後調整目錄結構,爲了方便,咱們將原來 webpack.config.js 文件修更名稱爲 webpack.commen.js,並複製兩份相同的文件出來,分別修改文件名爲 webpack.prod.jswebpack.dev.js

├─package.json
  ├─dist
  ├─src
- ├─webpack.config.js
+ ├─webpack.common.js  // webpack 公共配置文件
+ ├─webpack.prod.js    // webpack 生產環境配置文件
+ ├─webpack.dev.js     // webpack 開發環境配置文件

因爲咱們文件調整了,因此在 package.json 中,打包命令也須要調整,而且配置 mode 模式。

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
- "build": "npx webpack -c webpack.config.js",
+ "build": "npx webpack -c webpack.dev.js --mode development",
+ "dist": "npx webpack -c webpack.prod.js --mode production"
},

1. 調整 webpack.common.js

咱們先調整 webpack.common.js 文件,將通用的配置保留,不是通用的配置刪除,結果以下:

// webpack.common.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  module: {
    noParse: function (content) {return /jquery|lodash/.test(content);},
    rules: [
    {
      test: /\.(png|svg|jpg|jpeg|gif)$/,
      include: [path.resolve(__dirname, 'src/')],
      use: [{
        loader: 'url-loader', // 根據圖片大小,把圖片轉換成 base64
        options: { limit: 10000 },
      },{
        loader: "image-webpack-loader",
        options: {
          mozjpeg: { progressive: true, quality: 65 },
          optipng: { enabled: false },
          pngquant: { quality: '65-90', speed: 4 },
          gifsicle: { interlaced: false },
          webp: { quality: 75 }
        }
      }]
    },{
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      include: [path.resolve(__dirname, 'src/')],
      use: [ 'file-loader' ]
    }]
  },
  plugins: [
      new HtmlWebpackPlugin({
          title: "leo study!",
          filename: "main.html",
          template: path.resolve(__dirname, 'src/index.html'), 
          minify: {
              collapseWhitespace: true,
              removeComments: true,
              removeAttributeQuotes: true,
          }
      }),
      new CleanWebpackPlugin()
  ],
}

2. 安裝 babel-loader

安裝 babel-loader 是爲了將 ES6 及以上版本的 JS 代碼轉換成 ES5。

npm install babel-loader @babel/core @babel/preset-env --save-dev

使用插件:

// webpack.common.js

rules: [
  // ... 省略其餘
  {
    test: /\.js$/,
    use: [{
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env']
      }
    }],
    exclude: /(node_modules|bower_components)/,
  }
]

關於 babel-loader 更多介紹能夠《查看文檔》https://webpack.js.org/loaders/babel-loader/。

3. 調整 webpack.dev.js

這裏咱們就須要用到 merge-webpack 插件進行配置合併了:

// webpack.dev.js

const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');

let devConfig = {
  mode: 'development',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\.(sc|c|sa)ss$/,
      use: [
        'style-loader', {
          loader: "css-loader",
          options: { sourceMap: true }
        }, {
          loader: "postcss-loader",
          options: {
              ident: "postcss", sourceMap: true,
              plugins: loader => [ require('autoprefixer')() ]
          }
        }, {
          loader: "sass-loader",
          options: { sourceMap: true }
        }
      ]
    }]
  }
}
module.exports = merge(common, devConfig)

4. 調整 webpack.prod.js

一樣對於生產環境的配置,咱們也須要用 merge-webpack 插件進行配置合併:

// webpack.prod.js

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');

let prodConfig = {
  mode: 'production',
  output: {
    filename: 'main.[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [{
      test: /\.(sc|c|sa)ss$/,
      use: [
        MiniCssExtractPlugin.loader, {
          loader: "css-loader",
          options: { sourceMap: true }
        },  {
          loader: "postcss-loader",
          options: {
            ident: "postcss", sourceMap: true,
            plugins: loader => [ require('autoprefixer')() ]
          }
        }, {
          loader: "sass-loader",
          options: { sourceMap: true }
        }
      ]
    }]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].[hash].css'
    }),
    new OptimizeCssAssetsPlugin({}),
    new UglifyJsPlugin({
      cache: true, parallel: true, sourceMap: true
    }),
  ],
}
module.exports = merge(common, prodConfig)

12、 webpack 監控自動編譯和啓用 js 的 sourceMap

1. 開啓 js 的 sourceMap

當 webpack 打包源代碼後,就很難追蹤到錯誤和警告在源代碼的位置。

如將三個源文件打包一個 bundle 中,其中一個文件的代碼報錯,那麼堆棧追中就會指向 bundle

爲了能方便定位錯誤,咱們使用 inline-source-map 選項,注意不要在生產環境中使用。

// webpack.dev.js

let devConfig = {
  // ... 省略其餘
+  devtool: 'inline-source-map'
}

2. 測試 sourceMap

爲了測試是否成功,咱們將 src/index.js 代碼中,在第 12 行上,添加一句日誌打印。

// src/index.js

// ... 省略其餘
+ console.log(111)

對比下開啓 sourceMap 先後的區別:

webpack12

3. 開啓監控自動編譯

若是每次咱們修改完代碼,都要手動編譯,那是多累的一件事。

爲此咱們使用 --watch 命令,讓咱們每次保存完,都會自動編譯。

爲此,咱們須要在 package.json 中的打包命令添加 --watch 命令:

// package.json

- "build": "npx webpack --config webpack.dev.js",
+ "build": "npx webpack --config webpack.dev.js --watch",

這裏僅對開發環境開啓,生產環境不須要使用。

十3、 webpack 熱更新

上一節介紹監控自動編譯,當咱們保存文件後,會自動編譯文件,可是咱們仍是須要手動去刷新頁面,才能看到編譯後的結果。

因而爲了自動編譯以後,再自動從新加載,咱們就可使用 webpack-dev-server 來啓動一個簡單 web 服務器,實時從新加載。

1. 開啓熱更新

插件安裝:

npm install webpack-dev-server --save-dev

使用插件:

// webpack.dev.js

const webpack = require('webpack');
const webpack = require('webpack');

let devConfig = {
  // ... 省略其餘
  devServer: {
    contentBase: path.join(__dirname, 'dist'), 
    compress: true,
    hot: true,
    overlay: true, 
    open:true,
    publicPath: '/',
    host: 'localhost',
    port: '1200'
 }
 plugins: [
    new webpack.NamedModulesPlugin(), // 更容易查看(patch)的以來
    new webpack.HotModuleReplacementPlugin() // 替換插件
 ]
}

啓動熱更新:

npx webpack-dev-server --config webpack.dev.js

經常使用配置:

contentBase: path.join(__dirname, 'dist'), //本地服務器所加載的頁面所在的目錄
clinetLogLevel: 'warning', // 可能值有 none, error, warning 或者 info (默認值)
hot:true,//啓動熱更新替換特性,須要配合 webpack.HotModuleReplacementPlugin 插件
host:'0.0.0.0', // 啓動服務器的 host
port:7000,      // 端口號
compress:true,  // 爲全部服務啓用gzip壓縮
overlay: true,  // 在瀏覽器中顯示全屏覆蓋
stats: "errors-only" ,// 只顯示包中的錯誤
open:true, // 啓用「打開」後,dev服務器將打開瀏覽器。
proxy: {   // 設置代理
    "/api": {
        target: "http://localhost:3000",
        pathRewrite: {"^/api" : ""}
    }
}

這時候咱們訪問 http://localhost:1200/main.html 就能夠看到頁面,而且修改文件,頁面也會同時刷新。

2. 優化命令

咱們能夠將 npx webpack-dev-server --config webpack.dev.js 寫到 package.json 中做爲一個命令:

// package.json

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "npx webpack --config webpack.dev.js --watch",
  "dist": "npx webpack --config webpack.prod.js",
+ "watch": "npx webpack-dev-server --config webpack.dev.js"
},

十4、 webpack 設置代理服務器和 babel 轉換及優化

1. 設置代理服務器

接着上一節,接下來給 webpack 設置代理服務器:

// webpack.dev.js

let devConfig = {
  // ... 省略其餘
  devServer: {
    // ... 省略其餘
    proxy: { 
      "/api": { // 以 '/api' 開頭的請求,會跳轉到下面的 target 配置
        target: "http://192.168.30.33:8080",
        pathRewrite: {
          "^api": "/mock/api"
        }
    }
 }
}

最後當咱們請求 /api/getuser 接口,就會轉發到 http://192.168.30.33:8080/mock/api

2. babel 轉換及優化

babel-loader 插件的安裝,已經提早介紹,在【11、 webpack 配置合併和提取公共配置】中。

這裏講一下 babel-loader 的優化。

babel-loader 能夠配置 cacheDirectory 來提升打包效率:

  • cacheDirectory:默認值 false,開啓後構建時會緩存文件夾,後續從緩存中讀取,將提升打包效率。

十5、 webpack 開啓 Eslint

安裝插件:

npm install eslint eslint-loader --save-dev

另外還須要安裝 eslint 解釋器、校驗規則等:

npm install babel-loader standard --save-dev

2. 添加 .eslintrc.js

在項目根目錄建立 .eslintrc.js,指定 eslint 規則。

這份配置內容有點多,能夠去 個人 gist 複製https://gist.github.com/pingan8787/8b9abe4e04bed85f9d7846e513ed2e11

3. 添加 .eslintignore

在項目根目錄建立 .eslintignore,指定 eslint 忽略一些文件不校驗,好比內容能夠是:

/dist/
/node_modules/

十6、 webpack 解析模塊拓展名和別名

在 webpack 配置中,咱們使用 resolve 來配置模塊解析方式。

這是很是重要的,好比 import _ from 'lodash' ,實際上是加載解析了 lodash.js 文件。

該配置就是用來設置加載和解析的方式。

在解析過程當中,咱們能夠進行配置:

1. resolve.alias

當咱們引入一些文件時,須要寫很長的路徑,這樣使得代碼更加複雜。

爲此咱們可使用 resolve.alias,建立 importrequire 的別名,使模塊引入更加簡單。

使用配置:

// webpack.common.js

module.exports = {
  entry: './src/index.js',
+ resolve: {
+   alias: {
+     '@' : path.resolve(__dirname, 'src/')
+   }
+ }
  // 省略其餘
}

alias 參數的含義:

使用 @ 來替代 path.resolve(__dirname, 'src/') 這個路徑,接下來咱們測試看看。

咱們在 src/ 目錄下新增 leo.js

// leo.js

export let name = 'pingan';

再到 src/index.js 中引入:

// index.js

import { name } from '@/leo.js';

這樣就能正常引入。

固然,咱們也能夠根據實際狀況,爲不一樣路徑設置不一樣別名

// webpack.common.js


alias: {
  '@' : path.resolve(__dirname, 'src/')
+ 'assets' : path.resolve(__dirname, 'src/assets/')
}

更多參數介紹,可訪問中文官網的介紹:
《resolve》

2. resolve.extensions

resolve.extensions 用來自動解析肯定的擴展,讓咱們在引入模塊的時候,能夠不用設置拓展名,默認值爲:

extensions: [".js", ".json"]

使用配置:

// webpack.common.js

import { name } from '@/leo';

十7、 webpack 配置外部拓展

當咱們使用 CDN 引入 jquery 時,咱們並不想把它也打包到項目中,咱們就能夠配置 externals 外部拓展的選項,來將這些不須要打包的模塊從輸出的 bundle 中排除:

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>

配置 externals

// webpack.common.js

module.exports = {
  // ... 省略其餘
+ externals: {
+   jquery: 'jQuery'
+ },
}

經過上面配置,咱們就不會把不須要打包的模塊打包進來。而且下面代碼正常運行:

import $ from 'jquery';

$('.leo').show();

更多參數介紹,可訪問中文官網的介紹:
《externals》

十8、 webpack 打包分析報表及優化總結

1. 生成報表

這裏咱們使用 webpack-bundle-analyzer 插件,來對打包後的文件進行數據分析,歷來找到項目優化的方向。

webpack-bundle-analyzer 使用交互式可縮放樹形圖可視化 webpack 輸出文件的大小。

安裝插件:

npm install webpack-bundle-analyzer --save-dev

這個咱們只有在開發環境中使用。

使用插件:

// webpack.dev.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
    // ...
  ]
}

配置完成之後,咱們執行 npm run build 打包,打包完成後,會自動打開一個數據報表分析的頁面,地址是 http://127.0.0.1:8888/

[外鏈圖片轉存失敗(img-IH7Ai82l-1565738603715)(https://user-gold-cdn.xitu.io/2019/8/12/16c86888dd548ee5?w=1433&h=715&f=png&s=48595)]

webpack-bundle-analyzer 將幫助咱們:

  • 看清楚咱們包內都包含什麼模塊;
  • 準確看出每一個模塊的組成;
  • 最後優化它!

咱們常常將報表中區域最大的模塊進行優化!

2. 經過報表優化項目

[外鏈圖片轉存失敗(img-hD4VmaUv-1565738603716)(https://user-gold-cdn.xitu.io/2019/8/12/16c86888dd548ee5?w=1433&h=715&f=png&s=48595)]

咱們能夠看出,打包後的項目中 lodash.js 佔了很是大的內存,咱們就針對 lodash.js 進行優化。

咱們將 lodash.js 改成 CDN 引入:

// index.html

<script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.js"></script>

而後去設置上一節講到的 externals

// webpack.common.js

externals: {
  jquery: 'jQuery',
+ lodash: '_'
},

再打包之後,能夠看到 lodash.js 已經不在包裏面了:

webpack15

而且打包後的文件,也能正常運行:

[外鏈圖片轉存失敗(img-Do0XZ0Ho-1565738603716)(https://user-gold-cdn.xitu.io/2019/8/12/16c86888e575e56a?w=661&h=610&f=png&s=18762)]

更多參數介紹,可訪問中文官網的介紹:
《webpack-bundle-analyzer》

參考資料

總結

本文是根據 《2019最新Webpack4.0教程4.x 成仙之路》 學習總結下來的學習之路,適合入門,涉及範圍較多,內容比較長,須要能靜下心來學習。

內容若是有誤,歡迎留言指點,我會及時修改。

本文代碼最終託管在個人 github 上,點擊查看(https://github.com/pingan8787/Leo-JavaScript/blob/master/Cute-Webpack/introduction/README.md)。

但願本身的文章會對各位有所幫助,也歡迎各位大佬指點。

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787/Leo_Reading/issues
ES小冊 js.pingan8787.com

微信公衆號

bg

相關文章
相關標籤/搜索