本編文章接着前兩篇文章進行項目webpack打包的優化css
一、react+webpack4搭建前端項目(一)html
二、react+webpack4搭建前端項目(二)react全家桶的使用前端
主要從如下幾個方面進行:vue
react
路由的異步加載css
處理
mini-css-extract-plugin
把css
從bundle
包中抽取optimize-css-assets-webpack-plugin
壓縮css
代碼postcss-loader,autoprefixer
對瀏覽器兼容性的css
代碼加前綴js
的處理
uglifyjs-webpack-plugin
代碼壓縮js
的bundle
包的提取(拆包)注意antd
版本"antd": "^3.8.3",
,高版本的antd
官方把圖標庫也構建到release包,因此致使打包變得很大,僅僅icon
圖標庫就有幾百KB,請看下圖。若是遇到這個問題,請下降antd
的使用版本到3.8.3之前 node
下邊打包優化的基礎代碼請點擊 源碼1.0.3。有不熟悉的同窗能夠看一下,下載該版本1.0.3,在項目根目錄執行 npm run dev
;同時切換到mock目錄,執行 npm run dev
,打開http://localhost:8081便可看到效果 主要實現的功能以下圖:react
簡歷管理的查詢,刪除,修改:webpack
用戶模塊的查詢,修改: ios
用戶模塊的添加:git
首先咱們看一下沒有優化前的js包大小,執行npm run build
github
這時候打包出的文件只有三個 index.html
模板文件 reset.min.css
是從靜態目錄copy進去的 app.1a9adec2b6012290869f.js
是咱們利用webpack
打包生成的。這裏邊包括項目中的全部js代碼,css代碼以及圖片data資源
工欲善其事必先利其器,咱們先安裝兩個很是有用的webpack插件
npm install -D clean-webpack-plugin webpack-bundle-analyzer
複製代碼
修改webpack.prod.config.js
,在plugins屬性下添加
new CleanWebpackPlugin(),
new BundleAnalyzerPlugin(),
複製代碼
咱們知道想文件的異步加載須要使用import("xxx")
,或者require.ensure
這種方法適用webapck1.x
2.x
。因此這裏採用import("xxx")
。
在vue中實現路由的異步加載很簡單,經過()=>import("xxx")
就能夠,那麼在react
中咱們也能夠這樣異步加載
咱們這裏實現路由的異步加載藉助react-loadable
插件
詳細使用請點擊 react-loadable使用方法
一、首頁編寫一個loadable.js
實現異步加載組件
import Loadable from 'react-loadable';
const LoadableComponent = (component) => Loadable({
loader: component,
loading: ()=>null,
});
export default LoadableComponent;
複製代碼
二、修改路由組件的加載方式
把container/index.js
文件組件的直接導入
import BlogIndex from "@/blog"
import ResumeIndex from "@/resume"
import UserIndex from "@/user"
複製代碼
改爲使用react-loadable
插件包裝一層加載組件的方式
import LoadableComponent from "@/loadable"
const BlogListPage = LoadableComponent(()=>import("./pages/list"))
const AddBlogPage = LoadableComponent(()=>import("./pages/add"))
複製代碼
接着修改user/index.js
,blog/index.js
,把路由組件改爲異步加載,改完以後測試一下打包以下圖
這時候已經把異步加載的路由組件單獨打包到其它單獨的文件。從922k減少到487k。
你會發現1.a64085be1c517b7e1ef2.js
單獨打包出來的200多k,能夠看到下圖包含了antd
的組件,這也證實antd按需加載的使用成功
在webpack4.x以前咱們使用extract-text-webpack-plugin
壓縮抽取css。
在webpack4.x咱們須要使用mini-css-extract-plugin
插件進行抽取css,mini-css-extract-plugin詳細使用文檔 修改webpack.base.config.js
對css
,less
文件的處理,以下
{
test: /\.css$/,
use:[
{
loader:MiniCssExtractPlugin.loader,
options:{
hmr: utils.isDev(), // 開發的時候,修改css熱更新,可是試了下不起做用
reloadAll:true,
}
},
// {
// loader: 'style-loader', // 建立 <style></style> // MiniCssExtractPlugin 有衝突,因此刪掉
// },
{
loader: 'css-loader', // 轉換css
options: { importLoaders: 1 }
}
]
},
{
test: /\.less$/,
use: [
{
loader:MiniCssExtractPlugin.loader,
options:{
hmr: utils.isDev(), // 開發的時候,修改less熱更新可是試了下不起做用
reloadAll:true,
}
},
// {
// loader: 'style-loader',
// },
{
loader: 'css-loader',
},
{
loader: 'less-loader', // 編譯 Less -> CSS
}
],
},
複製代碼
由於style-loader
和MiniCssExtractPlugin.loader
有衝突,在配置的時刪除了style-loader
對樣式的處理,測試打包結果以下
此時已經成功把css樣式從bundle抽離出。bundle包從487k減少到381k。
css
代碼咱們打開任意一個打包後的css文件,發現css代碼沒有壓縮。因此咱們須要對css壓縮。安裝optimize-css-assets-webpack-plugin
,optimize-css-assets-webpack-plugin詳細使用文檔
npm install -D optimize-css-assets-webpack-plugin
複製代碼
在webpack.prod.config.js添加
optimization`屬性(webpack4.x的代碼壓縮和拆包都在這裏處理,這是和webpack3.x的不一樣)
optimization: {
// 壓縮css
minimizer: [
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
discardComments: { removeAll: true } // 移除註釋
}
})
]
}
複製代碼
測試打包:
對比一下兩次打包的css文件大小,已經有必定的減少或者打開打包後的css文件代碼也壓縮了,這就表明壓縮成功。
可是咱們發現js的bundle包變大了,這是爲何呢? 由於咱們重寫了optimization
屬性的minimizer
,會把webpack自帶的壓縮方式給覆蓋掉,這裏須要咱們本身定義js的壓縮方式。
這裏和webpack3.x同樣使用uglifyjs-webpack-plugin
插件,uglifyjs-webpack-plugin詳細使用文檔,安裝
npm install -D uglifyjs-webpack-plugin
複製代碼
而後在minimizer
屬性下添加下邊代碼
// 自定義js優化配置,將會覆蓋默認配置
new UglifyJsPlugin({
parallel: true, //使用多進程並行運行來提升構建速度
sourceMap: false,
uglifyOptions: {
warnings: false,
compress: {
unused: true,
drop_debugger: true,
drop_console: true,
},
output: {
comments: false // 去掉註釋
}
}
})
複製代碼
從新測試打包比較和以前的js文件的大小同樣!到此咱們對css的處理告一段落!
在webpack3.x的時候咱們都是用webpack內置的CommonsChunkPlugin
來拆包。webpack4.x發生了很大變化。 webpack4.x要想進行拆包,須要先對splitChunks
有必定的瞭解。splitChunks
就算你什麼配置都不作它也是生效的,源於webpack有一個默認配置,這也符合webpack4的開箱即用的特性。
splitChunks
的默認配置以下
splitChunks: {
// async表示只從異步加載得模塊(動態加載import())裏面進行拆分
// initial表示只從入口模塊進行拆分
// all表示以上二者都包括
chunks: "async",
minSize: 30000, // 大於30k會被webpack進行拆包
minChunks: 1, // 被引用次數大於等於這個次數進行拆分
// import()文件自己算一個
// 只計算js,不算css
// 若是同時有兩個模塊知足cacheGroup的規則要進行拆分,可是maxInitialRequests的值只能容許再拆分一個模塊,那尺寸更大的模塊會被拆分出來
maxAsyncRequests: 5, // 最大的按需加載(異步)請求次數
// 最大的初始化加載請求次數,爲了對請求數作限制,不至於拆分出來過多模塊
// 入口文件算一個
// 若是這個模塊有異步加載的不算
// 只算js,不算css
// 經過runtimeChunk拆分出來的runtime不算在內
// 若是同時又兩個模塊知足cacheGroup的規則要進行拆分,可是maxInitialRequests的值只能容許再拆分一個模塊,那尺寸更大的模塊會被拆分出來
maxInitialRequests: 3,
automaticNameDelimiter: '~', // 打包分隔符
name:true,
cacheGroups: {
// 默認的配置
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
// 默認的配置,vendors規則不命中的話,就會命中這裏
default: {
minChunks: 2, // 引用超過兩次的模塊 -> default
priority: -20,
reuseExistingChunk: true
},
},
}
複製代碼
打包測試,和不添加splitChunks
打包結果一致
由於默認是async
,只從異步加載的模塊拆分。能夠看到只有app.js
是入口文件(同步加載)沒有對app.js
進行拆分。這個項目使用react-loadable
異步加載,本項目中有7個組件採用這種方式加載。可是從打包結果能夠看異步加載的組件拆分出來10個chunk
。那麼是爲何呢?
使用webpack-bundle-analyzer
分析能夠看出有三個chunk
是異步組件引用antd
中的組件進行拆分出來的chunk
。
假如咱們把chunks:async
改爲chunks: "initial"
進行打包測試:
打包結果以下圖
打包結果徹底不一樣,由於app.js
是同步加載,app.js
被拆分,此時發現app.js
很是小。相反拆分出來的vendors~app.4fd9181b8f618e9fcac6.js
比較大,這是由於這個chunk
包含項目入口文件包含的全部第三方庫。而異步加載的7個組件最終打包出來的仍是7個chunk
,這些異步加載的組件打包出來的每一個chunk
包含除了vendors~app.4fd9181b8f618e9fcac6.js
打包進去的第三方庫之外的代碼和組件自己代碼。
那麼同窗們會想了,把chunks:initial
改爲chunks: "all"
會是什麼結果呢?那麼咱們進行測試一下
打包結果以下圖
咱們知道all
不只從同步組件拆分,還從異步加載中拆分。
從打包結果看,是對initial
和async
的合併。即把異步組件拆分,也把同步組件拆分。
那麼結論來了,由於本項目包含異步加載,須要對異步組件和同步組件同時拆分,因此此項目採用chunks: "all"
進行bundle
的拆分。若是項目中同步加載的組件chunk
不大,能夠不對同步加載組件進行拆分,使用chunks:async
。固然若是項目中異步加載的組件chunk
不大,也能夠不對異步加載組件進行拆分,使用chunks:initial
。固然也能夠混用,對於緩存組單獨設置
既使採用chunks: "all"
的方式咱們發現。拆分出來venders~app.js
的chunk
(node_modules
的第三方庫)也比較大。隨着第三方插件使用的增多這個chunk
會變的愈來愈大。因此咱們這裏對他進行拆分。也就是把node_modules
中使用的插件也拆分紅不一樣的chunk
咱們拆包的策略是按照體積大小、共用率、更新頻率從新劃分咱們的包,使其儘量的利用瀏覽器緩存。
分析項目的插件,能夠按幾下分類插件
這些都是更新頻率很是低,公用率高,說起大,因此單獨抽取。只要這些包不更新,拆包的chunk
文件名就不會變。就一直緩存在瀏覽器
接下來咱們根據這個分類拆包,增長cacheGroups茶包的規則
antdui: {
priority: 2,
test: /[\\/]node_modules[\\/](antd)[\\/]/, //(module) => (/antd/.test(module.context)),
},
// 拆分基礎插件
basic: {
priority: 3,
test: /[\\/]node_modules[\\/](moment|react|react-dom|react-router|react-router-dom|mobx|mobx-react|axios)[\\/]/,
}
複製代碼
打包測試:
這裏已經成功拆分出來antdui~app.js
,basic~app.js
。使用webpack-bundle-analyzer
分析能夠精確的看到antd,moment|react|react-dom|react-router|react-router-dom|mobx|mobx-react|axios插件被拆分。
不知道同窗們有沒有發現問題? 一、打包的hash
都是同樣的,並且每次打包的hash還都不同。 解決方法, output
添加
chunkFilename: utils.assetsPath("js/[name].[chunkhash].js")
複製代碼
new MiniCssExtractPlugin(options)
初始化參數
chunkFilename: utils.assetsPath('css/[id].[chunkhash].css'),
複製代碼
二、venders~app.js
不見了 antdui~app.js
,basic~app.js
只是拆分了antdui|moment|react|react-dom|react-router|react-router-dom|mobx|mobx-react|axios
這些插件。還有其它的node_modules
的插件會被拆分到venders~app.js
。這裏須要知道maxInitialRequests
這個屬性的做用了。
maxInitialRequests
:最大的初始化加載請求次數,爲了對請求數作限制,不至於拆分出來過多模塊
由此發現,加載app.js
的時候有三個文件會同步加載app.js
,antdui~app.js
,basic~app.js
。
須要把maxInitialRequests
的值修改爲更大,修改爲5
maxInitialRequests: 5,
複製代碼
打包測試以下圖:
查看結果venders~app.js
從app.js
中拆分出來啦。
源碼以下:
react+webpack4+react-router5+react-loadable+mobx
系列文章
一、react+webpack4搭建前端項目(一)基礎項目搭建