后端視野學 Webpack ,文武雙全?
大家好,我是小菜。一個希望能夠成為 吹著牛X談架構(gòu) 的男人!如果你也想成為我想成為的人,不然點個關(guān)注做個伴,讓小菜不再孤單!
本文主要介紹 Webpack 使用
如有需要,可以參考
前端認知
挺多人對前端開發(fā)是存在一定的誤解的,感覺會點 H5 + C3 + JS 就等于會前端開發(fā),但近幾年前后端分離的模式逐漸流行起來,就說明前端早已沒有之前那么簡單。
站在我這個后端的視角上倒覺得, 前端是個文官,后端是個武將,不能說做到能文能武,但起碼求武的同時不能不識一丁,退一兩步來說,當前端實習妹子遇到 Bug 束手無措的時候,你這偽境前端若能出手相助~那在她人眼中你就是一位 '架著七彩祥云而來的蓋世英雄~'
如果說你會 Bootstrap 加上 Layui,那么就說你會前端,難免會被人拍死在沙灘上~ 實際上的前端開發(fā)是由以下幾個模塊組成:
- 模塊化(js 的模塊化,css 的模塊化,資源的模塊化)
- 組件化(復用現(xiàn)有的 UI 結(jié)構(gòu),樣式,行為)
- 規(guī)范化(目錄結(jié)構(gòu)的劃分、編碼規(guī)范化、接口規(guī)范化、文檔規(guī)范化、Git分支管理)
- 自動化(自動化構(gòu)建、自動部署、自動化測試)
與后端如出一轍,該有的模塊都有。
說到工程化,在后端開發(fā)中存在主流的解決方案有 Maven 工程 和 Gradle 工程。前端工程化解決方案也有 webpack 和 vite。那么就進入我們今天的正題,走進 Webpack
Webpack
一、概念認知
本質(zhì)上,webpack 是一個用于現(xiàn)代 JavaScript 應用程序的靜態(tài)模塊打包工具。當 webpack 處理應用程序時,它會在內(nèi)部從一個或多個入口點構(gòu)建一個依賴圖,然后將你的項目中所需的每一個模塊組合成一個或多個 bundles,它們均為靜態(tài)資源,用來展示你的內(nèi)容。
以上內(nèi)容摘于官網(wǎng),官里官氣的。下面我們簡單概括一下
- 概念總結(jié):webpack 是前端項目工程化的具體解決方案
- 功能總結(jié):
提供了友好的前端模塊化開發(fā)的支持
提供了代碼壓縮混淆、處理瀏覽器兼容Js、以及性能優(yōu)化等強大功能
- 優(yōu)點總結(jié):提高了前端開發(fā)效率和項目的可維護性
二、基本使用
實踐出真知!我們直接使用來加強認識。
首先我們需要創(chuàng)建一個空白目錄,然后在空白目錄中執(zhí)行 npm init -y 來初始化包管理配置文件 package.json
可以簡單理解為這個 package.json 就相當于 maven 工程中的 pom.xml 文件
在 Maven 工程中我們通常上都是把源代碼放在 src 目錄底下,該 webpack 工程類似,因此我們下一步便是在該目錄下創(chuàng)建 src 目錄,繼而創(chuàng)建兩個文件 index.html (首頁) 和 index.js (腳本文件)
我們傳統(tǒng)上要引入 Jquery 文件,一般有兩種方式
- 一種是下載 jquery.mini.js 文件,然后在項目中引入
- <script src="../js/jquery.js"></script>
- 一種是引用網(wǎng)上現(xiàn)成的 CDN 庫,這樣可以不用下載
- <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
兩種方式各有優(yōu)劣,這里不做過多說明!
既然我們該項目是使用 npm 初始化的,那我們便可以使用 npm 來幫我們下載好所需要的包
- npm install jquery -s
添加成功后我們可以在 package.json 文件中看到我們剛剛下載的包,這種方式有沒有讓你回想到 maven 的 maven install 命令,這種奇怪的熟悉感~
等 jquery 包安裝完成后,我們就可以在 node_modules 目錄下查看到剛剛安裝的包
然后在項目中進行引用
瀏覽器查看 JS 運行正常
以上方式也是傳統(tǒng)的引包方式,跟 webpack 仍是沒有半點關(guān)系。接下來我們就來看看 webpack 是如何使用的。
1、webpack 安裝
在終端中運行如下命令,安裝與 webpack 相關(guān)的兩個包:
- npm install webpack@5.42.1 webpack-cli@4.7.2 -D
擴展
- npm install xxx -S,也就是 npm install module_name --save 寫入dependencies
- npm install xxx -D,也就是 npm install module_name --save-dev寫入devDependencies
devDependencies ,是我們開發(fā)的時候需要用到的一些包,只需要用于開發(fā)階段,真正打包上線的時候并不需要這些包,dependencies,這個則是需要發(fā)布到生產(chǎn)環(huán)境中的。
2、webpack 配置
我們需要在項目的根目錄中,創(chuàng)建一個名為 webpack.config.js 的 webpack 配置文件,并初始化如下的基本配置:
- module.exports = {
- mode: "development"
- }
其中的 mode 是個可變值,存在兩個可選值
- development
1、 適用于開發(fā)環(huán)境
2、不會對打包生成的文件進行代碼壓縮和性能優(yōu)化
3、打包速度快,適合在開發(fā)階段使用,能夠快速響應頁面的更改
- production
1、適用于生產(chǎn)環(huán)境
2 、會對打包生成的文件進行代碼壓縮和性能優(yōu)化
3、打包速度很慢,僅適合在項目發(fā)布階段使用
1)配置文件的作用
webpack.config.js 是 webpack 的配置文件,webpack 在真正開始打包構(gòu)建之前,會 先去讀取這個配置文件,從而基于給定的配置,對項目進行打包
由于 webpack 是基于 node.js 開發(fā)出來的打包工具,因此在它的配置文件中是支持 node.js 相關(guān)的語法和模塊進行 webpack 個性化配置的
然后我們這里先打個 載入點① ,先回到剛剛說到的 webpack 使用,等會再回來介紹 webpack!
在Java中有句熟悉的話:萬物皆對象 ,因此在前端工程中我們同樣有句話:萬物皆模塊
我們已經(jīng)不需要傳統(tǒng)的 js 導入方式:
- <script src="../node_modules/jquery/dist/jquery.min.js"></script>
我們可以在有需要 jquery 的地方使用 import 的方式導入,jquery 是頁面 index.html 需要的嗎?并不是,而是 index.js 腳本文件需要,所以我們只需要在 index.js 文件中導入
然后我們還需要修改 package.json 文件:
我們新增了 dev 腳本 ,在 script 節(jié)點下的腳本,可以通過 npm run 執(zhí)行。
然后我們在終端上運行 npm run dev 命令,啟動 webpack 進行項目的打包構(gòu)建
啪一下,很快啊!就在項目目錄中生成了一個 dist 目錄,并存在 main.js 腳本文件
我們繼而在 index.html 文件中引入該 main.js 文件,先直接看結(jié)果,我們右鍵在瀏覽器打開
可以發(fā)現(xiàn),js 運行正常,那么 main.js 是啥玩意?
在 **webpack 4.x 和 5.x ** 的版本中有如下默認約定:
- 默認的打包入口文件為 src/index.js
- 默認的輸出文件路徑為 dist/main.js
規(guī)定是die的,人是活的,因此我們可以在 webpack.config.js 中修改打包的默認約定!
既然了解了約定,因此我們就可以知道在 main.js 中包含了 index.js 內(nèi)容,我們可以直接查看 main.js 文件,結(jié)果如我們所料:
我們回到之前的 載點① 繼續(xù)剛剛 webpack.config.js 配置文件的說明
我們在 webpack.config.js 文件中可以通過 entry 節(jié)點指定打包的入口,然后通過 output節(jié)點指定打包的出口。
這就是我們上面所說的打破默認規(guī)則!
上面我們也說完了 webpack 的基本使用,那我們下面就來看看 webpack 中的插件使用
三、插件使用
插件 顧名思義就是用來擴展 webpack 的功能,通過安裝和配置第三方的插件,可以擴展 webpack 的能力,從而讓 webpack 使用起來更加方便。最常用的 webpack 有兩個:
- webpack-dev-server
1、類似于 node.js 階段用到的 nodemon 工具
2、每當修改了源代碼,webpack 會自動進行項目的打包和構(gòu)建
- html-webpack-plugin
1、類似于一個模板引擎
2、可以通過此插件自定制 index.html 頁面中的內(nèi)容
我們先來看如何使用第一個插件
1)webpack-dev-server
webpack-dev-server 可以讓 webpack 監(jiān)聽項目源代碼的變化,從而進行自動打包構(gòu)建
① 安裝
使用以下命令即可在項目中安裝該插件
- npm install webpack-dev-server@3.11.2 -D
② 配置
1、需要修改 package.json 中的 script
- "scripts": {
- "dev": "webpack server"
- }
2、運行 npm run dev 命令
可以看到一句話:項目正在運行于 localhost:8080/ 。并且運行后并沒有出現(xiàn) dist 目錄
然后我們通過該地址訪問卻沒有看到我們想要的頁面,而是需要點擊 src 目錄才能訪問
根據(jù)以上結(jié)果,我們可能有如下疑問:
- 為什么運行 npm run dev 會出現(xiàn)了一個訪問地址呢?
這是因為 webpack-dev-server 會啟動一個 實時打包的 http 服務器
- 打包生成的文件在哪?
想要解答這個問題,我們就得需要知道兩點 - 配置和不配置 webpack-dev-server 的區(qū)別
1、不配置 webpack-dev-server 的情況下,webpack 打包生成的文件,會存放到實際的物理磁盤上(根據(jù) output 指定路徑進行存放)
2、配置 webpack-dev-server 的情況下,打包生成的文件會存放到內(nèi)存上,不再根據(jù) output 節(jié)點指定的路徑存放,這樣的好處是提高了實時打包輸出的性能,因此內(nèi)存比物理磁盤速度快很多
- 生成到內(nèi)存中的文件該如何訪問?
生成到內(nèi)存中的文件,默認是放到了項目的根目錄中,但是是虛擬不可見的,我們可以直接用 / 表示項目根目錄,后面跟上要訪問的文件名稱, 即可訪問內(nèi)存中的文件。
以三個問題收尾,我們來說下一個插件 html-webpack-plugin
2)html-webpack-plugin
我們上面通過訪問 webpack server 給定的 URL 地址,發(fā)現(xiàn)不能直接訪問到我們的 index 頁面,這難免有些缺陷,有缺陷自然就會有改進,這就可以聊到 html-webpack-plugin 這個插件了~!
① 安裝
老樣子,我們需要通過以下命令進行安裝
- npm install html-webpack-plugin@5.3.2 -D
② 配置
③ 運行
我們通過運行 npm run dev ,然后看結(jié)果
通過該插件,我們可以看到已經(jīng)可以直接通過路徑訪問該頁面~
這里有小伙伴可能會提出問題,如果我不想通過 8080 端口可以嗎,甚至不想通過 localhost 訪問可以嗎?答案是可以的,我們可以通過 devServer 節(jié)點 對 webpack-dev-server 插件進行更多的配置:
- devServer: {
- // 首次打包成功后,自動打開瀏覽器
- open: true,
- // 在 http 協(xié)議中,如果端口號是 80,則可以被省略
- port: 8081,
- // 指定運行的主機地址
- host: '127.0.0.1'
- },
然后我們運行項目后通過 127.0.0.1:8081 訪問頁面:
到這里我們就已經(jīng)介紹了兩個插件的使用,接下來我們將看點不一樣的東西~!
四、loader使用
我們在開頭的時候已經(jīng)說過一句話,在前端工程化中,萬物皆模塊。因此我們可以在 index.js 腳本文件中通過 import 的方式導入 jquery js文件。那遇到 css 文件是否一樣能夠通過 import 導入?我們不妨一試:
當我們想要通過 import 的方式導入該 css文件,控制臺卻給了我們一句話 :你可能需要一個適當?shù)膌oader來處理這種文件類型,適當?shù)?loader?。那就進入正題,什么是 loader!
在實際開發(fā)過程中,webpack 默認只能打包處理以 .js 后綴名結(jié)尾的模塊。其他非 .js 后綴名結(jié)尾的模塊,webpack 是處理不了,也就是會出現(xiàn)我們上面的那種情況,但怎么處理呢?就需要像提示文本所說的那樣,我們需要下載一個適當?shù)?loader 來處理這種文件類型。
loader 加載器有許多種,但它們的作用就只有一個,那就是 幫助 webpack 來打包處理特定的文件模塊
- css-loader:可以打包處理 .css 相關(guān)的文件
- less-loader:可以打包處理 .less 相關(guān)的文件
- babel-loader: 可以打包處理 webpack 無法處理的高級 JS 語法
接下來我們就來處理上面遇到 css 導包的問題
① 安裝
通過以下命令來安裝處理 css 文件的 laoder
- npm i style-loader@3.0.0 css-loader@5.2.6 -D
② 配置
我們需要在 webpack .config.js 文件中配置相應的 loader 規(guī)則
- module: {
- rules: [
- // 處理 .css 文件的 loader
- { test: /\.css$/, use: ['style-loader', 'css-loader'] },
- ]
- }
③ 運行
繼而我們運行文件,瀏覽器看效果
該結(jié)果已經(jīng)說明了 css-loader 已經(jīng)起到作用了。我們看下規(guī)則的編寫方式是怎么樣的:
- { test: /\.css$/, use: ['style-loader', 'css-loader'] }
其中 test 表示匹配的文件類型, use 表示對應要調(diào)用的 loader
- use 數(shù)組中的 loader 順序是固定的
- 多個 loader 的調(diào)用順序是 從后往前調(diào)用
其它loader的使用方式與上面一致,都是需要先安裝,然后在 webpack.config.js 文件中配置
1)less-loader
安裝
- npm i less-loader@10.0.1 less@4.1.1 -D
配置
- module: {
- rules: [
- // 處理 .css 文件的 loader
- { test: /\.css$/, use: ['style-loader', 'css-loader'] },
- // 處理 .less 文件的 loader
- { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
- ]
- }
2)babel-loader
安裝
- npm i babel-loader@8.2.2 @babel/core@7.14.6 @babel/plugin-proposal-decorators@7.14.5 -D
配置
- module: {
- rules: [
- // 處理 .css 文件的 loader
- { test: /\.css$/, use: ['style-loader', 'css-loader'] },
- // 處理 .less 文件的 loader
- { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
- // 處理JS高級語法的 loader
- { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
- ]
- }
上面我們看到幾種 loader 的作用,那么其中處理流程是怎么樣的呢?我們用張圖解釋下:
五、打包發(fā)布
完成以上項目開發(fā)后,我們就要來到 打包發(fā)布 的階段,前面所做的一切,到最后肯定都是需要發(fā)布的,那么為了能讓項目在生產(chǎn)環(huán)境中高性能運行,就需要對項目打包發(fā)布。
① 配置
打包發(fā)布同樣需要配置,我們需要在 package.json 文件下的 script 節(jié)點 進行配置:
其中 --model 是一個參數(shù)項,用來指定 webpack 的運行模式,我們在上面已經(jīng)介紹過了~然后通過指令 npm run build,我們就可以在項目的根路徑下看到我們熟悉的 dist 目錄了
但是如果沒有指定的規(guī)則配置,默認會將打包后的文件都放到 dist 目錄下,但是如果我們想要將 js 文件 放到 js目錄下,image 文件放到 image 目錄下 我們就需要在 webpack.config.js 進行相應的配置
前面我們 js 文件的生成目錄已經(jīng)通過 output 節(jié)點 進行配置了
那么我們還需要配置其他文件的輸出目錄,這里以圖片類型的文件為例:
我們同樣是在 webpack.config.js 文件中配置,不過此時是在 rules 節(jié)點 中進行配置:
進行到這步我們已經(jīng)差不多完成了打包任務,但是我們?nèi)绻牧?js 生成目錄,這個時候會發(fā)生什么呢?
我們發(fā)現(xiàn)會生成冗余的文件,并沒有把舊文件刪除,這難道每次打包都要進行手動刪除嗎?當然不是!為了在每次打包發(fā)布時 自動清理掉 dist 目錄中的舊文件,可以安裝并配置 clean-webpack-plugin 插件
安裝
npm install clean-webpack-plugin@3.0.0 -D
配置
運行
六、Source Map
這種 Source Map 就有點意思了,我們后端上線后,如果出現(xiàn)問題,我們通常會進入到服務器中查看報錯日志。那么前端如果出現(xiàn)問題就很方便了,我們可以直接通過 F12 打開控制臺查看報錯日志,而且也可以對 js 文件進行 debug。但是我們上面說過通過 mode 指定 production 值后會對代碼進行壓縮,那么調(diào)試是一件即為困難的事情。
Source Map 就是用來解決這種問題的。
1)概念
Source Map 是一個信息文件,里面存儲著位置信息,也就是 轉(zhuǎn)換后 -> 轉(zhuǎn)換前 的位置映射。在它的幫助下,出錯的時候,可以直接顯示原始代碼,而不是轉(zhuǎn)換后的壓縮代碼,可以在一定程度上提高排錯效率。
2)使用
正常在開發(fā)環(huán)境下,webpack 是默認開啟了 Source Map 功能,當程序運行出錯的時候,可以直接在控制臺提示錯誤位置的信息
但是這種提示是不友好的,它記錄的是壓縮后代碼的位置,這樣導致的問題就是實際運行報錯的行數(shù) 與 源代碼的行數(shù) 不匹配,這將成為我們排錯路上的 絆腳石 ~!
既然如此,那我們就帶著問題解決問題!
3)所遇問題
① 問題 1:實際運行報錯的行數(shù) 與 源代碼的行數(shù) 不匹配
那么要解決這個問題也很簡單,就需要在 webpack.config.js 中添加以下配置:
配置完查看結(jié)果,至此我們可以發(fā)現(xiàn) 運行報錯的行數(shù) 與 源代碼的行數(shù) 是相匹配的!
② 問題 2:生產(chǎn)環(huán)境中容易暴露源碼
以上我們雖然已經(jīng)可以定位到源碼的錯誤,但是如果在生產(chǎn)環(huán)境中,暴露源碼終歸不是一件好事,因此我們同樣要解決該問題。
解決該問題的方式也很暴力,直接打包的時候在webpack.config.js文件中將mode 指定為 production,這樣不會顯示報錯行數(shù),也不會顯示源碼內(nèi)容
- mode: "production"
③ 問題 3:生產(chǎn)環(huán)境需顯示行數(shù)隱藏源碼
上面那種方式過于暴力,行數(shù)和源碼一股腦都不給你顯示了。那有沒有比較這種的方式,可以顯示行數(shù)但不顯示源碼?答案肯定是有的!我們只需將 devtool 的值配置為 nosources-source-map 即可
- devtool: 'nosources-source-map'
配置完畢我們看效果:
該方式既可以顯示報錯行數(shù)也可以隱藏源碼,是一種十分合適解決方案。
因此我們做個總結(jié)
4)總結(jié)
- 開發(fā)環(huán)境
將 devtool 的值設置為 eval-source-map ,有利于精準定位到具體的錯誤行
- 生產(chǎn)環(huán)境
關(guān)閉 Source Map 或?qū)?devtool 的值設置為 nosource-source-map ,有利于防止源碼泄漏,提高安全性