前言
一個umijs項目,打包后發現體積過大,想優化, 看到各種博客上的優化手段是基於webpack的,於是我花了幾天把項目轉成webpack5的, 優化打包后比原來還大.... 最終還是在原來的umijs基礎上進行了優化.
打包分析
umi項目在package.json加一個腳本語句 "analyze": "cross-env ANALYZE=1 umi build", 執行yarn analyze 即可在ANALYZE server上得到依賴包分析圖
"scripts": {
"start": "cross-env UMI_ENV=dev umi dev",
"build": "cross-env UMI_ENV=prod umi build",
"analyze": "cross-env ANALYZE=1 umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
webpack需要安裝 webpack-bundle-analyzer 插件 並在配置文件中配置 new BundleAnalyzerPlugin().
針對性優化(antd echart lodash momentjs)
經過分析發現, antd echart lodash momentjs四個依賴包占的體積最大
antd
umijs對antd組件庫有良好支持, 使用插件集@umijs/preset-react或@umijs/plugin-antd整合antds組件庫就自動是按需引入, 在webpack下需要使用bebel插件 babel-plugin-import 並在webpack.config.js(這個更靠譜)或babelrc配置
echart
echartc5的按需引入在官網有示例 實例
// 引入 echarts 核心模塊,核心模塊提供了 echarts 使用必須要的接口。
import * as echarts from 'echarts/core';
// 引入柱狀圖圖表,圖表后綴都為 Chart
import { BarChart } from 'echarts/charts';
// 引入提示框,標題,直角坐標系,數據集,內置數據轉換器組件,組件后綴都為 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
DatasetComponentOption,
TransformComponent
} from 'echarts/components';
// 標簽自動布局,全局過渡動畫等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必須的一步
import { CanvasRenderer } from 'echarts/renderers';
// 注冊必須的組件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
// 接下來的使用就跟之前一樣,初始化圖表,設置配置項
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
// ...
});
實測對項目整體打包體積的優化用處不大, 采取了定制echarts.min.js的方式 定制地址
echarts4的體積比echart5小, 頁面生成echarts.min.js加入到項目的public文件夾
在document.ejs引入
<script src="<%= context.config.publicPath +'echarts.min.js'%>" > </script>
在.umirc.js添加配置
externals: {
echarts: 'echarts'
},
使用示例: echart組件封裝
import React, { useEffect, useState, useRef } from 'react'
import echarts from 'echarts'
const Echarts = (props) => {
const { option } = props
const [chart, setChart] = useState()
const domRef = useRef()
useEffect(() => {
const instance = echarts.init(domRef.current)
const chartResize = () => {
instance.resize()
}
setChart(instance)
window.addEventListener('resize', chartResize)
return () => {
window.removeEventListener('resize', chartResize)
}
}, [])
useEffect(() => {
if (chart) {
chart.setOption(option)
}
}, [option])
return <div ref={domRef} style={{ height: '100%', width: '100%' }} />
}
export default Echarts
lodash
代碼中的全部引入改為部分引入
```
import _ from 'lodash'
改為
import { extend, omit, difference } from 'lodash'
```
devDependencies中安裝兩個插件 babel-plugin-lodash 和 lodash-webpack-plugin
.umirc.js中配置
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
export default defineConfig({
...
extraBabelPlugins: ['lodash'],
chainWebpack: (config, { webpack }) => {
if (process.env.NODE_ENV === 'production') { // 生產模式開啟
config.plugin('LodashModuleReplacementPlugin').use(
new LodashModuleReplacementPlugin()
); // 壓縮lodash
}
},
})
momentjs
moment的體積也是很大,使用webpack.IngorePlugin插件忽略其locale能很好的壓縮體積
.umirc.js中配置
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
export default defineConfig({
...
extraBabelPlugins: ['lodash'],
chainWebpack: (config, { webpack }) => {
if (process.env.NODE_ENV === 'production') { // 生產模式開啟
config.plugin('igncore').use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
config.plugin('LodashModuleReplacementPlugin').use(
new LodashModuleReplacementPlugin()
); // 壓縮lodash
}
},
})
也可以使用dayjs替換moment, dayjs體積非常小. antd組件庫有使用到moment,也需要進行替換 官方文檔操作說明