从 UmiJS 迁移到 Vite 过程
为什么要替换UmiJS
UmiJS
对于开发者而言,好处有开箱即用、配置少、功能多、文档齐全等等。对于团队来说更容易协作,更多注意力关注于需求的实现,进而提升开发效率。
随着项目日益增长,需求不断迭代的情况下:一次启动一个项目要1分钟以上,修改一次代码热更新半天,极度吃内存。 特别是我们平台是一个微前端项目,总共有40来个子应用,想想同时需要启动多个子应用进行开发...💢💢💢
总结下对于 UmiJS
主要痛点是:
- 启动时间过长
- 热更新慢
- 框架高度封装,扩展功能不方便,自定义插件开发难度较高
尽管我们对全平台进行了一次体积优化、构建速度优化,但是效果还是不显著。
为什么选择 Vite
最主要的几个点是:
- 极速的服务启动
- 轻量快速的热重载
- 优化的构建
极速的服务启动
当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。
Vite 通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。
- 依赖:使用
go
编写的esbuild 预构建依赖
, 速度比js
编写的打包器预构建依赖快 10-100 倍。 - 源码:非
js
类文件(tsx
、jsx
)时常会被编辑,但是又不需要所有的源码都被加载。(例如基于路由拆分的代码模块)。Vite
以原生ESM
方式在浏览器请求源码时按需提供源码,让浏览器接管打包程序的部分工作。
迁移
- 按
Vite
官方指令生成一个vite-react
项目模板,并安装vite-plugin-legacy-qiankun
插件对qiankun
进行支持。
main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from "react-router-dom";
import { createLifecyle, getMicroApp } from 'vite-plugin-legacy-qiankun';
const appName = 'vite-react';
const microApp = getMicroApp(appName);
const render = () => {
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>,
);
};
if (microApp.__POWERED_BY_QIANKUN__) {
createLifecyle(appName, {
mount() {
console.log('mount', appName);
render();
},
bootstrap() {
console.log('bootstrap', appName);
},
unmount() {
console.log('unmount', appName);
},
});
} else {
render();
}
- 启动后发现报错
[less] '~@sensoro-design/styles/style/themes/default.less' wasn't found. Tried
原因:vite 无法识别 ~
符号
解决方案:添加 resolve.alias
配置替换
export default defineConfig({
// ...
resolve: {
alias: [
// https://github.com/vitejs/vite/issues/2185#issuecomment-784637827
{
find: /^~/,
replacement: '',
},
],
}
})
- 使用
vite-plugin-externals
配置外部扩展
export default defineConfig({
// ...
plugins: [
// ...
viteExternalsPlugin({
react: 'React',
'react-dom': 'ReactDOM',
lodash: '_',
}),
]
})
- 报错
import { bpfrpt\_proptype\_WindowScroller } from "../WindowScroller.js
原因:在 react-virtualized
被打包过程中, vite
未删除对已移除代码的引用
解决方案:先进行了手动移除处理
import type { PluginOption } from 'vite';
import { createRequire } from 'node:module';
import { URL } from 'node:url';
import { join } from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs';
const WRONG_CODE = `import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";`
export function virtualized(): PluginOption {
return {
name: 'flat:react-virtualized',
configResolved: async () => {
// @ts-ignore
const url = import.meta.url;
const require = createRequire(url)
const reactVirtualizedPath = require.resolve('react-virtualized')
const { pathname: reactVirtualizedFilePath } = new URL(reactVirtualizedPath, url)
const file = reactVirtualizedFilePath
.replace(
join('dist', 'commonjs', 'index.js'),
join('dist', 'es', 'WindowScroller', 'utils', 'onScroll.js'),
)
const code = readFileSync(file, 'utf-8')
const modified = code.replace(WRONG_CODE, '')
writeFileSync(file, modified)
},
}
}
vite
打包正式环境 require is not defined
原因:vite
不支持 require
引入文件,一些第三方的包会使用这种方式引用。
解决方案:开启打包混合模式转换
export default defineConfig({
// ...
build: {
commonjsOptions: {
transformMixedEsModules: true,
},
},
})
结语
替换 vite
之后,对开发时的启动速度和热更新速度有质的提升,后续有其他新发现会再次更新。
转载自:https://juejin.cn/post/7240998073647136829