开源项目地址:https://github.com/nervosnetwork/ckb-explorer-frontend
很多人都听说过比特币、以太坊等区块链项目,也了解过区块链的工作原理,可能还动手写过 Solidity
智能合约代码。对于一个之前未曾了解过区块链的新手来说,接触一个区块链项目最好的途径可能就是它的区块浏览器(Blockchain Explorer
)了,为什么这么说呢,因为相比于区块链全节点,区块浏览器够直观、易懂和清晰。
区块浏览器最大的价值就是用清晰直观的 Web 元素展示复杂且不易被普通人琢磨的区块、交易等数据,绝大部分的区块链项目都是采用点对点的 P2P
网络,各个全节点之间通过一对一地相互交换数据维持全网的信息流通,所以对于普通人来说,想要直观看到网络中传输的信息并不是很方便,于是区块浏览器诞生了。
既然是展示区块链网络流通的信息,那么这些信息到底是什么呢?其实很简单,无非就是区块、交易、地址、网络状态和一些统计信息,对于比特币区块浏览器来说,你可以看到最新的区块、交易信息,全网的难度和算力信息、一段时间的交易数量和平均交易费等信息,当然你也可以看到当前最新的比特币价格信息。例如5月13日炒得很热的比特币减半,你就可以在区块的详细信息中看到当前的奖励数量(6.25 BTC)。
当然这篇文章不是来讨论比特币和以太坊的区块浏览器的,对于一个区块链项目开发者而言,如何做出一个质量说得过去且开源的区块浏览器项目,才是这篇文章的重点。换言之,如何做出一个尽量符合 Web 最佳实践的开源项目,我想这对于很多致力于写好代码的开发者来说,都会很有借鉴意义。
对于一个开源项目来说,代码质量和架构是不能马虎的,不能说要照搬社区的最佳实践模板,起码也得保证足够得易扩展、结构清晰、文档易懂、格式统一、测试完备……这个好像可以列很长,总之对于开源项目来说,为了能让项目更拿得出手,我想大多数开发者都会尽量把代码写得足够漂亮、高质量。
有幸参与到 Nervos CKB Explorer
项目的前端开发,经历了一个开源项目从零开始一点点成长的过程,关于 Nervos CKB
的详细介绍不是本文的重点,如果你想了解这个区块链项目本身,Google 或者百度都能找到大量的介绍信息。简单来说 Nervos CKB
是比特币的升级版,在比特币的基础上引入了更加完备的智能合约,根据挖矿和网络情况动态调整出块时间、引入二级增发来平衡区块奖励不断减半引发的激励不足和安全风险。
对于 Nervos CKB
来说,链上有大量的区块、交易、脚本、网络状态等信息,如果不去做处理分析并合理的归来展示,那么旁人是很难清晰直观地了解它,这就像任何一个优质的开源项目,文档都是不可或缺的。
Nervos CKB
区块浏览器包含两部分,一部分是[后端服务CKB Explorer
],一部分是[前端应用 CKB Explorer Frontend
],后端服务主要是处理链上的区块和交易信息,然后加工出各种各样的信息,前端应用将这些数据更人性化地展示给用户,本文重点介绍前端应用。
作为一个 Web 应用,我们选择了 React
框架,并且搭配 React 全家桶 Create React App / Router / Hooks / Dom
等。CSS 框架选择了 styled-components
,使得 React 组件和样式更加模块化,引入了 Enzyme/Jest
组合来完成 React 应用的单元和 UI 测试,作为时下最流行的 TypeScript
当然不能缺席,同时适配 PC 和 Mobile 的各种尺寸。引入了 Echarts
作为我们图表展示的第三方库,帮助我们绘制满足各种不同需求的图表。
对于 React 应用来说,状态管理是极其重要的,我们采用 React Hooks
而非 React Redux
是因为我们认为 Hooks 在绝大部分场景下可以达到和 Redux 类似的效果,当然在状态管理方案上我们也借鉴了 Redux 的很多思想和最佳实践。
对于一个面向全球的开源项目,还要适配多语言,我们提供了英文和中文两个语言版本,并提供了切换按钮。为了保证代码格式的一致性,我们引入了 prettier / eslint / stylelint
。对于开源项目来说, CI 也是不可或缺的,我们同时引入了 Travis 和 GitHub Actions。
我们希望 [CKB Explorer Frontend] 项目更符合开源的气质和标准,当然可能还有很多地方不够完善,但是我们依然觉得值得拿出来分享,开源和分享本来就符合区块链去中心化的特质,所以我们愿意分享自己的一些心得,同时也欣然接受外界的建议和批评。
我们采用 pages / components / routers / contexts / services / locales / assets / types / utils / __tests__ / __mocks__
的项目组织结构,在 Create React App 推荐的项目结构基础上补充了一些我们独有的子目录。
所有的页面全部位于 pages
目录下,组件位于 components
目录下,路径相关的配置和代码位于 routers
目录下,全局状态管理交由 contexts
处理,services
则主要处理 Api 接口的 Fetch 方法以及封装各个业务逻辑的数据请求和处理,locales
管理本地化多语言的配置,assets
存放了项目所需要的图片和字体资源,types
存放了 TypeScript 需要的数据结构,utils
则存放了项目所需要的各种工具方法和常量,__tests__
存放了项目的所有单元和 UI 测试,__mocks__
存放了项目测试所需要的模拟数据。
我们采用 prettier / eslint / stylelint / husky
来规范和检查 ts
和 css
代码,保证所有开发者的本地格式都是一致的,以及 push 到 GitHub 的代码格式也是统一的,作为开源项目,可能会有其他开发者参与贡献代码,所以必要的代码规范和检查是必需的。
另外为了更好地实现组件化和模块化,我们采用了 [styled-components] 这种 css-in-js
的第三方库,对于大多数组件和页面,我们都采用了 ComponentName/index.tsx
和 ComponentName/styled.tsx
代码组织结构,尽量减少代码耦合,增强可阅读性。
由于我们有独立的 UI/UX 设计规范,所以绝大部分组件都是自定义实现,少部分复用 Ant Design
,由于复用第三方组件库的组件并不是很多,所以在选择组件库时并没有存在过多纠结。
对于响应式 UI 框架来说,状态管理是一个绕不过去的话题,面对逐渐膨胀的需求,前端需要管理各种状态信息,哪些信息需要封装在组件内部,哪些需要作为全局状态,以及如何管理多个组件或者页面状态共享等等,我们在借鉴 Redux 的基础上,根据 Hooks
的特性,我们构建一套基于 React Hooks
的状态管理方案。
React Hooks
可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性,官方文档介绍 Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数,简单来说,useState
提供了组件内部的状态管理机制,useEffect
相当于状态更新的控制器和过滤器,useContext
提供了全局状态管理机制,useReducer
可以用来管理组件本地的复杂 state。
在设计状态归属的问题上,我们采用了尽量封装组件内部的状态管理,使得使用者不需要关心组件内部的状态是如何处理的,而对于一些全局的状态,例如后端 Api 数据、组件全局状态、本地化状态等,我们采用了 useContext / useReducer
结合的方式。
具体而言,我们将全局状态管理都存放在 src/contexts/ 目录下,其中包含4个子目录,分别为 actions / providers / reducer / states
,actions
包含了所有的全局状态指令,providers
提供了 useContext / useReducer
嵌入到 root dom
节点的方法,reducer
包含了所有的全局状态更新方法,states
则是全局状态数据结构和初始值。当然为了便于阅读和理解,我们对各个子目录安装业务逻辑进行了不同的划分,防止业务增多时带来不必要的臃肿。
对于组件内部的状态管理,我们倾向于使用 useState / useEffect
来封装,useEffect
可以代替 React 的生命周期方法,完成一些特定情况下的状态更新和处理,同时允许副作用的存在,我们将所有的组件封装到 src/components/
目录下,当然凡事也不是绝对的,对于 Header / Search
这种需要应对全局状态的组件,我们同时使用了内部状态和全局状态管理的方式。
对于前端应用来说,测试同样是必不可少的,我们除了对 utils
目录下的工具方法提供了完备的单元测试外,还针对组件和页面引入了相关的 UI 测试,包括 UI 组件检查和快照对比测试,基本上可以满足大部分的测试场景,由于页面还有改版升级的可能性,所以并没有对页面中的每个元素做详细的检查和数据 mock
。
在测试框架选型上,我们选择了 Facebook 的 Jest
和 Airbnb 的 Enzyme
,Jest
用于单元测试, Enzyme
在 React 组件检查测试和快照测试上都是非常不错的选择,而且两者的学习成本都不高,可以很快上手,快速实现较为完备的测试用例。
对于前端应用来说,追求测试覆盖度意义不是很大,首先绝大部分的 UI 并不是纯函数,其中包括了大量的异步请求、Hooks
方法、Dom
元素处理等,这些引入测试用例的复杂度要高很多,但是换来的质量可能并不没有很大的提高,同时前端页面经常出现改版升级等需求,每一次改版都需要对 UI 测试做调整,性价比不是很高。
对于 Nervos CKB Explorer
项目我们还有进一步完善和提高的空间,业务上需要满足区块、交易、地址、Token、图表、Nervos DAO
以及搜索,而且随着 Nervos CKB
的不断发展,未来还会有跟多的需求,这就对我们项目本身的扩展性和可维护性提出了很高的要求,我们也会在这个过程中不断尝试和调整。
在技术上我们希望 Nervos CKB Explorer 项目可以更符合开源精神和技术的最佳实践,我们希望可以给 Nervos CKB 社区和 Web 开发社区提供一些有益的业务和技术参考,同时我们也希望更多的开发者加入到 Nervos CKB 的社区生态中,欢迎大家给我们贡献代码和 Star,项目的 GitHub 地址为: https://github.com/nervosnetwork/ckb-explorer-frontend