Webpack 4 新手入門(mén)教程锦爵,全面講解

什么是webpack?

說(shuō)白了webpack只是一個(gè)打包工具子房,在webpack之前就已經(jīng)有很多打包工具了形用,比如Gulp,webpack是基于node開(kāi)發(fā)出來(lái)的证杭, 因此只能在node環(huán)境下運(yùn)行webpack

本教程主要講解webpack基本的功能使用田度,基本是按照官網(wǎng)教程講解,只是對(duì)官網(wǎng)教程做了整合及部分修改處理:

  • webpack 環(huán)境安裝
  • 創(chuàng)建項(xiàng)目
  • 管理資源
  • 管理輸出
  • 開(kāi)發(fā)環(huán)境配置
  • 模塊熱替換
  • 生產(chǎn)環(huán)境配置
  • 代碼分離
  • 緩存
    本教程基本按以上功能講解

本教程環(huán)境依賴版本為:webpack 4.43.0(目前最新版本)

一.webpack 環(huán)境安裝

  • 本地安裝
npm install --save-dev webpack
npm install --save-dev webpack-cli
  • 全局安裝
npm install --global webpack

官方不推薦全局安裝 webpack解愤。這會(huì)將你項(xiàng)目中的 webpack 鎖定到指定版本每币,并且在使用不同的 webpack 版本的項(xiàng)目中,可能會(huì)導(dǎo)致構(gòu)建失敗琢歇。

查看webpack版本號(hào)

webpack -V

如果安裝成功則會(huì)顯示版本號(hào) 如:

Version: webpack 4.43.0

二.創(chuàng)建項(xiàng)目

  • 創(chuàng)建文件夾webpack-demo,并在終端打開(kāi)
    運(yùn)行如下命令行:
npm init -y
npm install webpack webpack-cli --save-dev

安裝成功后項(xiàng)目結(jié)構(gòu)如下:


image.png
  • 新增文件如下 ( 注意:本文中 +號(hào)表示 添加兰怠,-號(hào)表示刪除
  webpack_demo
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js
image.png
  • 添加剛剛新增的文件內(nèi)容
    src/index.js
function component() {
  var element = document.createElement('div');

  // Lodash 只是一個(gè)js的插件 優(yōu)化了很多原生js的寫(xiě)法 下面的 _join 可以理解成 原生js里array的 join 方法  webpack 是依賴于Lodash這個(gè)插件的
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

index.html

<!doctype html>
<html>
  <head>
    <title>起步</title>
    <script src="https://unpkg.com/lodash@4.16.6"></script>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

調(diào)整 package.json 文件
我們還需要調(diào)整 package.json 文件,以便確保我們安裝包是私有的(private)李茫,并且移除 main 入口揭保。這可以防止意外發(fā)布你的代碼。

{
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
+   "private": true,//新增-------------------
-   "main": "index.js",//刪除--------------------------
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "webpack": "^4.0.1",
      "webpack-cli": "^2.0.9"
    },
    "dependencies": {}
  }
  • 在瀏覽器運(yùn)行 index.html 就會(huì)看到 Hello webpack 這句話了
    image.png
  • 創(chuàng)建一個(gè) dist 文件夾

dist 文件夾就是我們的生產(chǎn)包魄宏,就是可以發(fā)布到線上的代碼

調(diào)整項(xiàng)目結(jié)構(gòu)秸侣,把index.html文件丟到dist里面

webpack_demo
  |- package.json
+ |- /dist
+   |- index.html
- |- index.html
  |- /src
    |- index.js

然后用npm 的方式安裝lodash 依賴(之前是直接引入的 src 地址文件)

npm install --save lodash

在src/index.js 引入 lodash

+ import _ from 'lodash';//增加  用import 方式引入
  function component() {
    var element = document.createElement('div');
  // Lodash用import 方式引入
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
  }
  document.body.appendChild(component());

同時(shí)刪除dist/index.html文件里面的之前 引入lodash的地址,并添加<script src="main.js"></script>

<!doctype html>
<html>
  <head>
    <title>起步</title>
    <!-- <script src="https://unpkg.com/lodash@4.16.6"></script> -->
  </head>
  <body>
    <!-- <script src="./src/index.js"></script> -->
    <!-- 注意:現(xiàn)在目錄里是沒(méi)有main.js 文件宠互,先這樣引進(jìn)來(lái) -->
    <script src="main.js"></script>
  </body>
</html>

執(zhí)行 npx webpack

Node 8.2+ 版本提供的 npx 命令味榛,可以打包webpack 文件(注意: 是npx不是 npm

E:\testItem\webpack_demo> npx webpack
Hash: 8747c90e1866f21be58c
Version: webpack 4.43.0
Time: 2236ms
Built at: 2020-05-19 9:35:46 PM
  Asset      Size  Chunks             Chunk Names
main.js  72.1 KiB       0  [emitted]  main
Entrypoint main = main.js
[1] ./src/index.js 282 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
    + 1 hidden module

WARNING in configuration
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/configuration/mode/

打包成功后dist文件夾自動(dòng)生成main.js文件,
在瀏覽器中打開(kāi) dist/index.html予跌,可正常顯示Hello webpack'搏色。


image.png

image.png
創(chuàng)建配置文件

創(chuàng)建配置文件可以按項(xiàng)目需自定義一些規(guī)則

 webpack-demo
  |- package.json
+ |- webpack.config.js //增加配置文件
  |- /dist
      index.html
 -    main.js  //刪除main.js
  .......//其他文件

webpack.config.js 添加內(nèi)容

const path = require('path');//引入路徑內(nèi)置依賴  不用單獨(dú)安裝

module.exports = {
  entry: './src/index.js',//表示入口文件
  output: {
    filename: 'bundle.js', //打包后輸出文件名稱
    path: path.resolve(__dirname, 'dist') //輸出目錄文件夾(dist)
  }
};

修改 dist/index.html 引入文件 bundle.js

<!doctype html>
<html>
  <head>
    <title>起步</title>
  </head>
  <body>
    <!-- 引入bundle.js -->
    <script src="bundle.js"></script>
  </body>
</html>

現(xiàn)在文件結(jié)構(gòu)如下


image.png

運(yùn)行 npx webpack --config webpack.config.js

E:\testItem\webpack_demo> npx webpack --config webpack.config.js
Hash: 8f98a49ae24fdf34e9d8
Version: webpack 4.43.0
Time: 369ms
Built at: 2020-05-19 10:12:29 PM
    Asset      Size  Chunks             Chunk Names
bundle.js  72.1 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[1] ./src/index.js 282 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
    + 1 hidden module

WARNING in configuration
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/configuration/mode/

在瀏覽器中打開(kāi) dist/index.html,可正常顯示Hello webpack'

添加npm 打包方式 "build": "webpack"
  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
+     "build": "webpack"  //添加代碼
    },
    "keywords": [],
    ......其他代碼
  }

使用 npm run build 命令

 E:\testItem\webpack_demo> npm run build

> webpack_demo@1.0.0 build E:\testItem\webpack_demo
> webpack

Hash: 8f98a49ae24fdf34e9d8
Version: webpack 4.43.0
Time: 393ms
Built at: 2020-05-19 10:31:44 PM
    Asset      Size  Chunks             Chunk Names
bundle.js  72.1 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[1] ./src/index.js 282 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
    + 1 hidden module

WARNING in configuration
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/configuration/mode/

npm 打包完畢后也能正常運(yùn)行

三券册、管理資源

本小節(jié)主要講解加載css频轿、image

加載 CSS

先安裝2個(gè)css依賴

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

webpack.config.js 添加依賴

 const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
+   module: { //這里是依賴包,所有依賴包都件放在這里面
+     rules: [
+       {
+         test: /\.css$/,//這里是正則 查找 css文件
+         use: [
+           'style-loader',//css依賴的包
+           'css-loader'//css依賴的包
+         ]
+       }
+     ]
+   }
  };
  • 添加樣式文件
    src/style.css
webpack_demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
+   |- style.css //添加的文件
    |- index.js
  |- /node_modules

src/style.css

.hello {
  color: red;
}
  • 引入 style.css 文件
    src/index.js
import _ from 'lodash';
+ import './style.css'; //添加的文件

function component() {
    var element = document.createElement('div');

    // 用npm的方式引入 lodash 插件
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+   element.classList.add('hello');//添加一個(gè)類名
    return element;
}

document.body.appendChild(component());

運(yùn)行npm run build

 E:\testItem\webpack_demo> npm run build

> webpack_demo@1.0.0 build E:\testItem\webpack_demo
> webpack

Hash: 36587c29888aada8451a
Version: webpack 4.43.0
Time: 3102ms
Built at: 2020-05-20 10:13:50 PM
    Asset      Size  Chunks             Chunk Names
bundle.js  75.8 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[1] ./src/index.js 338 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
[4] ./src/style.css 519 bytes {0} [built]
[6] ./node_modules/css-loader/dist/cjs.js!./src/style.css 264 bytes {0} [built]
    + 3 hidden modules

WARNING in configuration
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/configuration/mode/

瀏覽器后臺(tái)查看變化


image.png
加載圖片
  • 常用于樣式background圖片顯示等
    先安裝文件依賴包
npm install --save-dev file-loader

webpack.config.js

const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
+       {
+         test: /\.(png|svg|jpg|gif)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

添加一個(gè)圖片


image.png

src/index.js 引入圖片

import _ from 'lodash';
import './style.css';
+ import Icon from './icon.png';//引入圖片

function component() {
    var element = document.createElement('div');

    // 用npm的方式引入 lodash 插件
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');
    // 將圖像添加到我們現(xiàn)有的 div烁焙。
    + var myIcon = new Image(); //添加圖片
    + myIcon.src = Icon;
    + element.appendChild(myIcon);
    return element;
}

document.body.appendChild(component());

src/style.css

  .hello {
    color: red;
+   background: url('./icon.png'); //背景圖片
  }

運(yùn)行npm run build 后打開(kāi) dist/index.html 文件 查看變化


image.png
image.png
加載數(shù)據(jù)

數(shù)據(jù)文件有的是內(nèi)置的航邢,直接引用即可,如JSON文件骄蝇,如果要引入比如XML這樣的文件膳殷,就要用到對(duì)應(yīng)的依賴包

npm install --save-dev xml-loader

webpack.config.js


  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
+       {
+         test: /\.xml$/,//新加文件
+         use: [
+           'xml-loader'
+         ]
+       }
      ]
    }
  };

src 下添加data.xml 文件 并加入內(nèi)容
src/data.xml

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Mary</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Call Cindy on Tuesday</body>
</note>

src/index.js 引入data.xml

import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
+ import Data from './data.xml';//引入
function component() {
    var element = document.createElement('div');

    // 用npm的方式引入 lodash 插件
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');
    // 將圖像添加到我們現(xiàn)有的 div。
    var myIcon = new Image();
    myIcon.src = Icon;

    element.appendChild(myIcon);
  + console.log("data",Data);//打印XML數(shù)據(jù)
    return element;
}

document.body.appendChild(component());

npm run build后 運(yùn)行瀏覽器打印數(shù)據(jù)


image.png

四九火、管理輸出

自動(dòng)配置 dist/index.html 文件里的引用
src目錄下新建 print.js 文件夾
src/print.js 添加內(nèi)容

export default function printMe() {
    console.log('我是 print.js 里面的類容');
  }

并且在 src/index.js 引入

import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
+ import printMe from './print.js';

function component() {
    var element = document.createElement('div');

    // 用npm的方式引入 lodash 插件
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');
    // 將圖像添加到我們現(xiàn)有的 div赚窃。
    var myIcon = new Image();
    myIcon.src = Icon;

    element.appendChild(myIcon);
    console.log("data", Data);

+    var btn = document.createElement('button');
+    btn.innerHTML = 'Click me and check the console!';
+    btn.onclick = printMe;
+    element.appendChild(btn);
    return element;
}

document.body.appendChild(component());

更新 dist/index.html 文件

<!doctype html>
<html>
  <head>
    <title>起步</title>
+    <script src="./print.bundle.js"></script>
  </head>
  <body>
    <!-- 引入bundle.js -->
-     <!-- <script src="bundle.js"></script> -->
+    <script src="./app.bundle.js"></script>
  </body>
</html>

webpack.config.js 調(diào)整入口文件 跟輸出文件

const path = require('path');

module.exports = {
    // entry: './src/index.js',
    entry: {
+       app: './src/index.js',
+       print: './src/print.js'
    },
    output: {
        // filename: 'bundle.js',
+       filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
........其他文件
    }

運(yùn)行 npm run build,dist文件夾會(huì)自動(dòng)生成 app.bundle.js 跟 print.bundle.js


image.png

瀏覽器運(yùn)行 dist/index.html


image.png
html-webpack-plugin 插件使用

在上一小節(jié)中如果我們更改了其中一個(gè)入口起點(diǎn)的名稱或者更改新的名稱后吃既,dist/index.html 并不會(huì)自動(dòng)跟新考榨,因此我們可以用html-webpack-plugin 插件來(lái)解決這個(gè)問(wèn)題

  • 安裝
npm install --save-dev html-webpack-plugin
  • webpack.config.js 調(diào)整
const path = require('path');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    // entry: './src/index.js',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
 +   plugins: [ //這里是放插件的地方
 +       new HtmlWebpackPlugin({
 +           title: '我是新的index標(biāo)題'
 +       })
 +   ],
    module: { //這里放依賴包的地方
    ....//其他代碼
  • 執(zhí)行 npm run build 后會(huì)發(fā)現(xiàn) dist/index.html文件類容已經(jīng)跟新
image.png
自動(dòng)清理dist文件

現(xiàn)在每次運(yùn)行npm run build 重新打包后,只會(huì)添加新的包鹦倚,之前dist下一些無(wú)用的老包還存在河质,可使用 clean-webpack-plugin 插件清理

  • 安裝
npm install 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/index.js',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
+       new CleanWebpackPlugin(),//注意 要放到 其他插件的上面,表示一開(kāi)始就把文件清理干凈
        new HtmlWebpackPlugin({
            title: '我是新的index標(biāo)題'
        })
    ],
    module: {
...//其他代碼

運(yùn)行npm run build之前 可在dist 文件夾下添加一個(gè)無(wú)用的文件(隨意)震叙,然后在重新打包掀鹅,可發(fā)現(xiàn)之前那些無(wú)用的文件都清除掉了

五、開(kāi)發(fā)環(huán)境配置

當(dāng) webpack 打包源代碼時(shí)媒楼,可能會(huì)很難追蹤到錯(cuò)誤和警告在源代碼中的原始位置乐尊。例如,如果將三個(gè)源文件(a.js, b.js 和 c.js)打包到一個(gè) bundle(bundle.js)中划址,而其中一個(gè)源文件包含一個(gè)錯(cuò)誤扔嵌,那么堆棧跟蹤就會(huì)簡(jiǎn)單地指向到 bundle.js限府。這并通常沒(méi)有太多幫助,因?yàn)槟憧赡苄枰獪?zhǔn)確地知道錯(cuò)誤來(lái)自于哪個(gè)源文件痢缎。

代碼報(bào)錯(cuò)位置查詢
  • 在src/print.js 文件中生成一個(gè)錯(cuò)誤
export default function printMe() {
    // console.log('我是 print.js 里面的類容');
    console.error('我是 print.js 里面的類容---并報(bào)了個(gè)錯(cuò)');
  }
  • 重新npm run build 打包胁勺,運(yùn)行瀏覽器點(diǎn)擊按鈕


    image.png

    image.png

    此時(shí)發(fā)現(xiàn)這個(gè)報(bào)錯(cuò)文件是我們打包好的app.bundle.js文件,并不是源文件print.js独旷,而且代碼已混淆署穗,看不出來(lái)本身報(bào)錯(cuò)的地方,沒(méi)有參考價(jià)值嵌洼,因此要改進(jìn)

  • 添加報(bào)錯(cuò)工具
    webpack.config.js 代碼添加工具
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
module.exports = {
    // entry: './src/index.js',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
+    devtool: 'inline-source-map',//wabpack 內(nèi)置工具  不需要npm安裝
    plugins: [

重新打包-并查看報(bào)錯(cuò)源代碼-已經(jīng)完全顯示本來(lái)的print.js文件及代碼


image.png
熱更新

之前我們想要預(yù)覽修改后的代碼效果案疲,需要手動(dòng)打包項(xiàng)目,并且要刷新瀏覽麻养,這樣很不方便褐啡,使用webpack-dev-server可用于開(kāi)發(fā)環(huán)境,實(shí)時(shí)更新代碼

  • 安裝
npm install --save-dev webpack-dev-server
  • webpack.config.js 修改
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
    CleanWebpackPlugin
} = require("clean-webpack-plugin")
module.exports = {
    // entry: './src/index.js',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    devtool: 'inline-source-map',
 +   devServer: {
 +      contentBase: './dist'
 +   },
    plugins: [
...//其他代碼
  • package.json 添加配置
{
  "name": "webpack_demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
+   "start": "webpack-dev-server --open"
  },
  "keywords": [],
  "author": "",
...//其他代碼

運(yùn)行npm run start 會(huì)生成一個(gè)本地服務(wù)器地址http://localhost:8080/回溺,運(yùn)行http://localhost:8080/后這樣瀏覽器就能實(shí)時(shí)刷新修改的代碼了春贸,不需要手動(dòng)操作了

E:\testItem\webpack_demo> npm run start

> webpack_demo@1.0.0 start E:\testItem\webpack_demo
> webpack-dev-server --open

i ?wds?: Project is running at http://localhost:8080/
i ?wds?: webpack output is served from /
i ?wds?: Content not from webpack is served from ./dist
i ?wdm?: wait until bundle finished: /
i ?wdm?: Hash: 862425721897c85f3b10
image.png

六、模塊熱替換

官網(wǎng)解釋:模塊熱替換(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一遗遵。它允許在運(yùn)行時(shí)更新所有類型的模塊萍恕,而無(wú)需完全刷新

啟用 HMR
  • webpack.config.js 更新
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
    CleanWebpackPlugin
} = require("clean-webpack-plugin")
+ const webpack = require('webpack');//HMR  是webpack 內(nèi)置的依賴包
module.exports = {
    // entry: './src/index.js',
    entry: {
   -       // app: './src/index.js',
   -        // print: './src/print.js'
   +   app: './src/index.js' //變成一個(gè)入口文件
    },
    output: {
        // filename: 'bundle.js',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
   +    hot: true
    },
    plugins: [
        new CleanWebpackPlugin(), //注意 要放到 其他插件的上面,表示一開(kāi)始就把文件清理干凈
        new HtmlWebpackPlugin({
            title: '我是新的index標(biāo)題'
        }),
  +     new webpack.HotModuleReplacementPlugin()//HMR  是webpack 內(nèi)置的依賴包
    ],
    module: {
  • 修改 src/index.js 文件
 ...//之前的代碼  
  document.body.appendChild(component());
+ if (module.hot) {
+   module.hot.accept('./print.js', function() {
+     console.log('Accepting the updated printMe module!');
+     printMe();
+   })
+ }
  • npm run start 運(yùn)行后 修改print.js 里面的打印類容
export default function printMe() {
    console.log('我是 print.js 里面的類容11122333');
    // console.error('我是 print.js 里面的類容---并報(bào)了個(gè)錯(cuò)');
  }

我們發(fā)現(xiàn)只要已更改 print.js里面的類容 index.js里面就能監(jiān)控到代碼更新


image.png

但是 我們點(diǎn)擊按鈕時(shí)還是打印的更改前的類容


image.png
  • 繼續(xù)修改代碼 src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
import printMe from './print.js';

function component() {
    var element = document.createElement('div');

    // 用npm的方式引入 lodash 插件
    element.innerHTML = _.join(['Hello', 'webpack1111111'], '');
    element.classList.add('hello');
    // 將圖像添加到我們現(xiàn)有的 div车要。
    var myIcon = new Image();
    myIcon.src = Icon;

    element.appendChild(myIcon);
    console.log("data", Data);

    var btn = document.createElement('button');
    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;
    element.appendChild(btn);
    return element;
}

- // document.body.appendChild(component());
+ let element = component(); // 存儲(chǔ) element允粤,以在  print.js 修改時(shí)重新渲染
+ document.body.appendChild(element);
if (module.hot) {
    module.hot.accept('./print.js', function () {
        console.log('print.js模塊發(fā)生了變化');
 -       // printMe();
 +      document.body.removeChild(element);
 +       element = component(); // Re-render the "component" to update the click handler
 +       element = component(); // 重新渲染 "component",以便更新 click 事件處理函數(shù)
 +       document.body.appendChild(element);
    })
}

這樣就實(shí)現(xiàn)了整個(gè)模塊自動(dòng)刷新了(包括修改style.css 文件)

七翼岁、生成環(huán)境配置

因?yàn)樯森h(huán)境跟開(kāi)發(fā)環(huán)境用的插件跟依賴有的地方是不同的类垫,因此分開(kāi)設(shè)置會(huì)跟好

  • 安裝
npm install --save-dev webpack-merge
  • 添加文件(3個(gè))
  webpack_demo
  |- package.json
  webpack.config.js //這里的配置文件不會(huì)再使用
+ webpack.common.js //方通用代碼的地方
+ webpack.dev.js //開(kāi)發(fā)配置文件
+ webpack.prod.js //生成配置文件
   /dist
   /src
    index.js
  • webpack.common.js
 const path = require('path');
 const {
     CleanWebpackPlugin
 } = require("clean-webpack-plugin")
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
     entry: {
         app: './src/index.js'
     },
     plugins: [
         new CleanWebpackPlugin(),
         new HtmlWebpackPlugin({
             title: 'Production'
         })
     ],
     output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist')
     },
     module: {
         rules: [{
                 test: /\.css$/,
                 use: [
                     'style-loader',
                     'css-loader'
                 ]
             },
             {
                 test: /\.(png|svg|jpg|gif)$/,
                 use: [
                     'file-loader'
                 ]
             },
             {
                 test: /\.xml$/,
                 use: [
                     'xml-loader'
                 ]
             }
         ]
     },
 };
  • webpack.dev.js
 const merge = require('webpack-merge');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   mode: 'development',
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist'
   }
 });
  • webpack.prod.js
 const merge = require('webpack-merge');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   mode: 'production',
 });
  • package.json 配置啟動(dòng)項(xiàng)
{
  "name": "webpack_demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "http://build": "webpack",  //可刪除
  +  "build": "webpack --config webpack.prod.js",
    "http://start": "webpack-dev-server --open",//可刪除
  +  "start": "webpack-dev-server --open --config webpack.dev.js"
  },
  "keywords": [],
...//下面的其他代碼

運(yùn)行 npm run start 跟 npm run build 都可正常運(yùn)行項(xiàng)目

開(kāi)發(fā)or生成環(huán)境判斷

使用 process.env.NODE_ENV 即可判斷,從 webpack v4 開(kāi)始, 指定 mode會(huì)自動(dòng)地配置

  • src/index.js 添加代碼
if (process.env.NODE_ENV !== 'production') {
    console.log('當(dāng)前是開(kāi)發(fā)環(huán)境');
}else{
    console.log('當(dāng)前是生成環(huán)境');
}
image.png

八琅坡、代碼分離

代碼分離可以打包多個(gè)js文件悉患,這樣可實(shí)現(xiàn)按需加載效果,之前我們只生成了一個(gè)app.bundle.js文件榆俺,接下來(lái)我們實(shí)現(xiàn)打包成多個(gè)文件

分離
  • 添加一個(gè)文件
    src/another-module.js
import _ from 'lodash';//這里其實(shí)已經(jīng)是重復(fù)引入了lodash依賴售躁,index.js里面也引入了,后續(xù)會(huì)解決這個(gè)問(wèn)題

console.log(
  _.join(['其他', '模塊', '加載了!'], ' ')
);
  • webpack.common.js 調(diào)整
 const path = require('path');
 const {
     CleanWebpackPlugin
 } = require("clean-webpack-plugin")
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
     entry: {
         app: './src/index.js',
+        another: './src/another-module.js'//添加入口文件
     },
+    optimization: {//防止重復(fù)代碼處理
+        splitChunks: {
+            chunks: 'all'
+         }
+     },
     plugins: [

npm run build 打包后生成單獨(dú)的another-module.js 文件


image.png

懶加載

懶加載的意思就是說(shuō)項(xiàng)目初始化的時(shí)候茴晋,如果沒(méi)有用到的頁(yè)面就不請(qǐng)求陪捷,只有當(dāng)需要用的時(shí)候才會(huì)去請(qǐng)求加載代碼

  • 修改src/print.js 內(nèi)容
console.log('print.js 模塊已經(jīng)加載! 請(qǐng)查看瀏覽器后臺(tái) network tab 工具');

export default () => {
  console.log('點(diǎn)擊了按鈕');//目的是只有點(diǎn)擊了按鈕print.js 這個(gè)模塊才加載
};
  • src/index.js 代碼

webpack webpack 提供了兩個(gè)類似的技術(shù)。第一種诺擅,也是推薦選擇的方式是市袖,使用符合 ECMAScript 提案import() 語(yǔ)法 來(lái)實(shí)現(xiàn)動(dòng)態(tài)導(dǎo)入。第二種烁涌,則是 webpack 的遺留功能苍碟,使用 webpack 特定的 require.ensure酒觅。讓我們先嘗試使用第一種

//懶加載----------------
 import _ from 'lodash';

 function component() {
    var element = document.createElement('div');
   var button = document.createElement('button');
   var br = document.createElement('br');

   button.innerHTML = 'Click me and look at the console!';
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
   element.appendChild(br);
   element.appendChild(button);


   button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
     var print = module.default;

     print();
   });

    return element;
  }
 document.body.appendChild(component());
image.png

image.png

九、緩存

緩存的目的就是每次打包跟新后沒(méi)有變化的代碼不會(huì)請(qǐng)求新的資源微峰,服務(wù)器端還是加載老的代碼阐滩,這樣可以節(jié)省服務(wù)器開(kāi)銷,為了識(shí)別新老代碼是否有變化县忌,可以給打包好的文件后綴添加hash值

  • webpack.common.js 修改
 const path = require('path');
 const {
     CleanWebpackPlugin
 } = require("clean-webpack-plugin")
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
     entry: {
         app: './src/index.js',
         another: './src/another-module.js'//添加入口文件
     },
     plugins: [
         new CleanWebpackPlugin(),
         new HtmlWebpackPlugin({
             title: 'Production'
         })
     ],
     output: {
        //  filename: '[name].bundle.js',//這里的后綴名是寫(xiě)死的
+      filename: '[name].[contenthash].js',//后綴名添加哈希值
        path: path.resolve(__dirname, 'dist')
     },
...//其他代碼

打包代碼后生成哈希值文件,如果文件類容沒(méi)變?cè)俅未虬脑捈绦В募粫?huì)有任何變化


image.png

十症杏、入門(mén)篇完結(jié)--

到目前為止,wabpack基本操作已基本涉及瑞信,再會(huì)厉颤!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凡简,隨后出現(xiàn)的幾起案子逼友,更是在濱河造成了極大的恐慌,老刑警劉巖秤涩,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帜乞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡筐眷,警方通過(guò)查閱死者的電腦和手機(jī)黎烈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匀谣,“玉大人照棋,你說(shuō)我怎么就攤上這事∥漪幔” “怎么了烈炭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)宝恶。 經(jīng)常有香客問(wèn)我符隙,道長(zhǎng),這世上最難降的妖魔是什么卑惜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任膏执,我火速辦了婚禮,結(jié)果婚禮上露久,老公的妹妹穿的比我還像新娘更米。我一直安慰自己,他們只是感情好毫痕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布征峦。 她就那樣靜靜地躺著迟几,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栏笆。 梳的紋絲不亂的頭發(fā)上类腮,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蛉加,去河邊找鬼蚜枢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛针饥,可吹牛的內(nèi)容都是我干的厂抽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丁眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼筷凤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起苞七,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藐守,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蹂风,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體卢厂,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年硫眨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了足淆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡礁阁,死狀恐怖巧号,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姥闭,我是刑警寧澤丹鸿,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站棚品,受9級(jí)特大地震影響靠欢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铜跑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一门怪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锅纺,春花似錦掷空、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)护锤。三九已至,卻和暖如春酿傍,著一層夾襖步出監(jiān)牢的瞬間烙懦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工赤炒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氯析,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓莺褒,卻偏偏與公主長(zhǎng)得像魄鸦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355