记一次react前端项目打包优化

4,330 阅读2分钟

前文

之前一年多前接手的一个react项目,前段时间因为做业务中台项目,对公司现有的应用项目做中台化改造,这期间将项目部署到uat环境,
测试期间,测试小妹妹和产品大叔都吐槽进入uat项目的时候要load很久,白屏时间超过30s,体验很差,
生产不至于这么慢但也是白屏时间挺长的,所以减少白屏时间增加用户体验成为了当务之急。

分析

通过控制台判断加载资源时间还有资源大小

资源加载时间和大小

通过开发者工具可以看到白屏的主要原因在于bundle.js这个打包后的文件过大,达到3.6M
加上uat环境带宽等问题的话,光加载这个bundle.js就花了30s+,所以白屏时间太长,用户体验差
要解决这个问题就得从这个bundle.js入手

通过webpack-bundle-analyzer来分析主要是哪些模块过大

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const webpackConfigDev = {
    plugins: [
        ......
        new BundleAnalyzerPlugin({ analyzerPort: 3012 }),
    ]
}

本地开发打包结果

这是本地开发时候打包的情况,没有gzip的情况下是这么大的,本地开发编译打包也是挺慢的
从上图看可以分析出几个比较大的模块,其中一个最大的是echarts,另外就是源文件src目录下的代码
所以优化分为三步来走:
1.优化echarts;
2.优化src下的业务代码;
3.对打包后的文件进行gzip压缩;

优化

优化echarts

echarts在项目中用到的地方不少,但是业务平时很少用到对应的模块,整个打包进去bundle.js只会让整个包变大
思路是echarts文件不打包进bundle.js,采用cdn的方法引入

优化echarts相关代码

1.入口文件index.html这里直接用script直接引入cdn的echarts文件
<head>
     <meta charset="UTF-8">
     <meta http-equiv="Cache-Control" content="max-age=604800" />
     <script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script>
     <title>TCRM</title>
 </head>
 <body>
 2.使用echarts的地方改为下面这样引入
原先的    var myChart = echarts.init(this.refs.char,'crm');
改版后    var myChart = this.$echarts.init(this.refs.char,'crm');

优化src文件

对于用户来说,可能每次操作的时候只操作对应的几个模块,其他模块很少操作到,如果能够按需加载那就可以化整为零
每次加载当前模块的chunk,既不影响用户使用,又减少加载的资源
参考了一下其他文章,决定采用react-loadable进行切割划分,按路由来切割资源

react-loadable相关代码

原先写法,组件引入
import Dashboard from './components/Dashboard';

使用react-loadable后
import Loadable from 'react-loadable';
const LoadingFun = () => {
    return <div className="center-div"><Spin spinning={true} size="large" tip="加载中..."/></div>;
};
const Dashboard = Loadable({loader: () => import('./components/Dashboard'), loading: LoadingFun});

webpack相关
const webpackConfigBase = {
    ......
    output: {
        path: resolve('./dist'),
        filename: 'bundle.[hash:6].js',
        chunkFilename: 'chunks/[name].[hash:6].js',
    }   
}

本地运行分chunks打包

分步打包碰到的问题

1.打包样式问题,所有的css打包到bundle.css中,但是采用按路由打包后测试的小妹妹反馈样式很奇怪
看了一下加载的资源,发现确实没有打包到不同路由下的样式,检查了一下,发现是webpack配置里面要配合改一下
const webpackConfigBase = {
    ......
    plugins: [
        // 提取css
        //原先的 new ExtractTextPlugin('bundle.[hash:6].css'),
        new ExtractTextPlugin({filename: 'bundle.[hash:6].css', allChunks: true}), // 增加一个allChunks:true 
    ]
}
2.chunk的名字问题,先要指定对应的chunkName参考 https://github.com/mrdulin/blog/issues/43

gzip压缩

项目是用的nginx做代理调用打包后的资源,所以可以考虑在nginx这一层增加配置配合gzip文件

新增相关配置

gzip  on;
gzip_min_length  1k;
gzip_buffers     4 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types       text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;

优化成果

echarts通过cdn引入,成功
bundle.js体积大大减小,加载时间也由原先的30s+降到了3s+,生产环境带宽更高会更快,成功
切换路由加载对应的chunk文件,使用正常,成功

2020.6.8更新

通过cdn引入echart中原先的写法会读取不到echart的资源,排查了一下重新做了修改
可以在控制台模拟是否能获取到echart的方法进行调试
原先的    var myChart = this.$echarts.init(this.refs.char,'crm');
改版后    var myChart = window.echarts.init(this.refs.char,'crm');