beeshell —— 开源的 React Native 组件库

栏目: IOS · Android · 发布时间: 5年前

内容简介:beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 Native 代码),涉及前端(FE)、iOS、Android 三端技术,兼顾通用性和定制化,支持自定义主题,用于开发和服务企业级移动应用。现在已经在 GitHub 上开源,地址:截止目前,beeshell 中的组件已经在美团外卖移动端应用蜜蜂 App 中广泛应用,而且已经持续了一年多时间,通过了各种业务场景、操作

beeshell —— 开源的 React Native 组件库

介绍

beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 Native 代码),涉及前端(FE)、iOS、Android 三端技术,兼顾通用性和定制化,支持自定义主题,用于开发和服务企业级移动应用。现在已经在 GitHub 上开源,地址: https://github.com/meituan/beeshell

截止目前,beeshell 中的组件已经在美团外卖移动端应用蜜蜂 App 中广泛应用,而且已经持续了一年多时间,通过了各种业务场景、操作系统、机型的实战考验,具备很好的稳定性、安全性和易用性,所以我们将其开源,以期发挥出更大的应用价值。

特性

  • UI 样式的一致性和定制化。
  • 通用性。主要使用 JS 来实现,保证跨平台通用性。
  • 定制化。我们在比较细的粒度上对组件进行拆分,通过继承的方式层层依赖,功能渐进式增强,为在任意层级上的继承扩展、个性化定制提供了可能。
  • 原生功能支持。组件库中的复合组件包含 Native 代码,支持图片选择、定位等原生功能。
  • 功能丰富。不仅仅提供组件,还提供了基础 工具 、动画以及 UI 规范。
  • 完善的文档和使用示例。

对比

在开源之前,我们对业界已经开源的组件库进行了调研,这里主要对比了 beeshell 与其他组件库的优势与劣势,为大家选择组件库提供参考意见。目前,业界开源的组件库比较多,我们在这里仅选取 Github Star 数 5000 以上的组件库,并从组件数量、通用性、定制化、是否包含原生功能、文档完善程度五个维度来进行对比分析

组件库 组件数量 通用性 定制化 是否包含原生功能 文档完善程度
react-native-elements 16 强,提供一套风格一致的 UI 控件 弱,若要定制化可能需要重写
NativeBase 28 强,提供一套风格一致的 UI 控件 中,支持主题变量
ant-design-mobile 41 强,提供一套风格一致的 UI 控件 中,部分可以支持定制化需求
beeshell 25 强,提供一套风格一致的 UI 控件 强,不仅支持主题变量,还支持使用继承的方式进行定制化扩展

通过对比可以看出,beeshell 只在组件数量上稍有劣势,在其他方面都一致或者优于其他项目。因为 beeshell 具备了良好的系统架构,所以丰富组件数量只时间问题,而且我们团队也已经有了详细的规划来完善数量上的不足。

系统设计

系统设计是将一个实际问题转换成相应解决方案的主动过程,是解决办法的描述。在通用的软件工程模型中,需求分析完成后的第一步就是系统设计。一个项目最终的稳定性、易用性在很大程度上也取决于系统设计这一步。

beeshell 组件库是为了更加快速的搭建移动端应用,为业务开发提供基础技术支持,大幅提升开发人效。然而,面对不同的业务方、不同的功能需求、不同的 UI 规范与交互方式,如何有效的兼顾所有的需求?这对系统设计提出了更高的要求,下面以抽象层次逐层降低的方式来详细介绍 beeshell 的系统设计。

框架设计

这些年,React Native 的出现为移动端开发提供了一种新的选择。React Native 相比原生开发有着更高的开发效率,同时比 HTML5、Hybrid 的性能更好,所以能够脱颖而出,这也使得越来越多的开发者开始学习和使用 React Native。

beeshell 组件库基于 React Native,向下通过 React Native 与 iOS、Android 平台进行系统层面的交互,向上提供开发者友好的统一接口,抹平平台差异,为用户开发业务功能提供服务支持。beeshell 扮演了一个中间者的角色,从而保证了移动端应用基础功能的稳定性、易用性。

beeshell —— 开源的 React Native 组件库

框架设计确定了 beeshell 的系统边界,指明了包含的功能与不包含的功能之间的界限。明确了系统边界,我们才能继续进行下面的分析、设计等工作。

设计原则

在进行组件库的详细设计之前,我们提出了几个设计原则:

  • JS 实现优先。使用 JS 来实现功能有几个好处:跨平台通用性、更高的开发效率、更低的学习和使用成本。
  • 继承与组合灵活运用。继承和组合都是实现功能复用、代码复用的有效的设计技巧,都是 设计模式 中的基础结构。继承允许子类覆盖重写父类的实现细节,父类的实现对于子类是可见的,一般称之为“白盒复用”,这对组件的定制化扩展很有效,beeshell 强大的定制化扩展的能力就是基于继承实现;组合是 React 推荐的方式,React 组件具有强大的组合模型,整体类和部分类之间不会去关心各自的实现细节,它们之间的实现细节是不可见的,一般称之为“黑盒复用”。beeshell 也广泛使用了组合,基于通用型的组件组合出更加丰富、强大、个性化的功能,在一定程度上提高了 beeshell 的定制化的能力。
  • 低耦合、高内聚。一个 beeshell 组件本质上就是一个 React 组件,React 组件之间主要通过 Props 通信,这属于数据耦合,相比于内容耦合、控制耦合等其他耦合方式,数据耦合是耦合程度最低的一种,受益于 React 的实现,beeshell 组件低耦合是自然而然的;而要做的高内聚,则对组件的编码实现方式有一定的要求,我们推行内聚方式中内聚程度比较高的交互内聚和顺序内聚。使用单一数据源,使各个元素操作相同的数据结构,实现交互内聚。使用不可变数据更新的方式,上一个环节的输出是下一个环节的输入,像流水线一样处理逻辑,这便是顺序内聚。

方案设计

整体上使用 JS 作为统一入口,多层封装隐藏实现细节,抹平 JS 与 Native、iOS 平台与 Android 平台的差异,开箱即用,降低了用户的学习和使用成本。局部上基于 React Native 的技术特点,分成 JS 组件部分和复合组件部分,两部分推行“松耦合”的开发模式,使得 Native 部分拥有替换变更的能力,提升组件库的灵活性。

beeshell —— 开源的 React Native 组件库

复合组件部分可以直接暴露 JS 接口,如果有需要,也可以在 JS 组件部分进行定制化封装。我们尽量保证 Native 部分功能的原子性、简洁性,有任何定制化需求都使用 JS 来统一实现,遵循 JS 实现优先的设计原则,保证跨平台通用的特性。下面分别介绍 JS 组件部分和复合组件部分的设计。

JS 组件部分设计

一个软件的设计分为三个设计层次:体系结构、代码设计和可执行设计。我们使用自上而下的方法,从体系结构开始进行 JS 组件部分的设计。

软件的体系结构的风格通常有 7 种:管道和过滤器,面向对象,隐式请求,层次化,知识库,解释程序和过程控制。

JS 组件部分使用了层次化的体系结构风格,整体分成三层:基础工具、通用组件、扩展组件,从上到下通用性逐渐减弱、定制化逐渐增强,功能渐进式增强,通过分层设计,各层各司其职,兼顾通用性和定制化。

beeshell —— 开源的 React Native 组件库

  • 基础工具(common):最基础的、通用的部分,包含 JS Utils、动画定义、UI 规范等。
  • 通用组件(components):把功能相似的组件进行归类,整理成一个个系列,每个系列内部使用继承的方式实现,层层依赖,功能渐进式增强,该部分专注通用性,不考虑定制化需求,保证代码的简洁性。同时,在比较细的粒度对组件进行拆分,提供了良好的可扩展性。
  • 扩展组件(modules):是对通用组件的继承扩展、组合应用,该部分专注定制化,在最大程度上满足业务上的需求,通用性较低。

我们扩展组件部分会提供大量的定制化组件,如果仍然不能满足需求,用户就可以借鉴扩展组件的实现,根据自己业务需求,在某一继承层级上继承通用组件,自行进行定制化扩展,这点充分体现了 beeshell 定制化的能力。

复合组件部分设计

既然是 React Native 组件库当然少不了 Native 部分,复合组件包含 Native 的功能。beeshell 组件库已经完成了 Native 部分的集成方案与规范,有良好的开发与使用体验,可以不断的集成原生功能。

beeshell —— 开源的 React Native 组件库

复合组件部分通过 JS 封装接口,保证了跨平台。Native 部分主要分成 Native Bridge 和纯 Native 两大部分,Bridge 是针对 React Native 的封装,必须在组件库中实现;而纯 Native 部分则可以通过 Pods/Gradle 依赖三方实现,有效的吸收利用原生开发的技术积累。

组件库实现

跨平台通用性保障

React Native 提供了一些内置组件,我们能使用 JS 来实现功能都是基于这些内置组件,这些内置的组件一些是跨平台通用的组件,如:View、Text、TextInput;而另一些是两个平台分别实现的,如 DatePickerIOS 和 DatePickerAndroid、AlertIOS 和 ToastAndroid。跨平台组件当然没有什么问题,我们可以专注业务功能的开发,问题是这些非跨平台的组件,给我们的业务功能开发带来极大困扰,下面举例说明。

iOS 平台的 DatePickerIOS 组件:

beeshell —— 开源的 React Native 组件库

Android 平台的 DatePickerAndroid 组件:

beeshell —— 开源的 React Native 组件库

不仅功能交互完全不同,而且类名、调用方式各异,这不仅满足不了业务需求,而且也有很高的学习和使用成本。这样类似的组件还有很多,如何抹平平台的差异,实现跨平台?我们提出的方案是优先使用 JS 来实现功能,这也是我们组件库的设计原则。

针对上面的问题我们开发了基于 ScrollView 的 Datepicker 组件,统一类名与调用方式,保证了跨平台通用性。

iOS 平台的 Datepicker 组件:

beeshell —— 开源的 React Native 组件库

Android 平台的 Datepicker 组件:

beeshell —— 开源的 React Native 组件库

Datepicker 是使用 JS 完全实现了一个完整功能,但是有的情况不需要实现完整的功能,我们可以通过 React Native 提供的 Platform 来进行局部的跨平台处理,例如 TextInput 组件。

iOS 平台的 TextInput 组件:

beeshell —— 开源的 React Native 组件库

Android 平台的 TextInput 组件:

beeshell —— 开源的 React Native 组件库

我们可以看到,在 Andriod 平台并没有清空图标,为了抹平平台的差异,提供更好的通用性,我们开发了 Input 组件,对 TextInput 进行封装与优化,利用 Platform 定位 Android 平台提供清空功能,

Input 组件在 Android 平台的效果:

beeshell —— 开源的 React Native 组件库

总之,beeshell 对跨平台通用性做了进一步的优化,遵循 JS 实现优先的原则,配合 Platform 平台定位 API 为组件的易用性、通用性提供了更好的保障。

定制化支持

随着移动互联网的快速发展,各类移动端产品涌现并且不断发展,这也让软件知识不断被普及,业务方对产品功能的定位逐渐从厂商主导转变为用户主导。产品功能更加精准,个性化、细化、深化是必然趋势,通过定制化服务来满足产品发展的要求也应运而生。不同行业、不同类型的产品,功能、特点各不相同,用某一种既定的软件产品来满足不同类型的需求,其适用性可想而知。定制化有良好的技术架构和技术优势,可定制、可扩展、可集成、跨平台,在个性化需求的处理方面,有着很好的优势,所以我们需要定制化。

综上所述,beeshell 把定制化作为核心特性,力求满足不同产品的定制化需求,下文将从组件的样式定制化和功能定制化两方面来进行阐述。

样式定制化

beeshell 的设计规范支持一定程度的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于品牌色、圆角、边框等的视觉定制。

beeshell —— 开源的 React Native 组件库

在组件库设计之初,就已经统一好了 UI 规范。我们根据 UI 规范,统一定义样式变量并放置在基础工具层中,即 beeshell/common/styles/varibles.js 文件中,在 React Native 应用中,样式变量其实就是普通的 JS 变量,可以很方便的进行复用与重写操作。React Native 提供了 StyleSheet 通过创建一个样式表,使用 ID 来引用样式,减少频繁创建新的样式对象,在组件库的样式变量应用中灵活使用 StyleSheet.createStyleSheet.flatten 来获取样式 ID 和样式对象。

在每个组的实现中,会事先引入基础工具层中的样式变量,使用统一的变量对象而不是在组件中自行定义,这样就保证了 UI 样式的一致性。同时,beeshell 提供了重置样式变量的 API,可以实现一键换肤。我们推荐 beeshell 的用户在开发移动应用时,事先定义好样式变量。一方面使用自己的样式变量重置 beeshell 的样式变量;另一方面在业务功能开发时,使用自己定义好的样式变量,从而保证整体 UI 的一致性。

功能定制化

样式定制化可以从宏观和整体的角度来实现,而功能的定制化则需要具体问题具体分析,从微观和局部的角度来分析和实现。下文将以 Modal 系列的实现为例,来详细介绍功能定制化。

在移动端的弹窗交互,与 PC 端相比一般会比较简单,我们把模态框、下拉菜单、信息提示等交互类似的组件统一归类为 Modal 系列,使用继承的方式实现。有人可能会问为什么使用继承而不用使用组合?前文已经讲过,组合的主要目的是代码复用,而继承的主要目的是扩展。考虑到弹窗交互有很多定制化的可能性,为了满足更好的扩展性,我们选择了继承。

首先我们看下几个组件的实现效果图,对 Modal 系列先有一个直观的认识。

Modal 组件:

beeshell —— 开源的 React Native 组件库

提供了遮罩、弹出容器以及淡入淡出(Fade)动画效果,弹出内容部分完全由用户自定义。这个组件通用性极强,没有任何定制化的功能。这里需要说明下,动画部分独立实现,提供了 FadeAnimated 和 SlideAnimated 两个子类,使用了策略模式与 Modal 系列集成,Modal 组件默认集成 FadeAnimated。

ConfirmModal 组件:

beeshell —— 开源的 React Native 组件库

继承 Modal 组件,对弹出内容做了一定程度的定制化扩展,支持标题、确认按钮、取消按钮以及自定义 body 部分的功能,通用性减弱,定制化增强。

SlideModal 组件:

beeshell —— 开源的 React Native 组件库

继承 Modal 组件,对动画、弹出容器做了重写,在初始化时实例化 SlideAnimated 类型对象,完成上拉、下拉动画,同时支持了自定义弹出位置的功能。

PageModal 组件:

beeshell —— 开源的 React Native 组件库

继承 SlideModal 组件,对弹出内容做了定制化扩展,支持标题、确认按钮、取消按钮以及自定义 body 功能,通用性减弱,定制化增强。

CheckboxModal 组件:

beeshell —— 开源的 React Native 组件库

CheckboxModal 组件由 PageModal 和 Checkbox 两个组件使用组合的方式实现,基于通用型组件组合出了更加强大功能,遵循继承与组合灵活运用的设计原则。

通过以上部分,我们已经对 Modal 系列已经有了直观的认识,然后我们来看下 Modal 系列的类图以及分层:

beeshell —— 开源的 React Native 组件库

动画部分在基础工具(common)中实现;在通用组件(components)中 Modal 组件聚合 FadeAnimated 动画,同时因为 SlideModal、ConfirmModal 比较通用,也在该部分实现;CheckboxModal 则定制化比较强,归类到扩展组件(modules)中。通过这种方式的分层,三层各司其职,使得组件库的层次结构更加清晰,不仅实现了定制化,还保证了通用部分的简洁性和可维护性。

复杂 Case 处理

相互递归处理异步渲染

React Native 应用的 JS 线程和 UI 线程是两个线程,与浏览器中共用一个线程的实现不同,所以我们可以看到 React Native 提供的操作 UI 元素的 API,都是通过回调函数的方式进行调用。

受益于 React,我们一般不需要直接操作 UI 元素,但是有的组件确实需要复杂的 UI 操作,例如完全由 JS 实现的 Scrollerpicker 组件:

beeshell —— 开源的 React Native 组件库

我们需要精确的计算容器以及每一项元素的高度,才能正确得到当前选中的项在数据模型(数组)中的索引。现在面临的问题是:在组件渲染完成后的生命周期 componentDidMount 并不能拿到正确容器的高度为,而使用 setTimeout 也会有延迟时长设置为多少的问题。我们选择使用递归来解决,一次 setTimeout 不行就执行多次。

beeshell —— 开源的 React Native 组件库

这里使用了交互递归,反复执行,直到得到有效的元素尺寸。

UI 尺寸容错机制

React Native 为用户提供了 style 属性来控制元素的样式,我们可以手动设置相关 UI 元素的尺寸。但是,在一些 Android 机器上,我们设置的元素尺寸与 measure 方法获取的尺寸信息不一致,经过大量 Android 机器的实际的测试,我们得到的结论是:有零点几像素的误差。

beeshell —— 开源的 React Native 组件库

我们把通过 measure 方法得到尺寸信息进行向上与向下取整,得到一个阈值范围,手动设置的尺寸信息只要在这个阈值范围内,就认为是有效尺寸,这种容错机制有效的兼容了极端情况,提高了组件的稳定性。

精细化布局控制

在使用 Form 组件时,最常见的需求就是校验功能,通常组件库的 Form 组件都会内置校验功能。然而,因为校验方式有同步与异步两种,校验结果展示的样式、位置五花八门,这就导致了校验功能的复杂度变得很高。

绝对定位:

beeshell —— 开源的 React Native 组件库

Static 定位:

beeshell —— 开源的 React Native 组件库

自定义位置

beeshell —— 开源的 React Native 组件库

如何有效的兼顾不同的需求?我们提出了校验独立实现的方式,在使用 Form 组件的父组件中,使用 CVD 来定义、配置校验规则,校验结果输出到统一的数据结构(单一数据源),基于这个数据结构,我们就能在任意时机、任意位置、使用任意样式来展示校验信息。

下面我们先介绍下 CVD:

beeshell —— 开源的 React Native 组件库

CVD 是一个针对复杂表单录入场景的分层解决方案,轻量级、跨平台、易扩展,内置在 beeshell 组件库中,可以直接使用。

CVD 把表单某个控件的录入的流程分成三层:

  • Connector 连接器,把用户输入的信息转化成所需的数据格式。
  • Validator 校验器,对格式化的数据进行校验。
  • Dependency 依赖处理器,处理当前控件与其他控件的依赖关系。

每一层都对单一数据源 Store 进行不可变数据更新,符合交互内聚和顺序内聚,内聚程度高。

每一层使用函数式组合的方式,定义 key(表单控件的唯一标志)与 key 对应的回调函数,避免了批量 if else ,可以有效降低程序的圆环复杂度。

下面以 Input 组件录入姓名为例,来具体说明,代码如下:

beeshell —— 开源的 React Native 组件库

onChange 中获取用户输入,调用 cvd.flow 然后就可以通过 cvd.getStore 获取到结果:

beeshell —— 开源的 React Native 组件库

通过校验功能独立实现,把校验信息输出到 Store 中,在需要的时候从 Store 中获取校验信息,可以更加精细化的控制元素的样式、位置与布局,兼容各种定制化需求。很多时候,只有我们想不到,没有做不到。

测试

代码的终极目标有两个,第一个是实现需求,第二个是提高代码质量和可维护性。测试是为了提高代码质量和可维护性,是实现代码的第二个目标的一种方法。

单元测试

单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证。在结构化编程的时代,单元测试中单元指的就是函数。beeshell 组件库全面使用单元测试,由组件的开发者完成。研究成果表明,无论什么时候作出修改都需要进行完整的回归测试,对于提供基础功能的组件来说更是如此,在生命周期中尽早地对软件产品进行测试将使效率和质量都得到最好的保证。Bug 发现的越晚,修改它所需的成本就越高,单元测试是一个在早期抓住 Bug 的机会。

单元测试的优点有以下几点:

  • 是一种验证行为。程序的每一项功能是测试来验证正确性,为后期的增加功能、代码重构提供了保障。
  • 是一种设计行为。单元测试使得我们从调用者的角度观察、思考,迫使开发者把程序设计成易于调用和可测试的,在一定程度上降低耦合性。
  • 是一种编写文档的行为。是展示函数、类使用的最佳文档。

beeshell 组件库使用 Jest 做为单元测试的工具,自带断言、测试覆盖率工具,实现开箱即用。

测试用例设计

测试用例的核心是输入数据,我们会选择具有代表性的数据作为输入数据,主要有三种:正常输入,边界输入,非法输入,下面以组件库中提供的 isLeapYear 工具函数来举例说明,代码如下:

beeshell —— 开源的 React Native 组件库

Jest 使用 test 函数来描述一个测试用例,其中的 toBe 边是一句断言。

函数使用了外部数据,正常输入肯定会有,这里的 2000'2000' 都是正常输入;边界输入和非法输入并不是所有的函数都有,这里为了说明使用了有这两种输入的例子,边界输入是有效输入的极限值,这里 0Infinity 是边界输入;非法输入是正常取值范围以外的数据, 'xx'false 则是非法输入。一般情况下,考虑以上三种输入可以找出函数的基本功能点,单元测试与代码编写是“一体两面”的关系,编码时对上述三种输入都是应该考虑的,否则代码的健壮性就会出现问题。

上文所说的测试是针对程序的功能来设计的,就是所谓的“黑盒测试”。单元测试还需要从另一个角度来设计测试数据,即针对程序的逻辑结构来设计测试用例,就是所谓的“白盒测试”。

还是以 isLeapYear 函数来进行说明,其代码如下:

beeshell —— 开源的 React Native 组件库

这里有一个 if else 语句,如果我们只提供一个 2000 的输入,只会测试到 if 语句,而不会测试 else 语句。虽然,在黑盒测试足够充分的情况下,白盒测试没有必要,可惜“足够充分”只是一种理想状态,难于衡量测试的完整性是黑盒测试的主要缺陷。而白盒测试恰恰具有易于衡量测试完整性的优点,两者之间具有极好的互补性,例如:完成功能测试后统计语句覆盖率,如果语句覆盖未完成,很可能是未覆盖的语句所对应的功能点未测试。

白盒测试也是比较常见的需求,Jest 内置了测试覆盖率工具,可以直接在命令中添加 --coverage 参数便可以输出单元测试覆盖率的报告,结果如下:

beeshell —— 开源的 React Native 组件库

可以看到代码的每一行都覆盖到了 Coverage 为 100%,在很大程度上保证了功能的稳定性。

UI 自动化测试

想要确保组件库的 UI 不会意外被更改,快照测试(Snapshot Testing)是非常有用的工具。一个典型的移动 App 快照测试案例过程是,先渲染 UI 组件,然后截图,最后和独立于测试存储的参考图像进行比较。使用 Jest 进行在快照测试,在 beeshell 中第一次对某个组件进行测试时,会在测试目录下创建一个 snapshots 文件夹,并将快照结果存放在该文件夹中。快照结果文件以 <组件名>.js.snap 命名,其内容为某个状态下的 UI 组件树。

下面以 Button 组件快照测试为例来说明:

beeshell —— 开源的 React Native 组件库

运行命令后得到快照结果:

beeshell —— 开源的 React Native 组件库

静态分析

经常与单元测试联系起来的开发活动还有静态分析(Static analysis)。静态分析就是对软件的源代码进行研读,查找错误或收集一些度量数据,并不需要对代码进行编译和执行。

静态分析效果较好而且快速,可以发现 30%~70% 的代码问题,可以在几分钟内检查一遍,成本低、收益高。beeshell 使用 SonarQube 进行静态代码检查。

SonarQube 是一个开源的代码质量管理系统,支持 25+ 种语言,可以通过使用插件机制与 Eclipse、VSCode 等工具集成,实现对代码的质量的全面自动化分析和管理。

SonarQube 通过对 Reliability(可靠性)、Security(安全性)、Maintainability(可维护性)、Coverage(测试覆盖率)、Duplications(重复)几个维度,对代码进行全方位的分析,通过设置 Quality Gates 保证代码质量。

beeshell 组件库的分析结果概况如图:

beeshell —— 开源的 React Native 组件库

可靠性达到 A 级别,是最高等级,表示无 Bug:

beeshell —— 开源的 React Native 组件库

安全性达到 A 级别,是最高等级,表示无漏洞:

beeshell —— 开源的 React Native 组件库

测试覆盖率平均达到 70% 以上

beeshell —— 开源的 React Native 组件库

开发与使用一致性

beeshell 组件库使用 npm 包的形式下载使用,下载成功后会放置在项目根目录的 node_modules 目录,然后在项目中通过引入模块的方式,引入 beeshell 的组件来使用。

那我们如何开发组件库?如何保证组件库的开发与使用的体验一致性?

首先,我们需要一个 demo 项目,这个项目是 beeshell 组件库的开发环境,是一个 React Native 应用。然后,我们把 beeshell 做为 demo 项目的依赖,在 demo 项目中下载安装。

现在,我们的问题就变成了 node_modules 目录中的 beeshell 如何和本地的 beeshell 源码进行同步。

npm link

我们知道可以使用 npm link 来开发 npm 包,原理如下:

beeshell —— 开源的 React Native 组件库

本质是就是使用 Symbol link,但是我们建立好软链接后,运行打包命令却报错了,错误信息为 Expected path '/xxx/xxx/index.js' to be relative to one of project roots

我们前端开发通常会用 Webpack 做为打包工具,而 React Native 应用使用的是 Metro,我们需要分析 Metro 来定位问题。

Webpack vs Metro

经过 Metro 的源码分析,我们发现 Metro 的打包方案与 Webpack 有较大差异,Webpack 是根据入口文件,即配置中的 entry 属性,递归解析依赖,构建依赖关系图而 Metro 是爬取特定路径下的所有文件来构建依赖关系图。

分析发现 Metro 的特定路径默认是运行打包命里的路径,以及 node_modules 下第一层目录,这样我们就定位到了问题的所在:

beeshell —— 开源的 React Native 组件库

Metro 在爬取文件的时候,通过软链接找到了全局的 beeshell 但是并没有继续判断全局的 beeshell 是否有软链接,所以无法爬取 beeshell 源码部分。

直接使用软链接

通过 ln -s 命令,直接建立 demo 项目 node_modules 下 beeshell 包 与 beeshell 源码的软链接:

beeshell —— 开源的 React Native 组件库

这种方式同时支持 Native 部分 iOS、Android 的源码开发,注意 Android 部分的需要在 setting.gradle 中调用 getCanonicalPath 方法获取建立软链接后的路径。

通过试验、发现问题、分析源码、定位问题、解决问题、方案完善这几个步骤,完整的实现了 beeshell 组件库的开发与使用的体验一致性,同时提升了组件库的开发效率。

未来展望

我们的目标是把 beeshell 建设成为一个大而全的组件库,不仅会不断丰富 JS 组件,而且会不断加强复合组件去支持更多的底层功能。因为我们支持全部引入和按需引入两种方式,用户不需要担心会引入过多无用组件而使得包体积过大,影响开发和使用效率。

beeshell 目前提供了 20+ 组件以及基础工具,基于良好的架构设计、开发体验,为我们不断地丰富组件库提供了良好的基础。同时在开发 React Native 应用的几年时间中,我们已经积累了 50+ 基础以及业务组件,我们后续会把积累的组件进行梳理与调整,全部迁移到 beeshell 中。因为我们的组件主要来源于我们的业务需求,但是业务场景有限,可能会使得 beeshell 的发展受到限制,所以我们将其开源。希望借助社区的力量不断丰富组件库的功能,尽最大努力覆盖到移动应用方方面面的功能,欢迎大家献计献策,多多支持。

我们为组件库发展规划了三个阶段:

  • 第一阶段,即我们现在所处的阶段,开源 20+ 组件,主要提供基础功能。
  • 第二阶段,对我们在开发 React Native 应用几年时间积累的组件进行整理,开源 50+ 组件。
  • 第三阶段,调研移动端 App 常用的功能,分析与整理,然后在 beeshell 中实现,开源 100+ 组件。

开源相关

Git 地址

beeshell

核心贡献者

前端: 小龙孟谦

Native: 渊博杨超

发现文章有错误、对内容有疑问,都可以关注美团技术团队微信公众号(meituantech),在后台给我们留言。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!

beeshell —— 开源的 React Native 组件库


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

REST in Practice

REST in Practice

Jim Webber、Savas Parastatidis、Ian Robinson / O'Reilly Media / 2010-9-24 / USD 44.99

Why don't typical enterprise projects go as smoothly as projects you develop for the Web? Does the REST architectural style really present a viable alternative for building distributed systems and ent......一起来看看 《REST in Practice》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具