開始
這一章講打包體積優化,這個也算是最重要的一章了,我之前可是花了很多時間去查資料怎麼優化打包體積的,不同版本的webpack之間還有一些區別,所以也算踩了很多的坑,所以這一章會比較長。
這邊我大概寫了一下頁面具體佈局,是下面這樣的:
我們再去看一下打包體積,有2.75M,已經算很大了: 我們使用一個打包視覺化的外掛來看看都有什麼被打包進去了,我們執行:yarn add webpack-bundle-analyzer -D
複製程式碼
在webpack.config.prod.js的plugins裡新增一行,注意埠可以修改,別衝突了:
new BundleAnalyzerPlugin({ analyzerPort: 8081 })
複製程式碼
修改完成後,執行yarn run build命令,在瀏覽器彈出視窗,我的是這樣的:
可以清晰的看到antd和react-dom就佔了一半多,下面來優化。1. 修改mode
我們去webpack.config.prod.js裡:
//mode:'development'
mode:'production' //修改成開發環境
複製程式碼
然後檢視打包體積,瞬間減少了一半多,修改成開發環境webpack會自動的去優化包體積,比如壓縮程式碼之類的:
2. antd按需載入
在控制檯執行:
yarn add babel-plugin-import -D
複製程式碼
然後去webpack.config.common.js配置:
plugins:[
"@babel/plugin-transform-runtime",
['import',{
libraryName:'antd',
libraryDirectory: 'es',
style:true
}]
]
複製程式碼
在less的配置裡修改:
{
loader:'less-loader',
options:{
javascriptEnabled: true
}
}
複製程式碼
然後我們去使用到antd元件的地方,修改成以下這樣的形式引入:
// import Col from 'antd/lib/col';
// import Row from 'antd/lib/row';
// import "antd/dist/antd.css"; //css也去掉
import {Col,Row} from 'antd'
複製程式碼
再執行打包命令,變成601kb:
3. mini-css-extract-plugin提取css
我們使用mini-css-extract-plugin來將css從js裡分離出來。在控制檯執行:
yarn add mini-css-extract-plugin -D
複製程式碼
在webpack.config.prod.js裡配置:
//在頂部引入
const MiniCssExtractPlugin=require('mini-css-extract-plugin');
//在plugins裡新增
new MiniCssExtractPlugin({//提取css
filename:'css/main.css'
}),
複製程式碼
這樣我們可以將css單獨分離到css資料夾裡。然後再打包看看:
我們發現js包變小,css也被分離出來了,但是css居然有223kb,開啟css檔案,我們發現css沒有被壓縮掉。我們在控制檯執行,這兩個外掛前者是壓縮css的,後者是壓縮js的,本來在生產環境下會壓縮js的,但是使用optimize-css-assets-webpack-plugin會導致壓縮js無效,所以我們需要額外引入一個壓縮js的外掛:
yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
複製程式碼
我們在webpack.config.common.js裡配置:
//這個配置和module,plugins是同級的
optimization:{
minimizer:[
new UglifyJsPlugin({//壓縮js
cache:true,
parallel:true,
sourceMap:true
}),
new OptimizeCSSAssetsPlugin()//壓縮css
]
},
複製程式碼
然後我們去打包,我們發現css已經變小了:
4. DllPlugin和DllReferencePlugin
在之前的打包圖我們可以看見包體積大部分是被react全家桶和babel佔用了,現在我們把這些給拿出來單獨放到一個js檔案裡,因為這些東西我們是不會去改變它的。
我們在根目錄下新建一個==webpack.config.dll.js==,然後在裡面配置,因為DllPLugin是webpack下的,所以我們不用下載:
const path=require('path')
const webpack =require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin');
//只需要使用yarn run dll一次就行
module.exports={
mode:'production',
entry:{
//這裡把react方面的東西和babel放到這裡
vendor:['react','react-dom','react-router-dom']
},
output:{
filename:'dll/_dll_[name].js',
path:path.resolve(__dirname,'dist'),
library:'_dll_[name]'
},
plugins:[
new webpack.DllPlugin({
name:'_dll_[name]',
path:path.resolve(__dirname,'dist/dll','mainfist.json')
}),
new CleanWebpackPlugin(['./dist/dll']),//刪除dll目錄下的檔案
]
}
複製程式碼
再去==webpack.config.common.js==裡配置:
//在plugins下新增
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist/dll', 'mainfist.json')
}),
複製程式碼
然後去package.json.裡配置:
//在scripts下面新增一條這個
"dll": "webpack --config webpack.config.dll.js"
複製程式碼
在控制檯執行:
yarn run dll
複製程式碼
我們發現已經被打包出來了,我們還需要去public/index.html進行引入:
//在body最後新增
<script src="dll/_dll_vendor.js"></script>
複製程式碼
然後去執行yarn run build:
檔案大小又變小了。5. @babel/polyfill
我們在之前的圖裡可以看見,core-js佔用了很大的一部分體積,這個就是babel/polyfill使用的庫。這裡我提供兩種方法。
1.@baebl/polyfill按需載入
我們可以使用useBuiltIns這個屬性,這個屬性是babel7新增的,我們需要這樣配置:
presets:[
[
'@babel/preset-env',
{
"targets": {
"browsers": [
"ie >=9",
"last 2 version",
"> 5%",
"not dead"
]
},
"useBuiltIns":"usage"
}
],
'@babel/preset-react'
],
複製程式碼
當我們這樣配置之後,我們就可以把index.js頂部的
//import '@babel/polyfill' //可以去掉這一行了
複製程式碼
然後我們再打包,執行yarn run build:
這個時候打包體積變成了132kb,但是我在使用這種方法的時候,在ie11下可以正常顯示,在ie10及以下就出現下面的錯誤了,: 目前我還沒找到解決方法,有解決方法的麻煩也跟我說一下,謝謝了。如果你不需要相容ie10或以下的話可以使用這種方法。2.提取@baebl/polyfill
第二種方法,我們可以直接提取@babel/polyfill,就像react全家桶一樣。我們去==webpack.config.dll.js==裡配置:
//新增@babel/polyfill
vendor:['react','react-dom','react-router-dom','@babel/polyfill']
複製程式碼
然後去index.js的頂部新增:
import '@babel/polyfill'
複製程式碼
然後我們去執行yarn run dll,可以看見vendor的包變大了:
然後我們執行yarn run build: 我們發現包體積和之前的方法差不多,然後我們去ie下看看: 只有在==ie8==下會出現這樣的錯誤,ie9及以上都是正常顯示的,相容性算是很不錯了,所以這兩種方法如何取捨就看自己專案需不需要相容ie了。6. react-router動態載入(react元件懶載入)
之前我們是全部的元件都在頁面上載入出來,這樣我們還沒點選的元件也會載入,這樣就導致浪費了。我們使用動態載入來讓點選到的元件才進行載入就好多了。
我們在控制檯執行:
yarn add react-loadable babel-plugin-syntax-dynamic-import -D
複製程式碼
如何在==webpack.config.common.js==裡配置:
plugins:[
"@babel/plugin-transform-runtime",
'babel-plugin-syntax-dynamic-import',//增加這一行
['import',{
libraryName:'antd',
libraryDirectory: 'es',
style:true
}]
]
複製程式碼
然後我們去使用路由的地方修改:
import Loadable from 'react-loadable';//注意要加上這一行
// import A from '../pages/A/A'
// import B from '../pages/B/B'
//修改成這樣子的寫法
const A = Loadable({
loader: () => import('../pages/A/A'),
loading:()=> {
return <div>Loading...</div>
}
});
const B = Loadable({
loader: () => import('../pages/B/B'),
loading:()=> {
return <div>Loading...</div>
}
});
複製程式碼
再去執行打包命令,然後檢視:
我們發現包體積變大了,這是因為我現在專案沒寫什麼東西,所以引入了外掛後,包就變大了,在元件寫多了之後,這個動態載入能減少很多的體積。我們可以來看一下效果:
頁面剛載入的時候是這樣的
點選一個路由後變成這樣: 可以看見動態的載入了一個js檔案。index.js體積解釋
這裡再說一下打包的圖,其實我在src下寫的程式碼很少,但是打包圖的這裡有個index.js卻有將近90kb大,這是為什麼?其實這個是antd按需載入打包進來的元件,我們可以試一下,這個是我現在主頁上大部分使用到的antd元件程式碼:
<div>
<Header/>
<Row>
<Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>
<Aside/>
</Col>
<Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>
<div className="content">
{this.props.children}
</div>
</Col>
</Row>
</div>
複製程式碼
我們將使用到的antd元件都註釋掉,只留下Header:
//import {Col,Row} from 'antd'
<div>
<Header/>
{/*<Row>*/}
{/*<Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>*/}
{/*<Aside/>*/}
{/*</Col>*/}
{/*<Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>*/}
{/*<div className="content">*/}
{/*{this.props.children}*/}
{/*</div>*/}
{/*</Col>*/}
{/*</Row>*/}
</div>
複製程式碼
然後我們再去打包:
現在src下的這個包已經變的很小了。7. splitChunks
然後我們將antd之類的第三方庫從主要的包裡分離出來。
我們在==webpack.config.common.js==裡的optimization裡配置,在和之前我們寫js和css壓縮的==minimizer==的同級的地方:
splitChunks:{
cacheGroups:{
vendors:{//node_modules裡的程式碼
test:/[\\/]node_modules[\\/]/,
chunks: "initial",
name:'vendors', //chunks name
priority:10, //優先順序
enforce:true
}
}
}
複製程式碼
然後再去執行打包命令:
我們可以發現關於antd的js和css都被抽離出來了,chunk Names為vendors的就是,而為main的就是我們自己寫的程式碼,我們自己寫的其實很少。雖然antd的元件比較大,但它們只會打包一次,而且在服務端配置gzip的情況下,體積又可以減少三分之一多,還是可以接受的。
結尾
最後我們將主包體積從2.75M優化到5kb左右,但其實我們是將一個大的包拆分成多個小包,並提取公共程式碼。
這裡其實還有一個使用externals的優化方法,然後使用CDN引入,但我這邊已經使用了DllPlugin了,就不使用那種方法了,兩種方法大家可以合理使用。
這一章寫了太多的東西了,而且稍微有點雜,但是應該也算是挺詳細了,但是我覺得webpack打包體積優化的還不止這些,如果你們還有其他能優化的方法,也和我說一下,謝謝了。
(ps:如果文章哪裡有錯誤,請在評論指出,謝謝)