引子
昨天有關 Webpack 筆記也是有許多人喜愛的,所以今天再接再厲彙總了第二篇筆記,歡迎各位指點不足之處。
之後的筆記應該會記錄一些實際開發了,希望在這個週末內徹底入門 Webapck。
- webpack (1)——核心概念的理解
- webpack(2)——配置項詳解
- …
1. mode
mode 配置項是 webpack4 新增的配置項,這個配置項是必須的。
如果使用的不是 webpack4 ,該配置項瞭解一下即可,使用了 webpack4 以上版本,也可以瞭解一下即可。
事實上它並非必須的,但是如果忽略它, webpack 會有個警告。
該配置項的屬性值型別是
String,並有三個可選項:
- production
- development
- none
1.1 production 預設值
production 預設值會給你提供一系列有效的預設值以便部署你的應用,它注重:
- 小的輸出體積
- 執行快速的程式碼
- 忽略僅在開發時需要的程式碼
- 不暴露原始碼和檔案路徑
- 易於使用的輸出產物
1.2 development 預設值
該預設顧名思義是注重最好的開發體驗,它注重:
- 瀏覽器除錯工具
- 快速開發週期中的快速增量編譯
- 在執行過程中提供有效的錯誤資訊
當人對於初學者來說,對於 webpack 的優化還有一段距離,首先我們大體瞭解一下即可。
它還有很多其他的優化預設值,但是效果可能並不美好,因為它針對的某些特定的大型專案,而我們只是入門,所以瞭解即可。
2. Module
module 中配置處理模組的規則。
2.1 配置 Loader
rules 配置模組的讀取和解析規則,通常用來配置 Loader。其型別是一個陣列,陣列裡每一項都描述瞭如何去處理部分檔案。配置一項 rules 時大致可通過以下方式來實現:
- 條件匹配:通過 test 、 include 、 exclude 三個配置項來命中 Loader 要應用規則的檔案。
- 應用規則:對選中後的檔案通過 use 配置項來應用 Loader,可以只應用一個 Loader 或者按照從後往前的順序應用一組 Loader,同時還可以分別給 Loader 傳入引數。
- 重置順序:一組 Loader 的執行順序預設是 從右到左 執行,通過 enforce 選項可以讓其中一個 Loader 的執行順序放到最前或者最後。
module: {
rules: [
{
// 命中 JavaScript 檔案
test: /.js$/,
// 用 babel-loader 轉換 JavaScript 檔案
// ?cacheDirectory 表示傳給 babel-loader 的引數,用於快取 babel 編譯結果加快重新編譯速度
use: [`babel-loader?cacheDirectory`],
// 只命中src目錄裡的js檔案,加快 Webpack 搜尋速度
include: path.resolve(__dirname, `src`)
},
{
// 命中 SCSS 檔案
test: /.scss$/,
// 使用一組 Loader 去處理 SCSS 檔案。
// 處理順序為從後到前,即先交給 sass-loader 處理,再把結果交給 css-loader 最後再給 style-loader。
use: [`style-loader`, `css-loader`, `sass-loader`],
// 排除 node_modules 目錄下的檔案
exclude: path.resolve(__dirname, `node_modules`),
},
{
// 對非文字檔案採用 file-loader 載入
test: /.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use: [`file-loader`],
},
]
}
複製程式碼
上面的例子基本將配置 loader 的大部分配置項都涵蓋了,非常清晰簡潔。
// 使用一組 Loader 去處理 SCSS 檔案。
// 處理順序為從後到前,即先交給 sass-loader 處理,再把結果交給 css-loader 最後再給 style-loader。
use: [`style-loader`, `css-loader`, `sass-loader`]
複製程式碼
在上面的例子中,對於多 Loader 處理方式中,採用的是陣列,執行數序為從左到右
除此之外,我們還可以通過一個 Object 方式來寫這一塊的程式碼
use: [
{
loader:`babel-loader`,
options:{
cacheDirectory:true,
},
// enforce:`post` 的含義是把該 Loader 的執行順序放到最後
// enforce 的值還可以是 pre,代表把 Loader 的執行順序放到最前面
enforce:`post`
},
// 省略其它 Loader
]
複製程式碼
對於 Loader 的最後一點補充就是關於命中檔案的三個配置項:text、 include、 exclude。
在上述例子中,這三兄弟的配置只傳入了一個字串或者是正則,其實他們還都可以支援陣列,陣列之間的關係為 “或”的關係,即檔案滿足陣列中的任何一個條件,都會被命中。
2.2 noParse
noParse 配置項可以讓 Webpack 忽略對部分沒采用模組化的檔案的遞迴解析和處理,這樣做的好處是能提高構建效能。 原因是一些庫例如 jQuery 、ChartJS 它們龐大又沒有采用模組化標準,讓 Webpack 去解析這些檔案耗時又沒有意義。
noParse 是可選配置項,型別需要是 RegExp、[RegExp]、function 其中一個。
// 使用正規表示式
noParse: /jquery|chartjs/
// 使用函式,從 Webpack 3.0.0 開始支援
noParse: (content)=> {
// content 代表一個模組的檔案路徑
// 返回 true or false
return /jquery|chartjs/.test(content);
}
複製程式碼
注意被忽略掉的檔案裡不應該包含 import 、 require 、 define 等模組化語句,不然會導致構建出的程式碼中包含無法在瀏覽器環境下執行的模組化語句。
2.3 parse
因為 Webpack 是以模組化的 JavaScript 檔案為入口,所以內建了對模組化 JavaScript 的解析功能,支援 AMD、CommonJS、SystemJS、ES6。 parser 屬性可以更細粒度的配置哪些模組語法要解析哪些不解析,和 noParse 配置項的區別在於 parser 可以精確到語法層面, 而 noParse 只能控制哪些檔案不被解析。 parser 使用如下:
module: {
rules: [
{
test: /.js$/,
use: [`babel-loader`],
parser: {
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES6 import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用 browserify
requireJs: false, // 禁用 requirejs
}
},
]
}
複製程式碼
3. Resolve
該配置項主要是配置 Webapck 如何尋找模組所對應的檔案。
Webpack 內建 JavaScript 模組化語法解析功能,預設會採用模組化標準里約定好的規則去尋找,但你也可以根據自己的需要修改預設的規則。
該配置項的屬性蠻多的,但是我覺得我能用得到的也就幾個=。=
3.1 alias
resolve.alias 配置項通過別名來把原匯入路徑對映成一個新的匯入路徑。例如使用以下配置:
// Webpack alias 配置
resolve:{
alias:{
components: `./src/components/`
}
}
複製程式碼
當你通過 import Button from `components/button` 匯入時,實際上被 alias 等價替換成了 import Button from `./src/components/button`。
以上 alias 配置的含義是把匯入語句裡的 components 關鍵字替換成 ./src/components/。
這樣做可能會命中太多的匯入語句,alias 還支援 $ 符號來縮小範圍到只命中以關鍵字結尾的匯入語句:
resolve:{
alias:{
`react$`: `/path/to/react.min.js`
}
}
複製程式碼
react$ 只會命中以 react 結尾的匯入語句,即只會把 import `react` 關鍵字替換成 import `/path/to/react.min.js`。
該方法的應用場景有待我去探索,真不太清楚這樣替換的原因。
但是我覺得是蠻有用的。
3.2 extensions
在匯入語句沒帶檔案字尾時,Webpack 會自動帶上字尾後去嘗試訪問檔案是否存在。 resolve.extensions 用於配置在嘗試過程中用到的字尾列表,預設是:
extensions: [`.js`, `.json`]
這個配置項應該有用,在處理 TypeScript、vue 這些檔案的時候,可以設定一下
3.3 enforceExtension
resolve.enforceExtension 如果配置為 true 所有匯入語句都必須要帶檔案字尾, 例如開啟前 import `./foo` 能正常工作,開啟後就必須寫成* import `./foo.js`。*
對於 Resolve 的其他配置項,大體瞭解一下即可,我覺得可能用的不是特別多。
3.4 Plugins
對於 Plugins 的使用,上一節也寫到過,還是那句話吧:
使用 Plugin 的難點在於掌握 Plugin 本身提供的配置項,而不是如何在 Webpack 中接入 Plugin。
4. DevServer
使用 DevServer 能幹啥?
- 提供 HTTP 服務來預覽本地檔案;
- 監聽檔案的變化並自動重新整理頁面;
- 支援 Source Map,以方便除錯。
DevServer 會啟動一個 HTTP 伺服器 用於服務網頁請求,同時會幫助啟動 Webpack,並接收 Webpack 發出的檔案更新訊號,通過 webSocket 協議自動重新整理網頁做到實時預覽。
4.1 開啟一個DevServer 服務
整合 DevServer ,首先需要安裝一下:
npm i -D webpack-dev-server
複製程式碼
如果不是通過 npm run 啟動,直接將 webpack-dev-server 安裝到全域性,直接使用,會報:
webpack-dev-server: command not found
安裝成功後,執行 webpack-dev-server 命令,接著一連串日誌輸出:
i 「wds」: Project is running at http://localhost:8080/
i 「wds」: webpack output is served from /
i 「wdm」: Hash: 5cece8a0d7243a4cf1ba
Version: webpack 4.8.3
Time: 1627ms
Built at: 2018-05-18 14:18:57
......
複製程式碼
4.2 ./dist/bundle.js 載入 404 問題
用瀏覽器直接開啟這個地址你會發現頁面空白,錯誤原因是 ./dist/bundle.js 載入404了。 同時你會發現並沒有檔案輸出到 dist 目錄,原因是 DevServer 會把 Webpack 構建出的檔案儲存在記憶體中,在要訪問輸出的檔案時,必須通過 HTTP 服務訪問。 由於 DevServer 不會理會 webpack.config.js 裡配置的 output.path 屬性,所以要獲取 bundle.js 的正確 URL 是 http://localhost:8080/bundle.js
4.3 實時預覽
webpack –watch 會開啟監聽模式,而 webpack 啟動預設是關閉的,開啟 DevServer 預設開啟監聽模式,所以修改需要被打包的檔案瀏覽器會被自動重新整理,這裡主要應用到了 Websocket ,有需要的童鞋可以去了解一下。
4.4 修改index.html並不會被重新整理的原因
如果嘗試修改 index.html 檔案並儲存,你會發現這並不會觸發以上機制,導致這個問題的原因是 Webpack 在啟動時會以配置裡的 entry 為入口去遞迴解析出 entry 所依賴的檔案,只有 entry 本身和依賴的檔案才會被 Webpack 新增到監聽列表裡。 而 index.html 檔案是脫離了 JavaScript 模組化系統的,所以 Webpack 不知道它的存在。
可以嘗試用 raw-loader 來處理一下 html
4.5 熱更新 –hot
當然上述實現頁面更改都是基於頁面重新整理實現的,DevServer 還有一種被稱作模組熱替換的重新整理技術——熱更新。
DevServer 預設是關閉熱更新的,可以通過
webpack-dev-server --hot
複製程式碼
來開啟
4.6 Source Map
webpack-dev-server --devtool source-map
複製程式碼
這個功能就不多說了。
4.7 devserver 配置項
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
hot: true,
open: `http://127.0.0.1:9000`,
// inline: true,
// contentBase: path.join(__dirname, "dist"),
compress: true,
port: 9000
}
複製程式碼
devServer 的配置項也是蠻多的,看了好久,發現有用的也就是這幾個吧:
- hot: 開啟熱更新;
- open:自動開啟要開發的網頁;
- inline:實時預覽功能,即頁面重新整理,用熱更新替代即可,沒必要管他;
- compress: 開啟 Gzip 壓縮;
- port:伺服器監聽的埠號,指定即可,如果不指定,預設是 8080 ,衝突了會自動順位 8081、8082,挺讚的。
該配置項還有很多其他的屬性,我覺得目前我是用不上,但不妨礙我們瞭解一下,在此我就不一一記錄了。
寫在最後
webpack 的基本操作到目前為止基本結束,他能完成的功能還是有很多的,從它的 N 多配置項就能看出來,但我們不需要全部記住,記住之前的核心概念和它的基本原理就可以,之後再根據自己的經驗去判斷它屬於哪一塊再去查文件就沒問題。
- 讓原始檔加入到構建流程中去被 Webpack 控制,配置 entry。
- 自定義輸出檔案的位置和名稱,配置 output。
- 自定義尋找依賴模組時的策略,配置 resolve。
- 自定義解析和轉換檔案的策略,配置 module,通常是配置 module.rules 裡的 Loader。
- 其它的大部分需求可能要通過 Plugin 去實現,配置 plugin。
參考
webpack4:模式與優化
深入淺出 Webpack
webpack 配置項
[HMR] Hot Module Replacement is disabled
Gzip