将一个老项目的 Web 应用框架升级为 Umi 4.0

背景

该项目使用的 Web 应用模板是react-starter-kit,使用的是 2017 年的版本,目前主要遇到如下几个问题:

  1. 一直没有太大的升级,只对依赖的 React、Webpack、AntDesign 进行必要的升级,升级和维护成本也比较高,并且缺少对 React Router、Vite、TypeScript 的支持,不利于之后的代码维护和新特性的使用。
  2. 打包性能比较差,目前需要 1 分 08 秒。

升级中遇到的问题

获取 URL 的查询字符串

在 react-starter-kit 中,可以通过 context 获取查询对象,例如:

js 复制代码
function action(context) {
  const { query } = context;
  return {
    component: <Admin query={query} />,
  };
}

而在 umi 中,在函数组件里可以通过 useSearchParams 获取,例如:

js 复制代码
function Admin() {
    const [searchParams, setSearchParams] = useSearchParams();
    return <div>{searchParams.get('name')}<div>
}

在类组件里可以通过 createSearchParams 获取,例如:

js 复制代码
class Admin extends React.Component {
  const searchParams = createSearchParams(window.location.search);
  render() {
    return <div>{searchParams.get('name')}<div>
  }
}

考虑到老项目里都是处理之后通过 props 传递给组件,则可以抽象成一个高阶组件,单独处理获取 URL 的查询字符串的逻辑,这样大部分组件都不需要进行改动,例如:

高阶函数 WrappedComponent

js 复制代码
const getSearchParams = () => {
  const searchParams = createSearchParams(window.location.search);
  if (!searchParams) return {}
  const params = {};
  for (const [key, value] of searchParams.entries()) {
    params[key] = value;
  }
  return params;
}

export default function WrappedComponent(WrappedComponent) {
  return (props) => {
    const searchParams = getSearchParams()
    return <WrappedComponent {...props} {...searchParams} />
  }
}
js 复制代码
class Admin extends React.Component {
  render() {
    return <div>{this.props.name}<div>
  }
}
export default WrappedComponent(Admin)

如何配置国际化

Ant Design 里支持使用 ConfigProvider 进行国际化配置,可以放在任何需要国际化的组件中,而我们希望该配置是全局性的,所以在 Umi 中可以配置在 layouts/index.tsx 里,例如:

js 复制代码
import { Outlet } from 'umi';
import {ConfigProvider} from 'antd'
import zhCN from "antd/locale/zh_CN";

export default function Layout() {
  return (
      <ConfigProvider locale={zhCN}>
          <div>
            <Outlet />
          </div>
      </ConfigProvider>
  );
}

在这里有一点需要注意,因为在老项目里我使用的日期库是 moment,则还需要加上 moment 的国际化配置,例如:

js 复制代码
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');

如果使用的 Ant Design 5.0 默认的 Day.js,则也需要进行相应的配置。

静态部署问题

我们老项目是使用静态站点托管,需要对每个路由单独输出 HTML 文件,配置如下:

js 复制代码
/* .umirc.ts */
export default defineConfig({
    exportStatic: {},
})

Ant Design 5.0 里的日期库自定义问题

我们老项目的日期库使用的 moment.js,而 Ant Design 5.0 默认使用的 Day.js,导致升级之后时间组件报错,在这里可以使用 @ant-design/moment-webpack-plugin 插件,无需对现有代码做任何修改直接替换成 Moment.js,配置如下:

js 复制代码
/* .umirc.ts */
export default defineConfig({
    chainWebpack: (config) => {
        config.plugin('moment-webpack-plugin').use(AntdMomentWebpackPlugin)
        return config
    },
    mfsu: {
        // @ts-ignore
        chainWebpack(config) {
            config.plugin('moment-webpack-plugin').use(AntdMomentWebpackPlugin)
            return config
        },
    },
})

在这里需要注意的是在 mfsu 里也同样要配置 chainWebpack,因为 mfsu 是默认开启的,不配置会导致无法替换成 Moment.js。

Ant Design 5.0 里的组件样式自定义问题

有时候我们希望可以自定义 Ant Design 5.0 里的组件样式,比如图片上传组件 Upload,则可以进行如下配置:

js 复制代码
<Upload
    listType="picture-card"
    accept="image/*"
  >
</Upload>

CSS 文件

css 复制代码
.ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload.ant-upload-select {
  width: 375px;
  height: 300px;
}

.ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload.ant-upload-select > .ant-upload {
  display: block;
}

考虑到这个样式修改是全局性的,所以建议在这里增加 className="avatar-uploader"(可以是任何值),好处是避免污染全局样式

js 复制代码
<Upload
    listType="picture-card"
    className="avatar-uploader"
    accept="image/*"
  >
</Upload>
css 复制代码
.ant-upload-wrapper.ant-upload-picture-card-wrapper.avatar-uploader .ant-upload.ant-upload-select {
  width: 375px;
  height: 300px;
}

.ant-upload-wrapper.ant-upload-picture-card-wrapper.avatar-uploader .ant-upload.ant-upload-select > .ant-upload {
  display: block;
}

总结

升级之后带来了如下好处:

  1. 降级了升级和维护成本。之前的 Web 应用模板没有任何封装,几乎无法升级,现在则可以通过 umi 进行升级。
  2. 升级之后可以天然享受到对 React Router、Vite、TypeScript、Ant Design、路由数据加载的支持,并且提供的 MFSU 拥有比 Vite 更快的打包速度,将打包速度从 1m8s 秒减少到 17s。

参考

相关推荐
顾安r2 小时前
11.8 脚本网页 星际逃生
c语言·前端·javascript·flask
Hello.Reader2 小时前
Data Sink定义、参数与可落地示例
java·前端·网络
im_AMBER2 小时前
React 17
前端·javascript·笔记·学习·react.js·前端框架
谷歌开发者3 小时前
Web 开发指向标 | Chrome 开发者工具学习资源 (六)
前端·chrome·学习
一晌小贪欢3 小时前
【Html模板】电商运营可视化大屏模板 Excel存储 + 一键导出(已上线-可预览)
前端·数据分析·html·excel·数据看板·电商大屏·大屏看板
发现你走远了3 小时前
连接模拟器网页进行h5的调试(使用Chrome远程调试(推荐)) 保姆级图文
前端·chrome
街尾杂货店&4 小时前
css - 实现三角形 div 容器,用css画一个三角形(提供示例源码)简单粗暴几行代码搞定!
前端·css
顺凡4 小时前
删一个却少俩:Antd Tag 多节点同时消失的原因
前端·javascript·面试
小白路过4 小时前
CSS transform矩阵变换全面解析
前端·css·矩阵
爬山算法4 小时前
Redis(110)Redis的发布订阅机制如何使用?
前端·redis·bootstrap