拥抱下一代前端工具链-Vue老项目迁移Vite探索
作者:京东物流 邓道远
背景描述
随着项目的不断维护,代码越来越多,项目越来越大。调试代码的过程就变得极其痛苦,等待项目启动的时间也越来越长,尤其是需要处理紧急问题的时候,切换项目启动,等待的时间就会显得尤为的漫长。无法忍受这种开发效率的我,决定将老项目迁移至vite。
距离Vite工具发布到现在已经有了一些日子了,工具链与生态已经趋于稳定,最新版本已经更新到了3.0,既然念头已起,心动不如行动。
1、什么是Vite
vite 发音为/vit/ 法语中就是快的意思,“人”如其名,就是快
- 一个开发服务器,它基于原生ES模块,提供了丰富的内建功能,如速度快到惊人的模块热更新(HRM)
- 一套构建指令,它使用rollop来打包你的代码,并且是预配置的,可输出用于生产环境的高度优化过的静态资源。
2、为什么快
众所周知,当冷启动服务器时,基于打包器的启动必须优先抓取并构建你的整个应用,然后才能提供服务,这一抓取构建的过程随着文件越来越多,时间也会越来越长。
而Vite却通过将应用中的木块区分为依赖和源码两类,从而优化了大量的服务器启动时间。
- 依赖 大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。
- Vite 将会使用 esbuild 预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。
- 源码 通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。
- Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。
3、如何完成老项目迁移
当前项目是Vue2.0,vue-cli4.0,node v14.18.2
3.1 首先我们需要先明确项目结构
与原来的Vue老项目相比,模板文件 index.html 需要从public挪到项目根目录中,Vite将 index.html 视为源码和模块图的一部分。由于我们只有一个入口文件,所以在index.html中需要引入main.ts
<script type="module" src="/src/main.ts"></script>
而且运行过程中可能会遇到下面写法引发的报错
<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> [vite] Internal server error: URI malforme
解决办法是可以写一个简单的插件替换一下
res = code.replace(/<%=\s+BASE_URL\s+%>/g, baseDir);
与Vue-cli相同,需要一个配置文件 vite.cofnig.js, 与原来的vue.config.js同级
3.2 安装依赖
既然我们使用Vite,那么我们需要安装一个vite依赖。但是我们的老项目是Vue2.0,vite优先支持Vue3.0,所以我们还需要一个转换工具 "vite-plugin-vue2"
npm i vite vite-plugin-vue2 -S
3.3 修改配置文件
修改package.json中的scripts,启动和打包方式使用vite
- "serve": "vite",
- "build": "vite build",
修改vite.config.js,与vue.config.js相似
import { defineConfig } from 'vite' import { createVuePlugin } from 'vite-plugin-vue2' // https://vitejs.dev/config/ 这一行可以增加编辑器代码提示 export default defineConfig({ plugins: [ createVuePlugin({ jsx: true, // 兼容项目中的jsx组件 vueTemplateOptions: {} }), ], resolve: { extensions: ['.vue', '.js', '.ts', '.jsx', '.tsx', '.json'], alias: [ { find: '@', replacement: '/src' } ] }, server: { open: true, // 控制台直接打开浏览器 host: 'xxxx.jd.com', // 本地host allowedHosts: ['.jd.com', '.jdwl.com', '.jd.co.th', '.jd.id'], port: 80, cors: true, proxy: { '/api': { target: 'https://xxx.jd.com', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '/api') } } }, })
3.4 剔除原来的webpack相关依赖
可以手动剔除 也可以重新启动一个vite项目再将所需代码移动到vite项目中
3.5 启动应用
这个时候我们就可以启动应用了,不出意外的话,会有许多的报错信息,不过不要慌,我们一个一个的解决
4、遇见的问题汇总
4.1 环境变量
webpackl里的环境变量是默认存储在process.env里的,而vite是存储在import.meta.env里的
import.meta.env.MODE: {string} 应用运行的模式。
import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。
import.meta.env.PROD: {boolean} 应用是否运行在生产环境。
import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。
当然,既然是老项目,这种调用位置会有很多,我们可以使用比较简单的做法来兼容
export default defineConfig({ define: { 'process.env': {} }, })
4.2 global 变量
因为VIte 是 ESM机制,有些包内部使用了 node 的 global对象,解决此问题可以通过自建pollfill, 然后在main.ts顶部引入
// polyfills if (typeof (window as any).global === 'undefined') { ;(window as any).global = window }
4.3 Scss全局变量报错
这一点是vite与vue-cli 配置方式不同引发,而且如果使用了环境变量也需要适配vite的写法兼容
export default defineConfig({ css: { preprocessorOptions: { scss: { additionalData: '$ossHostVariable: \'import.meta\u200b.env.VUE_APP_OSS_HOST\';' } } } })
4.4 path 报错
Vite 是 ESM机制 path是node的包,所以需要兼容浏览器的引入方式,需要安装依赖 “path-broswserfiy”
只需要将引入的包替换即可
import path from 'path' // 替换成 import path from 'path-broswserfiy'
4.5 Require报错
问题的引发与上面一致 都是模块加载方式的不同导致的,可以通过"
vite-plugin-require-transform"插件来解决
import requireTransform from 'vite-plugin-require-transform' export default defineConfig({ plugins: [ requireTransform({}) ] })
4.6 vue组件的动态导入
vue的组件导入方式有很多,vite可以支持 () => import('**/**.vue')的方式导入,不过与webpack的区别在于需要补全文件的后缀,动态导入需要 import.meta.glob的方式
const load = import.meta.glob('@/views/**/index.vue'); export const constantRoutes: any = [ { path: '/404', component: load['404'] }, ]
4.7 编译时的分包策略
const SPLIT_CHUNK_CONFIG = [ { match: /[\\/]src[\\/]_?common(.*)/, output: 'chunk-common', }, { match: /[\\/]src[\\/]_?component(.*)/, output: 'chunk-component', }, ]; const rollupOptions = { output: { chunkFileNames: 'assets/js/[name]-[hash].js', entryFileNames: 'assets/js/[name]-[hash].js', assetFileNames: 'assets/static/[name]-[hash].[ext]', manualChunks(id) { for (const item of SPLIT_CHUNK_CONFIG) { const { match, output } = item; if (match.test(id)) { return output; } } if (id.includes('node_modules')) { return id.toString().split('node_modules/')[1].split('/')[0].toString(); } }, }, }
5、启动时间
不多说了 上图
不过还会有一些问题,开发模式下比如页面首次加载时间比较缓慢,大约在5s左右,不过这也是可以理解的,毕竟编译过程都交给了浏览器,相比于老项目冷启动动辄2 3分钟的体验,已经是天大的提升了。
6、总结
最后再来回顾一下,整体的迁移过程。
首先,明确项目结构,index.html模板文件 提到根目录下,统计增加vite.config.js文件。
然后,编写配置文件 vite.config.js 注意与 vue.config.js上的语法区别,注意兼容写法。
最后,处理项目中两种打包工具的不兼容写法。大部分还是模块规范的区别,node环境的变量以及语法所引发,可以通过各种各样的插件来兼容解决。
以上即为本次迁移的全部过程,丰富、优化了前端工具链的构建流程,极大的提升了开发人员的幸福感,以及开发体验,项目冷启动时间更是提升了百分之99%。虽然前期遇到了许多的坑,但是成功后的感受就是一个字,"真香"。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
高并发场景下常见的限流算法及方案介绍
作者:京东科技 康志兴 应用场景 现代互联网很多业务场景,比如秒杀、下单、查询商品详情,最大特点就是高并发,而往往我们的系统不能承受这么大的流量,继而产生了很多的应对措施:CDN、消息队列、多级缓存、异地多活。 但是无论如何优化,终究由硬件的物理特性决定了我们系统性能的上限,如果强行接收所有请求,往往造成雪崩。 这时候限流熔断就发挥作用了,限制请求数,快速失败,保证系统满负载又不超限。 极致的优化,就是将硬件使用率提高到100%,但永远不会超过100% 常用限流算法 1. 计数器 直接计数,简单暴力,举个例子: 比如限流设定为1小时内10次,那么每次收到请求就计数加一,并判断这一小时内计数是否大于上限10,没超过上限就返回成功,否则返回失败。 这个算法的缺点就是在时间临界点会有较大瞬间流量。 继续上面的例子,理想状态下,请求匀速进入,系统匀速处理请求: 但实际情况中,请求往往不是匀速进入,假设第n小时59分59秒的时候突然进入10个请求,全部请求成功,到达下一个时间区间时刷新计数。那么第n+1小时刚开始又打进10个请求,等于瞬间进入20个请求,肯定不符合“1小时10次”的规则,这种现象...
- 下一篇
把 ChatGPT 加入 Flutter 开发,会有怎样的体验?
前言 ChatGPT 最近一直都处于技术圈的讨论焦点。它除了可作为普通用户的日常 AI 助手,还可以帮助开发者加速开发进度。声网社区的一位开发者"小猿"就基于 ChatGPT 做了一场实验。仅 40 分钟就实现了一个互动直播 Demo。他是怎么做的呢?他将整个过程记录了下来。 (文章转载自开发者的个人博客,以下为正文) “遇事不决,AI 力学” ~ ChatGPT 可以说是 2023 开年最热门的话题, 它不仅在极短时间内风靡了整个技术圈,更是病毒式地席卷了圈外的各个行业,并对各大企业都起到了实质性影响: 谷歌紧急推出 “Bard” 对抗 ChatGPT 微软发布新 Bing 集成 ChatGPT 复旦发布首个类 ChatGPT 模型 MOSS 国内阿里、百度、昆仑万维、网易、京东都开始新一轮 AI 军备 那 ChatGPT 究竟有什么魔力能让“群雄折腰”?这和 ChatGPT 的实现有很大关系: 与以往的统计模型不行,ChatGPT 不是那种「一切都从语料统计里学习」的 AI,相反 ChatGPT 具备有临场学习的能力,业内称之为 in-context learning ,这也是为什...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路