主頁 > 前端設計 > 還不會 webpack ? 一文帶你用 webpack 打造溜溜的前端工具流 !

還不會 webpack ? 一文帶你用 webpack 打造溜溜的前端工具流 !

2021-04-24 13:28:22 前端設計

在這里插入圖片描述

文章目錄

    • 一、前言
      • 1. webpack 是什么 ?
      • 2. 為什么要用 webpack 或者類似的靜態資源打包工具 ?
    • 二、你能識訓
    • 三、步入正題
      • 1. 安裝 webpack 和 webpack cli 來開始構建我們自己的前端專案
      • 2. webpack 是可以 0 配置使用的
      • 3. 利用 webpack.config.js 手動定制自己的 webpack
      • 4. 通過配置 html-webpack-plugin 插件來自動打包創建 html 并將打包后的資源自動引入
      • 5. 通過配置 webpack-dev-server 來實作瀏覽器的自動重繪和代碼熱更新功能,
      • 6. 通過配置 package.json 中的 scripts 來指定我們操作的命令
      • 7. 通過配置 loader 來處理 css 并插入到頁面上
      • 8. 通過配置 less-loader 來處理 less 檔案
      • 9. 通過使用 mini-css-extract-plugin 將 css 進行抽離
      • 10. 通過配置 postcss-loader 和 autoprefixer 插件實作為 css3 屬性自動添加兼容性瀏覽器前綴
      • 11. 通過配置 optimize-css-assets-webpack-plugin 插件來壓縮 css
      • 12. 通過配置 babel 來將高級語法轉換為兼容性更強的低級語法
      • 13. 通過配置 ESLint 來添加語法校驗
      • 14. 全域變數引入的問題
      • 15. 通過配置 url-loader、file-loader、html-loader 來處理圖片
      • 16. 配置打包檔案分類
      • 17. 打包多頁應用
      • 18. 配置除錯利器【source-map】
      • 19. 通過配置 watch 實作實時打包
      • 20. 使用 2 個小插件來如虎添翼
      • 21. 通過配置 Proxy 解決 Webpack 跨域問題
      • 22. 通過配置 webpack 的 resolve 來實作自定義匯入
    • 四、后語
    • 五、參考

一、前言

1. webpack 是什么 ?

  • webpack 是一個靜態模塊打包工具,簡單理解就是可以將你的專案中的靜態資源(html、css、js、images、json等),按照既有的依賴關系構建起一張資源映射網,通過配置的 loader 和 plugin 的配合來最終輸出 1 個或者多個 bundle,
  • 😂,哈哈,前面這句話對于新手理解起來并不友好,白話表述就是: 你的專案里面寫的東西多了,會有很多的 html、js、css、圖片等一些靜態資源,檔案資源太多如果再加上命名不規范最終你的專案會變得 “一塌糊涂” ,webpack 這個工具可以根據你的專案之中檔案與檔案、資源與資源之間相互參考的關系自動的將他們打包成 1 個或者幾個檔案,
  • 舉個🌰:唐三要煉制暴雨梨花針,一開始煉制所需的原材料 深海沉銀母發金 等這些相當于(html、js、css)等靜態資源、鐵匠爐 相當于 webpack、在煉制程序中添加的其它輔助材料特殊的錘煉技藝等相當于 loader 和 plugin,那么最終產出的暴雨梨花針的成品就相當于 webpack 最終的打包成的 bundle,

深海沉銀母 + 發金 + … + 輔助材料 + 特殊的錘煉技藝 => 鐵匠爐【產出暴雨梨花針】
html + css + js + images + … + loader + plugin => webpack 【產出 1 個或多個 bundle】

當然 webpack 的妙用絕不止于此,因為 webpack 底層是依賴 nodeJS 的能力,所以 webpack 有著及其豐富的 loader 和 plugin ,甚至你可以自己去寫一個你需要的 loader 和 plugin,

2. 為什么要用 webpack 或者類似的靜態資源打包工具 ?

  • 可以有效的整合專案中的靜態資源最終打包輸出 1 個或者幾個 bundle,
  • 可以打包的程序中配合 loader 和 plugin 實作代碼壓縮和加密【可以免去自己去代碼壓縮網站手動壓縮】
  • 由于新的技術的發展 less 和 scss 等預編譯語言方便了開發但是編譯是一個麻煩事,webpack 可以配合指定的 loader 在打包的程序中完成這些并且會對代碼進行優化,
  • ES Next 規范不斷的迭代,有很多 ECMAScript 新特性在當前的瀏覽器是不支持的,所以 webpack 可以配合 babel 實作這些高級語法的降維轉換,轉換成當前瀏覽器認識的代碼(你可以用 ES 7、8、9的新特性來撰寫代碼但是一點也不耽誤最終打包出來的 bundle 在瀏覽器中的運行)【 這塊最簡單的 🌰 就是,瀏覽器不認識 export default、import 但是 webpack 中你依然可以使用這些語法,只不過在打包的時候 webpack 自己實作了一套方案將這個功能實作了而已 】,
  • 有了 webpack 的支持還可以進行代碼分割,減少主 bundle 的體積以獲得最優的用戶體驗,
  • node 生態及其廣泛,其包管理工具 npm 有很多前端優秀的包,可能我們只能是通過 cdn 的方式在 html 中 通過 script 標簽將其引入,但是借助 webpack 的能力,我們大可直接將包 npm 下來然后直接在想用的腳本中將其 import 進去即可,比較方便,
  • 一些其它的定制化的需求,webpack 借助對應的 loader 和 plugin 也都可以實作,

二、你能識訓

👺 webpack 的基本 12 項配置,
🚀 體驗到快速構建開發的快感,
🌈 感受到更加絲滑的編碼體驗,
🎉 一步步教你打造溜溜的前端作業流,
📦 利用 webpack 開箱即用,插件化的特點,學會通過各種配置來滿足自己的業務需求,

🗣 建議大家拿起筆記本一步一步跟下去 !!!

三、步入正題

1. 安裝 webpack 和 webpack cli 來開始構建我們自己的前端專案

  1. 先創建一個空的專案目錄,然后用 vs code 打開,
    在這里插入圖片描述
    在這里插入圖片描述
  2. 初始化當前專案

~$ yarn init -y

此時專案里面會多一個 package.json 檔案來管理專案依賴,
在這里插入圖片描述

  1. 初始化 git

~$ git init

此時當前專案目錄多了一個 .git 隱藏目錄,
在這里插入圖片描述

  1. 先安裝 webpack 和 webpack-cli

~$ yarn add webpack@4.46.0 webpack-cli@3.3.12 -D --save

執行完這個命令后會發現當前工程多了一個 node_modules 以后專案中裝配的所有依賴的包都自動放在 node_modules 下面管控著,與此同時 package.json 也會記錄我們安裝的開發依賴和生產依賴,
在這里插入圖片描述
小結 :
到此時我們已經通過 webpack 和 webpack-cli 來將我們的專案構建起來了,還是比較簡單的,剩下的作業就是通過了解如何使用 webpack 來幫助我們構建一個溜溜的前端作業流,
并且我們也順便初始化好了我們的 git,之后可以選擇一個遠程倉庫進行關聯,
ok,這一步我們順利的完成了,

2. webpack 是可以 0 配置使用的

什么是 0 配置使用 ? 就是 webpack 是可以做的開箱即用的不需要任何配置也可以實作它的一些基本功能,例如打包,

  1. 我們先新建一個 src 目錄,
  2. 然后分別新建 index.jstest.js

test.js

const util = function util() {
    console.log("TODO ...");
};
module.exports = util;

index.js

const util = require("./test");
util();

然后運行一下 index.js,發現列印了 TODO ...,接下來我們要利用 webpack 的打包能力了,
運行命令 :

~$ npx webpack

你會發現當前專案的根目錄多出了一個 dist 檔案夾,這就是 webpack 打包出來之后的結果,這里面有個壓縮過的 main.js,先運行下 main.js 發現也列印了 TODO …,
在這里插入圖片描述
但是我有 2 個疑問 :

  • webpack 是怎么將我這兩個檔案給打包成一個檔案了 ?
    在 0 配置的環境下,webpack 會自動的將 src 目錄下的 index.js 作為入口,其里面參考的任何資源 webpack 都會將其打包進去,上述 index.js 依賴了 test.js 所以打包的時候將兩個檔案一起打包了,
  • 明明兩個檔案的代碼加起來才那么點為什么打包出來的代碼反而看上去多了呢 ?
    因為瀏覽器是不認識 module.exports 和 require 語法的,但是我們寫代碼的時候使用這種語法卻是很方便的,所以呀為了讓打包出來之后的檔案也可以在瀏覽器中正常運行 webpack 自己實作了一套方案來兼容 module.exports 和 require 語法,所以代碼看上去顯得多了,
    我們可以驗證下這一點的,首先在 dist 目錄下新建一個 index.html 然后在里面分別參考 src 下的 index.js 和當前目錄下的 main.js,做個對比一看便知,
    首先引 src 下的 index.js,由于瀏覽器不認識 module.exports 和 require 語法所以報錯了,
    在這里插入圖片描述
    然后引 index.html 當前目錄的 main.js,由于 webpack 在進行打包的時候對這種語法兼容過了,所以可以正常產出結果,
    在這里插入圖片描述

小結 :
我們已經初步認識了 webpack 的打包能力,也嘗到了 webpack 0 配置的甜頭,但是這種 0 配置是比較弱的,要想我們的前端作業流妥妥的強大, 0 配置是遠遠不能滿足需求的,

3. 利用 webpack.config.js 手動定制自己的 webpack

比如我們想自己指定 webpack 的入口,自己指定打包出來的檔案名叫什么 …

  1. 在專案根目錄下創建 webpack.config.js
  2. 我們可以通過配置 webpack 的 entery 屬性和 outputfilename 屬性、path ,屬性來指定當前 webpack 的入口和 webpack 打包產出的目錄以及檔案名,

webpack.config.js

const path = require("path");
module.exports = { // 配置 webpack
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄】
    },
};

然后我們洗掉掉 dist 目錄再次執行 webpack 打包命令,
會發現生成的 dist 目錄下的打包后的檔案由原來的 mian.js 變成了 bundle.js
在這里插入圖片描述
我們都知道,有些時候瀏覽器對于兩次同樣的請求會走到快取里面,為了消除這個問題我們可以配置下,在打包出來的 bundle.js 后面加上 1 個 8 位的 hash 值,
修改 webpack.config.js 中的 output 中的 filename 中的屬性值,將 bundle.js 改為 bundle.[hash:8].js,再次洗掉掉根目錄的 dist 檔案夾重新執行 webpack 打包命令,
你會發現 bundle 后面有了一串 hash 值,

webpack.config.js

const path = require("path");
module.exports = { // 配置 webpack
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
};

在這里插入圖片描述

  1. 我們可以通過配置 mode 屬性來指定當前 webpack 打包的模式,
    因為在開發的時候我們可能會去查閱打包后的檔案,但是目前打包后的檔案已經被壓縮所以查閱起來不是特別方便,鑒于此我們可以指定 webpack 的打包模式為開發環境模式 development

webpack.config.js

const path = require("path");
module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
};

洗掉根目錄下的 dist 目錄并重新 webpack 打包命令,
你會發現打包后的檔案不是壓縮過得了,
在這里插入圖片描述
小結 :
這里我們已經可以通過 webpack.config.js 來配置自己的 webpack,指定入口檔案的位置、指定打包產出檔案目錄的位置以及檔案名名稱、指定當前的打包模式,
這就完了嗎 ?不還沒有 🎶 …

4. 通過配置 html-webpack-plugin 插件來自動打包創建 html 并將打包后的資源自動引入

我們使用 webpack 打包出來的檔案最終都是要放到瀏覽器中運行的,我們也可以每次在打包出來的 dist 目錄中手動創建 html 并將打包后的資源手動引入就像一開始我們那樣,但是這樣會耗費很多精力,我們可以通過在 webpack 中配置 html-webpack-plugin 插件來自動幫助我們完成這些事情,

  1. 安裝 html-webpack-plugin 插件

~$ yarn add html-webpack-plugin@4.5.2 -D --save

  1. 將其匯入 webpack.config.js
  2. 在 plugins 這個插件陣列中配置使用 html-webpack-plugin 插件,
  3. html-webpack-plugin 插件有幾個常用配置項
    -1). template【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
    -2). filename【指定打包后的 html 檔案的名稱】
    -3). hash【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
    -4). minify【壓縮打包后的 html 配置項】(removeAttributeQuotes 洗掉所有雙引號、collapseWhiteSpace 洗掉所有折疊行)

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
        }),
    ],
};

洗掉根目錄下的 dist 目錄并重新執行 webpack 打包命令,
你會發現在 dist 目錄下有個 index.html,index.html 里面已經自動的引入了 bundle,我們可以運行下這個 index.html,
在這里插入圖片描述

在這里插入圖片描述
此時你發現沒有任何問題,
這個時候我們再把 minify 屬性配好,洗掉下打包后的 index.html 中的引號與折行

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
    ],
};

洗掉根目錄下的 dist 目錄并執行 webpack 打包命令,
此時你會看見 dist 目錄下生成的 index.html 是已經經過洗掉折行和雙引號之后的結果了,再次運行也是可以正常運行的,
在這里插入圖片描述
在這里插入圖片描述
小結 :
這里我們實作了通過配置 webpack 的 html-webpack-plugin 插件在打包時自動生成 html 檔案并引入 bundle,
👍 堅持下去 …

5. 通過配置 webpack-dev-server 來實作瀏覽器的自動重繪和代碼熱更新功能,

其它的 Vue 和 React 腳手架都有這種功能,就是代碼一改變,瀏覽器自動重繪,這種功能在開發時是非常有用的,我們也可以通過配置 webpack-dev-server 來實作類似功能,

  1. 安裝 webpack-dev-server

~$ yarn add webpack-dev-server -D --save

  1. 在 webpack.config.js 中配置 webpack-dev-server 來實作功能,
    配置 webpack 的 devServer 屬性的時候有幾個屬性需要我們知道的 :
    -1). contentBase【指定靜態服務目錄】
    -2). progress【啟動靜態服務器的時候顯示進度條】
    -3). port【指定埠號】
    -4). open【自動打開瀏覽器】
    -5). compress【為所有服務啟動 gzip 壓縮】

webpack.config.js

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

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3000, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
    ],
};

<iframe id="eARh8xtV-1618302412658" src="https://player.youku.com/embed/XNTEzNzY2NTEwOA==" allowfullscreen="true" data-mediaembed="youku"></iframe>

webpack-dev-server

小結 :
通過配置 webpack-dev-server(WDS) 我們實作了瀏覽器自動重繪以及代碼的熱更新,注意這里面有個點是需要我們注意的 :

  • webpack-dev-server 就是 webpack 的靜態服務實際上在任何時候訪問的都是打到記憶體中的檔案,而不是真實的物理磁盤上的檔案,
  • 當我們指定了 contentBase 的時候,是否配置啟用 html-webpack-plugin 插件決定了 webpack-dev-server 將以何種方式將需要的內容打到記憶體中,
    • 如果未啟用 html-webpack-plugin 插件則 webpack-dev-server 會按照設定的 contentBase 設定的目錄去尋找 “bundle.js” 與 “index.html” 將其打到記憶體,然后運行靜態服務訪問記憶體中的檔案,
    • 如果啟用了 html-webpack-plugin 插件則 webpack-dev-server 會按照 html-webpack-plugin 的相關配置(template 屬性)去找到對應的 “index.html” 以及找到 “bundle.js” 將其打進記憶體中,然后運行靜態服務訪問記憶體中的檔案,
  • 所以才會有這個現象 => 當啟用 html-webpack-plugin 插件的時候,即使刪掉根目錄下的 dist 打包目錄,程式依然可以正常運行,

用 2 個視頻來配合上述的描述 :
-未啟用 html-webpack-plugin 插件

<iframe id="CRNZJBNE-1618469069705" src="https://player.youku.com/embed/XNTEzODY1MDE2NA==" allowfullscreen="true" data-mediaembed="youku"></iframe>

未啟用 html-webpack-plugin

-啟用 html-webpack-plugin 插件

<iframe id="Xqfw4VMD-1618469150688" src="https://player.youku.com/embed/XNTEzODY1Mjg1Mg==" allowfullscreen="true" data-mediaembed="youku"></iframe>

已啟用 html-webpack-p

6. 通過配置 package.json 中的 scripts 來指定我們操作的命令

我們在執行構建打包命令和運行 webpack 的靜態服務的命令都是用的默認的命令,人家有的是這樣運行的 => yarn buildyarn dev ,這樣既顯得高大上又簡化了操作,下面我們也來搞一下,

  1. 添加 scripts 屬性并配置 build 命令,
  "scripts": {
    "build": "webpack --config webpack.config.js",
  },
  1. 添加配置 dev 命令,
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server"
  },

package.json

{
  "name": "test-webpack",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server"
  },
  "devDependencies": {
    "html-webpack-plugin": "4.5.2",
    "webpack": "4.46.0",
    "webpack-cli": "3.3.12",
    "webpack-dev-server": "^3.11.2"
  }
}

這個時候我們就可以通過執行 yarn build 來運行打包構建指令、執行 yarn dev 來運行 webpack 靜態服務指令了,
此時 yarn build “等于” npx webpack、yarn build “等于” webpack-dev-server,

<iframe id="tIHdL1GH-1618472333484" src="https://player.youku.com/embed/XNTEzODgyNjExMg==" allowfullscreen="true" data-mediaembed="youku"></iframe>

update package.json scripts

小結 :
通過在 package.json 中配置 scripts 屬性,現在終于可以美觀的大方的通過 yarn build 和 yarn dev 命令來構建和運行 webpack 靜態服務了,后面如果大家還有其它的命令也可以使用類似的方式去配置,還是比較快捷的,

7. 通過配置 loader 來處理 css 并插入到頁面上

  1. 為什么要需要單出處理 css ? 是因為 webpack 默認在打包的時候不會打包 css 檔案,所以就導致最終 css 不會輸出到 dist 目錄中所以也就無法通過在 html 中通過 link 方式來參考 css 資源,所以我們需要在 js 檔案中引入 css 并對 css 進行處理將其輸出到 html 上,這樣瀏覽頁面的時候就可以看到樣式了,
  • 安裝 css-loader 和 style-loader

~$ yarn add css-loader style-loader -D --save

  • css-loader 主要是處理 @import (“xx.css”) 這種語法的【將兩個 css 檔案處理成一個】、style-loader 主要是將處理好的 css 內容插入到 head 標簽中,
  • 更改 webpack 配置,添加 module 屬性,以及 module 屬性下的 rules 屬性并配置,
    -1). rules 下的每一個物件都對應 webpack 模塊檔案中的一條處理規則,
    -2). 每一個處理規則可以使用多個 loader,
    -3). 每一條規則中可以有 test 、use、loader 三個屬性,test 的作用主要是規定哪種檔案適用此規則、use 的作用是標名當前規則使用的 loader,其中 use 的值可以是【字串、陣列】,當為字串時表使用哪個 loader、當為陣列時表為使用哪些 loader,
    rules: [
            { test: /\.css$/, use: ["style-loader", "css-loader"], }
        ],
    },

webpack.config.js

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

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
    ],
    module: {
        rules: [
            { test: /\.css$/, use: ["style-loader", "css-loader"], }
        ],
    },
};

創建 index.css 和 test.css 并在 index.css 中匯入 test.css,在 index.js 中匯入 index.css,

index.css

@import "./test.css";
body {
    background-color: green;
}

test.css

body {
    color: hotpink;
}

index.js

require("./index.css");
const util = require("./test");
util();

運行 yarn dev 命令查看效果,
在這里插入圖片描述
在這里插入圖片描述
由此可見我們實作了將 css 插入到 html,并如實的看到了效果,

  1. 如果我突然想在模板 html 中手動寫樣式呢 ?雖然這種需求極少但是有些時候迫不得已還是會這么干的,
    自己先加上試試看 :

src/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
</head>
<body>
    99
</body>
</html>

再運行 yarn dev 命令查看效果,可以看到我們在模板 html 中新加的樣式被放到了最上面,所以導致被下面的樣式覆寫,通常我們自己在 html 寫的樣式的優先級都應該是最高的,也就是說正常我們期望我們在 html 寫的樣式應該在最下方,界面現在應該呈現出藍色才對,
在這里插入圖片描述
所以下面需要我們更改 css 的規則, use 屬性里面的 loader 呢使用物件形式來滿足定制化的需求,

module: {
    rules: [
        { test: /\.css$/, use: [{
            loader: "style-loader",
            options: {
                insert: function insertAtTop(element) {
                    var parent = document.querySelector('head');
                    // eslint-disable-next-line no-underscore-dangle
                    var lastInsertedElement =
                        window._lastElementInsertedByStyleLoader;

                    if (!lastInsertedElement) {
                        parent.insertBefore(element, parent.firstChild);
                    } else if (lastInsertedElement.nextSibling) {
                        parent.insertBefore(element, lastInsertedElement.nextSibling);
                    } else {
                        parent.appendChild(element);
                    }

                    // eslint-disable-next-line no-underscore-dangle
                    window._lastElementInsertedByStyleLoader = element;
                },
            },
        }, "css-loader"], }
    ],
},

options 屬性可以提供更加精確的控制,比如我們為了實作上述需求可以實作一個 insert 方法放在這里,
然后再運行 yarn dev 命令,即可看見我們在 html 中寫的樣式已經生效了,
在這里插入圖片描述

webpack.config.js

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

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
    ],
    module: {
        rules: [
            { test: /\.css$/, use: [{
                loader: "style-loader",
                options: {
                    insert: function insertAtTop(element) {
                        var parent = document.querySelector('head');
                        // eslint-disable-next-line no-underscore-dangle
                        var lastInsertedElement =
                            window._lastElementInsertedByStyleLoader;

                        if (!lastInsertedElement) {
                            parent.insertBefore(element, parent.firstChild);
                        } else if (lastInsertedElement.nextSibling) {
                            parent.insertBefore(element, lastInsertedElement.nextSibling);
                        } else {
                            parent.appendChild(element);
                        }

                        // eslint-disable-next-line no-underscore-dangle
                        window._lastElementInsertedByStyleLoader = element;
                    },
                },
            }, "css-loader"], }
        ],
    },
};

小結 :
通過配置 css-loader 和 style-loader 我們現在已經可以處理 css 并將其插入到 html 中使其生效了,也就是說我們完全可以用現在的架構去構建頁面了,但是目前的配置還是較弱,需要后續的配置來增強當前專案的擴展能力,比如當我們使用 css 預編譯語言時 webpack 在打包構建時會進行自動編譯然后打包構建,當然類似這種功能需要后續的配置來完成實作,

8. 通過配置 less-loader 來處理 less 檔案

現今有很多的 css 預編譯語言,我們使用起來也是非常的順手,但是在上線之前都需要編譯成 css ,現在我們可以不用自己手動去編譯,我們直接可以通過 webpack 的配置能力來幫助我們完成這個編譯的作業,

  1. 安裝 less-loader

~$ yarn add less less-loader@6.2.0 -D --save

  1. webpack.config.js 中添加處理 less 檔案的規則
module: {
        rules: [
            { test: /\.css$/, use: [{
                loader: "style-loader",
                options: {
                    insert: function insertAtTop(element) {
                            var parent = document.querySelector('head');
                            // eslint-disable-next-line no-underscore-dangle
                            var lastInsertedElement =
                                window._lastElementInsertedByStyleLoader;

                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling);
                            } else {
                                parent.appendChild(element);
                            }

                            // eslint-disable-next-line no-underscore-dangle
                            window._lastElementInsertedByStyleLoader = element;
                        },
                },
            }, "css-loader"], },
            { test: /\.less$/, use: [{
                loader: "style-loader",
                options: {
                    insert: function insertAtTop(element) {
                            var parent = document.querySelector('head');
                            // eslint-disable-next-line no-underscore-dangle
                            var lastInsertedElement =
                                window._lastElementInsertedByStyleLoader;

                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling);
                            } else {
                                parent.appendChild(element);
                            }

                            // eslint-disable-next-line no-underscore-dangle
                            window._lastElementInsertedByStyleLoader = element;
                        },
                },
            }, "css-loader", "less-loader"], }
        ],
    },

再新建 index.less 檔案書寫樣式
index.less

body {
    div {
        width: 100px;
        height: 100px;
        background-color: sandybrown;
    }
}

更改模板 html 的 dom 元素

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
</head>
<body>
    <div>
        99
    </div>
</body>
</html>

index.js 匯入 index.less

require("./index.less");
require("./index.css");

const util = require("./test");
util();

再運行 yarn dev 命令,查看效果,發現 less 書寫的樣式已經生效,頁面上的 div 有了自己的背景色,
在這里插入圖片描述
到這步有人會迷惑,不要迷惑,有人會想為什么要這么配 loader ?use 屬性里面 loader 的順序會不會影響專案 ?答案時肯定的,use 屬性中 loader 的放置順序必須嚴格按照 => 【先右后左,先下后上】的原則,即最先用到的 loader 放在最下最右邊,后續用到的依次往上往左放置,

webpack.config.js

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

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [{ // 配置決議處理 css 模塊的規則
                loader: "style-loader", // 使用 style-loader
                options: {
                    insert: function insertAtTop(element) { // 保證專案中的 css 放在 header 標簽的字標簽中的最前面
                            var parent = document.querySelector('head');
                            // eslint-disable-next-line no-underscore-dangle
                            var lastInsertedElement =
                                window._lastElementInsertedByStyleLoader;

                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling);
                            } else {
                                parent.appendChild(element);
                            }

                            // eslint-disable-next-line no-underscore-dangle
                            window._lastElementInsertedByStyleLoader = element;
                        },
                },
            }, "css-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [{ // 配置決議處理 less 模塊的規則
                loader: "style-loader",
                options: {
                    insert: function insertAtTop(element) {
                            var parent = document.querySelector('head');
                            // eslint-disable-next-line no-underscore-dangle
                            var lastInsertedElement =
                                window._lastElementInsertedByStyleLoader;

                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling);
                            } else {
                                parent.appendChild(element);
                            }

                            // eslint-disable-next-line no-underscore-dangle
                            window._lastElementInsertedByStyleLoader = element;
                        },
                },
            }, "css-loader", "less-loader"], } // 使用 less-loader
        ],
    },
};

小結 :
通過配置 less 和 less-loader 我們已經可以在專案中正常的使用 less 了,當然如果你想在自己的專案中使用其它的 css 預編譯語言,也按照這個邏輯去配置就也沒問題的,

9. 通過使用 mini-css-extract-plugin 將 css 進行抽離

雖然我們實作將 css 插入 html 并最終看到了想要的效果,但這有個問題,就是因為我們是通過 style-loader 將處理好的 css 以 style 標簽的形式進行插入的,如果你的 css 過多就會導致 html 最終打包的體積過大,也不美觀,所以我們要對 css 進行抽離,最好是通過 link 標簽的形式進行引入,當然通過 webpack 的配置能力我們只需要借助 mini-css-extract-plugin 插件就可以幫助我們自動完成這件事情,

  1. 安裝 mini-css-extract-plugin 插件

~$ yarn add mini-css-extract-plugin -D --save

  1. 更改 weback.config.js 組態檔
    -1). 在 plugins 下增加此插件,并指定打包后產出的 css 名稱
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
// ...
plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],	
-2). 將 css 規則和 less 規則中的 style-loader 的配置干掉,然后使用插件提供的 loader 屬性,這樣就可以將 style-loader 的內嵌式插入變成 mini-css-extract-plugin 插件 loader 屬性的 link 引入式,
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "less-loader"], } // 使用 less-loader
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "less-loader"], } // 使用 less-loader
        ],
    },
};

再次運行 yarn dev 命令查看效果,
在這里插入圖片描述
可以看到效果沒啥問題,并且確實也是 link 形式引入的我們的 bundle.css,
小結 :
當通過配置 minli-css-extract-plugin 插件將 css 抽離出來,再借助 html-webpack-plugin 插件的能力將抽離出來的 css 通過 link 標簽的方式進行引入,就越來越接近常規的開發模式了,

10. 通過配置 postcss-loader 和 autoprefixer 插件實作為 css3 屬性自動添加兼容性瀏覽器前綴

在開發中類似一些 css3 屬性我們通常會在前面加上各種前綴以兼容不同瀏覽器,
舉個🌰

div {
	transform: rotate(90deg);
	-webkit-transform: rotate(90deg);
}

當然以前都是開發者自己手寫,但是同樣代碼寫了好幾遍,有時候就感覺很煩,所以我們依然可以借助 webpack 的配置能力使用 postcss-loader 和 autoprefixer 插件來自動添加兼容性瀏覽器前綴,

  1. 安裝 postcss-loader 和 autoprefixer

~$ yarn add postcss-loader@4.0.4 autoprefixer@9.8.0 -D --save

  1. 更改 webpack.config.js,在 css 規則和 less 規則中添加 postcss-loader
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], } // 使用 less-loader
        ],
    },
  1. 在專案根目錄新增 postcss.config.js 檔案,然后里面配置下 autoprefixer 插件,
module.exports = {
    plugins: [require("autoprefixer")],
};
  1. 在 package.json 中添加 browserslist 屬性,
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");

module.exports = { // 配置 webpack
    mode: "development", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], } // 使用 less-loader
        ],
    },
};

postcss.config.js

module.exports = {
    plugins: [require("autoprefixer")],
};

package.json

{
  "name": "test-webpack",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server"
  },
  "devDependencies": {
    "autoprefixer": "9.8.0",
    "css-loader": "^5.2.1",
    "html-webpack-plugin": "4.5.2",
    "less": "^4.1.1",
    "less-loader": "6.2.0",
    "mini-css-extract-plugin": "^1.4.1",
    "postcss-loader": "4.0.4",
    "style-loader": "^2.0.0",
    "webpack": "4.46.0",
    "webpack-cli": "3.3.12",
    "webpack-dev-server": "^3.11.2"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

運行 yarn build 命令,在生成的 dist 目錄下查看打包的 bundle.css 中已經添加了前綴,
在這里插入圖片描述
小結 :
通過配置 postcss-loader 和 autoprefixer 插件我們實作了自動為 css3 屬性添加兼容性瀏覽器前綴,免去了手工添加的苦楚,但要切記最后一步在 package.json 中配置 browserslist 屬性不能省略,否則不會有效果的,

11. 通過配置 optimize-css-assets-webpack-plugin 插件來壓縮 css

css 這邊的 webpack 配置基本差不多了,但是還差一步就是代碼壓縮,
因為 js webpack 默認是壓縮的,但是 css 則不會,所以必須借助 optimize-css-assets-webpack-plugin 插件來壓縮 css,但是如果一旦使用該插件則 webpack 默認壓縮 js 的功能就會被取消掉,所以我們可以借助 uglifyjs-webpack-plugin 插件來壓縮 js,

  1. 安裝 optimize-css-assets-webpack-pluginuglifyjs-webpack-plugin 插件,

~$ yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D --save -D --save

  1. 更改 webpack.config.js ,添加 optimization 配置項,使用 optimize-css-assets-webpack-plugin 插件優化 css 打包

先更改 webpack.config.js 中的 mode 屬性值為 production,因為如果是 development 模式設定優化項是沒有任何效果的,

mode: "production", // 指定 webpack 的打包模式【 development、production 】

優化 css 之前 : 【 js 是 webpack 默認壓縮,css 是未被壓縮 】
在這里插入圖片描述
在這里插入圖片描述
優化 css 之后 : 【 js 的 webpack 默認壓縮被取消,css 已被壓縮 】

const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
optimization: {
     minimizer: [
         new OptimizeCSSAssetsWebpackPlugin(),
     ],
 },

在這里插入圖片描述
在這里插入圖片描述

  1. 使用 uglifyjs-webpack-plugin 插件優化 js 打包

優化 js 之后 : 【 js 已被壓縮,css 已被壓縮 】

const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
 optimization: {
     minimizer: [
         new UglifyJsWebpackPlugin({
             cache: true, // 是否開啟快取
             parallel: true, // 是否并行壓縮
             sourceMap: true, // 是否開啟原始碼映射
         }),
         new OptimizeCSSAssetsWebpackPlugin(),
     ],
 },

在這里插入圖片描述
在這里插入圖片描述
小結 :
通過配置 optimize-css-assets-webpack-plugin 插件和 uglifyjs-webpack-plugin 插件我們實作了 css 和 js 壓縮,目前打包的 html、css、js 檔案都已經處于已經打包壓縮的狀態了,這在一定程度上減少了包的體積,提高了網頁的訪問速度,

12. 通過配置 babel 來將高級語法轉換為兼容性更強的低級語法

目前雖然谷歌等瀏覽器對 ES6 的新特性支持的還不錯,甚至 chrome 都支持了 ES7 等更高級的語法,但是有些瀏覽器可能還沒有支持這些 ES6、ES7、ES Next 的高級語法,就比如最某些手機瀏覽器中雖然是 webkit 內核但是就是沒有支持 ES6 語法,這讓我一度很頭疼,只能用那些原來的又臭又長的低版本語法去做兼容,實際上通過 webpack 我們可以配置 babel 來幫助我們將這件事情實作自動化,就是說自動幫助我們將高級語法轉換為兼容性更強的低級語法,
在講如何配置之前先科普下 babel 幫助我們轉換語法的大致程序(導播上圖 …),
在這里插入圖片描述

是這樣的,如果我們單純的下載 babel 的相關包不做任何配置的話,webpack 是不會鳥我們的,所以我們需要通過 loader 來告訴 webpack 針對 js 檔案我們要做特殊處理,所以我們需要一個 babel-loader,但是這還不夠上圖大家都可以看懂,就是高級語法先被決議編譯成對應的 AST 語法樹,然后再呼叫我們指定的預設模塊進行 AST 層面的語法轉換,轉換完畢后再將轉換后的 AST 語法樹進行重組生成新的轉換后的代碼,但是這一系列作業總得有人做呀 ?所以我們還需要 @babel/core(babel 的核心模塊) 和 @babel/preset-env (babel 的預設模塊),當 babel-loader 呼叫 @babel/core 處理 js 檔案的時候,@babel/core 就會呼叫自身的 transform 方法進行處理,但是我們如果指定了預設模塊的話,就會按照我們指定的預設模塊中的規則進行語法轉換,而這個預設模塊可以理解為是所有高級語法轉換為低級語法的插件集合,因為如果我們自己一個一個裝的話成本太大,索性 babel 直接定義了幾個對應環境的預設模塊,模塊里面就包含這各種需要的轉換規則,
了解了這些前置知識我們就可以說具體的配置步驟啦,

  1. 通過配置 webpack 的 babel-loader、@babel/core、@babel/preset-env 來將 ES6 高級語法轉換為低級語法
  • 安裝 babel-loader、@babel/core、@babel/preset-env

~$ yarn add babel-loader @babel/core @babel/preset-env -D --save

  • 配置 webpack.config.js,在 module 的 rules 中再加一條處理 js 的規則
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"],
                },
            } },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"],
                },
            } },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

index.js

require("./index.less");
require("./index.css");
const util = require("./test");
util();
const arrowFunc = () => {
    console.log("我是箭頭函式");
};
arrowFunc();

執行 yarn build 命令查看打包后的 js bundle 檔案,發現確實將箭頭函式轉換為普通函式了,
在這里插入圖片描述
執行 yarn dev,查看效果發現沒什么問題,
在這里插入圖片描述
但是即使這樣我們也是只是可以將一部分的高級語法轉換為兼容性更好的低級語法,如果后面我們遇到了預設模塊里面沒有包含的高級語法轉換規則我們怎么辦?
這個時候我們就可以一個一個手動去安裝這些插件來使我們的 babel 轉換功能充實強大起來,

  1. 通過使用 @babel/plugin-proposal-class-properties@babel/plugin-proposal-decorators 插件來處理 class 語法以及裝飾器語法
    其中 class 語法和裝飾器語法就是 babel 預設模塊里不曾包含的插件,所以對于 class 和裝飾器轉換的插件需要我們自行安裝,
  • 安裝 @babel/plugin-proposal-class-properties@babel/plugin-proposal-decorators 插件

~$ yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators -D --save

  • 更改 webpack.config.js 配置,添加 plugins 屬性并使用這兩個插件來增強 babel,
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"],
                    plugins: [
                        ["@babel/plugin-proposal-decorators", { legacy: true, }],
                        ["@babel/plugin-proposal-class-properties", { loose: true, }],
                    ],
                },
            } },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                    ],
                },
            } },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

index.js

require("./index.less");
require("./index.css");
const util = require("./test");
util();
const arrowFunc = () => {
    console.log("我是箭頭函式");
};
arrowFunc();
@log
class Confirm {
    bgColor = "#000";
}
console.log(new Confirm().bgColor);
function log(target) {
    console.log(target, "裝飾器");
}

運行 yarn build 命令,查看打包后的 bundle.js 發現確實幫助我們將 class 轉換為了普通函式,裝飾器語法也進行了轉換,
在這里插入圖片描述
運行 yarn dev 命令查看效果,確實列印了我們需要列印的結果,
在這里插入圖片描述

  1. 通過使用 @babel/plugin-transform-runtime 來處理更高級的 Generator 語法以及轉換程序中進行一些優化
    實際上 @babel/plugin-transform-runtime 包是依賴 @babel/runtime 包的,因為比如我們使用了一些高級一點的語法比如 Generator 語法的時候 @babel/plugin-transform-runtime 會到 @babel/runtime 包里面去尋找對應的幫助函式,并將其打進最終輸出的 bundle.js 中,因為 babel 只是進行語法層面的轉換,api 層面的轉換大都是由 @babel/runtime 和 @babel/polyfill 包來做的,所以這種 api 層面的轉換都需要將一些幫助函式的補丁代碼注入到我們的 bundle.js 中(所以這兩個包【@babel/runtime 和 @babel/polyfill】安裝的時候都需要裝進生產依賴中),
    同時 @babel/plugin-transform-runtime 在 babel 作業運行時也對其流程進行了一定優化,比如 Babel可能會在輸出中注入一些跨檔案相同的代碼,像 function _classCallCheck(instance, Constructor) { /* ... */ } 這種代碼多了也是資源上的浪費,使用 @babel/plugin-transform-runtime,它可以將上面的 _classCallCheck 函式物體替換成參考,這樣在使用到的地方直接參考一下即可就沒有必要各處寫 _classCallCheck 函式物體了,
  • 安裝 @babel/plugin-transform-runtime 插件

~$ yarn add @babel/plugin-transform-runtime -D --save

  • 安裝 @babel/runtime 補丁包

~$ yarn add @babel/runtime --save

  • 配置 webpack.config.js,添加 @babel/plugin-transform-runtime 插件,
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                        "@babel/plugin-transform-runtime",
                    ],
                },
            } },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                        "@babel/plugin-transform-runtime",
                    ],
                },
            } },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

index.js

require("./index.less");
require("./index.css");
const util = require("./test");
util();
const arrowFunc = () => {
    console.log("我是箭頭函式");
};
arrowFunc();
@log
class Confirm {
    bgColor = "#000";
}
console.log(new Confirm().bgColor);
function log(target) {
    console.log(target, "裝飾器");
}
function * getStatus() {
    yield 1;
}
console.log(getStatus().next(), "generator");

運行 yarn build 命令,發現打包后的檔案已經將 Generator 語法轉換并且已經打好補丁
在這里插入圖片描述
在這里插入圖片描述
運行 yarn dev 命令查看效果,發現報錯了,
在這里插入圖片描述
但這個鳥錯誤顯然不是咱們自己代碼的錯誤,多半是 node_modules 中存在問題,所以我們可以在處理 js 的babel-loader 中加上 include 和 exclude 屬性來將 node_modules 目錄排除出去,

 module: { // 配置決議模塊的眾多規則
     rules: [
         { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
         { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
         { test: /\.js$/, 
             use:{ // 使用 babel-loader 進行 js 高級語法轉換
             loader: "babel-loader",
             options: {
                 presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                 plugins: [ // 補缺 babel 預設模塊
                     ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                     ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                     "@babel/plugin-transform-runtime",
                 ],
             },
         },
         include: path.resolve(__dirname, "src"),
         exclude: /node_modules/,
      },
     ],
 },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, 
                use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                        "@babel/plugin-transform-runtime",
                    ],
                },
            },
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

然后再運行 yarn dev 再次查看效果,發現已經正常了,
在這里插入圖片描述

  1. 通過配置 @babel/runtime-corejs3 來替換 @babel/runtime
    實際上還有很多的 @babel/runtime 包 polyfill 不了的 api,比如還有這些【Promise、Array.prototype.includes、Object.assign、Array.prototype.map …】等,這些 api 的轉換就需要依賴 @babel/polyfill 包,但是目前在 babel 官網上看到,明確表示 @babel/polyfill 包已經被廢棄,所以這種方式就不推薦使用了,我們其實還是可以借助 @babel/plugin-transform-runtime 包來解決當前面臨的窘境的,這個插件有個屬性是 corejs ,默認值是 fasle ,但是我們可以指定 corejs 的值為其它的值 【2、3】,
    在這里插入圖片描述
    當其值為默認值 false 的時候默認是使用 @babel/runtime 進行 polyfill 的,通過圖片中的英文描述我們可以知道 core-js2 可以 polyfill 那些非實體屬性的所有,但是對于實體屬性還是無能為力,而 core-js3 則是在可以 polyfill 包含實體屬性在內的所有,所以我們直接將 corejs 的屬性值指定為 3 ,然后安裝 @babel/runtime-corejs3 即可,
    所以前面用的 @babel/runtime 包就可以 remove 掉了,因為 core-js 3 包含了原來的 @babel/runtime@babel/polyfill
  • 安裝 @babel/runtime-corejs3

~$ yarn add @babel/runtime-corejs3 --save

  • 修改 webpack.congfig.js 添加 corejs 屬性并將其值指定為 3,
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, 
                use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                        ["@babel/plugin-transform-runtime", { "corejs": 3, }], // 替代 @babel/runtime 和 @babel/polyfill
                    ],
                },
            },
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, 
                use:{ // 使用 babel-loader 進行 js 高級語法轉換
                loader: "babel-loader",
                options: {
                    presets: ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
                    plugins: [ // 補缺 babel 預設模塊
                        ["@babel/plugin-proposal-decorators", { legacy: true, }], // 處理裝飾器語法
                        ["@babel/plugin-proposal-class-properties", { loose: true, }], // 處理 class 語法
                        ["@babel/plugin-transform-runtime", { "corejs": 3, }], // 替代 @babel/runtime 和 @babel/polyfill
                    ],
                },
            },
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};
  • 移除 @babel/runtime 包,

~$ yarn remove @babel/runtime --save

  • index.js 中新增 includes 和 Promise 測驗代碼

index.js

require("./index.less");
require("./index.css");
const util = require("./test");
util();
const arrowFunc = () => {
    console.log("我是箭頭函式");
};
arrowFunc();
@log
class Confirm {
    bgColor = "#000";
}
console.log(new Confirm().bgColor);
function log(target) {
    console.log(target, "裝飾器");
}
function * getStatus() {
    yield 1;
}
console.log(getStatus().next(), "generator");
console.log("aa".includes("a"), ": 是否包含");
const promise = new Promise((resolve) => {
    resolve("哈哈");
});
promise.then(res => {
    console.log("promise 123", res);
});

運行 yarn build 指令查看輸出結果,發現確實已經將 Promise 、includes、Generator 轉換了
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
運行 yarn dev 命令查看效果,發現均可以正常列印,
在這里插入圖片描述

  1. 新建 .babelrc babel 組態檔(注意這是一個隱藏檔案,檔案名前面有個點)并將 babel 的相關配置從 webpack.config.js 中進行抽離,
    webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

.babelrc

{
    "presets": ["@babel/preset-env"], // 使用 babel 預設模塊進行轉換
    "plugins": [ // 補缺 babel 預設模塊
        ["@babel/plugin-proposal-decorators", { "legacy": true }], // 處理裝飾器語法
        ["@babel/plugin-proposal-class-properties", { "loose": true }], // 處理 class 語法
        ["@babel/plugin-transform-runtime", { "corejs": 3 }] // 替代 @babel/runtime 和 @babel/polyfill
    ]
}

再次運行命令 yarn build 和 yarn dev 查看都是沒有問題的,

小結 :
這一小節我們實作了 babel 對高級語法的轉換,并對 babel 的轉換機制與用法有個簡單的了解,熟悉了 babel 在 webpack 的配置情況,到此我們就可以實作語法轉換功能了,再梳理下我們這個小結用到的包 :

1 babel-loader
2 @babel/core
3 @babel/preset-env
4 @babel/plugin-proposal-class-properties
5 @babel/plugin-proposal-decorators
6 @babel/plugin-transform-runtime
7 @babel/runtime-corejs3

13. 通過配置 ESLint 來添加語法校驗

  1. ESLint 規則校驗需要根據需求到 ESLint 官網勾選需要的校驗規則并下載對應的 json 檔案到自己的工程專案中
    因為 ESLint 官網中的選項有很多,本文這里就不做其它勾選了,直接選取它默認的示例 json 配置做案例即可,讀者可以自行到官網定制下載 傳送門 ,
    因為這個 eslintrc.json 檔案是一個隱藏檔案所以下載到我們的專案根目錄后要重命名一下就在前面加個點變成 .eslintrc.json 即可,
    在這里插入圖片描述
  2. 需要在 webpack.config.js 中進行配置
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
         { test: /\.js$/, use: {
            loader: "eslint-loader",
            options: {
                enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
            },
        },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
         { test: /\.js$/, use: {
            loader: "eslint-loader",
            options: {
                enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
            },
        },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

運行 build 命令發現 eslint 提示語法有錯誤,我們基于提示一個一個去更改即可,這無疑算得上是我們的一大助力,在一定程度上減少了 bug 的產生,
在這里插入圖片描述
小結 :
這一節我們實作了 eslint js 的語法規則校驗,這樣我們在日后開發一直遵守我們制定好的 eslint 規范即可,這會使得代碼變得更加可維護,bug 也更少,但是為了后面我們可以順利演示其它的配置,這個 eslint 的配置暫時就注釋了,
webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

14. 全域變數引入的問題

在我們的日常專案中肯定會用到一些包,這些包暴露出來的物件都是掛載 window 上的,我們也成這類物件叫全域物件或者全域變數,那么還有一些其它的三方包也會依賴 window 上掛載好的那個全域物件,最典型的就是 jQuery,有很多其它的庫是依賴 jQuery 的所以就會有一個問題,我們如何將 jQuery 的 $ 掛載到 window 上呢 ?
再說具體實作方案之前先來看下問題 :

  • 先安裝 jQuery

~$ yarn add jquery --save

  • 然后更改 index.js
    index.js
import $ from 'jquery';
console.log($, window.$);

運行命令 yarn dev ,發現 $ 可以列印出來 jQuery 函式,但是 window.$ 列印的是 undefined,
怎么解決這個問題呢 ? 怎么能將 $ 也可以掛載到 window 上呢 ?

  1. 使用 expose-loader

安裝 expose-loader

~$ yarn add expose-loader -D --save

webpack.config.js 中配置,在 module 中再加一條規則

    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
         { test: require.resolve("jquery"), use: "expose-loader?$", }
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
         { test: require.resolve("jquery"), use: "expose-loader?$", }
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

再次運行 yarn dev 命令發現 $window.$ 都列印了,
在這里插入圖片描述

  1. 使用 cdn 配合 webpack.config.js 中的 externals 屬性的方式

先將 cdn 在 html 中引入

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <div>
        99
    </div>
</body>
</html>

然后在 webpack.config.js 中添加 externals 屬性

externals: {
     jquery: "$",
},

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { test: /\.js$/, use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
            include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
            exclude: /node_modules/,
         },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", }
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: {
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

運行 yarn dev,查看效果發現 $window.$ 都是列印了 jQuery 函式的,
在這里插入圖片描述
其實 externals 也可以不配置,因為 jQuery 是通過 cdn 的方式引入的,這樣不論是 $ 還是 window.$ 肯定都是可以拿到 jQuery 的,但是如果在 index.js 代碼中的最前面加上這樣的匯入陳述句就會導致最終將 jQuery 打包進自己的 bundle 中,所以為了防止這種情況才使用的 externals 屬性,指明不打包 jQuery,有問會問,誰會這么蠢都已經引入 cdn 了還在代碼里面自己 import ? 須知一個專案是需要多人合作的若其它的合作者不知道外面已經引入 cdn 了呢?

小結 :
通過這一節我們了解了解決第三方全域模塊怎么全域引入的問題,記住兩種方式即可 :

expose-loader 或者 cdn + externals 屬性

15. 通過配置 url-loader、file-loader、html-loader 來處理圖片

問題 : 就是如果還按照原來的使用方式,圖片默認最終打包的時候不會被打包進 dist 目錄,

  • html 中通過 img 標簽引入
  • js 動態創建圖片
  • css 引入背景圖片

解決方案 :

  1. 解決 js 中動態創建圖片問題
    因為 js 直接按照原來的寫法去直接賦值 src 圖片相對路徑是不行的,因為最終圖片不會打包到 dist 目錄中,所以我們需要使用 url-loader 來處理這個情況,url-loader 依賴 file-loader 所以我們安裝的時候要將這兩個 loader 都裝下來,同時 url-loader 還可以通過配置 limit 屬性來控制圖片的輸出,比如我們可以設定圖片不足 20k 的直接 base64 處理,大于等于 20k 的直接借助 file-loader 的能力輸出真實圖片,

  2. 解決 css 中引入背景圖片的問題
    css 這里面不需要安裝其它任何的 loader 了,因為 css-loader 就已經對此進行了處理了,所以在 background 中使用圖片是絲毫沒有問題的,

  3. 解決 html 中通過 img 標簽引入圖片的問題
    html 中 img 標簽引入 src 屬性的時候也會有路徑的問題,我們可以借助 html-withimg-loader 來處理但是這個 loader 已經超過 1 年沒有開發者維護了,所以還是不建議使用它了,我們還可以使用 html-loder 通過配置 attrs 引數來指定 html 中哪些標簽的哪些屬性可以經過 html-loader 處理,這樣一來我們就可以在 html 中和往常一樣書寫代碼了,

首先 安裝 url-loaderfile-loaderhtml-loader

~$ yarn add file-loader url-loader html-loader@0.5.5 -D --save

然后 更改 webpack.config.js 中的配置

    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ MiniCSSExtractPlugin.loader, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

接著 我們分別使用 html、js、css 的方式參考圖片看看效果是否正常,
index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <div>
        99
        <img src="./dva.jpg">
    </div>
    <div class="container">
        
    </div>
</body>
</html>

index.less

body {
    // div {
    //     width: 100px;
    //     height: 100px;
    //     background-color: sandybrown;
    //     transform: rotate(45deg);
    // }
    .container {
        width: 100px;
        height: 100px;
        background: url('./dva.jpg');
        background-size: cover;
    }
}

index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";

console.log($, window.$);
const image = new Image();
image.src = dvaLogo;
document.body.appendChild(image);

然后運行 yarn dev 命令,查看效果發現三種方式參考的圖片均正常顯示
在這里插入圖片描述
小結 :
這一節我們通過配置 webpack的 url-loader、file-loader、html-loader 實作了圖片的處理,現在就可以和往常一樣正常的使用圖片了,

16. 配置打包檔案分類

目前我們打包出來的靜態資源全部在 dist 目錄下,但是我們想像 css 和 image 這種單獨輸出到一個目錄中,也就是把打包出來的檔案分下類 :

  1. 打包分類處理
  • css 分類
    css 分類比較容易就是在使用 mini-css-extract-plugin 插件的 filename 屬性上加上 css/ 即可,
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
    ],

在這里插入圖片描述

  • 圖片分類
    圖片分類就在 url-loader 中加上 outputPath 屬性指明打包后將產出的路徑
{ 
    test: /\.(png|jpg|gif|webp|jpeg)$/, 
    use: { 
        loader: "url-loader", 
        options: { 
            esModule:false,
            limit: 1 * 1024,
            outputPath: "./img/",
        },
    } 
},

在這里插入圖片描述
2. 介紹個小 skill ,怎么在 webpack 使用 iconfont ?

首先到 阿里巴巴矢量圖示庫 去找個圖示然后下載
在這里插入圖片描述
然后將相關檔案 copy 一份到咱們的 src 下的 iconfont/right 的目錄中
在這里插入圖片描述
在這里插入圖片描述
然后 webpack.config.js 需要重新加一下 url-loader 來單獨處理下這些奇怪的檔案,將是這些檔案結尾的【eot、svg、ttf、woff、woff2】,將這些檔案打到 dist/iconfont/right 目錄中

{
    test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
    use: { 
        loader: "url-loader", 
        options: { 
            esModule:false,
            limit: 20 * 1024,
            outputPath: "./iconfont/right/",
            // publicPath: "https://www.baidu.com",
        },
    } 
},

在這里插入圖片描述
然后我們就可以正常使用了,

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <div>
        99
        <img src="./dva.jpg">
    </div>
    <div class="container">
    </div>
    <span class="iconfont">&#xe618;</span>
</body>
</html>

index.css

@import "./test.css";

body {
    background-color: green;
}

@font-face {
    font-family: 'iconfont1';
    src: url(./iconfont/right/iconfont.eot);
    src: url(./iconfont/right/iconfont.eot?#iefix) format('embedded-opentype'),
        url(./iconfont/right/iconfont.woff2) format('woff2'),
        url(./iconfont/right/iconfont.woff) format('woff'),
        url(./iconfont/right/iconfont.ttf) format('truetype'),
        url(./iconfont/right/iconfont.svg#iconfont) format('svg');
  }

.iconfont {
    font-family: "iconfont1" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

這里需要注意的是,人家讓我們復制下面這段代碼

@font-face {
  font-family: 'iconfont';
  src: url('iconfont.eot');
  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
      url('iconfont.woff2') format('woff2'),
      url('iconfont.woff') format('woff'),
      url('iconfont.ttf') format('truetype'),
      url('iconfont.svg#iconfont') format('svg');
}

但是在 webpack 里面我們要把 url 里面的路徑指向我們的 iconfont/right 目錄下且去掉引號,就變成了上面我們貼出的 index.css 中的那段代碼了,

貼下 webpack.config.js 代碼

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

運行 yarn dev ,發現出現了小圖示,
在這里插入圖片描述
至于為什么圖示不是網站上呈現的藍色而是粉色,是因為還記得咱們在 test.css 中設定的 color: hotpink; 呢嗎 ?

實際上使用 iconfont 有 3 種方式,我們這里面只是介紹最復雜的使用方式,剩下兩種一個是引入 css 一個是引入 js,都比較簡單,所以介紹了下比較復雜的實作,
在這里插入圖片描述
不過更多的時候我們工程專案中的靜態資源都是單獨放在一臺 cdn 服務器上,比如圖片都存放在七牛云或者自己的 cdn 節點,這個時候 html、js、css 中參考的圖片地址一定要變成對應的 cdn 的地址,這個可以在 webpack.config.js 中配置一下,可以更改處理圖片的 url-loader 中使用 publicPath 屬性指向 cdn 資源地址即可,
比如我們的 cdn 地址為 https://www.baidu.com 我們可以這樣設定,

{ 
     test: /\.(png|jpg|gif|webp|jpeg)$/, 
     use: { 
         loader: "url-loader", 
         options: { 
             esModule:false,
             limit: 1 * 1024,
             outputPath: "./img/",
             publicPath: "https://www.baidu.com",
         },
     } 
 },

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    entry: "./src/index.js", // 指定 webpack 入口
    output: {
        filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

這樣再運行 yarn build 命令,發現 html 和 css 參考的圖片地址都變成了 cdn 的資源地址,
在這里插入圖片描述
在這里插入圖片描述
由于這個是模擬的給大家看效果的,就不用 yarn dev 去看頁面效果了,
模擬的效果看完我們可以將 publicPath 先注釋掉,

小結 :
這一節我們實作了打包檔案分類,同時也介紹了我們使用 iconfont 的時候最復雜的那種方法在 webpack 中的使用方式,也順便說明了當我們引 cdn 服務器上的圖片資源該怎么配置,

17. 打包多頁應用

上面介紹的是打包單頁應用,那如果是打包多頁應用呢 ? 比如我們希望最終可以打包出來 2 個頁面,一個是 index.html 另一個是 other.html ,index.html 引自己的 index.js,other.html 引自己的 other.js,

  1. 新建 other.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    other.html
</body>
</html>
  1. 新建 other.js
console.log("other");
  1. webpack.config.js 需要更改一下配置, entry 要換成物件形式來指定多個入口、output 中的 filename 要由 “bundle.[hash:8].js” 換成 “[name].[hash:8].js”、html-webpack-plugin 要使用兩次并且要借助 chunks 屬性為各自的頁面引入對應的 js 資源,
entry: {
    home: "./src/index.js",
    other: "./src/other.js",
},
 ...
output: {
    // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
    filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
    path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
},
...
new HtmlWebpackPlugin({
    template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
    filename: "index.html", //【指定打包后的 html 檔案的名稱】
    hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
    minify: { // 【壓縮打包后的 html 配置項】
        removeAttributeQuotes: true, // 洗掉所有雙引號
        collapseWhitespace: true, // 洗掉所有折疊行
    },
    chunks: ["home"],
}),
new HtmlWebpackPlugin({
    template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
    filename: "other.html", //【指定打包后的 html 檔案的名稱】
    hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
    minify: { // 【壓縮打包后的 html 配置項】
        removeAttributeQuotes: true, // 洗掉所有雙引號
        collapseWhitespace: true, // 洗掉所有折疊行
    },
    chunks: ["other"],
}),

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
};

然后運行 yarn build 查看打包結果,
在這里插入圖片描述
在這里插入圖片描述
然后運行 yarn dev 查看效果,發現兩個頁面均正常,
在這里插入圖片描述
在這里插入圖片描述
小結 :
這一節我們實作了打包多頁應用,配置起來還是比較簡單的 👊,

18. 配置除錯利器【source-map】

因為我們最終打包出來的 bundle 是一個壓縮后的檔案,如果里面有代碼報錯是極為不好除錯的,所以我們需要配置下 source-map,即使有的代碼錯了,我們直接可以定位到源代碼出錯的位置,而不是定位到壓縮后的代碼某處,

  1. 配置 source-map 之前呈現的狀態
    先故意偽造個錯誤將 console.log 寫成 console.lo

index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";

console.log($, window.$);
const image = new Image();
image.src = dvaLogo;
document.body.appendChild(image);
class Confirm {
    constructor() {
        console.lo("故意偽造的錯誤");
    }
}
new Confirm();

運行命令 yarn dev 發現報錯并不明顯,
在這里插入圖片描述
2. 配置 soucre-map 之后呈現的狀態

  • 我們只需要在 webpack.config.js 中配置 devtool 屬性,值為 "source-map" 即可,
  • 再次運行命令 yarn dev ,發現報錯資訊更加明顯,
    在這里插入圖片描述
    小結 :
    這一節我們知道了通過配置 source-map 我們就可以更加方便、精準的除錯錯誤了,

19. 通過配置 watch 實作實時打包

如果我們有個需求就是每次代碼變動的時候都可以進行實時打包而不是通過我們自己輸入命令 yarn build 去手動打包,我們就需要去配置 webpack 的 watch 屬性了,

  1. 配置 watch 屬性實作實時打包
    更改 webpack.config.js 的配置,添加 watch 屬性與 watchOptions 屬性,
watch: true,
watchOptions: {
    poll: 1000,
    aggregateTimeout: 500,
},

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
};

先運行下 yarn build,然后在檔案中做一些改動,發現確實是實時打包了,因為產生了好多 js bundle 檔案,產生這么多檔案的原因就是代碼更改后 500 毫秒自動執行了打包命令,
在這里插入圖片描述
但是這樣太丑了,每次打包后上次打包的結果依然還留著,所以我們需要借助 clean-webpack-plugin 插件來在打包的時候自動洗掉上次打包的檔案目錄,使得我們看到的始終是最新打包的,

  1. 解決打包后 dist 目錄依然存留上次打包的檔案的問題

首先安裝 clean-webpack-plugin

~$ yarn add clean-webpack-plugin -D --save

接著在 webpack.config.js 進行配置使用(因為最新版的 clean-webpack-plugin 插件已經和過去的用法不一樣了,具體用法請移步官網)

...
plugins: [
	...
	new CleanWebpackPlugin(),
],
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
};

此時我們的 clean-webpack-plugin 插件就配好了,現在就可以實作每次代碼輸入改變 500ms 之后會自動洗掉上一次 build 的結果然后自動重新生成 build 的結果,
比如當前的 index.js 內容如下
index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";

console.log($, window.$);
const image = new Image();
image.src = dvaLogo;
document.body.appendChild(image);
class Confirm {
    constructor() {
        console.log("故意偽造的錯誤jkl");
    }
}
new Confirm();

運行命令 yarn build
然后再度更改 index.js 檔案中 console 中的內容,將 console.log(故意偽造的錯誤jkl) 變成 故意偽造的錯誤asd
index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";

console.log($, window.$);
const image = new Image();
image.src = dvaLogo;
document.body.appendChild(image);
class Confirm {
    constructor() {
        console.log("故意偽造的錯誤asd");
    }
}
new Confirm();

然后查看自動打包的結果,發現已經將上一次 build 的結果洗掉生成了最新 build 的結果,
在這里插入圖片描述
小結 :
這一節我們完美實作了通過配置 webpack 的 watch 屬性實作了實時打包構建功能,并借助 clean-webpack-plugin 插件成功洗掉上一次構建的結果,

20. 使用 2 個小插件來如虎添翼

這一節主要介紹兩個小插件的使用【copy-webpack-plugin、“banner-plugin”】,日常

  1. 專案中可能有一些目錄或者檔案不需要走 webpack 打包但是最后也想在 build 的時候輸出到打包后的目錄,比如專案的 doc 目錄,這個時候我們可以借助 copy-webpack-plugin 來實作,
  • 安裝 copy-webpack-plugin 插件

~$ yarn add copy-webpack-plugin@6.4.1 -D --save

  • webpack.config.js 中添加配置使用該插件
...
plugins: [
	...
    new CopyWebpackPlugin({
       patterns: [
           { from: "doc", to: "./doc", },
       ],
   }),
]
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
};
  • 專案根目錄新建 doc 檔案夾,然后新建 doc.md 里面寫上內容
    在這里插入圖片描述
    然后運行命令 yarn build ,就看到了專案根目錄中的 doc 檔案夾完整的輸出到了 dist 目錄下,
    在這里插入圖片描述
  1. 有些時候我們可能通過 webpack 來構建我們自己的 npm 包,這個時候我們的代碼檔案最好可以加上著作權宣告,因為其它的 npm 包都是著作權宣告的,所以我們可以借助 webpack 自帶插件 banner 插件來實作,
  • 修改 webpack.config.js ,匯入 webpack 并配置使用 banner 插件,
...
plugins: [
	...
	new Webpack.BannerPlugin("make 2021 by FruitJ"),
],
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const Webpack = require("webpack");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
        new Webpack.BannerPlugin("make 2021 by FruitJ"),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
};

接下來再運行 yarn build 命令發現打包出來的 js bundle 檔案中的內容前面有我們加的著作權說明,
在這里插入圖片描述
小結 :
這一節我們通過配置使用 copy-webpack-plugin 插件實作了非打包 檔案/目錄 的復制,通過配置使用 webpack 的 banner 插件實作了在打包出來的 js bundle 中添加著作權說明,

21. 通過配置 Proxy 解決 Webpack 跨域問題

為什么會有跨域問題嘞 ? 這個問題多出現在開發環境中,后端服務和前端不在同一【協議、域名、埠號】內,就會出現這種跨域問題,這也是在開發程序中不可避免的問題,當然這個通常做法就是后端同學設定一下就好了,但是如果不想麻煩后端的話,前端自己通過配置 devServer 的代理也是可以解決的,

先看看問題所在
index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";

fetch('http://localhost:3005/user')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

毫無疑問的出現了跨域問題就是因為同時本地服務,協議與域名都一樣但是埠號不一樣,從 3010 埠向 3005 埠的服務發送請求所以必然跨域,
在這里插入圖片描述
通過配置 webpack 的 devServer 的 Proxy 來解決跨域問題

  1. 新建一個 server.js 檔案,在里面通過 node 啟個服務,
    server.js
const express = require("express");

const app = express();
app.get("/api/user", (req, res) => {
    res.json({
        name: "FruitJ",
    });
});
app.listen(3005);

代碼的意思就是開啟一個本地服務,埠是 3005 ,當我們訪問本地服務 3005 埠的 /user 這個 api 地址的時候就會回傳一條 json 資料,

  1. 配置 webpack.config.js ,在 devServer 中添加 Proxy 配置,
proxy: { // 【 處理跨域問題 】
    "/api": "http://localhost:3005",
    pathRewrite: { "/api": "", }, // 重寫請求地址,將 api 替換成空
},

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const Webpack = require("webpack");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
        proxy: { // 【 處理跨域問題 】
            "/api": "http://localhost:3005",
            pathRewrite: { "/api": "", }, // 重寫請求地址,將 api 替換成空
        },
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
        new Webpack.BannerPlugin("make 2021 by FruitJ"),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
};
  1. index.js 中通過 fetch api 發出一條請求 http://localhost:3005/user 的請求,
    index.js
import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";

fetch('/api/user')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

先運行命令開啟服務

~$ node server.js

再運行命令 yarn dev 查看效果,發現成功的解決了跨域的問題
在這里插入圖片描述
那么 webpack 是怎么解決跨域問題的呢 ?
在這里插入圖片描述
就是頁面發送的請求先發送給當前自己同【協議、域名、埠號】的 webpack devServer 服務器,然后由這個 devServer 服務器向 server.js 啟的 3005 埠的服務轉發請求,因為服務器與服務器之間的通信是沒有跨域這一說的,所以通過設定代理服務器就可以解決這個跨域的問題,在咱們的 webpack 中這個 devServer 就充當了代理服務器,
小結 :
這一節我們通過配置 webpack 的 Proxy 代理,完美的解決了跨域問題,極大的提升了開發效率,

22. 通過配置 webpack 的 resolve 來實作自定義匯入

  1. 自定義指定匯入資源的包的查找順序
    首先我們知道當前工程中某個檔案引入資源的查找路徑是當前工程的 node_modules ,如果沒有找到就到上一層尋找,
    如果我們有個需要就是只允許在當前目錄的 node_modules 中查找該怎么配置 ?
    可以通過 webpack 的 resolve 屬性的 modules 屬性來配置(查找順序是從左向右)
...
resolve: {
    modules: [path.resolve("node_modules")], // 自定義指定匯入資源的包的查找順序
},
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const Webpack = require("webpack");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
        proxy: { // 【 處理跨域問題 】
            "/api": "http://localhost:3005",
            pathRewrite: { "/api": "", }, // 重寫請求地址,將 api 替換成空
        },
        // before(app) { // 鉤子【 mock 資料的時候可以使用 】
        //     app.get("/api/user", (req, res) => {
        //         res.json({
        //             name: "FruitJ",
        //         });
        //     });
        // },
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
        new Webpack.BannerPlugin("make 2021 by FruitJ"),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
    resolve: {
        modules: [path.resolve("node_modules")], // 自定義指定匯入資源的包的查找順序
    },
};
  1. 自定義指定匯入資源省略后綴的查找順序
    就是當我們想引入某個 js 的時候我們希望這樣匯入 import utils from "./utils"; 而不是這樣匯入 import utils from "./utils.js"; 通俗說就是想引入 js 的時候不加后綴,
...
resolve: {
...
    extensions: [".js", ".css"], // 自定義指定匯入資源省略后綴的查找順序
},
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const Webpack = require("webpack");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
        proxy: { // 【 處理跨域問題 】
            "/api": "http://localhost:3005",
            pathRewrite: { "/api": "", }, // 重寫請求地址,將 api 替換成空
        },
        // before(app) { // 鉤子【 mock 資料的時候可以使用 】
        //     app.get("/api/user", (req, res) => {
        //         res.json({
        //             name: "FruitJ",
        //         });
        //     });
        // },
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
        new Webpack.BannerPlugin("make 2021 by FruitJ"),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
    resolve: {
        modules: [path.resolve("node_modules")], // 自定義指定匯入資源的包的查找順序
        extensions: [".js", ".css"], // 自定義指定匯入資源省略后綴的查找順序
    },
};

修改 index.js,引入 test.js 但是不加后綴 .js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";
import util from "./test";

util();

運行 yarn dev 命令,發現 test.js 中的 util 方法中的列印陳述句執行了,
在這里插入圖片描述

  1. 自定義指定匯入資源的別名
    某些時候例如我們想匯入 bootstrap.css ,可能我們會這么寫 import "bootstrap/dist/css/bootstrap.min.css"; ,但是這么寫太長了,所以我們可以設定一個別名,引入的時候引入別名就好了,
...
resolve: {
	...
    alias: { // 自定義指定匯入資源的別名
        "bootstrap-css": "bootstrap/dist/css/bootstrap.min.css",
    },
},
...

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsWebpackPlugin = require("uglifyjs-webpack-plugin");
const Webpack = require("webpack");
const OptimizeCSSAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = { // 配置 webpack
    mode: "production", // 指定 webpack 的打包模式【 development、production 】
    // entry: "./src/index.js", // 指定 webpack 入口
    entry: {
        home: "./src/index.js",
        other: "./src/other.js",
    },
    output: {
        // filename: "bundle.[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        filename: "[name].[hash:8].js", // 指定 webpack 打包出來的檔案的名稱
        path: path.resolve(__dirname, "dist"), // 指定 webpack 打包的產出路徑【這塊的路徑必須是一個絕對路徑,這里規定為專案根目錄的 dist 目錄,可以添加 [hash] 每次 build 的時候都會生成新的檔案,來防止瀏覽器快取問題、冒號8 表示只顯示 8 位的 hash 值 】
    },
    devServer: {
        contentBase: "./dist", // 指定 dev-server 的服務器目錄
        progress: true, // 在啟動靜態服務器時顯示進度條
        port: 3010, // 指定埠號
        open: true, // 自動打開瀏覽器
        compress: true, // 為所有服務啟用 gzip 壓縮
        proxy: { // 【 處理跨域問題 】
            "/api": "http://localhost:3005",
            pathRewrite: { "/api": "", }, // 重寫請求地址,將 api 替換成空
        },
        // before(app) { // 鉤子【 mock 資料的時候可以使用 】
        //     app.get("/api/user", (req, res) => {
        //         res.json({
        //             name: "FruitJ",
        //         });
        //     });
        // },
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "index.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["home"],
        }),
        new HtmlWebpackPlugin({
            template: "./src/other.html", //【 指定以哪個 html 檔案為模板自動生成打包后的 html 檔案 】
            filename: "other.html", //【指定打包后的 html 檔案的名稱】
            hash: true, //【在引入 bundle 的時候后面加上 hash 值來防止瀏覽器的快取問題】
            minify: { // 【壓縮打包后的 html 配置項】
                removeAttributeQuotes: true, // 洗掉所有雙引號
                collapseWhitespace: true, // 洗掉所有折疊行
            },
            chunks: ["other"],
        }),
        new MiniCSSExtractPlugin({
            filename: "css/bundle.css",
        }),
        new CleanWebpackPlugin(), // 洗掉 dist 目錄【默認就是洗掉 dist 目錄所以不用傳引數】
        new CopyWebpackPlugin({
            patterns: [
                { from: "doc", to: "./doc", },
            ],
        }),
        new Webpack.BannerPlugin("make 2021 by FruitJ"),
    ],
    module: { // 配置決議模塊的眾多規則
        rules: [
            { test: /\.css$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader"], }, // 使用 css-loader
            { test: /\.less$/, use: [ 
                {
                    loader: MiniCSSExtractPlugin.loader,
                    options: {
                        publicPath: "../",
                    },
                }, "css-loader", "postcss-loader", "less-loader"], }, // 使用 less-loader
            { 
                test: /\.js$/, 
                use: ["babel-loader"], // 使用 babel-loader 進行 js 高級語法轉換
                include: path.resolve(__dirname, "src"), // 只處理 src 下的 js 檔案
                exclude: /node_modules/,
            },
            { 
                test: /\.(png|jpg|gif|webp|jpeg)$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./img/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            {
                test: /\.(svg|eot|ttf|woff|woff2)\??.*$/, 
                use: { 
                    loader: "url-loader", 
                    options: { 
                        esModule:false,
                        limit: 1 * 1024,
                        outputPath: "./iconfont/right/",
                        // publicPath: "https://www.baidu.com",
                    },
                } 
            },
            { 
                test: /\.html$/, 
                use: {
                    loader: "html-loader",
                    options: {
                        attrs: ['img:src', 'img:data-src', 'audio:src'],
                    }
                } 
            },
        //  { test: require.resolve("jquery"), use: "expose-loader?$", },
        //  { test: /\.js$/, use: {
        //     loader: "eslint-loader",
        //     options: {
        //         enforce: "pre", // pre 代表在下面的 loader 之前執行、post 相反
        //     },
        // },include: path.resolve(__dirname, "src"),exclude: /node_modules/, },
        ],
    },
    externals: { 
        jquery: "$",
    },
    optimization: {
        minimizer: [
            new UglifyJsWebpackPlugin({
                cache: true, // 是否開啟快取
                parallel: true, // 是否并行壓縮
                sourceMap: true, // 是否開啟原始碼映射
            }),
            new OptimizeCSSAssetsWebpackPlugin(),
        ],
    },
    devtool: "source-map",
    watch: true, // 開啟監聽
    watchOptions: {
        poll: 1000, // 每秒監聽一次變化
        aggregateTimeout: 500, // 代碼輸入 500ms 后代碼無變化的時候執行打包命令
    },
    resolve: {
        modules: [path.resolve("node_modules")], // 自定義指定匯入資源的包的查找順序
        extensions: [".js", ".css"], // 自定義指定匯入資源省略后綴的查找順序
        alias: { // 自定義指定匯入資源的別名
            "bootstrap-css": "bootstrap/dist/css/bootstrap.min.css",
        },
    },
};

index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "./index.less";
import "./index.css";
import util from "./test";
import "bootstrap-css";

util();

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            background-color: aqua;
        }
    </style>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
    <div>
        99
        <img src="./dva.jpg">
    </div>
    <div class="container">

    </div>
    <span class="iconfont">&#xe618;</span>

    <button class="btn btn-success">success</button>
</body>
</html>

然后運行 yarn dev 命令,查看 success 按鈕確實已經應用上了 bootstrap 的樣式,
在這里插入圖片描述
至于為什么 body 的背景色由綠色變成了白色,是因為被 bootstrap 的 body 樣式覆寫了,這個我們可以在靠前的位置引入 bootstrap,

index.js

import $ from "jquery";
import dvaLogo from "./dva.jpg";
import "bootstrap-css";
import "./index.less";
import "./index.css";
import util from "./test";

util();

再看效果就是綠色背景了
在這里插入圖片描述
小結 :
經過這一節我們了解了,可以通過配置 webpack 的 resolve 屬性來實作自定義匯入,

四、后語

本文是從 0 到 1 開始一點一點搭建 webpack 幫助大家打造自己的前端作業流,到這里我們基于 webpack 構建的專案就具備基本開發能力了,我們總結下 :
webpack可以配置哪些項 ?

  • mode【 webpack 模式配置 】
  • entry【 入口相關配置 】
  • output【 出口相關配置 】
  • devServer【 靜態服務相關配置 】
  • module【 規則(loaders)相關配置 】
  • plugins【 插件相關配置 】
  • optimization【 優化項相關配置 】
  • resolve【 自定義資源查找和引入相關配置 】
  • externals【 指明不打包某個資源的配置 】
  • devtool【 開發工具相關配置(比如 sorce-map) 】
  • watch【 開啟實時監聽的開關 】
  • watchOptions【 實時監聽實時打包相關配置 】

有很多人認為這個玩意配置這么多東西有什么用 ?
實際上問這個問題的同學應該是前端方面的初學者,因為這個問題以前我也會問,為什么用 ? 因為這套工具可以極大程度上提高我們的編碼速率,而且就算費工夫配置也只是一開始費點功夫而已,后面使用起來直接爽到飛起,況且現在很多的腳手架基本這些配置都幫你弄好了,你上去直接開箱即用即可(比如 react 腳手架、vue 腳手架、antd、ant-pro 、umi、dva 等),一句話我們可以通過配置 webpack 可以將以前我們手動干的活變成插件幫助我們自動完成,甚至可以獲得一些良好另樣的開發體驗就像 devServer 的實時重繪等,最重要的是當我們的重復代碼太多我們也可以通過配置進行公共代碼抽離,代碼壓縮、加密等這些插件幫助我們做了,它不放心、不安心、不香嗎 ? 😘

本文到此就截止啦,謝謝一路跟下來的朋友們,也希望大家可以識訓一些東西,本文只是介紹了一些基本的用法和功能,原理尚未進行深入探索,全當是幫助不太了解 webpack 的前端同學引路吧,文章中雖然經過審閱但是難免會有錯字、代碼片段錯誤、貼圖錯誤、甚至 npm 包不斷升級可能跟到某處就卡了,如果出現這些問題請在博文下方留言,筆者發現第一時間進行處理,

本文是筆者一點點構建出來的絕對可以放心食用 🐮,

git 倉庫

👊 下一篇文章關于 webpack 優化的已經提上日程,后續將會與大家見面 !

五、參考

  • webpack 4.0 官網
  • npm 官網
  • copy-webpack-plugin
  • 引入codemirror時報錯,webpack中resolve.extensions配置產生的問題
  • node_modules 的查找路徑是怎樣的?
  • webpack中如何使用iconfont字體圖示
  • webpack中使用iconfont字體圖示的方法
  • Babel學習系列4-polyfill和runtime差別(必看)
  • babel的polyfill和runtime的區別
  • @babel/polyfill和@babel/plugin-transform-runtime區別與
  • webpack4-- 處理html中引入的圖片
  • webpack中處理html中引入的<img>圖片
  • 遇到 bug:“ TypeError:this.getOptions is not a function ”
  • 完美解決webpack打包css背景圖片路徑問題

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/279605.html

標籤:其他

上一篇:WinForm 表單屬性FormBorderStyle設定為none怎么讓視窗可以移動

下一篇:滑鼠移動淡入淡出Canvas小球效果_特炫

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more