create-react-app 打包优化(antd、echarts)

玉臂匠
• 阅读 11560

我做 react 开发时通常是直接用的 create-react-app。最近想分析一下一个用 create-react-app 开发的项目的打包结果,看看有没有什么可以优化的地方。

项目情况

执行 npm run eject 导出配置(单向操作,不可逆)。
项目中使用的一些库:

"dependencies": {
    "antd": "^3.9.2",
    "axios": "^0.18.0",
    "echarts": "^3.8.5",
    "less": "^3.0.1",
    "moment": "^2.21.0",
    "react": "^16.4.2",
    "react-dom": "^16.2.0",
    "react-router-dom": "^4.2.2",
},
"devDependencies": {
    "babel-loader": "7.1.2",
    "babel-plugin-import": "^1.6.5",
    "webpack": "3.8.1",
    "webpack-bundle-analyzer": "3.0.2",
}

antd 按需加载

按照官网配置,使用 babel-plugin-import,在 package.json 中配置:

  "babel": {
    "plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": true
        }
      ]
    ]
  }

项目中直接使用:

import { Button } from 'antd';

Moment.js locale 打包优化

create-react-app 的 webpack 已经做好配置了:

plugins: [
    ...
    // Moment.js is an extremely popular library that bundles large locale files
    // by default due to how Webpack interprets its code. This is a practical
    // solution that requires the user to opt into importing specific locales.
    // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
    // You can remove this if you don't use Moment.js:
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
    ...
]

router component 懒加载

import React from 'react';

export default class Bundle extends React.Component {
    state = {
        mod: null
    }

    componentWillMount() {
        this.load(this.props);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.load !== this.props.load) {
            this.load(nextProps);
        }
    }

    async load(props) {
        this.setState({
            mod: null
        });
        /*
          使用 props.load() 返回的是一个 promise
         */
        const mod = await props.load();

        this.setState({
            mod: mod.default ? mod.default : mod
        });
    }

    render() {
        return this.state.mod ? this.props.children(this.state.mod) : null;
    }
}
const lazyLoad = loadComponent => props => (
    <Bundle load={loadComponent}>
        {Comp => (Comp ? <Comp {...props} /> : <Loading/>)}
    </Bundle>
);

使用:

// dynamic import
const Demo = lazyLoad(() => import('../components/demo'));

// react-router
<Route path="/demo" component={Demo} />

分析项目打包情况

使用工具webpack-bundle-analyzer,将打包内容转换成可缩放的树状图。

// 安装
yarn add -D webpack-bundle-analyzer

config/webpack.config.dev.jsconfig/webpack.config.prod.js 中添加:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
...
plugins: [
    ...
    new BundleAnalyzerPlugin(),
    ...
]
...

默认在 127.0.0.1:8888 页面显示。
添加在 config/webpack.config.dev.js后,每次 npm start 时都会弹出分析页面。
添加在 config/webpack.config.prod.js后,每次 npm build 时都会弹出分析页面。
项目分析结果:
create-react-app 打包优化(antd、echarts)

发现问题:

  1. 多个 chunk 中重复打包了相同的 antd 组件代码(table, pagination, .etc)。
  2. echarts 全部打包了进来,体积太大。

优化

antd 组件代码重复打包问题

由于我对 webpack 不算太熟,知道 webpack 3 中可以用 plugin CommonsChunkPlugin 抽取公共代码,但具体用法不甚明了,折腾了很久都没有作用,终于在 antd github 的 issues 中找到答案

plugins: [
    ...
    new webpack.optimize.CommonsChunkPlugin({
      minChunks: 2,
      minSize: 0,
      children: true,
      deepChildren: true,
      async: true
    }),
    ...
]

似乎去掉 name 就可以了?这一点我还没搞清楚是为什么。

echarts 按需加载

参考在 webpack 中使用 ECharts

import echarts from 'echarts/lib/echarts';
import 'echarts/lib/chart/map';
import 'echarts/lib/chart/pie';
import 'echarts/lib/chart/scatter';
import 'echarts/lib/chart/effectScatter';
import 'echarts/lib/component/geo';
import 'echarts/lib/component/tooltip';
import chinaJson from 'echarts/map/json/china.json';

...
echarts.registerMap('china', chinaJson);
...

需要注意,可以按需引入的模块列表见 https://github.com/ecomfe/ech...

优化结果

create-react-app 打包优化(antd、echarts)

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
玉臂匠
玉臂匠
Lv1
两岸猿声啼不住,轻舟已过万重山。
文章
4
粉丝
0
获赞
0