记解决 `antd is not defined` 解决ant design 打包体积过大的问题

用 react antd开发了一个页面,最后webpack打包的大小竟然达到了 1.9M ,gzip压缩之后也有500kb。

这超出了能承受的范围,我一个小网站哪有这么大的带宽。

1. 找原因

开始的时候并不知道是antd的锅,后来发现了一些工具可以提供UI来分析打包的js的组成部分。比如这个: https://www.npmjs.com/package/webpack-bundle-analyzer

借助这个工具,我看到了打包的js绝大部分都是antd带来的。我首先确认了我配置了antd官方提供按需加载的,所以应该不是按需加载出了问题。然后经过仔细分析发现主要是下面4个原因:

icons

antd的icons占用了很大的部分。原因是正常情况下icons是不会按需加载的,只能全部引用。很多人也遇到这个问题,antd官方给出了一个workaround,稍微有点麻烦,因为你需要自己去找你引用了那些icon:https://github.com/ant-design/ant-design/issues/12011#issuecomment-420038579

base css

我的页面基本上只用了一个table,但是antd的css体积也达到了了几百kb。原因是antd的css虽然可以按需加载,但是一些基础的base css是一定会被打包的。这一点没有找到解决方案。

moment.js

我自己没有用到moment.js,但是antd用到了moment.js,moment.js也是占用了不小的体积。这个是有一个plugin可以减少moment.js的体积的。原理是让webpack只加载你用到了语言包。插件是:new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/)

 

lodash

同样我没有用到lodash,但是antd用到了。lodash也有一个plugin去减少webpack打包的体积:lodash-webpack-plugin

2. 使用antd的公共cdn去解决。

上面分析了antd之所以很大的原因。有些是解决不了的,比如css太大的问题。那么自然就想到了能不能不把antd打包进去,而是在网页中通过cdn引入antd呢?cdn又不走我的网站带宽。答案是可以的,这就是webpack的externals配置。于是我决定使用antd的cdn去解决打包体积太大的问题。

3. 解决 antd is not defined 问题。

开始的时候这样做的,在webpack的externals里面只配置了antd

 

  externals: {
    'antd': 'antd'
  },

 

然后在页面引入antd的cdn

<link rel="stylesheet" href="https://cdn.bootcss.com/antd/3.23.3/antd.min.css">
<script src="https://cdn.bootcss.com/antd/3.23.3/antd.min.js" type="text/javascript"></script>

这样做之后,整个打包的体积直接降到了几百kb,不过遗憾的是打开页面出现了 antd is not defined。这个开始也是束手无策,网上并没有搜到好的解决办法。后来找到了原因,不能直接引入antd的cdn,在这之前要把antd依赖的其他资源也加进来。那么antd依赖的哪些呢?首先react和react-dom是必须的。加进来之后,还是有问题。于是再仔细读antd的文档,发现下面的内容:

支持环境#

    现代浏览器和 IE9 及以上(需要 polyfills)。
    强烈不推荐使用已构建文件,这样无法按需加载,而且难以获得底层依赖模块的 bug 快速修复支持。

    注意:3.0 之后引入 antd.js 前你需要自行引入 moment。

吐槽下这个推荐。虽然它强烈不推荐使用已构建文件,但是没办法啊,antd的按需加载做的确实有问题。

因为我用的3.x 版本,所以还要引入polyfills和moment。加上之后,终于可以了。同时因为webpack去掉了polyfills,react,react-dom,最终的打包体积只剩下了100kb了(gzip压缩前)。

最终的代码:

  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM',
    'antd': 'antd'
  },
  <link rel="stylesheet" href="https://cdn.bootcss.com/antd/3.23.3/antd.min.css">
  <script src="https://cdn.bootcss.com/babel-polyfill/7.6.0/polyfill.min.js"></script>
  <script src="https://cdn.bootcss.com/react/16.9.0/umd/react.production.min.js"></script>
  <script src="https://cdn.bootcss.com/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
  <script src="https://cdn.bootcss.com/moment.js/2.24.0/moment.min.js"></script>
  <script src="https://cdn.bootcss.com/moment.js/2.24.0/locale/zh-cn.js"></script>
  <script src="https://cdn.bootcss.com/antd/3.23.3/antd.min.js" type="text/javascript"></script>

最后温馨提示,用cdn最好加上fallback,当cdn不幸挂了的话,换另一家cdn。

<script>window.antd||document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.23.6/antd.min.js"><\/script>')</script>

 

上一篇:【java】关于Cannot refer to the non-final local variable list defined in an enclosing scope解决方法


下一篇:Target runtime Apache Tomcat 6.0 is not defined 解决方法(转)