我给 Answer 提了俩 PR

有个 OpenBuild 的社区生态项目貌似搁置得有点久了,发起者想要继续迅速地推进,但一直没什么起色,一时间也找不到其他合适的人——没办法,只能我去接下来了。

这个项目要做的事是给开源问答平台 Answer 开发一个支持用 Web3 钱包登录的插件;从要实现的功能上来看,这应该是个很小的项目,开发加上联调前后端算在一起估计 1.5~3 个人日。

然而,现实却给了我一棒槌……

需求分析

初步从官方的插件开发文档来看,要做的应该是「连接器-后端插件」。

以此为前提,大致了解了下几个已有连接器的代码发现,每个插件只能指定一种类型,且后端插件是不能直接支持 UI 的,它们都是跳转到外部的授权用 URL。

可是,Web3 钱包登录并没有现成的外部授权用 URL,要实现需求那就可能得另外编写个配套的「路由-标准 UI 插件」,开发一个页面:

  1. 显示连接钱包按钮;
  2. 连接钱包后用户签名;
    1. 从后端获取 nonce,前端传入钱包地址;
    2. 前端唤起钱包让用户签名;
  3. 签名后调用后端授权接口,前端传入用户签名信息、钱包地址等;
  4. 请求成功后返回到主界面。

上面文字加粗部分是需要与后端进行数据交互的,也就是得有两个后端接口。

流程看起来很简单是吧?也确实是很简单!

开发过程

后端部分几个月前就已大体开发完成,基本只差前端界面和联调。

由于这个项目没有前后端分离,我要是完整运行的话,从官方文档的信息来看,得安装 Docker、数据库等。

但我本地之前没安装这些,目前也没有做其他用到这些的项目的打算,不可能单单为了这而去安装几乎用不到的软件占用宝贵的电脑存储空间。

于是,我就先采用纯前端的方式把界面布局、样式和功能开发好,即便后端接口请求都失败了;算上阅读文档、代码熟悉插件基本机制的时间,大概用了 1 人日左右完成。

跟负责后端的人约了周末的一天集中联调,争取搞定交付,可却挫折连连……

因为我本地没有安装并设置后端环境,无法走正常的插件加载运行流程,有些问题在开发阶段并未遇到;当让后端小伙伴下载我的代码跑整个流程时,各种「奇奇怪怪」的问题就冒了出来……

起初,基本一遇到前端问题就发起视频会议,看他是怎么操作的,我指导他去解决——搞了几次我突然发觉,这不就是传说中的「结对编程」吗?😂😂😂

后来我心想:「这样下去不行啊,实在是太低效了!」

最终,我尝试放下心中的芥蒂,让他指导我如何把后端跑起来,就可以自己去测试并调整前端代码了。

被指导后发现,实际我真的只需额外安装 Go 就行,数据库直接用 macOS 自带的 SQLite 即可,更不用去搞 Docker——真应该一开始就让他当我的「导航员」!

虽说之后并没有顺风顺水,但我们无需再开视频会议了,有问题只需微信上发个截图并简单描述下就可以了,效率大大提升!

我在测试自己开发的插件时,还发现了一个插件加载机制上的 bug,就顺手修掉并提了个 PR,成就额外 +1!😁😁😁

经过一两天的收尾,我们开发的插件也交付了,在官方 reviewer 的指导与建议下,将原本的两个插件合并为一个——表面上是「路由-标准 UI 插件」,实则也是「连接器-后端插件」。

至此,我们集中在这三五天里处理掉了「便秘」问题,撒花!🎉🎉🎉

踩坑经验

本次是基于主项目版本 1.4.0 开发,官方文档、插件体系的不完善以及自己较为别扭的心态令我踩了些坑,下面针对前端开发人员分享下本地调试的要点,以便少走弯路!

首先,对像我一样介意的人再次强调下——只需额外安装 Go,数据库可用 macOS 自带的 SQLite!

以我们开发的插件为例,假设插件名为 connector-wallet——

后端环境

确保在主项目的 cmd/answer/main.go 里引入了插件包,即使它当前并不存在:

import (
answercmd "github.com/apache/incubator-answer/cmd"

_ "github.com/apache/incubator-answer-plugins/connector-wallet"
)

无论是纯前端插件还是「表面上是前端插件」的插件,在调试时需将用模板生成的代码放到 ui/src/plugins 文件夹下,并在根文件夹创建 go.work 文件:

go 1.22.0

toolchain go1.23.2

use (
.
./ui/src/plugins/connector-wallet
)

执行 make ui 构建前端代码,再用 go build -o answer ./cmd/answer/main.go 编译后端代码,会生成 answer 文件,接下来的操作都用它。

执行 ./answer init -C ./answer-data/ 初始化系统,需要在浏览器中访问 http://localhost 填写信息,其中数据库要选择 SQLite 且文件存放路径把 /data 替换成 answer-data 文件夹的绝对路径。

执行 ./answer run -C ./answer-data/ 启动后端服务,再次访问 http://localhost 即可登录初始账号并到后台启用要调试的插件!

最后将 ui/.env.development 中的 REACT_APP_API_URL 改为 http://localhost:80/ 就能启动前端开发服务器访问后端接口了。

前端环境

安装好依赖后,需将插件文件夹下的几个文件夹删除,否则会引起问题:

  • 删除 dist 文件夹和 package.json 中的 mainmoduletypesexports 字段,否则页面渲染的是编译后的文件,源文件的变动不会响应刷新;
  • 删除 node_modules,否则插件中读取的 i18n 配置不是主项目的,可能是由于 react-i18next 底层没使用单例模式而实际产生了两份配置。

发布插件

若前端插件中添加了额外的依赖,需要修改插件包中 vite.config.ts 的配置:

import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';

export default defineConfig({
plugins: [
...,
cssInjectedByJsPlugin(), // 有样式文件引入时必须,不然会样式错乱
...,
],
build: {
...,
rollupOptions: {
external: [
..., // 把自己额外的依赖进行声明
],
output: {
globals: {
..., // 把自己额外的依赖进行声明
},
},
},
},
});

结语

感谢 OpenBuild 提供的这次机会,虽说一开始因为有我认为更重要更优先的事需要去做而不太想接……但时间使劲儿挤挤的话还是会有的嘛!

感谢后端小伙伴的积极配合,让我们一起把这拖延几个月的「便秘」问题给解决了!

感谢 Answer 官方的 reviewers 陪我在 PR 里练英语,为我之后的国际化发展开了个好头儿!

虽然之前我也给其他几个开源项目提过 PR,但基本都是小修小补,每次都没啥交流就直接合进去了;这次给 Answer 做贡献让我有了真正的做开源的感觉!

Salute to all OPEN SOURCERORs!!!