《webpack實戰(zhàn)-入門、進(jìn)階和調(diào)優(yōu)》讀后總結(jié)
webpack打包原理
(function(modules) {
// 模塊緩存
var installedModules = {};
// 實現(xiàn)require
function __webpack_require__(moduleId) {
...
}
// 執(zhí)行入口模塊的加載
return __webpack_require__(__webpack_require__.s = 0);
})({
// modules: 以key-value的形式儲存所有被打包的模塊
0: function(module, exports, __webpack_require__) {
// 打包入口
module.exports = __webpack_require__("3qiv")
},
"3qiv": function(module, exports, __webpack_require__) {
// index.js 內(nèi)容
}
})
- 最外層立即執(zhí)行匿名函數(shù)。包裹bundle,構(gòu)成自身作用域
-
installedModules對象。每個模塊只在第一次被加載的時候執(zhí)行,導(dǎo)出值存儲到這個對象里面,當(dāng)再次被加載的時候就從中取值,不會重新執(zhí)行。 -
__webpack_require__函數(shù)。對模塊加載的實現(xiàn)。 -
modules對象。工程中所有產(chǎn)生了依賴關(guān)系的模塊都會以key-value形式放在這里。 - bundle運(yùn)行時,先加載入口模塊,再依次執(zhí)行模塊代碼,解析模塊依賴。
entry
webpack通過context和entry兩個配置項共同決定入口文件路徑。
enrty的配置支持字符串、數(shù)組、對象、函數(shù)形式。
- 數(shù)組類型入口:將多個資源預(yù)先合并,數(shù)組的最后一個元素是實際的入口路徑。
- 對象類型入口:key是chunk name,value是入口路徑。
- 函數(shù)類型入口:支持返回Promise對象來進(jìn)行異步操作
此處可以應(yīng)用優(yōu)化
optimization.splitChunks,提取公共模塊??梢岳每蛻舳司彺?,加快頁面渲染速度。
output
- filename
輸出資源文件名,支持相對路徑,支持模板語法動態(tài)生成文件名。
| 變量名稱 | 描述 |
|---|---|
| [name] | 指代chunk name |
| [hash] | 指代webpack此次打包所有資源生成的hash |
| [chunkhash] | 指代當(dāng)前chunk內(nèi)容的hash |
| [id] | 指代當(dāng)前chunk的id |
| [query] | 指代filename配置項中的query |
- path
指定資源輸出的位置,必須為絕對路徑。 - publicPath
指代資源的請求位置,請求url相對路徑的前綴。
loader
webpack一切皆模塊,loader幫助webpack識別js、json之外的文件,從而維護(hù)模塊之間的關(guān)系。
output = loader(input)
loader 配置
- 引入loader
module.exports = {
// ...
module: {
rules: [{
test: /\.css$/,
use: ['css-loader'],
}]
}
}
test 接受正則表達(dá)式/正則表達(dá)式數(shù)組,只有匹配的模塊才使用該規(guī)則;
use 接受一個數(shù)組,將從后向前的調(diào)用數(shù)組中定義的loader。
- exclude/include
exclude優(yōu)先級高于include
此處配置
exclude: /node_modules/可以提高不必要的loader執(zhí)行,提高編譯效率
- enforce
接受prepost兩種字符串類型值,強(qiáng)制指定loader的執(zhí)行順序
自定義loader
- 啟用緩存:使用
this.cacheable控制 - 獲取options:引入
const loaderUtils = require("loader-utils");,通過loaderUtils.getOptions(this)獲取配置對象
代碼分片
代碼分片和公共模塊提取
通過入口劃分代碼,適合于接口綁定在全局對象上的庫,和多頁面應(yīng)用。
SplitChunksPlugin
將多個chunk中公共的部分提取出來
資源異步加載
模塊數(shù)量過多,資源體積過大時,可以吧一些暫時使用不到的模塊延遲加載。
原理:import().then() require.ensure
配置:使用特有注釋對chunk命名
import(/* webpackChunkName: "bar" */ './bar.js').then(({add}) => {
// ...
})
生產(chǎn)環(huán)境配置
開啟production模式、環(huán)境變量配置
module.exports = {
mode: 'production',
plugins: [
new webpack.DefinePlugin({
ENV: 'production'
})
]
}
source map
source map指的是將編譯、打包、壓縮后的代碼映射回源代碼的過程。幫助追查線上問題。
devtool: 'source-map'
安全問題
source map會暴露源碼,但是沒有map文件無法調(diào)試代碼,解決方案如下:
hidden-source-map: 編譯產(chǎn)出完整map文件,但是不會引用。利用第三方工具(Sentry),手動上傳map文件;
nisources-source-map:隱藏文件具體內(nèi)容,但是可以查看錯誤棧和日志的準(zhǔn)確行數(shù);
nginx對白名單開放.map文件訪問權(quán)限。
資源壓縮
配置項: config.optimization.minimize,開啟了mode: production 后不需要人為設(shè)置。
自定義壓縮插件 terser-webpack-plugin
module.exports = {
optimization: {
// 覆蓋默認(rèn)的 minimizer
minimizer: [
new TerserPlugin({
test: /\.js(\?.*)?$/i, // 作用范圍
exclude: /\/exculdes/,
cache: true, // 是否開啟緩存,傳入字符串可以指定緩存目錄
parallel: 2, // 允許多進(jìn)程壓縮
sourceMap: true // 生成 source map,需要同事配置 devtool
})
]
}
}
緩存
output.filename: 'bundle@[chunkhash].js'
通常使用chunkhash作為文件版本號,使用 html-webpack-plugin 輸出動態(tài)HTML,自動更新最新的資源名到html中。
打包優(yōu)化
縮小打包作用域
動態(tài)鏈接庫和 DllPlugin
DllPlugin和Code Splitting有點類似,都可以用來提取公共模塊。Code Splitting思路是設(shè)置一些特定的規(guī)則并在打包過程中根據(jù)這些規(guī)則提取模塊,Dlllpugin則是將vendor完全拆出,獨立打包,實際工程構(gòu)建是就不用對它再做處理,直接取用。