将一个老项目的 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。

参考

相关推荐
工呈士3 分钟前
HTML 模板技术与服务端渲染
前端·html
皮实的芒果5 分钟前
前端实时通信方案对比:WebSocket vs SSE vs setInterval 轮询
前端·javascript·性能优化
鹿九巫5 分钟前
【CSS】层叠,优先级与继承(三):超详细继承知识点
前端·css
奕云6 分钟前
react-redux源码分析
前端
咸鱼一号机7 分钟前
:global 是什么
前端
专业掘金7 分钟前
0425 手打基础丸
前端
五号厂房7 分钟前
Umi Max 如何灵活 配置多环境变量
前端
红尘散仙10 分钟前
六、WebGPU 基础入门——Vertex 缓冲区和 Index 缓冲区
前端·rust·gpu
南望无一10 分钟前
webpack性能优化和构建优化
前端·webpack
il11 分钟前
Deepdive into Tanstack Query - 2.0 Query Core 概览
前端·javascript