性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議
如何輸出Webpack構(gòu)建分析
輸出Webpack構(gòu)建信息的.json文件:webpack --profile --json > stats.json
--profile:記錄構(gòu)建中的耗時信息--json:以json格式輸出構(gòu)建結(jié)果,最后只輸出一個json文件(包含所有的構(gòu)建信息)
web可視化查看構(gòu)建分析:得到了webpack構(gòu)建信息文件stats.json,如何進行很好的可視化查看?
- 方案一:通過可視化分析工具Webpack Analyse,是個在線Web應用,上傳stats.json文件就可以;不過好像需要翻墻;
- 方案二:安裝
webpack-bundle-analyzer工具npm i -g webpack-bundle-analyzer,生成stats.json后直接在其文件夾目錄執(zhí)行webpack-bundle-analyzer后,瀏覽器會打開對應網(wǎng)頁并展示構(gòu)建分析webpack-bundle-analyzer stats.json -p 8888文檔地址webpack-bundle-analyzer - webpack-dashboard是一款統(tǒng)計和優(yōu)化webpack日志的工具,可以以表格形勢展示日志信息。其中包括構(gòu)建過程和狀態(tài)、日志以及涉及的模塊列表
- jarvis是一款基于webapck-dashboard的webpack性能分析插件,性能分析的結(jié)果在瀏覽器顯示,比webpack-bundler-anazlyer更美觀清晰GitHub文檔地址
npm i -D webpack-jarvis
webpack.config.js配置:
const Jarvis = require("webpack-jarvis");
plugins: [
new Jarvis({
watchOnly: false,
port: 3001 // optional: set a port
})
];
port:監(jiān)聽的端口,默認1337,監(jiān)聽面板將監(jiān)聽這個端口,通常像http://localhost:port/
host:域名,默認localhost,不限制域名。
watchOnly:僅僅監(jiān)聽編譯階段。默認為true,如果高為false,jarvis不僅僅運行在編譯階段,在編譯完成后還保持運行狀態(tài)。
界面:看到構(gòu)建時間為:Time: 11593ms(作為優(yōu)化時間對比)

webpack配置優(yōu)化
webpack在啟動時會從配置的Entry出發(fā),解析出文件中的導入語句,再遞歸解析。
對于導入語句Webpack會做出以下操作:
- 根據(jù)導入語句尋找對應的要導入的文件;
- 在根據(jù)要導入的文件后綴,使用配置中的Loader去處理文件(如使用ES6需要使用babel-loader處理)
針對這兩點可以優(yōu)化查找途徑
1、優(yōu)化Loader配置
Loader處理文件的轉(zhuǎn)換操作是很耗時的,所以需要讓盡可能少的文件被Loader處理
{
test: /\.js$/,
use: [
'babel-loader?cacheDirectory',//開啟轉(zhuǎn)換結(jié)果緩存
],
include: path.resolve(__dirname, 'src'),//只對src目錄中文件采用babel-loader
exclude: path.resolve(__dirname,' ./node_modules'),//排除node_modules目錄下的文件
},
2、優(yōu)化resolve.modules配置
resolve.modules用于配置webpack去哪些目錄下尋找第三方模塊,默認是['node_modules'],但是,它會先去當前目錄的./node_modules查找,沒有的話再去../node_modules最后到根目錄;
所以當安裝的第三方模塊都放在項目根目錄時,就沒有必要安默認的一層一層的查找,直接指明存放的絕對位置
resolve: {
modules: [path.resolve(__dirname, 'node_modules')],
}
3、優(yōu)化resolve.extensions配置
在導入沒帶文件后綴的路徑時,webpack會自動帶上后綴去嘗試詢問文件是否存在,而resolve.extensions用于配置嘗試后綴列表;默認為extensions:['js','json'];
及當遇到require('./data')時webpack會先嘗試尋找data.js,沒有再去找data.json;如果列表越長,或者正確的后綴越往后,嘗試的次數(shù)就會越多;
所以在配置時為提升構(gòu)建優(yōu)化需遵守:
- 頻率出現(xiàn)高的文件后綴優(yōu)先放在前面;
- 列表盡可能的??;
- 書寫導入語句時,盡量寫上后綴名
因為項目中用的jsx較多,所以配置extensions: [".jsx",".js"],
基本配置后查看構(gòu)建速度:Time: 10654ms;配置前為Time: 11593ms
使用DllPlugin優(yōu)化
在使用webpack進行打包時候,對于依賴的第三方庫,如react,react-dom等這些不會修改的依賴,可以讓它和業(yè)務代碼分開打包;
只要不升級依賴庫版本,之后webpack就只需要打包項目業(yè)務代碼,遇到需要導入的模塊在某個動態(tài)鏈接庫中時,就直接去其中獲取;而不用再去編譯第三方庫,這樣第三方庫就只需要打包一次。
接入需要完成的事:
- 將依賴的第三方模塊抽離,打包到一個個單獨的動態(tài)鏈接庫中
- 當需要導入的模塊存在動態(tài)鏈接庫中時,讓其直接從鏈接庫中獲取
- 項目依賴的所有動態(tài)鏈接庫都需要被加載
接入工具(webpack已內(nèi)置)
DllPlugin插件:用于打包出一個個單獨的動態(tài)鏈接庫文件;
DllReferencePlugin:用于在主要的配置文件中引入DllPlugin插件打包好的動態(tài)鏈接庫文件
配置webpack_dll.config.js構(gòu)建動態(tài)鏈接庫
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
mode: 'production',
entry: {
// 將React相關模塊放入一個動態(tài)鏈接庫
react: ['react','react-dom','react-router-dom','react-loadable'],
librarys: ['wangeditor'],
utils: ['axios','js-cookie']
},
output: {
filename: '[name]-dll.js',
path: path.resolve(__dirname, 'dll'),
// 存放動態(tài)鏈接庫的全局變量名,加上_dll_防止全局變量沖突
library: '_dll_[name]'
},
// 動態(tài)鏈接庫的全局變量名稱,需要可output.library中保持一致,也是輸出的manifest.json文件中name的字段值
// 如react.manifest.json字段中存在"name":"_dll_react"
plugins: [
new DllPlugin({
name: '_dll_[name]',
path: path.join(__dirname, 'dll', '[name].manifest.json')
})
]
}
webpack.pro.config.js中使用
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
...
plugins: [
// 告訴webpack使用了哪些動態(tài)鏈接庫
new DllReferencePlugin({
manifest: require('./dll/react.manifest.json')
}),
new DllReferencePlugin({
manifest: require('./dll/librarys.manifest.json')
}),
new DllReferencePlugin({
manifest: require('./dll/utils.manifest.json')
}),
]
注意:在webpack_dll.config.js文件中,DllPlugin中的name參數(shù)必須和output.library中的一致;因為DllPlugin的name參數(shù)影響輸出的manifest.json的name;而webpack.pro.config.js中的DllReferencePlugin會讀取manifest.json的name,將值作為從全局變量中獲取動態(tài)鏈接庫內(nèi)容時的全局變量名
執(zhí)行構(gòu)建
webpack --progress --colors --config ./webpack.dll.config.js
webpack --progress --colors --config ./webpack.prod.js
html中引入dll.js文件
構(gòu)建時間對比:["11593ms","10654ms","8334ms"]
HappyPack并行構(gòu)建優(yōu)化
核心原理:將webpack中最耗時的loader文件轉(zhuǎn)換操作任務,分解到多個進程中并行處理,從而減少構(gòu)建時間。
接入HappyPack
安裝:npm i -D happypack
重新配置rules部分,將loader交給happypack來分配:
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({size: 5}); //構(gòu)建共享進程池,包含5個進程
...
plugins: [
// happypack并行處理
new HappyPack({
// 用唯一ID來代表當前HappyPack是用來處理一類特定文件的,與rules中的use對應
id: 'babel',
loaders: ['babel-loader?cacheDirectory'],//默認設置loader處理
threadPool: happyThreadPool,//使用共享池處理
}),
new HappyPack({
// 用唯一ID來代表當前HappyPack是用來處理一類特定文件的,與rules中的use對應
id: 'css',
loaders: [
'css-loader',
'postcss-loader',
'sass-loader'],
threadPool: happyThreadPool
})
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: ['happypack/loader?id=babel'],
exclude: path.resolve(__dirname,' ./node_modules'),
},
{
test: /\.(scss|css)$/,
//使用的mini-css-extract-plugin提取css此處,如果放在上面會出錯
use: [MiniCssExtractPlugin.loader,'happypack/loader?id=css'],
include:[
path.resolve(__dirname,'src'),
path.join(__dirname, './node_modules/antd')
]
},
}
參數(shù):
threads:代表開啟幾個子進程去處理這一類文件,默認是3個;
verbose:是否運行HappyPack輸出日志,默認true;
threadPool:代表共享進程池,即多個HappyPack示例使用一個共享進程池中的子進程去處理任務,以防資源占有過多
代碼壓縮用ParallelUglifyPlugin代替自帶的 UglifyJsPlugin插件
自帶的JS壓縮插件是單線程執(zhí)行的,而webpack-parallel-uglify-plugin可以并行的執(zhí)行
配置參數(shù):
uglifyJS: {}:用于壓縮 ES5 代碼時的配置,Object 類型test: /.js$/g:使用正則去匹配哪些文件需要被 ParallelUglifyPlugin 壓縮,默認是 /.js$/include: []:使用正則去包含被壓縮的文件,默認為 [].exclude: []: 使用正則去包含不被壓縮的文件,默認為 []cacheDir: '':緩存壓縮后的結(jié)果,下次遇到一樣的輸入時直接從緩存中獲取壓縮后的結(jié)果并返回,默認不會緩存,開啟緩存設置一個目錄路徑workerCount: '':開啟幾個子進程去并發(fā)的執(zhí)行壓縮。默認是當前運行電腦的 CPU 核數(shù)減去1sourceMap: false:是否為壓縮后的代碼生成對應的Source Map, 默認不生成
...
minimizer: [
// webpack:production模式默認有配有js壓縮,但是如果這里設置了css壓縮,js壓縮也要重新設置,因為使用minimizer會自動取消webpack的默認配置
new optimizeCssPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true
}),
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
// 是否輸出可讀性較強的代碼,即會保留空格和制表符,默認為輸出,為了達到更好的壓縮效果,可以設置為false
beautify: false,
//是否保留代碼中的注釋,默認為保留,為了達到更好的壓縮效果,可以設置為false
comments: false
},
compress: {
//是否在UglifyJS刪除沒有用到的代碼時輸出警告信息,默認為輸出
warnings: false,
//是否刪除代碼中所有的console語句,默認為不刪除,開啟后,會刪除所有的console語句
drop_console: true,
//是否內(nèi)嵌雖然已經(jīng)定義了,但是只用到一次的變量,比如將 var x = 1; y = x, 轉(zhuǎn)換成 y = 1, 默認為否
collapse_vars: true,
}
}
}),
]
構(gòu)建結(jié)果對比:["11593ms","10654ms","8334ms","7734ms"]
整體構(gòu)建速度從12000ms降到現(xiàn)在的8000ms
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
JS獲取浮動(float)元素的style.left值為空的快速解決辦法
這篇文章主要介紹了JS獲取浮動(float)元素的style.left值為空的快速解決辦法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02
js+html5實現(xiàn)canvas繪制橢圓形圖案的方法
這篇文章主要介紹了js+html5實現(xiàn)canvas繪制橢圓形圖案的方法,涉及html5圖形繪制的基礎技巧,感興趣的朋友可以參考一下2016-05-05
easyUI實現(xiàn)(alert)提示框自動關閉的實例代碼
下面小編就為大家?guī)硪黄猠asyUI實現(xiàn)(alert)提示框自動關閉的實例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11

