Ant Design Pro实战:从搭建到优化的完整开发经验分享

俊杰(打工版) 框架 阅读 1,993
赞 3 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

上周接手一个老 Ant Design Pro 项目,打开首页直接卡住 3 秒多,表格页滚动掉帧,切换菜单时明显卡顿。最离谱的是,登录后首屏加载时间飙到 5.2 秒(本地 dev server,没开 sourcemap),用户反馈“点一下等半天”,我本地开发都忍不住想砸键盘。

Ant Design Pro实战:从搭建到优化的完整开发经验分享

这项目用了 Ant Design Pro V5,基于 Umi + React + Ant Design,页面不算特别复杂,但 bundle 体积大得离谱——主包 4.8MB,vendors 包 6.1MB。光是 antd 组件就全量引入了,lodash 也整个打进来了,更别说一堆没用的图表库和工具函数。

找到瓶颈了!

先别急着改代码,得知道慢在哪。我干了三件事:

  • 用 Chrome DevTools 的 Performance 面板录了一次首页加载,发现 scripting 时间占了 70% 以上,主要是大量模块初始化和 React 渲染
  • npx source-map-explorer build/static/js/*.js,一眼看到 antd、moment、echarts、lodash 占了大头
  • 在 Umi 配置里开了 analyze: { analyzerMode: 'server' },启动后自动打开 bundle 分析图,vendors 里 antd 相关模块密密麻麻

结论很明确:**包太大 + 按需加载没配好 + 首屏渲染做了太多事**。

核心优化:砍包 + 懒加载 + 渲染瘦身

折腾了两天,主要动了三块地方,效果立竿见影。

1. 彻底解决 antd 全量引入问题

项目里明明用了 babel-plugin-import,但配置错了。原来写的是:

// .umirc.ts 错误配置
export default {
  extraBabelPlugins: [
    ['import', { libraryName: 'antd', style: true }],
  ],
}

结果 Umi 内部已经内置了按需加载,再手动加反而冲突。正确做法是:删掉 extraBabelPlugins 里的 import 配置,Umi 默认就支持 antd 按需加载。改完后,antd 相关体积从 2.1MB 降到 400KB 左右。

另外,检查所有组件是否真的按需引入。比如有人写了 import { Button, Table, Modal } from 'antd',这是对的;但如果有 import antd from 'antd' 就完蛋了。全局搜了一遍,修了两处。

2. 路由级懒加载 + 组件级懒加载

Ant Design Pro 默认用 Umi 的动态路由,但有些页面还是同步加载。我把所有非首屏页面都改成懒加载:

// config/routes.ts
export default [
  {
    path: '/dashboard',
    component: './Dashboard',
    // 改成
    component: () => import('@/pages/Dashboard'),
  },
  {
    path: '/user',
    component: () => import('@/pages/User'),
  }
]

更狠的是,对页面内部的大组件也做懒加载。比如有个数据看板页,里面嵌了三个大图表,我用 React.lazy + Suspense 包起来:

const ChartA = React.lazy(() => import('./ChartA'));
const ChartB = React.lazy(() => import('./ChartB'));

const Dashboard = () => {
  return (
    <div>
      <Suspense fallback={<Spin />}>
        <ChartA />
        <ChartB />
      </Suspense>
    </div>
  );
};

这样首屏只加载必要内容,图表等用户滚动到可视区域再加载(配合 IntersectionObserver 更佳,但这里先求快)。

3. 干掉 moment,换成 dayjs

antd 依赖 moment,但 moment 太重(300KB+)。Umi 提供了替换方案,在 .umirc.ts 里加:

export default {
  define: {
    'process.env.USE_DAYJS': true,
  },
  chainWebpack(memo) {
    memo.plugins.delete('moment');
  },
}

同时安装 dayjsantd-dayjs-webpack-plugin

npm install dayjs antd-dayjs-webpack-plugin

然后在 config/config.ts 里配置:

import AntdDayjsWebpackPlugin from 'antd-dayjs-webpack-plugin';

export default {
  chainWebpack(config) {
    config.plugin('antd-dayjs').use(AntdDayjsWebpackPlugin);
  }
}

搞定后,moment 相关代码彻底消失,减了 300KB+。注意:有些老代码用了 moment 的 API,得手动替换成 dayjs,但工作量不大。

4. 首屏渲染优化:别在 render 里干重活

发现有个列表页,每次渲染都要处理上千条数据,还用了 map + filter + sort 嵌套,直接卡死。优化思路:**计算移到 useEffect 里,结果缓存**。

优化前:

const UserList = ({ users }) => {
  const filteredUsers = users
    .filter(u => u.active)
    .sort((a, b) => a.name.localeCompare(b.name))
    .map(u => ({ ...u, displayName: ${u.name} (${u.role}) }));

  return <Table dataSource={filteredUsers} />;
};

优化后:

const UserList = ({ users }) => {
  const [filteredUsers, setFilteredUsers] = useState([]);

  useEffect(() => {
    const result = users
      .filter(u => u.active)
      .sort((a, b) => a.name.localeCompare(b.name))
      .map(u => ({ ...u, displayName: ${u.name} (${u.role}) }));
    setFilteredUsers(result);
  }, [users]);

  return <Table dataSource={filteredUsers} />;
};

虽然简单,但实测列表渲染从 1200ms 降到 200ms 以内。如果数据量更大,还可以加 useMemo 缓存,但这里 useEffect 足够了。

其他小优化(带过)

  • 删掉不用的依赖:项目里装了 lodash,但只用了 debouncethrottle,直接换成原生或 tiny-lodash,省了 70KB
  • 图片压缩:用 imagemin-webpack-plugin 压缩静态资源,图片体积减半
  • 开启 Gzip:Nginx 层配置 gzip,传输体积再减 70%
  • 避免在 render 里创建新函数:把 onClick={() => handle(id)} 改成 useCallback 包裹,减少子组件重渲染

性能数据对比

优化前后关键指标(本地 dev server,无 sourcemap,Chrome 无痕模式):

  • 首屏加载时间:5.2s → 800ms(下降 85%)
  • 主包体积:4.8MB → 1.1MB
  • vendors 体积:6.1MB → 1.9MB
  • 内存占用:从 400MB+ 降到 200MB 左右

上线后,用户反馈“终于不卡了”,老板也松了口气。其实很多优化都是老生常谈,但 Ant Design Pro 项目容易踩的坑就是:默认配置不够激进,开发者又懒得调,结果包越滚越大。

最后说两句

这次优化后,仍有两个小问题:一是某些低端机上长列表滚动还是轻微掉帧(后续考虑虚拟滚动),二是首屏 API 请求太多(可合并或缓存)。但整体体验已经从“不能用”变成“流畅”,值了。

以上是我个人对 Ant Design Pro 性能优化的实战总结,核心就是:**砍包、懒加载、别在 render 里干重活**。有更优的实现方式欢迎评论区交流,比如你们怎么处理超大表格的?我还在找更好的方案。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论