聲明:所有的文章demo都在我的倉庫里
代碼分離
代碼分離的有點在於:
- 切割代碼,生成不同的打包文件,按需加載這些文件。
- 每個bundle的體積更小
- 控制外部資源的加載順序
常用的方法有:
- 入口起點:使用入口
entry手動分離 - 防止重復:使用
SplitChunksPlugin去重和分離chunk - 動態導入:通過模塊的內聯函數調用分離的代碼
入口起點
新增另一個文件another-module.js文件,並在webpack.config.js中進行配置。
entry:{//打包入口
index:'./src/index.js',
another:'./src/another-module.js'
},
進行打包后,結果正常。
優點:常用常規的寫法。
缺點:1.如果有相同的模塊,不會去重,還是會在每個bundle中被重復的引用。2.不能將核心代碼進行分割
防止重復
入口依賴
配置dependOn選項,可以在多個chunk之間進行共享模塊。
SplitChunkPlugin
為了解決多個bundle引入相同模塊的問題,引入這個模塊進行去重。
SplitChunkPlugin將公共的模塊引入到已有的入口中,或者提取到新的chunk。
相關配置如下:
//webpack.config.js
optimization:{
splitChunks:{
chunks:'all'
}
},
SplitChunkPlugin創建了新的chunk,如下圖所示,shared.bundle.js。將我其他頁面所使用的js引入的lodash模塊引入這個文件中。

*** 以上代碼在webpack-demo5中
緩存
通常部署文件是將webpack打包出來的/dist文件,部署到server上,客戶端通過訪問server的網站及資源。
由於客戶端訪問server時,非常耗時和耗流量,於是瀏覽器采用緩存技術,可以直接從緩存中獲取相關的內容,降低了請求的速度和流量。但是這也有一個缺點:如果文件名跟之前的一致,瀏覽器會認為這個文件沒有做修改,還是會從緩存中獲取相關內容。
我們想要的現象是:文件沒做修改時,瀏覽器從緩存中獲取,文件修改了,重新獲取。
輸出文件的文件名
webpack提供了一個substitution(可替換的模版字符串)的方式,通過帶括號字符串來模版化文件名。其中的[contenthash]是根據資源內容創建唯一的hash。當資源內容變化時,[contenthash]也會發生變化。
相關配置如下:
entry:'./src/index.js',
output:{//打包出口
filename:"[name].[contenthash].js",//打包后的文件名稱
path:path.resolve(__dirname,'dist')//路徑
},
使用contenthash,將內容變化直接反應打包輸出文件的變化。

文件不做修改,再次運行npm run build時,文檔描述如下:

在我的實際操作中,我的打包文件是不變的。
第一次:

第二次:

可能跟webpack版本的關系所致。。。
模塊的概念
runtime:每個模塊的加載和模塊的解析邏輯。
manifest:解析和映射模塊之間的聯系
提取引導模版
將runtime代碼,提取到一個單獨的chunk中。optimization.runtimeChunk:'single'表示為所有的chunk創建一個runtime bundle。
代碼如下:
optimization:{
runtimeChunk:'single'
},

將所有的第三方庫,如lodash/react等提取到單獨的vendor chunk文件中。由於這些第三方庫不會去頻繁的修改源代碼,所以可以讓更少的向server發請求。
配置如下:
const path=require('path');
const {CleanWebpackPlugin}=require('clean-webpack-plugin')
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
mode:'development',
entry:'./src/index.js',
output:{//打包出口
filename:"[name].[contenthash].js",//打包后的文件名稱
path:path.resolve(__dirname,'dist')//路徑
},
devtool: 'inline-source-map',
devServer:{
contentBase:'./dist'
},
optimization:{
runtimeChunk:'single',
splitChunks:{
cacheGroups:{
vendor:{
test:/[\\/]node_modules[\\/]/,
name:'vendor',
chunks:'all'
}
}
}
},
plugins:[
new CleanWebpackPlugin({
cleanStaleWebpackAssets:false
}),
new HtmlWebpackPlugin({
title:'管理輸出'
})
]
}
結果會出現一個帶有vendor的文件。

在main文件里,不再含有來自node_module的vendor代碼,而且體積也減少了。
模塊標識符
新增print模塊,並在index中進行引入,最終打包的結果跟之前比較結果如下:
我本地打包只有main的文件進行了變化----符合預期
然而官網上展示的例子是不一樣,引出了需要引入optimization.moduleIds:'hashed'---苦笑不得
*** 以上代碼在webpack-demo6中
環境變量
可以在package.json中配置相關的命令行,可以快速的執行開發環境和生產環境。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --env development"
},
表示執行development環境。
模塊熱替換(HMR)
模塊熱替換(HMR--hot module replacement):在程序運行過程中,若有替換/添加/刪除模塊,只更新修改的部分,不需要更新整個頁面。
此功能暫不支持生產環境。
代碼配置如下:
devServer:{
contentBase:'./dist',
hot:true
},
在index頁面加入代碼
if(module.hot){
module.hot.accept('./print.js',function(){
console.log('update the module1');
Print()
})
}
注意:執行時使用npm run start,啟動服務,可查看熱更替。

*** 以上代碼在webpack-demo7中
模塊熱更替跟熱更新是兩回事。模塊熱更新是指修改了某個部分代碼,不會刷新頁面,而是在頁面更新這個模塊。熱更新是指及時刷新頁面。
Tree shaking
概念
是指在打包的時候,剔除沒有用到的代碼。
但是只支持ES module的import和export用法。
實踐
打包過程分成3部分:
import會被打包成/* harmony import */做前綴,表明這段是import進來的export會被打包成/* harmony export */做前綴,表明這段是export的- 純函數,會被打包成
/*#__PURE__*/,表明這個函數是純函數,可以被tree shaking掉
代碼如下:
package.json
"name": "webpack-demo8",
"sideEffects":false,
webpack.config.js
optimization:{
usedExports:true
}
*** 以上代碼在webpack-demo8中
我的倉庫地址,github,歡迎star~~
(完)
