React Native的组件开发一直处在一个比较尴尬的处境。在官方未给予相关示例与脚手架的情况下,社区中依然诞生了许许多多的React Native组件。因为缺少示例与规范,很多组件库仅含有一个index.js
文件。这种基础的目录结构也导致了一些显而易见的问题,例如“如何测试”,“如何预览”,“如何开发”……本文将为各位提供一种React Native组件开发的示例目录结构
及相关配置指南
。
示例目录结构
.
├── src
│ └── index.js
├── test
│ └── index.test.js
├── demo
│ ├── .gitignore
│ ├── .watchmanconfig
│ ├── App.js
│ ├── app.json
│ ├── babel.config.js
│ ├── metro.config.js
│ └── package.json
├── .eslintrc.js
├── babel.config.js
├── README.md
├── .gitignore
└── package.json
目录结构主要区分为4块内容根目录
,src目录
,test目录
,demo目录
。
根目录包含了eslint配置
,babel配置
,README
, gitignore
, package.json
。其中babel配置
与package.json中
的依赖
定义是为了运行测试用例而存在的。
src目录包含了当前React Native组件的源码,是组件开发最主要的目录。
test目录包含了当前React Native组件的测试相关代码。
demo目录包含了一个独立的Expo项目,其中App.js
文件是开发组件示例最主要文件,其中会引用src目录
中提供的组件来进行开发与展示。该目录的配置详情会在下文中继续展开。
为什么用Expo来进行开发与展示?
Expo是一个基于React Native包裹的React Native应用开发框架。许多React Native的开发者对于Expo依然持怀疑态度。不可否认的是用Expo来开发React Native应用确实存在一些问题,例如:
- 引入Expo SDK后,应用体积过大的问题
- 缺乏应用在后台运行的能力
- …
但是绝大多数Expo的弊端是我们在组件开发中不会遇到或者可以避开的,那么随之而来的便是Expo的优点:
- 快速安装与上手
- 快速在网页、模拟器、实机上预览或测试
- 与React Native的无缝兼容性
相信开发过React Native的同学一定会抱怨它沉重的依赖安装,与繁琐的调试过程,而Expo正好轻量化了这两个过程,不仅加速
了我们的组件开发
与预览
,也在我们的组件目录中去除了Native端相关的代码,轻量化
了我们的目录结构
。
相关配置指南
引入Expo
为组件项目引入Expo可能没有听上去这么容易,因为我们在上文的目录结构中将src目录
定义成与demo目录
平行的目录结构,这就导致了metro
(React Native打包工具)的默认配置将无法正常打包demo目录
中的React Native代码。为了解决这个问题,我们就需要手动去调整metro
的配置文件,而metro配置文档
又以“精简”著称,于是配置metro
便成了一个极大的困难点。
准备工作
首先我们需要安装Expo CLI工具
$ npm install -g expo-cli
在组件库的根目录
中运行
$ expo init demo
然后选择
blank template
managed workflow
你便在demo目录
中生成了一个可运行的Expo项目, 可以通过运行以下命令来预览当前的Expo项目
$ cd demo
$ yarn start
配置metro
旧版本metro通常使用
rn-cli.config.js
作为配置文件名,而新版本则使用
metro.config.js
作为配置文件名。旧版本
metro
的配置文件格式也与新版本有较大的差别。本文将重点关注新版本
metro
的配置。
在demo目录
中创建名为metro.config.js
的metro
配置文件,并在Expo的应用配置文件app.json
中添加如下字段用于重置项目根目录
配置与注入自定义的metro
配置文件
"packagerOpts": {
"projectRoots": "",
"config": "metro.config.js"
}
在metro.config.js
中添加如下内容
const path = require('path');
const blacklist = require('metro-config/src/defaults/blacklist');
const escapeRegexString = require('escape-regex-string');
module.exports = {
resolver: {
blacklistRE: blacklist([
new RegExp(
`^${escapeRegexString(path.resolve(__dirname, '..', 'node_modules'))}\\/.*$`,
),
]),
providesModuleNodeModules: [
'react-native',
'react',
'prop-types',
],
extraNodeModules: {
'@babel/runtime': path.resolve(__dirname, 'node_modules/@babel/runtime'),
},
},
projectRoot: path.resolve(__dirname),
watchFolders: [
path.resolve(__dirname, '..'),
],
};
来仔细解析一下上面的配置项
providesModuleNodeModules
: 该配置项为当前项目提供额外的providesModule
路径解析名。providesModule
简单来说就是一个提供文件路径别名的手段。例如在一个文件头部添加如下的注释,你就可以在项目别处通过import test from 'test'
直接引入该文件。/**
*/
```
在这里我们将注入在src目录
中被引用的三个库react-native
, react
, prop-types
,使得src目录
中的引用能正确被metro
解析。
-
extraNodeModules
: 该配置旨在为当前项目提供额外引入的模块,配置格式为[{ 模块名 : 路径 }]
。我们在这里配置src目录
中需要的额外模块,例如运行测试时所需要的@babel/runtime
模块。 -
blackListRE
: 配置一个正则,打包时忽略掉正则匹配到的路径。在这里我们将根目录
中的node_modules
路径下的所有内容忽略,目的是因为在根目录
下的node_modules
中会存在与demo目录
下node_modules
中相同的库,例如react-native
,react
,prop-types
。这就会使得providesModule
在解析时产生重名,从而导致jest-haste-map
报错。 -
projectRoot
: 配置项目的根目录。 -
watchFolders
: 为项目引入除projectRoot
外额外的目录,在这里我们将上层的根目录
加入metro
的关注列表。
配置完metro
,即可在App.js
中引入src目录
中的组件
import React from 'react';
import { StyleSheet, View } from 'react-native';
import Component from '../src';
const App = () => (
<View style={styles.container}>
<Component />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
现在运行yarn start
,就能顺利看到你的组件在Expo中展示了。
小结
本文主要提供了一种React Native组件的目录结构,与“如何在一个React Native组件工程中引入一个含Expo工程的子目录”的相关配置指南。这里还需要需要说明的一点是,React Native组件的目录结构可以有千万种,本文只是提供一种可行的思路供大家参考,如有更好的方案也欢迎交流与学习。本文将重点放在了引入Expo的配置指南上,如需查看该目录结构的所有文件配置,请转至Github。
相关
- react-native-component-cli – 快速生成该目录结构的脚手架工具
- react-native-hsv-color-picker – 基于该目录结构的组件案例