一.可視化 webpack 輸出文件的大小
添加webpack-bundle-analyzer
yarn add webpack-bundle-analyzer --dev
可視化只在項(xiàng)目本地打包的時(shí)候,在測(cè)試或者語(yǔ)法或者生產(chǎn)打包的時(shí)候,不應(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(),);}
運(yùn)行 yarn run analyze 即可看到,剩下的事情就是想辦法減小這些包的體積
二.在不改動(dòng)業(yè)務(wù)代碼的情況下,減小公共依賴
生產(chǎn)環(huán)境啟用壓縮等插件,去除不必要插件
webpack 開啟 gzip 壓縮
拆分業(yè)務(wù)代碼與第三方庫(kù)及公共模塊
按需加載
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.這些包不可能不引入,但是他們都是全局依賴的,可以使用瀏覽器自己的緩存來(lái)實(shí)現(xiàn)不重復(fù)加載。將項(xiàng)目中需要的一些公共依賴包,并且不常變動(dòng)的,單獨(dú)取出,不再每次都打包編譯(如React,Redux等)。而是通過(guò)使用 script 標(biāo)簽形式 cdn 引入,這樣在有緩存的情況下,這些資源均走緩存,不必加載。但如 antd 這樣的庫(kù),整個(gè)包體積較大,庫(kù)文件也會(huì)按需加載,不必單獨(dú)取出,并且里面可能會(huì)有 bug,需要更新。
2.1 cdn 引入方式
找到對(duì)應(yīng)的cdn加速服務(wù),如在https://www.bootcdn.cn/中找,配置 webpack,使其打包的時(shí)候不在將這些資源打包:
config.externals={'react':'React','react-dom':'ReactDOM',}
鍵表示 require 或者 import 時(shí)候的字符串,值表示的當(dāng)前環(huán)境下的變量,比如引入 React 之后,React 被作為全局對(duì)象,webpack 就回去尋找React對(duì)象。
2.2 公共模塊CommonsChunkPlugin
why? 路由按需加載之后,每個(gè)頁(yè)面的js有相同的包引入,導(dǎo)致每個(gè)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ā)送到瀏覽器時(shí),會(huì)在運(yùn)行時(shí)通過(guò) Manifest 來(lái)解析和加載模塊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 是能把第三方代碼完全分離開,即每次只打包項(xiàng)目自身的代碼。Dll這個(gè)概念是借鑒了Windows系統(tǒng)的dll,一個(gè)dll包,就是一個(gè)純純的依賴庫(kù),它本身不能運(yùn)行,是用來(lái)給你的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"
打包的時(shí)候先執(zhí)行 npm run build:dll,會(huì)在打包目錄下生成 vendor-manifest.json 文件與 vendor.dll.js 文件。
再執(zhí)行npm run build
注意:npm run build:dll 為開發(fā)人員本地打包vendor,打包完成之后會(huì)在/public/static文件下生成vendor.dll.js、vendor.dll.js.gz和vendor-manifest.json三個(gè)文件,線上打包不必在執(zhí)行此命令,如果vendor沒(méi)有更新,不必在 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(),返回一個(gè)Promise,加載成功后可以在then方法中獲取加載的內(nèi)容,Webpack內(nèi)置對(duì)import( *)語(yǔ)句的支持。
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'))