一.可視化 webpack 輸出文件的大小
添加webpack-bundle-analyzer
yarn add webpack-bundle-analyzer --dev
可視化只在項目本地打包的時候,在測試或者語法或者生產(chǎn)打包的時候,不應(yīng)該添加可視化配置怠惶,因此需用cross-env配置可視化環(huán)境變量
package.json scripts 添加:
"analyze": "cross-env TC_NODE_ENV=analyze react-app-rewired build",
webpack配置文件:
const{BundleAnalyzerPlugin}=require('webpack-bundle-analyzer');if(process.env.TC_NODE_ENV==='analyze'){config.plugins.push(newBundleAnalyzerPlugin(),);}
運行 yarn run analyze 即可看到,剩下的事情就是想辦法減小這些包的體積
二.在不改動業(yè)務(wù)代碼的情況下家制,減小公共依賴
生產(chǎn)環(huán)境啟用壓縮等插件,去除不必要插件
webpack 開啟 gzip 壓縮
拆分業(yè)務(wù)代碼與第三方庫及公共模塊
按需加載
1 壓縮
uglifyjs-webpack-plugin
gzip壓縮:比較耗性能泡一,所以在開發(fā)環(huán)境并不開啟颤殴,只在生產(chǎn)環(huán)境開啟:
if(env==='production'){config.plugins.push(newUglifyESPlugin({uglifyOptions:{compress:{warnings:false,drop_console:true,collapse_vars:true,reduce_vars:true,},output:{beautify:false,comments:false,},},sourceMap:true,}),// gzipnewCompressionPlugin({filename:'[path].gz[query]',algorithm:'gzip',test:newRegExp('\\.('+['js','css'].join('|')+')$'),threshold:10240,minRatio:0.8,}));}
2.這些包不可能不引入,但是他們都是全局依賴的鼻忠,可以使用瀏覽器自己的緩存來實現(xiàn)不重復(fù)加載涵但。將項目中需要的一些公共依賴包,并且不常變動的,單獨取出贤笆,不再每次都打包編譯(如React蝇棉,Redux等)。而是通過使用 script 標(biāo)簽形式 cdn 引入芥永,這樣在有緩存的情況下篡殷,這些資源均走緩存,不必加載埋涧。但如 antd 這樣的庫板辽,整個包體積較大,庫文件也會按需加載棘催,不必單獨取出劲弦,并且里面可能會有 bug,需要更新醇坝。
2.1 cdn 引入方式
找到對應(yīng)的cdn加速服務(wù)邑跪,如在https://www.bootcdn.cn/中找,配置 webpack呼猪,使其打包的時候不在將這些資源打包:
config.externals={'react':'React','react-dom':'ReactDOM',}
鍵表示 require 或者 import 時候的字符串画畅,值表示的當(dāng)前環(huán)境下的變量,比如引入 React 之后宋距,React 被作為全局對象轴踱,webpack 就回去尋找React對象。
2.2 公共模塊CommonsChunkPlugin
why? 路由按需加載之后谚赎,每個頁面的js有相同的包引入淫僻,導(dǎo)致每個js文件都有重復(fù)的代碼,抽離這部分代碼到公共模塊壶唤。
在webpack配置文件中entry加入雳灵,例:
plugin加入:
newwebpack.optimize.CommonsChunkPlugin({name:'vendor',filename:'[name].[hash].js',minChunks:({resource})=>(resource&&resource.indexOf('node_modules')>=0&&resource.match(/\.js$/)),}),// 完成打包并發(fā)送到瀏覽器時,會在運行時通過 Manifest 來解析和加載模塊newwebpack.optimize.CommonsChunkPlugin({name:'manifest',filename:'[name].[hash].js',minChunks:Infinity,}),newwebpack.optimize.CommonsChunkPlugin({name:'main',async:'vendor-async',children:true,minChunks:({resource},count)=>(resource&&resource.indexOf('node_modules')>=0&&resource.match(/\.js$/)&&count>=2),}),newwebpack.optimize.CommonsChunkPlugin({name:'main',async:'common',minChunks:(module,count)=>(count>=2),}),
2.3 DLLPlugin
DLLPlugin 是能把第三方代碼完全分離開闸盔,即每次只打包項目自身的代碼细办。Dll這個概念是借鑒了Windows系統(tǒng)的dll,一個dll包蕾殴,就是一個純純的依賴庫,它本身不能運行岛啸,是用來給你的app引用的钓觉。
新建 webpack.config.dll.js
constpath=require('path');constwebpack=require('webpack');constCompressionPlugin=require('compression-webpack-plugin');module.exports={entry:{vendor:['echarts'],},output:{path:path.resolve('./public/static'),filename:'[name].dll.js',library:'[name]_[hash]',},plugins:[newwebpack.DllPlugin({path:path.resolve('./public/static','[name]-manifest.json'),name:'[name]_[hash]',}),newwebpack.optimize.UglifyJsPlugin({compress:{warnings:false,},}),newCompressionPlugin({filename:'[path].gz[query]',algorithm:'gzip',test:newRegExp('\\.('+['js','css'].join('|')+')$'),threshold:10240,minRatio:0.8,}),],};
在webpcak配置文件中加入
newwebpack.DllReferencePlugin({manifest:require('./public/static/vendor-manifest.json')})
在入口html文件中引入 vendor.dll.js
<scripttype="text/javascript"src="/static/vendor.dll.js"></script>
package.json加入
"build:dll":"webpack --config webpack.dll.config.js"
打包的時候先執(zhí)行 npm run build:dll,會在打包目錄下生成 vendor-manifest.json 文件與 vendor.dll.js 文件坚踩。
再執(zhí)行npm run build
注意:npm run build:dll 為開發(fā)人員本地打包vendor荡灾,打包完成之后會在/public/static文件下生成vendor.dll.js、vendor.dll.js.gz和vendor-manifest.json三個文件,線上打包不必在執(zhí)行此命令批幌,如果vendor沒有更新础锐,不必在 npm run build:dll,利用瀏覽器緩存荧缘。
已加入cdn的不必再配置vendor皆警。
2.4 抽離css樣式(extract-text-webpack-plugin)
constExtractTextPlugin=require('extract-text-webpack-plugin');newExtractTextPlugin({filename:'static/css/[name].[contenthash:8].css',allChunks:true,}),
3.按需引入
如antd、lodash截粗、echarts都有按需加載的方式信姓,可以去官方看
4.按需加載
思路:import(*).then(),返回一個Promise绸罗,加載成功后可以在then方法中獲取加載的內(nèi)容意推,Webpack內(nèi)置對import( *)語句的支持。
asyncComponent.js
importReactfrom'react';exportdefaultfunctionasyncComponent(importComponent){classAsyncComponentextendsReact.Component{constructor(props){super(props);this.state={Component:null,};}asynccomponentDidMount(){const{default:Component}=awaitimportComponent();this.setState({Component,});}render(){const{Component}=this.state;returnComponent?<Component{...this.props}/>:null;}}returnAsyncComponent;}
路由引入方式:
AsyncComponent(()=>import('../containers/Home/Home'))