webpack从入门到精通(四)优化打包配置总结①
1.?HMR
HMR 即模塊熱替換(hot module replacement)的簡稱,當(dāng)你對代碼進(jìn)行修改并保存后,webpack 將對代碼重新打包,并將新的模塊發(fā)送到瀏覽器端,瀏覽器通過新的模塊替換老的模塊,這樣在不刷新瀏覽器的前提下就能夠?qū)?yīng)用進(jìn)行更新。
一個模塊發(fā)生變化,只會重新打包這一個模塊(而不是打包所有模塊), 極大的提升構(gòu)建速度。
1)配置修改
基本代碼結(jié)構(gòu)為之前博客里使用的webpack開發(fā)環(huán)境devServer。
使用webpack-dev-server,設(shè)置 hot 屬性為 true。
?devServer: {contentBase: resolve(__dirname, 'build'),compress: true,port: 3000,open: true,// // 開啟HMR功能// // 當(dāng)修改了webpack配置,新配置要想生效,必須重新webpack服務(wù)hot: true}2)運行指令:npx webpack-dev-server
3)樣式文件的修改
css、less可以使用HMR功能:因為style-loader內(nèi)部實現(xiàn)了。
我們修改我們的開發(fā)環(huán)境css代碼,可以發(fā)現(xiàn)頁面樣式改變了,控制臺打印如下:
4)js文件的修改
我們的js代碼如下:
index.js
// 引入 import print from './print'; import '../css/iconfont.css'; import '../css/index.less'; ? console.log('index.js文件被加載了~'); ? print(); ? function add(x, y) {return x + y; } ? console.log(add(1, 3));print.js
console.log('print.js被加載了~'); ? function print() {const content = 'hello webpack';console.log(content); } ? export default print;我們修改了print.js的代碼后,控制臺輸出如下:
可以發(fā)現(xiàn),我們雖然只修改了print.js,但是index.js也同時被加載了。
js默認(rèn)不能使用HMR功能 --> 需要修改js代碼,添加支持HMR功能的代碼
我們可以對js代碼進(jìn)行處理:
index.js
if (module.hot) {// 一旦 module.hot 為true,說明開啟了HMR功能。 --> 讓HMR功能代碼生效module.hot.accept('./print.js', function() {// 方法會監(jiān)聽 print.js 文件的變化,一旦發(fā)生變化,其他模塊不會重新打包構(gòu)建。// 會執(zhí)行后面的回調(diào)函數(shù)print();}); }這次修改print.js后,控制臺輸入如下:
2. source-map
我們在打包中,將開發(fā)環(huán)境中源代碼經(jīng)過壓縮,去空格,babel編譯轉(zhuǎn)化,最終可以得到適用于生產(chǎn)環(huán)境的項目代碼,這樣處理后的項目代碼和源代碼之間差異性很大,會造成無法debug的問題。
舉例來說,如果壓縮等處理過的生產(chǎn)環(huán)境中的代碼出現(xiàn)bug,調(diào)試的時候只能定位到壓縮處理后的代碼的位置,無法定位到開發(fā)環(huán)境中的源代碼。
sourcemap就是為了解決上述代碼定位的問題,簡單理解,就是構(gòu)建了處理前的代碼和處理后的代碼之間的橋梁。主要是方便開發(fā)人員的錯誤定位。這里的處理操作包括:
I)壓縮,減小體積
II)將多個文件合并成同一個文件
III)其他語言編譯成javascript,比如TypeScript和CoffeeScript等
webpack在打包中同樣支持Sourcemap,并且提供了十幾種的組合。
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map我們只需要在配置文件中增加配置即可:
devtool: 'eval-source-map'devtool屬性可以接受以下值:
不同的值會明顯影響到構(gòu)建(build)和重新構(gòu)建(rebuild)的速度。
其中一些值適用于開發(fā)環(huán)境,一些適用于生產(chǎn)環(huán)境。對于開發(fā)環(huán)境,通常希望更快速的source map,需要添加到bundle中以增加體積為代價;但是對于生產(chǎn)環(huán)境,則希望更精準(zhǔn)的source map,需要從bundle中分離并獨立存在。
? 下面是選擇哪個值的思路:開發(fā)環(huán)境:速度快,調(diào)試更友好速度快(eval>inline>cheap>...)eval-cheap-souce-mapeval-source-map調(diào)試更友好souce-mapcheap-module-souce-mapcheap-souce-map ?--> eval-source-map / eval-cheap-module-souce-map ?生產(chǎn)環(huán)境:源代碼要不要隱藏? 調(diào)試要不要更友好內(nèi)聯(lián)會讓代碼體積變大,所以在生產(chǎn)環(huán)境不用內(nèi)聯(lián)nosources-source-map 全部隱藏hidden-source-map 只隱藏源代碼,會提示構(gòu)建后代碼錯誤信息--> source-map / cheap-module-souce-map3. oneOf
webpack原本的loader是將每個文件都過一遍,比如有一個js文件,rules中有10個loader,第一個是處理js文件的loader,當(dāng)?shù)谝粋€loader處理完成后webpack不會自動跳出,而是會繼續(xù)拿著這個js文件去嘗試匹配剩下的9個loader,相當(dāng)于沒有break。而oneOf就相當(dāng)于這個break。
用法:
rules:[oneOf:[{test:/\.css$/,use:[...common_css_loader]},{test:/\.less$/,use:[...common_css_loader,'less-loader']},{test:/\.html/,loader:'html-loader'}] ] ?4.?babel緩存
babel-loader在執(zhí)行的時候,可能會產(chǎn)生一些運行期間重復(fù)的公共文件,造成代碼體積大而冗余,同時也會降低編譯效率。可以加上cacheDirectory參數(shù)開啟babel緩存。
? ? ? ? {test: /\.js$/,loader: 'babel-loader',options: {// 開啟babel緩存// 第二次構(gòu)建時,會讀取之前的緩存cacheDirectory: true}}5. 靜態(tài)資源緩存
靜態(tài)資源緩存是前端性能優(yōu)化的一個點,所以在前端開發(fā)過程中,一般會最大限度的利用緩存(這里主要是強緩存)。回到本文主題,在使用webpack構(gòu)建的項目中,稍有不慎的話,即使服務(wù)器設(shè)置了緩存策略,可能構(gòu)建的項目無法實現(xiàn)靜態(tài)資源緩存。那么webpack怎樣才能達(dá)到使用緩存的效果呢,下面就來談?wù)勥@個問題。
我們都知道,webpack有各種hash值,包括每次項目構(gòu)建hash,不同入口的chunkhash、文件的內(nèi)容contenthash,這么多hash,它們有什么區(qū)別呢?
-
hash
hash是跟整個webpack構(gòu)建項目相關(guān)的,每次項目構(gòu)建hash對應(yīng)的值都是不同的,即使項目文件沒有做“任何修改”。
其實是有修改的,因為每次webpack打包編譯都會注入webpack的運行時代碼,導(dǎo)致整個項目有變化,所以每次hash值都會變化的。由此推斷使用該方式是無法達(dá)到緩存的。
-
chunkhash
chunkhash,從字面上就能猜出它是跟webpack打包的chunk相關(guān)的。具體來說webpack是根據(jù)入口entry配置文件來分析其依賴項并由此來構(gòu)建該entry的chunk,并生成對應(yīng)的hash值。不同的chunk會有不同的hash值。一般在項目中把公共的依賴庫和程序入口文件隔離并進(jìn)行單獨打包構(gòu)建,用chunkhash來生成hash值,只要依賴公共庫不變,那么其對應(yīng)的chunkhash就不會變,從而達(dá)到緩存的目的。
一般在項目中對webpack的entry使用chunkhash,具體表現(xiàn)在output配置項上:
moudule.exports = {entry: {app: './src/main.js',vendor: ['react', 'redux', 'react-dom', 'react-redux', 'react-router-redux']},output: {path:path.join(__dirname, '/dist/js'),filename: '[name].[chunkhash].js'}... }-
contenthash
contenthash表示由文件內(nèi)容產(chǎn)生的hash值,內(nèi)容不同產(chǎn)生的contenthash值也不一樣。在項目中,通常做法是把項目中css都抽離出對應(yīng)的css文件來加以引用。比方在webpack配置這樣來用:
?plugins: [new MiniCssExtractPlugin({filename: 'css/built.[chunkhash:10].css'})]上面配置有一個問題,因為使用了chunkhash,它與依賴它的chunk共用chunkhash。
比方在上面app chunk例子中依賴一個index.css文件,index.css的hash是跟著app的chunkhash走的,只要app文件變更的話,那么即使index.css文件沒有變化,它的hash值也是會跟著變化的,導(dǎo)致緩存失效。
那么這時我們可以使用extra-text-webpack-plugin里的contenthash值,保證即使css文件所處的模塊里就算其他文件內(nèi)容改變,只要css文件內(nèi)容不變,它的hash值就不會變。
?plugins: [new MiniCssExtractPlugin({filename: 'css/built.[contenthash:10].css'})]?
總結(jié)
以上是生活随笔為你收集整理的webpack从入门到精通(四)优化打包配置总结①的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Promise和Async-Await的
- 下一篇: webpack从入门到精通(四)优化打包