坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.5.13

前言

前面我们也简单的接触过WebAssemblyrust基础学习--搭配webAssembly - 知乎 (zhihu.com),也曾将我们之前写的扫雷小游戏编译成wasm部署到web上:rust基础学习--基于Bevy实现扫雷小游戏day8 - 知乎 (zhihu.com)

但是我们实际上都只是在学如何套壳子,没有任何涉及逻辑的,所以想了下准备来写一个babel插件。

虽然有些本末倒置,毕竟要写感觉可以直接基于swc去写。

但是别忘了,旧项目是属于能不动基本就不动的,所以要把旧项目的babel替换成swc,需要技术审核比如插件支持度什么的,所以对于旧项目来说,成本最低最稳定的还是使用babel

另外说下这里不分析性能、不追求代码优雅,只是一个方案,github链接:


环境

因为这个插件的目的是在项目编译阶段,所以自然是node环境,到时打包wasmtarget也得是nodejs


需求

其实一两年前公司的一个项目重构,在重构过程中因为大量的无注释代码搞得头疼,就有了强制开发写函数注释的想法。

那么我们需要整理下:

  1. 要知道这人写在哪个文件以及是什么文件,目标仅限于.js文件
  2. 只针对于export出去的function(包括箭头函数)
  3. 找到没有注释的导出函数

实现

第一点知道是什么文件这点简单,有的是办法,但是第二点和第三点就比较麻烦了,我们需要知道代码长什么样。

这种时候自然是我们的babel上场,有了它,我们可以轻松知道哪些是export的:exportdeclaration

然后我们在这个基础上去分析第三点即可。

js版本

于是我基于这个想法实现了一个babel插件,代码比较简单,这里直接放出:

  • ExportDeclaration:使用了export关键字的
  • leadingComments:放在函数头部的就是leadingComments
  • FunctionDeclaration:函数声明,比如export function xx () {}
  • VariableDeclaration:变量声明,比如export const xx = xxx,因为箭头函数和函数也可以这么声明,所以我们还需要在里面判断,ArrowFunctionExpressionFunctionExpression这两种。

其它不多说了,相信大家对babel或多或少有所了解,如果有哪里不懂可以评论区里说下。

后面我们rust就不解释了~


项目初始化

我们这里直接创建lib的:

然后配置下Cargo.toml

噢,差点忘了,在这之前你还需要安装wasm-pack,至于如何安装,可以去看搭配WebAssembly那篇文章,这里不多说。

这就行了


rust实现

这里直接贴代码:

  • #[wasm_bindgen],如果你的函数需要暴露到js中,那么这个是必须的。
  • wasm_bindgen::closure::Closure::wrap:将一个闭包转换成js函数,其实js-sys提供了Function,并且可以基于它创建js函数,但是这就本末倒置了,我们希望的是逻辑是rust实现的。这里也不一定要用函数,也可以是一个闭包。
  • Reflect::setReflect::get不用多说,给一个对象赋值和读对象的键值,这里我是通过递归去寻找深层的字段,如果你有更好的方案请务必在评论区里说下,不胜感激~
  • declarations.map:也就是Array::map,注意不要用iter().map(),这样是会报错的,打了半天log才发现。

代码写的有些乱,因为遇到一些类型转换之类的问题,它会很暴力的直接panic,并且错误信息不可读,所以这里无奈写了一堆错误log和兜底赋值,不然一个?就解决了。

其它也没啥好说的了,逻辑也就这样。

然后我们来打包。


打包

这里我们直接通过npm来运行指令,基于npm的原因是后面如果我们想打包成一个npm包,那么npm是必要的,所以直接省事:

然后配置下script:

  • out-dir:表示打包的文件夹名字
  • --out-name:入口文件名
  • -t:自然就是target,这里我们选择nodejs

然后打包完成,在根目录会出现一个dist文件夹:

那么到这就完成了


使用

因为我们没有发布npm包,所以只能手动将这个文件夹里的内容复制到项目中,inedx.js中有对wasm的加载逻辑,所以我们不必写load wasm的逻辑,直接导入即可:


测试

就不测试了,主要是得放图,很麻烦~


总结

内容很少,但是耗时很长,因为还在学习中没有好的调试方案。。。如果你有好的调试方案请务必和我说下,谢谢!