webpack 配置哪些優化?
module.exports = { //... module: { noParse: /jquery|lodash/, //不去解析jquery | lodash 中的依賴庫 } }; 複製程式碼
如果js中引入jquery, webpack會去解析jq中是否有依賴庫,配置noParse
後打包時候忽略解析配置的庫,提高打包效率。
2.解析時指定和排除查詢目錄
module:{ rules:[ { test:/\.js$/, exclude:/node_modules/, // 解析不包含的目錄,兩者寫其一即可 include:path.resolve('src'), // 即系包含的目錄,兩者寫其一即可 use:{ loader:'babel-loader', options:{ presets:[ '@babel/preset-env', '@babel/preset-react' ... 複製程式碼
exclude
排除目錄不進行解析。
3.指定目錄不打包
IgnorePlugin
是webpack
內建外掛,可以忽略第三方包不進行打包
舉例:
moment包
比如引入第三方依賴庫moment
, 該庫主要是對時間進行格式化,並且支援多個國家語言。
moment打包問題
import moment from 'moment' //設定語言 moment.locale('zh-cn'); let r = moment().endOf('day').fromNow(); console.log(r); 複製程式碼
雖然只設置了一種語言,但是在打包的時候,moment
會將所有語言引入。這樣就導致包很大,打包速度又慢 。
我們需要把其他不需要的與語言包剔除
而moment
的包含./locale/
該欄位路徑的檔案目錄就是各國語言的目錄,比如./locale/zh-cn
就是中文語言
IgnorePlugin使用
let Webpack = require('webpack'); plugins:[ new Webpack.IgnorePlugin(/\.\/locale/,/moment/) ] 複製程式碼
如果在moment
中引入了./locale
目錄的內容,會忽略掉
傳遞給IgnorePlugin
的第一個引數resourceRegExp
引數並不針對匯入或必需的已解析檔名或絕對模組名進行測試,而是針對在匯入發生的原始碼中傳遞給require或import的字串進行測試。例如,如果您試圖排除node_modules/moment/locale/*.js
,這是行不通的
使用第二個contextRegExp
引數選擇匯入發生的特定目錄。下面的程式碼將導致這些locale檔案被忽略
問題存在與解決
如果上述方法忽略了./locale/
的目錄,那麼所有語音都會被忽略,如果需要引入中文,需要手動配置
import moment from 'moment' //手動引入所需要的語言包 import 'moment/locale/zh-cn'; moment.locale('zh-cn'); let r = moment().endOf('day').fromNow(); console.log(r); 複製程式碼
4.DllPlugin動態連結庫
場景舉例:
當打包一個react專案的時候,專案中引入reacr
和react-dom
兩個包,而這兩個庫很大且基本不會變,每次專案打包都會對打包,浪費時間和效能。
處理方法: 將react和react-dom單獨打包好,然後動態連結引入即可。如果第二次打包,那麼發現react和react-dom已經被打包好了,那麼直接找到打包好的檔案,不需要再次打包。
實現
src 下 index.js 檔案引入react
和react-dom
import React from 'react' import {render} from 'react-dom' render('<h1>jsx</h1>') 複製程式碼
src 下建立test.js
檔案
module.exports = 'joker'; 複製程式碼
建立webpack.config.react.js
對react
包單獨打包
let path = require('path'); let webpack = require('webpack'); module.exports = { mode:'development', entry:{ react:['react','react-dom'] }, output:{ filename:'_dll_[name].js',//產生的檔名_dll_react.js path:path.resolve(__dirname,'dist'), library:'_dll_[name]',//_dll_react // // libraryTarget:'var', }, plugins:[ new webpack.DllPlugin({ name:'_dll_[name]',//這個name要與output中的library同名 path:path.resolve(__dirname,'dist','manifest.json') }) ] } 複製程式碼
打包出一個_dll_react.js
和一個是清單manifest.json
然後在index.html去引用這個打包後的檔案
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div id="root"></div> <script type="text/javascript" src="/_dll_react.js"></script> </body> </html> 複製程式碼
但是現在,我們引用react
或react-dom
的時候,我們需要判斷是否在清單裡,這時候,我們就需要在我們正式的webpack.config.js裡進行配置, 需要使用到webpack內建外掛webpack.DllReferencePlugin
let path = require('path'); let webpack = require('webpack'); let HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { devServer:{ port:3000, open:true, contentBase:'./dist' }, mode:'development', entry:'./src/index.js', output:{ filename:'bundle.js', path:path.resolve(__dirname,'./dist') }, module:{ rules:[ { test:/\.js$/, use:{ loader:'babel-loader', options:{ presets:[ '@babel/preset-env', '@babel/preset-react' ] } } } ] }, plugins:[ new webpack.DllReferencePlugin({ manifest:path.resolve(__dirname,'dist','manifest.json') }), new HtmlWebpackPlugin({ template:'./src/index.html', filename:'index.html' }) ] } 複製程式碼
5.抽離公共程式碼
場景舉例: 當多頁應用重複使用部分公用程式碼時,每次單頁都會重複載入這些公用程式碼會造成一下問題: 相同資源,重複載入,增加使用者流量和伺服器成本
處理方法: 那麼,如果將這些公共程式碼抽取出來,並讓瀏覽器快取起來,使用者在請求資源的時候,可以直接讀取快取中的這些程式碼,這樣就能解決以上問題。
如何抽取公共程式碼: 現在存在如下檔案結構
other.js ↑ ------------- ↑↑ a.jsb.js ↓↓ ------------- ↓ index.js 複製程式碼
如上圖,index.js
和other.js
都依賴了a.js
和b.js
,那麼只需要將a.js
和b.js
抽離出來並打包成common.js
,然後讓index.js
和other.js
直接引用common.js
即可.
1.webpack.config.js配置 使用optimization的splitChunks屬性
module.exports = { optimization:{ splitChunks:{//分割程式碼塊,如果只有一個入口,就不需要分割了,只有多頁,才需要把公共的抽離出來 cacheGroups:{//快取組 common:{//公共的模組 chunks:'initial',//剛開始就要抽離 minSize:0,//大小大於0位元組的時候需要抽離出來 minChunks:2,//重複2次使用的時候需要抽離出來 } } } }, ... } 複製程式碼
npm run build得到的檔案為:
dist | ----- common~index~other.js | ----- index.js | ----- other.js | ----- index.html 複製程式碼
這樣,index.js
和other.js
都引用了抽離出來的公共程式碼common~index~other.js
如何抽離第三方庫 假設在上面的基礎上,index.js 和 other.js都引用了jquery庫,那麼這樣來配置抽離第三方庫 vendor屬性的配置,是用於抽取第三方庫的(詳看程式碼和註釋)
module.exports = { optimization:{ splitChunks:{ //分割程式碼塊,如果只有一個入口,就不需要分割了,只有多頁,才需要把公共的抽離出來 cacheGroups:{ //快取組 common:{ //公共的模組 chunks:'initial', minSize:0, minChunks:2, }, vendor:{test:/node_modules/,//把這個目錄下符合下面幾個條件的庫抽離出來 chunks:'initial',//剛開始就要抽離 minSize:0,//大小大於0位元組的時候需要抽離出來 minChunks:2,//重複2次使用的時候需要抽離出來 } } } }, ... } 複製程式碼
但是這樣會存在問題——程式碼從上到下執行,會先執行common,然後執行vendor,而在執行common的時候,就把jquery抽離出來打包到跟a.js和b.js裡面去了,後面的vendor就沒有什麼效果了。這並不是個好方案,我們最好是能夠將庫單獨抽離出來,於是,可以這麼操作: 在vendor新增權重屬性:priority,將權重提高,使得先去抽離第三方庫,再去抽離a.js和b.js
module.exports = { optimization:{ splitChunks:{//分割程式碼塊,如果只有一個入口,就不需要分割了,只有多頁,才需要把公共的抽離出來 cacheGroups:{//快取組 common:{//公共的模組 chunks:'initial', minSize:0, minChunks:2, }, vendor:{ priority:1,//新增權重 test:/node_modules/,//把這個目錄下符合下面幾個條件的庫抽離出來 chunks:'initial',//剛開始就要抽離 minSize:0,//大小大於0位元組的時候需要抽離出來 minChunks:2,//重複2次使用的時候需要抽離出來 } } } }, ... } 複製程式碼
打包結果為
common~index~other.js579 bytes index.html388 bytes index.js7.38 KiB other.js7.38 KiB vendor~index~other.js306 KiB 複製程式碼