如何使用 GoGoCode 一键 Vue2 转换 Vue3

news2024/11/16 21:29:27

前言

从今年年初开始,项目开始升级优化,将之前的 Vue2 旧版本整体升级到 Vue3 版本。在重写了几个 Vue 文件后,我发现做的都是一些机械性的工作,效率低且重复性大。于是就试着搜索了一下有没有什么能够批量转换代码格式的工具,发现了阿里的这个基于 AST 的 JavaScript/Typescript/HTML 代码转换工具——GoGoCode。

时间已经过去大半年了,写篇博客记录一下,希望能帮到有需要的朋友。

gogocode-2

官网上关于 Vue2 升级 Vue3 大抵有两种方案。第一种介绍了一套 Vue2 升级工具,利用这套工具能够快速地把 Vue2 代码升级到 Vue3。但是过程较为繁琐,出现错误的可能性较大,网上也没有什么详细介绍和成功案例,最主要是我没有成功的运行。第二种则就是普通的转换,利用自己编写的转换规则按部就班转换。所以我选择了第二种,,灵活性较大,可以根据各个项目的特点按需要编写转换规则,然后规规矩矩逐个文件代码转换,转换完成之后对比有无错误语法,再运行测试是否有缺陷,比较直观。

安装插件

在 VSCode 拓展中搜索 GoGoCode 并安装即可。

在安装完成之后,就可以在需要转换的 Vue2 文件上点击鼠标右键,选择“用 GoGoCode 转换”,即可打开“GoGoCode PlayGround”。

可以看到四块内容,左上方显示的是源码,右上方为可以编辑的转换规则,下方的两块内容则是转换前后代码的对比。

操作过程

构造实例

调用 $(code, options) 即可将一段代码或一个 ast 节点构造为 GoGoCode 的核心 AST 实例。

其中 code 为需要被实例化的代码或 AST 节点,options 为一个对象,包括 parseOptions、astFragment、isProgram。

入参说明类型举例
code需要被实例化的代码或 AST 节点string NodePath Node‘var a = 1’
optionsparseOptions解析 js 时,它与 babel/parse 的 options 完全一致
解析 html、vue 时需要传入 language
object{ plugins: [‘jsx’] }
{ language: ‘html’ }
{language: ‘vue’ }
astFragment需要插入到代码中的 ast 节点Node{ content: astNode }
isProgram是否需要返回完整 ast js 的完整 ast
最外层节点是 File 类型
html 完整 ast 是 document 类型
Boolean默认为 true

因此,我们可以这样写将 vue2 文件中的代码构造为 AST 实例。

const ast = $(source, { parseOptions: { language: "vue" } });

获取节点

所有的节点获取操作都会返回一个新的 AST 实例。

ast.find

在把代码从字符串解析成 AST 后,我们进入第二步,从一整段代码中精确查找到我们要修改的 AST 节点。

GoGoCode 提供了直观的「用代码找代码」的方式,和 jQuery 查找 DOM 一样,你只需要编写一段代码片段作为「代码选择器」,GoGoCode 就能智能地帮你匹配到源码中和它吻合的片段。

例如我们使用.find()方法,分别查找 template 和 script 各作为一个整体 ,方便后续操作。

最后用 generate 把节点输出成代码字符串。

function transform(fileInfo, api, options) {
  const $ = api.gogocode;
  const source = fileInfo.source;
  const ast = $(source, { parseOptions: { language: "vue" } });

  const template = ast.find("<template></template>");
  const script = ast.find("<script></script>");

  return ast.generate();
}

操作节点

将获取到的节点通过编写的规则转换,将是我们的第三步。不过在此之前,我们需要了解一下通配符和.replace()方法。

KaTeX parse error: Expected group after '_' at position 1: _̲ 通配符

假设你想在下面代码中挑选出对于变量 a 的声明和初始化语句:

const a = 123;

按照之前介绍的,我们只要像下面这么写就可以了:

const aDef = ast.find("const a = 123");

但这只能匹配到 const a = 123,对于 const a = 456 就无能为力了,在实际的代码匹配中,我们往往不确定代码的全貌,这时候 GoGoCode 支持使用通配符来做模糊匹配:

const aDef = ast.find("const a = $_$0");

有时我们不止需要一个通配符,你可以在代码选择器中书写 $ 0 、 0、 0 1 、 1、 1_ 2 、 2、 2_$3……达到你的目的。

$$$ 通配符

假设有下面的代码:

console.log(a);

console.log(a, b);

console.log(a, b, c);

按照之前的写法,我们可以用以下几种选择选择器进行查找。

ast.find(`console.log()`);
ast.find(`console.log($_$0)`);
// 上面两条语句会找到全部三行代码

ast.find(`console.log($_$0, $_$1)`);
// 这条语句会找到前两行代码

ast.find(`console.log($_$0, $_$1, $_$2)`);
// 这条语句只会找到第三行代码

可以看出 GoGoCode 的通配符匹配的原则:写得越多,查询限制越大。

如果你想匹配任意数量的同类型节点,GoGoCode 提供了 $ 形式的通配符,对于上面不定参数的语句,你可以统一使用 < k b d > a s t . f i n d ( ′ c o n s o l e . l o g ( 形式的通配符,对于上面不定参数的语句,你可以统一使用 <kbd>ast.find('console.log( 形式的通配符,对于上面不定参数的语句,你可以统一使用<kbd>ast.find(console.log($0)') 来匹配。

ast.replace

日常我们在编辑器中批量修改代码的时候也会经常使用到「查找\替换」的功能去做一些基本操作,但它们都基于字符串或正则表达式,对于不同的缩进、换行乃至加不加分号都无法兼容,而利用 GoGoCode 的代码选择器特性配合 replace 方法,可以让你以接近字符串替换的形式完成 AST 级别的代码替换操作。

function log(a) {
  console.log(a);
}

function alert(a) {
  alert(a);
}

如果我们想给 log 函数改名成 record,用 replace 做非常简单:

ast.replace("function log($$$0) { $$$1 }", "function record($$$0) { $$$1 }");

现在,我们就可以开始编写规则了。目的是将 vue2 中的语法规则升级为 Vue3 的语法规则,同时将 ui 组件库 element-ui 升级为 element-plus,主要分为以下几部分。

1.插槽。Vue3 中需要在外面包裹上一层 tempplate,写法也由内层的 slot=“xxx” 变为外层的 #xxx。

template.replace(
  '<$_$ slot="filter" $$$0>$$$1</$_$>',
  "<template #filter><$_$ $$$0>$$$1</$_$></template>"
);

template.replace(
  '<el-dropdown-menu slot="dropdown" $$$0>$$$1</el-dropdown-menu>',
  "<template #dropdown><el-dropdown-menu $$$0>$$$1</el-dropdown-menu></template>"
);
  1. el-button type=“text” 需要转换为 el-button type=“primary” link。
template.replace(
  '<el-button type="text" $$$0>$$$1</el-button>',
  '<el-button type="primary" link $$$0>$$$1</el-button>'
);

3.去掉 export default{}。

script.replace("export default {$$$}", "$$$");

4.去掉 components、mixins。

script.replace("components:{}", "").replace("mixins:[]", "");

5.去掉 props,并将里面的’props:{xxx}'的形式转换为’const props=defineProps({xxx})'的形式。

script.replace("props:{$$$}", "const props=defineProps({$$$})");

6.去掉 data、return,并将里面’xxx:yyy’的形式转换为’let xxx=$ref(yyy)'的形式。

script.find("return {}").replace("$_$:$_$", "let $_$=$ref($_$)");

7.去掉 conputed,并将里面’xxx(){}'的形式转换为’const xxx=computed(()=>{})'的形式。

script
  .find("computed:{}")
  .replace("$_$(){$$$}", "const $_$=computed(()=>{$$$})");

8.去掉 watch,由于 watch 有多种写法:有无 deep、有无 handler,所以这里按顺序都走了一遍。

script
  .find("watch:{}")
  .replace("$_$:{handler($_$){$$$}}", "watch(()=>$_$,($_$)=>{$$$})")
  .replace("$_$:{handler(){$$$}}", "watch(()=>$_$,()=>{$$$})")
  .replace(
    "'$_$':{handler($_$){$$$},deep:true}",
    "watch(()=>$_$,($_$)=>{$$$},{deep:true})"
  )
  .replace("'$_$':{handler($_$){$$$}}", "watch(()=>$_$,($_$)=>{$$$})")
  .replace("$_$($_$){$$$}", "watch(()=>$_$,($_$)=>{$$$})")
  .replace("$_$(){$$$}", "watch(()=>$_$,()=>{$$$})")
  .replace("watch:{$$$}", "$$$");

9.去掉 filters,两种写法都走一遍。

script
  .find("filters:{}")
  .replace("$_$:function($_$){$$$}", "const $_$=computed(($_$)=>{$$$})")
  .replace("$_$($_$){$$$}", "const $_$=computed(($_$)=>{$$$})")
  .replace("filters:{$$$}", "$$$");

10.去掉 methods,同样有多种可能存在的形式:有无 async、有无参数,按顺序都走一遍。

script
  .find("methods:{}")
  .replace("async $_$($$$0){$$$1}", "const $_$=async($$$0)=>{$$$1}")
  .replace("$_$($$$0){$$$1}", "const $_$=($$$0)=>{$$$1}")
  .replace("async $_$(){$$$}", "const $_$=async()=>{$$$}")
  .replace("$_$(){$$$}", "const $_$=()=>{$$$}")
  .replace("methods:{$$$}", "$$$");

10.生命周期的改变。

script
  .replace("created(){$$$}", "onBeforeMount(()=>{$$$})")
  .replace("mounted(){$$$}", "onMounted(()=>{$$$})")
  .replace("beforeUnmount(){$$$}", "onBeforeUnmount(()=>{$$$})")
  .replace("unmounted(){$$$}", "onUnmounted(()=>{$$$})")
  .replace("beforeDestroy(){$$$}", "onBeforeUnmount(()=>{$$$})")
  .replace("destoryed(){$$$}", "onUnmounted(()=>{$$$})");

成果展示

gogocode

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1116081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPE(Single Pair Ethernet)

以太网标准 讲SPE&#xff08;Single Pair Ethernet&#xff09;之前我们先了解一下以太网标准&#xff1a; CategoryStandardCable length(m)Data rateDuplex CapabilityWiresFast Ethernet10/100BASE-T10010Mb/s to 100Mb/sFull4Gigabit Ethernet1000/10GBAST-T1001Gb/s to …

UOS系统无法开机问题解决

1、问题截图1 &#xff1a; 2、问题截图2 &#xff1a; 3、问题截图3&#xff1a; 解决方案&#xff1a; 修复磁盘无效&#xff0c;建议拷贝数据&#xff0c;还原系统 请先拷贝数据 进live模式在root a或root b 或系统盘找到Home文件夹里-找到用户名-里面就是用户的数据&am…

四川竹哲电商:抖店怎么修改经营类目?

抖店是抖音推出的一款电商工具&#xff0c;通过抖店可以帮助商家在抖音上开展经营活动。在抖店平台上&#xff0c;商家需要选择经营类目&#xff0c;以便在相应的领域展示商品和提供服务。然而&#xff0c;有时候商家可能需要修改经营类目&#xff0c;以适应经营策略调整或扩大…

什么是无磁远传水表?工作原理是怎样的?

无磁远传水表是一种新型的智能水表&#xff0c;与传统水表相比&#xff0c;它具有更高的精度和可靠性&#xff0c;并且可以实现远程读数和控制。那么&#xff0c;无磁远传水表的工作原理是怎样的呢?下面&#xff0c;小编来为大家介绍下什么是无磁水表?它的工作原理是怎样的&a…

MySQL 三大日志(bin log、redo log、undo log)

redo log redo log (重做日志) 是 InnoDB 存储引擎独有的&#xff0c;它让 MySQL有了崩溃恢复的能力&#xff0c;是事务中实现 持久化的重要操作 比如 MySQL 实例宕机了&#xff0c;重启时&#xff0c;InnoDB 存储引擎会使用 redo log 恢复数据&#xff0c;保证数据的持久性与…

数字孪生技术:重塑企业经营的未来

在当今数字化时代&#xff0c;企业经营面临了前所未有的挑战和机遇。数字孪生技术作为新一代数字化工具&#xff0c;正在成为企业走向成功的关键。数字孪生是一种通过数字模型在虚拟世界中模拟和反映物理实体、过程和系统的技术&#xff0c;它为企业经营带来了许多重要的帮助。…

Sourcetree突然打不开,双击打开,图片闪一下就没反应了

解决方案如下&#xff1a; 1.点击图标&#xff0c;右键点击“打开文件所在位置 2.返回上一级&#xff0c;找到Atlassian文件夹 3.进入此文件夹下&#xff0c;删除SourceTree.exe_Url文件夹 4.再双击桌面的Sourcetree图标&#xff0c;可以正常打开。 最近刚遇到此问题&#x…

【广州华锐互动】智慧水务3D可视化数字孪生大屏定制开发

污水处理流程的复杂性需要一种有效的方法进行理解和优化。传统的2D图表和文字描述方法往往无法全面、直观地展示污水处理的各个环节。然而&#xff0c;智慧排水3D数字化管控系统可以为污水处理流程提供更深入、更全面的理解&#xff0c;从而帮助改进污水管理。 首先&#xff0c…

Vue2双向数据绑定的原理

Vue.js 是采用数据劫持结合发布者-订阅者模式的方式&#xff0c;通过Object.defineProperty()来劫持各个属性的setter&#xff0c;getter&#xff0c;在数据变动时发布消息给订阅者&#xff0c;触发相应的监听回调 Vue双向数据绑定主要有以下几个步骤&#xff1a; 模板解析 事件…

为何说只有 1 种实现线程的方法?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 今天我们来学习为什么说本质上只有一种实现线程的方式&#xff1f;实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里&#xff1f; 实现线程是并发编程中基础中的基础&#xff0c;因为我们必须要先实现多线程…

虹科活动 | 探索全新AR应用时代,虹科AR VIP研讨会广州场回顾!

文章来源&#xff1a;虹科数字化AR 阅读原文&#xff1a;https://mp.weixin.qq.com/s/7tmYR42Tw5XLn70fm8Nnew 主题演讲 本次研讨会&#xff0c;虹科特邀 “工业AR鼻祖” 美国Vuzix公司的首席应用工程师郑慎方先生进行主题演讲&#xff0c;并邀请到了各界的专业人士和企业代表参…

ESRI ArcGIS Pro 3.0-3.0.2图文安装教程及下载

ArcGIS 是由美国著名的地理信息系统公司 Esri 开发的一款地理信息系统软件。ArcGIS Pro是一款功能强大的单桌面 GIS 应用程序&#xff0c;是在桌面上创建和处理空间数据的基本应用程序。ArcGIS Pro支持数据可视化和数据高级分析&#xff0c;可以创建 2D 地图和3D 场景。它支持跨…

无需公网IP,通过内网穿透轻松搭建微信公众号开发本地调试环境!

文章目录 前言1. 配置本地服务器2. 内网穿透2.1 下载安装cpolar内网穿透2.2 创建隧道 3. 测试公网访问4. 固定域名4.1 保留一个二级子域名4.2 配置二级子域名 5. 使用固定二级子域名进行微信开发 前言 在微信公众号开发中&#xff0c;微信要求开发者需要拥有自己的服务器资源来…

如何建立风险、内控与合规三位一体的管控体系?

为指导企业开展风险管理工作&#xff0c;进一步提高管理水平&#xff0c;增强竞争力&#xff0c;促进稳步发展&#xff0c;自2006年开始&#xff0c;我国国资委、财政部等相关部委借鉴COSO理论及国际上影响较大的风险管理和内部控制标准&#xff0c;结合国内的实际情况&#xf…

构建跨平台应用程序:Apollo在移动开发中的应用

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

软件工程与计算(二十二)软件开发过程模型

&#xff08;自顶向下&#xff0c;逐层细化&#xff09; 目录 一.软件开发的典型阶段 1.需求工程 2.软件设计 3.软件构造 4.软件测试 5.软件交付 6.软件维护 二.软件生命周期模型 三.软件过程模型 四.构建-修复模型 五.瀑布模型 六.增量迭代模型 七.演化模型 八…

优维产品最佳实践第12期:IT资源管理首页丰富

​ 背 景 当我们进入平台后&#xff0c;默认跳转至IT资源管理首页&#xff0c;因此该页面的优化与丰富将极大的提高平台使用者的体验和效率。优化后的首页可以更好地展示常用模型、小产品、外部系统、以及保存的所有关系查询和快速查询条件&#xff0c;使用户能够更快捷、方便…

抖音同城热搜榜上榜技巧有哪些

抖音同城热搜榜上的话题通常是具有一定热度和社会关注度的。因此&#xff0c;在制作视频时&#xff0c;可以关注一些热门话题&#xff0c;如社会热点、明星八卦、节日庆典等。以社会热点为例&#xff0c;可以关注一些突发事件、政策变革等&#xff0c;这样可以在短时间内吸引大…

SystemVerilog Assertions应用指南 Chapter1.20“ $past”构造

1.20“ $past”构造 SVA提供了一个内嵌的系统任务“$past”,它可以得到信号在几个时钟周期之前的值。在默认情况下,它提供信号在前一个时钟周期的值。结构的基本语法如下 $past (signal_name ,number of clock cycles) 这个任务能够有效地验证设计到达当前时钟周期的状态所采用…

数据分析案例-基于snownlp模型的MatePad11产品用户评论情感分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…