umi3.5升4,react16.8升18过程和踩坑记录(附完整升级文档)

987 阅读4分钟
起因:热更新太慢了,想改成mfsu,于是直接来一波大升级。(主要需求空缺,今天闲着没事)

本地 node是14.21.3

首先,我是直接删除node_modules以绝后患。

package.json
    更改react版本
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
    更改umi版本
    "umi": "^4.0.40",
    更改@type
    "@types/node": "^18.11.11",
    "@types/react": "^18.0.26",
    "@umijs/max": "4.0.40"
    更改启动命令
    umi dev(build) -> max dev(build)
    umi g tmp -> max setup

直接yarn 开整

  1. ok第一个问题
fatal - AssertionError [ERR_ASSERTION]: Invalid config values: dva
Invalid value for dva:
"hmr" is not allowed

发现是yarn.lock忘记删了,删除掉重新yarn 2. 继续报错

error commander@12.0.0: The engine "node" is incompatible with this module. Expected version ">=18". Got "14.21.3"
找半天也没找到那配置的,而且也不可能把node升到18,于是 暂且 
yarn config set ignore-engines true ok,继续
  1. 又报了第一个错误,good,看来还是得仔细检查一下,又翻了一遍官方文档发现是hmr属性umi4不再支持,如下在config.ts中

image.png

  1. 继续报错
fatal - AssertionError [ERR_ASSERTION]: Invalid config keys: nodeModulesTransform, dynamicImport
好像是一些配置无效了,依然是config.js 删除掉就好

image.png

至此安装依赖完成,尝试启动

  1. 第一个错误,一堆插件引入失效,看上去很可怕,首先dva相关。查阅百度,umi/max不再支持dva:{}这种约定式配置了。创建新项目时会自动安装,但半路升级就得手动引入了
yarn add @umijs/plugin-dva
这里主要使用npm或者yarn需要和上边保持一致,否则会冲突
配置  plugins: ['@umijs/plugins/dist/dva'],
这个时候疯狂报
fatal - Error: Register plugin E:/aproduct/test/ark-datawarehouse-
pc/node_modules/@umijs/plugin-dva/lib/index.js failed, since Cannot read property 't' of undefined
或者
fatal - AssertionError [ERR_ASSERTION]: plugin ./node_modules/@umijs/plugins/dist/dva is 
already registered by E:/aproduct/test/ark-datawarehouse-
pc/node_modules/@umijs/plugins/dist/dva.js, plugin from E:/aproduct/test/ark-datawarehouse-
pc/node_modules/@umijs/plugins/dist/dva.js register failed.
查了一小时百度没搞好,好吧裂开,踩坑了。于是删掉lock和依赖还有.umi。
再次查看官方文档。将comfig.ts修改为如下.根据官方文档说。umi4不需要显示配置插件。只需要model:{}即可。这次貌似跑起来了。

image.png

ok,至此umi相关基本正常了。还会报一些依赖引入的问题,不过不是什么大问题了,这个因项目而异。 (结尾ps: 遇到了@withAliveScope这种写法的一个组件,百度也没查明白。第一反应就是好像spring的注解啊,js也能这么写嘛?---更新:后边搞明白了,类似keep alive做缓存用的,但由于暂不准备学react系源码,所以原理暂不剖析)


团队今年决定大刀阔斧,对后台项目做一次统一的升级。umi从3到umi/max react升18 antd统一升4.x pro-component升2.x

再补充几个坑点:

1:umi/max 不再支持 document.ejs ,里边的引用需要单独配置 2:history.listen监听问题,效果不同于umi3。需根据业务具体改变实现逻辑 -------------更新、完整升级文档产出

  • 环境准备:
    node: '20.19.0'
    删除node_modules、/src/.umi、yarn.lock、npm的缓存
    指令:rm -rf node_modules yarn.lock src/.umi/ && npm cache clean -f

package.json对应版本:
版本限制:

"engines": {
"node": ">=20.19.0"
},

升级:
"@ant-design/pro-components": "^2.3.27",
"react": "^18.2.6",
"react-dom": "^18.2.6",
"react-router": "6.19.0",
"react-router-dom": "6.19.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@umijs/max": "^4.0.0",
"react-activation": "^0.9.12",

"mockjs": "^1.1.0",

删除:
"umi": "^3.2.0",
"umi-plugin-keep-alive": "0.0.1-beta.29",
"@umijs/fabric": "^2.2.0",
"@umijs/plugin-blocks": "^2.0.5",
"@umijs/plugin-qiankun": "^2.11.0",
"@umijs/preset-ant-design-pro": "^1.2.0",
"@umijs/preset-react": "^1.4.8",
修改script命令行:
umi g tmp ===> max setup,
构建指令的umi 全部替换成max

config/config.ts配置修改:
移除以下属性:
nodeModulesTransform: {
type: 'none',
exclude: [],
},
dynamicImport: {
loading: '@/components/PageLoading/index',
},
增加以下属性:
fastRefresh: true,
mfsu: {},
// 手动增加plugins,umi4的入口文件不在时document.ejs 需要手动编译注入模版
plugins: [
require.resolve('../plugins/plugin.templateHtml.ts'), // 参考manage-pc:feature/package-update的plugins/plugin.templateHtml.ts
],
// 主应用需要
router: [
{
path: '/choose-school/', // path使用/,可以匹配所有子应用路由
microApp: 'choose-school-sub',
},
]
// 部分全局css属性没有通过地址引用 可以通过以下配置引入
lessLoader: {
javascriptEnabled: true,
modifyVars: {
...themeConfig
}
},
// 子应用需要
qiankun: {
slave: {},
},
// 主应用需要
qiankun: {
master: {
apps: [
{
name: 'choose-school-sub', // 院校小程序子应用
entry: subUrlObj[REACT_APP_ENV]['choose-school-sub'],
singleton: true, // 单例模式(防止多次初始化) 主要增加这个
},
],
},
},
修改以下配置:
dva: { }, // 不能删除 否则.umi下不会引用相关拓展包
model: {}, // 不能删除 否则.umi下不会引用相关拓展包

config/routes.ts配置修改:
移除以下配置:
// 主应用需要
router: [
{
path: '/choose-school/', // path使用/,可以匹配所有子应用路由
microApp: 'choose-school-sub',
},
]

展开源码

// 将字符串中的所有路径转换为数组 v5版本的路由路径可能包含参数和查询字符串
function getAllPathsV5(str: string) {
let arr = str.split('/').map((item, index) => index > 0 ? `/${item}` : item)
if (!arr.some(item => item.includes('?'))) {
return [arr.join('')]
}
const brr = []
while (arr.some(item => item.includes('?'))) {
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i].includes('?')) {
const str1 = '/'
const str2 = arr[i].replace('?', '')
arr[i] = str1
brr.push(arr.join('').replace(////g, '/').replaceAll('?', ''))
arr[i] = str2
brr.push(arr.join('').replace(////g, '/').replaceAll('?', ''))
arr.splice(i, 1)
continue
}
}
}
return brr.sort((a, b) => a.length - b.length)
}



const resetRoutesV5ToV6 = (temp: any[]) => {
const arr: any = []
temp.forEach((item) => {
if (item?.path?.includes('?')) {
const paths = getAllPathsV5(item.path);
paths.forEach((path) => {
arr.push({
...item,
path,
});
});
} else {
arr.push(item);
}

if (item.routes?.length) {
item.routes = resetRoutesV5ToV6(item.routes);
}
});
return arr;
}

用resetRoutesV5ToV6重置一下routes

文件中需要调整的地方:
1、keep-alive 调整为 react-activation
KeepAlive改为import { AliveScope } from 'react-activation';
umi4 移除了keep-alive 插件 可以使用react-activation 插件实现
2、prompt 调整为 useBlocker钩子函数
umi4 移除了prompt 插件 可以使用useBlocker 实现离开路由的拦截
Prompt 改成引用src/components/Prompt
3、React升级到18之后,移除了defaultProps
可以在super(props)内实现
4、props.children替换为Outlet
5、location改为useLocation取值
6、models里面的subscriptions监听的方法,需要手动触发一次。
umi4种的history.listen做了调整,刷新页面不执行
7、Link
路径需要调整成全路径
Link的to属性 不接受state 需要抽离出来
8、useIntl导出方式
import { useIntl } from 'react-intl';

9、useActivate、useAliveController导入由umi改为‘react-activation’

10、路由跳转改成全路径跳转,routes配置不允许存在?

11,commonModel 改成从useSelector获取

12.history.goBack改成history.back

13.match中取得值(/a/b/:id)import {useParams} from 'umi'const {id} = useParams()

14.query中取得值(/a/b?id=1)import {useSearchParams} from 'umi'import {parse} from 'querystring'const [searchParams] = useSearchParams()const { id } = parse(searchParams.toString())

15.path ( /a/b )import { useLocation } from 'umi';const { pathname: path }: any = useLocation();

16.dispatchimport { useDispatch } from 'umi';const dispatch = useDispatch()

17.keepAlive 调整 更改引用并用AliveScope包裹----import { keepAlive } from 'umi'---import { AliveScope, keepAlive } from 'react-activation'

18.router.tsconponent为404的 增加path: '*'

19.hisoty.push携带query

import {history} from 'umi'query变成search

history.push({
pathname:'/a/b',--qyery: {id}
++search:?id=${id},
});