20

面向 dapp 开发者的前端工程实践

 3 years ago
source link: https://blog.dteam.top/posts/2020-11/dapp-frontend-practices.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

老实讲,促使本文写作的动机有三点:

  • blog 和公众号好久没更新了,间隔这么长时间,总得写点什么来宣告自己的存在。
  • 这段时间项目的开发自我总结,包括自己犯的错误。
  • 跟一些团队和开发者打过交道后,发现一些本应是常识的内容,似乎并没有想象中那么普及。

由于我目前的空闲时间有限,也就以条目的形式随意写一点东西吧。

语言和框架

按理说,这部分内容完全是多余,但其实不是。

在我的印象里,国内前端开发应该基本上被三大框架瓜分得差不多,但怪事恰恰被我遇上:某 dapp 项目在我介入的时候,居然发现了久违的 jQuery ,而且完全没有任何前端工程而言:一个 html 文件 + 一堆 js 文件。

这里首先声明,我已不是当年的我,现在早已对各类工具无感,只要能办成事,挣到钱,其实无所谓。因此 jQuery 并不在我歧视之列,并且自己写的 vscode-page 其实也用了历史悠久的模板库: handlebars.js

上面那个 jQuery 工程的问题在于:代码杂乱无章,到处可见复制黏贴的痕迹,即便放在 10+ 年前,该工程也不能说得上好。因此,除非你对自己的代码掌控力十分自信且得到大家认可,还是俗套一点:选择一个前端框架,这样起码会有一个不错的起点。

至于语言,有条件的话还是采用 TypeScript,单单类型检查就能让你避免很多潜在问题。此外,也别忘了一些配套设施:自动化的代码风格检查、vscode 插件等等。 这里摘抄一下以前文章的内容

工程相关

因为本质上 vscode 插件开发是前端工程的范畴,并且我们团队主要采用 TypeScript ,因此用到的插件和规范如下:

代码风格:

风格可商量余地:

  • “strict”: true + “no-any”: false,允许

相关插件:

  • ESLint
  • Bracket Pair Colorizer 2
  • Prettier
  • markdownlint
  • indent-rainbow
  • Path Intellisense
  • Peacock

最后,补充一个极大提高效率的 vscode 插件: tabnine ,谁用谁知道。

数据精度

数据精度问题让我丢了大人,至今觉得过意不去。但是,这类问题在做后端时候从未出现,现在想来,有几个原因:

  • 数据精度问题并非我的知识盲区,在数据库设计(比如数据库内精度到“分”)和后端类型(Java 选择 BigDecimal)选择上都会注意这一点。
  • 对于 JavaScript / TypeScript 的这方面知识储备不如后端,且对问题重视不足,混淆了数据范围和数据精度的含义。
  • 当时处于救火赶工状态,选择了捷径。

结果待到上线日,出现了状况。

由于 dapp 项目对于数字很敏感,稍有差池就会出现问题,因此作为 dapp 开发者需要对数据精度保持高度重视。这里列出几个我觉得比较重要的地方:

  • 一般情况下,避免四舍五入。尤其是跟价格相关的部分,四舍五入肯定会有问题。如果出于显示目的不能显示全部,那么只能截取。
  • 选择字符串传入传出,避免直接使用 number 来转换。
  • 使用成熟类库完成计算,个人推荐: bignumber.js 。相比起其他同类库,使用简单,并且非常类似 java 的 bigdeimal。同时,作者贡献了 big.js 和 decimal.js ,分别用于不同情况,各位可自行搜索相关资料。

合约交互

本来,我觉得像 ethers.js 这么好用的库没有理由不被很多人知道。结果恰恰相反,实在让人大跌眼镜!

除非你有非常特异的需求,并且不仅限于跟合约交互,比如还想去试试发消息和存储,我建议直接使用 ethers.js,不要用 web3.js。原因很简单:

  • ethers.js 更简单好用,没那么多废话。
  • human readable abi,根本不需要你再去生成什么 abi 文件,用哪些方法单单复制出来函数签名就好了,省掉了不必要的构建步骤。
  • 合约方法更好用,完全的对象化。
  • 钱包支持。

假如你还想增强合约方法(比如你想一次性完成:先预估 gas,然后设置 gaslimit ,然后执行合约方法)也很方便。

状态管理

页面状态很关键,对于 dapp 更是如此。因为这里至少有两个地方需要注意:

  • 程序运行时自身导致的状态变化
  • 因为链上状态变化而导致的状态变化

以 uniswap 兑换为例:

  • 前者是,你输入一个数字之后,另一个的数字会依据当前的市场行情自动算出并填充;
  • 后者是,当 pool 内变化而导致价格变化,这一点同样要体现出来。通俗点说就是数字要自动更新。

所有这些状态应该在前端各个页面流畅地体现出来,即这里牵涉到状态传递地问题。如果不使用状态管理工具库的话,其实很容易写出很繁杂地代码。

可能有人说,这个简单,一个全局对象就行了:一个全局的 json 对象。不错,单从静态最终结果而言,全局对象是数据共享的最简单方法。但是,如何应对数据的变化呢?即,数据变化后能方便地通知出去。你可能会说,这个也很简单,封装成一个 Observable 然后让需要页面订阅就行了。不错哟,连 Observable 都知道。

但,即便如此,我还是希望劝你不要自己干这个事情,因为很快就会又有新的需求出现,而这些已经在那些成熟的状态管理库里实现好了。

这里,我推荐 Akita ,简单、轻量、好用,相比 redux 和 ngrx 而言。

至于如何接收链上通知,你可以去看看 ethers.js 的文档,其中有相关的介绍。我建议的最简使用方式,直接监听 block mined 事件,然后去获取你需要的内容。

Web3 和 Metamask

Metamask 在做些 breaking change 的事情,涉及到 API 的变化,比如不再注入 web3 ,取而代之的是 window.ethereum 。如果你还抄的是网上那些老代码,最好赶紧检查一下尽快替换。

关于 api 的情况,请检查 其开发文档

部署

最后,说一说部署方式,这一点我原本以为也是常识性内容。

dapp 基本上就是一个静态站点,部署其实很简单,直接一个 web server 就行了。在当今处处大吹特吹“云原生”的时代,我们是不是也应该蹭蹭热点呢?!

停止自己买机器,然后搭 web server,再上传文件的做法!这里,我也发现不少人也没搞清楚前端构建是怎么回事。还以为放进去的代码可以很容易让人看出来咋回事。这完全是 10+ 年前的思维!

就当下而言,主流前端框架基本都至少具备了打包、压缩和混淆的功能,最后的代码基本没法看。因此,这种担心基本是多余的。

就部署方式而言,当前简单、省钱且更优的做法就是选用云服务商的:oss + cdn 架构。比起自建服务器而言,效果完全不是一个档次。

好了,这次就说这么多吧,等有时间再细聊。

广告时间

或许你对以下的付费内容感兴趣 …… :smile:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK