曲折的 Vue 3 重构后台之路
3个月前,曾经有过想法重构现在的后台。Vue 3 也正式发布很久了,所以是时候重构到 Vue 3 了。但是由于当时尝试了很多 UI 库之后都没有找到一个好用的库。没有一个库能很好的支持 TSX。所以在多次更换 UI 库之后放弃了。
三个月之后的现在,偶然看到一个新库 naive ui,第一感觉这个库没有特别之处, UI 上和 antd 基本一致,就是换了个颜色?之后看了一下代码,嗯,全都是用TypeScript 写的。于是就有了试试的想法。一番 demo 之后决定捡起三个月前的项目重构成 naive-ui。
CommonJS 在 prod 中的问题
刚开始基本都是一帆风顺,很快的就重构了之前用 element-ui 写的没法看的 table组件。但是之后在build之后的prod环境下出了问题。dev 和 prod不一致。prod 开发一直白屏,控制台却没有任何报错和警告。这让我直接慌了,难道又要失败了?后来发现可能是 router guard 这块有问题,注释掉 guard 之后,果然就有报错了。但是还是不知道哪里的问题,因为没有 sourcemap。
我在解决问题之后构建了一个最小化复现项目,你想要来看看是什么原因导致的吗?reproduction
这个是一个 CommonJS 模块,是这样导入的。
import * as camelcaseKeys from 'camelcase-keys'
在开发环境是一点问题都没有啊。生产环境就报错了。那么为什么会在 router guard 中出问题了,是因为在 router guard 中做了请求的鉴权,然后 response 做了一次 camelCase 处理用到了这个库。奇怪的是没有报错,而是在 router guard 一直在做死循环。
router guard 的代码如下,请求库采用 umi-request,鉴权接口用 github api 代替:
router.beforeEach(async (to) => {
if (to.meta.isPublic) {
return
} else {
// 在这里发送请求, 一般用于鉴权. 由于是复现, 随便用了接口请求
const res = await RESTManager.api.users.octocat.repos.get()
console.log(res)
if (!res) {
return '/login'
}
}
})
// ...
//RESTManager.instance.interceptors.response.use(async (response, option) => {
// const newRes = await response.clone().json()
// return camelcaseKeys(newRes)
//})
一般情况下,res 会输出响应体然后到达目标 route,但是输出的响应体却是空的,然后一直在跳转 /login
,往复。但是并没有报 camelcaseKeys is not a function.
这就很奇怪。
然后我就在想既然是 CommonJS 的问题,就加个 rollup-plugin-commonjs 插件试试,然后就在 prod 中出现了,这样的报错。
我直接懵了,这又是啥,这又是哪个库。后来我又想,不应该啊,vite 都 v2 怎么可能处理不了 CommonJS 模块,然后我就升级了一下 vite 版本(因为是 3 个月前的项目),但是还是不行。最后我用 create-vite-app 新建了一下 demo,一样的代码(最小化版本)试一下,是 ok 的。那一定是我哪里配置有问题。vite.config 肯定是没问题的,一共就没几行。后来在对比 tsconfig.config.json 时,发现少了一行,"esModuleInterop": true,
,这谁想得到,最会被人忽略的地方。加上之后一切都变好了。然后我去看了下 3 个月前的官方给的模板,果然,没有加这一行。啊,原来是官方害了我。
快乐的 naive-ui 之旅
naive-ui 还是写起来很舒服的,全程 tsx 无红线,类型提示没有问题。最重要的是遇到什么 bug 随时能和作者对接,深入探讨。顺便还水了几个pr。和之前 element-ui 写起来真的是一个天上一个地下。当然这个库还在初期,还需要社区的大力贡献。全程 tsx 写起来真的是很舒服了,除了 vue 本身一点局限性,不能 pass 任意 props 之外,其他写起来比 react fc 还舒服。
build 内存溢出的问题
终于,5 天时间重构的差不多了,是时候投入生产了。但是在一次提交之后,github ci 过不去了,原因是 build 的时候出现了 build out of memory。
这次提交了一个组件中导入了大量的不同的图标库。有 5 个图标库,而用具名导入的方式会导入整个模块,在 build 环境下进行 tree shake。所以一下导入了 5 个库之后出现了 out of memory。(一个图标库大概几十 M-100M,还是很大的)。
解决办法是全部改写成默认导出。如下
大功告成,github ci 不再出现内存溢出的问题,自动化部署完成。
大家不管在开发环境还是生产环境的 build 中遇到 node 占用内存过大,可以优先看看是不是某些库因为全量导入导致的哦。
最后来几张图吧。