搭建 RN 组件库

最近,在维护一个 RN 项目时,发现存在一些问题。当咱们开始使用 RN 以前,确定会作一些技术调研,好比技术难度、社区活跃度、小伙伴们的了解程度等,其中不可忽视的是有无现成成熟的 组件库 使用,这将使项目开发周期和效率有所提升。html

当咱们作好技术选型,选定好 组件库 后,随着项目的开发和不断迭代,可能会出现这么一些问题:前端

  1. 只使用了 组件库 中几个组件而已;
  2. 组件库中的组件须要作一些修改,可是修改起来却比较麻烦;
  3. 每每自定义的组件已经有十几个了;

那么这个时候,能够自定义组件,将第三方组件库替换掉,提取本身的组件发布到 npm 上。今天,咱们就来聊聊如何 搭建RN组件库。主要仍是学习如何开发一个组件库这么一个过程。过程很重要node

提早考虑的问题

当咱们决定开发一个 RN组件库 的时候,有几个问题须要提早考虑下:react

  1. RN组件库目录结构大概长啥样?
  2. 如何开发、预览、验证咱们写的组件?
  3. 如何发布组件库?

问题一:RN组件库目录结构长啥样

由于,咱们自定义的组件基本都是纯 js 的文件,不多有涉及到原生的功能(主要是不会0_0)。android

所以,咱们的目录组织结构,只须要有个 components 文件夹、一个入口文件index.js(将组件统一导出)、一个package.json文件,就能够了。固然,若是你有 icon assets 或者一些其余的目录也能添加进来。ios

这里须要多说一点,咱们只用关心最终上传 npm 的目录,而不用关心与预览相关的目录结构。好比 有两种方式,一种是当作一个RN项目开发,经过 npx react-native init xxx 来初始化项目。一种是 expo,不用搭建 RN 环境。git

我用的是第一种,因此 个人目录大体以下:github

.
├── README.md
├── app.json
├── android/
├── ios/
├── gulpfile.js
├── index.js
├── package.json
├── dist
│   ├── README.MD
│   ├── index.js
│   ├── package.json
│   └── src
│       ├── components
│       ├── icons
│       ├── themes
│       └── utils
└── src
    ├── App.js
    ├── component-path
    ├── components
    ├── icons
    ├── routes
    ├── themes
    ├── utils
    └── views

dist 目录 就是我最终用来发布 npm 的目录。dist/components 下的组件,是从 src/components 拷贝而来,其余相似目录,同理。至于其余文件和目录怎么来的,后面会讲到。npm

问题二:如何开发、预览、验证咱们写的组件

在开发组件的过程当中,须要实时预览组件的效果,那么组件在预览页面的引入方式多是这样的:json

// 预览页面可能位于 src/views/ButtonDemo.js
import { Button } from  '../components'

组件开发完,发布后,想要看线上组件的实际效果,引入可能会变成这样:

import { Button } from  'react-native-unit-zjp'

若是,你开发了有一些组件,有一些预览页面,那么,你在开发过程 和 发布后,为了预览组件,可能须要频繁修改组件路径。并且,还有一个问题,就是在开发完组件,预发布的时候,没法提早预览即将发到线上的组件效果。(我碰到过一个问题,就是本地开发,引入组件看效果的时候,没有任何问题;发布到线上,引入的时候,会报警告)

其实,咱们能够有一个统一修改组件引入路径的地方,解决这些问题。

src/component-path 下 添加 index.js 文件:

import  *  as  components  from  '../components'; // 本地调试
// import \* as components from '../../dist'; // 发布前测试包
// import \* as components from '../../node\_modules/react-native-unit-zjp'; // 正式依赖的包。

module.exports  = {
  Theme: components.Theme  ||   require('../themes/Theme'),
  ...components
};

有了这个开关文件后,预览页面的组件就能够这么引入了:

import { Button } from  '../component-path'

在组件开发,预发布,发布后 这几个阶段,只须要切换这一个路径就够了。

上面文件中之因此 要加 '../../node\_modules',是由于当 dist 目录下 的 package.json 存在时,直接从 react-native-unit-zjp 引入组件,会指向 dist 目录。

从这点能够得出,若是想要以特定名称引入某文件时,不想写长长的路径的话,能够在该目录下,新建一个 pacakage.json 而后指定它的 name 就能够了

问题三:如何发布组件库

发布 npm 包,其实很简单,就一句命令行的事 npm publish,固然,得从拥有一个 npm 帐号开始。这里就不细说了,能够看看官网,或者网上其余教程,很详细,一分钟教你发布npm包。这里只讨论,基于这个项目,怎么发布。

基于上面的思考,dist 成为了咱们的组件库发布目录了。这里之因此,单独弄个 dist 目录,只是为了将组件库自己所用到的依赖,与整个项目所用到的依赖区分开。若是,不想这么考虑,彻底能够不用 dist 目录,直接在 package.jsonfiles 字段配置须要发布的文件 及 目录。

若是想要 dist 目录,应该有如下这样的流程:

  1. 提交代码至 git,而后拷贝相关目录 到 dist(可用 gulp,下面会讲)
  2. cd dist
  3. npm version xxx
  4. npm publish

解决这三个问题后,咱们能够开始建立项目了。

建立 RN组件库项目

上面提到过,咱们只关心用于发布的 dist 目录,所以,怎么建立项目,就看我的喜爱。若是有现成 RN 开发环境,能够直接初始化一个 RN 项目。若是不想费力搭建 RN 开发环境,能够试试 expo。这里,我就用第一种了。

一、初始化 react-native 项目

npx react-native init xxx

二、开发组件

src/components 目录下开发你的组件。怎么开发组件,这里就不讲了,就当是一个 RN 项目来开发,该建啥目录,缺啥引啥,router 啥的。

组件开发完后,在 src/components 最好有个 导出组件的文件 index.js:

import  Button  from  './Button/Button.js';
export { Button }

三、添加发布文件夹 dist

为了目录清晰,以及有个 单独的 package.json 管理 发布包的版本,所以,决定单独弄个 dist 文件夹。将须要发布的文件及目录拷贝至 dist 目录中。

dist 目录 添加 package.json,执行 npm init 获得以下文件:

{
  "name": "react-native-unit-zjp",
  "version": "0.0.4",
  "description": "## 一套拿来就用的 ReactNative 组件库",
  "main": "index.js",
  "scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1"
  },
  "keywords": [
    "react-native"
  ],
  "author": "zhangjinpei",
  "license": "ISC",
  "dependencies": {
    "react-native-linear-gradient": "^2.5.6",
    "react-native-root-siblings": "^4.0.6"
  },
  "devDependencies": {},
  "repository": {
    "type": "git",
    "url": "xxx"
  },
  "bugs": {
   "url": "xxx"
  },
  "homepage": "xxx",
  "files": [
    "index.js",
    "README.md",
    "src"
  ]
}

四、拷贝组件到 dist/src 下

为了保持他们之间的引用路径,保持 dist 目录结构,跟 src 目录类似。

为了方便,这里经过 gulp 拷贝文件,配置以下:

const  gulp  = require('gulp');
const  rimraf = require('rimraf');
const { src, dest, task, series} = gulp;

task('clean', (cb) => {
  rimraf('dist/src', cb);
});

task('components', () => {
  return  src('src/components/\*\*/\*.\*')
    .pipe(dest('dist/src/components/'));
});

task('icons', () => {
  return  src('src/icons/\*\*/\*.\*')
    .pipe(dest('dist/src/icons/'));
});

task('themes', () => {
  return  src('src/themes/\*\*/\*.\*')
    .pipe(dest('dist/src/themes/'));
});

task('utils', () => {
  return  src('src/utils/\*\*/\*.\*')
    .pipe(dest('dist/src/utils/'));
});

task('readme', () => {
  return  src('./README.md')
    .pipe(dest('dist/'));
});

exports.default = series('clean', 'components', 'icons', 'themes', 'utils', 'readme');

五、导出组件

如今组件有了,还须要有个统一的地方导出组件。在 `dist` 目录添加入口文件,内容以下:

import  Theme  from  './src/themes/Theme'; // 这个是主题配置 如不须要 能够去掉
import  * as myUnit from './src/components';

module.exports  = {
  Theme,
  ...myUnit
};

这个时候,组件库的架子基本就差很少了,剩下的就是慢慢完善你的组件库了。

这是个人项目 react-native-unit-zjp,目前还在开发中,欢迎提出问题并star。

其余问题

npm 版本维护

当咱们开发好组件,或者是开发中时,须要将包提交到 npm 上,须要有个版本号,记录更改。

版本号,通常使用三位数来描述,以点来分割,例如:1.0.0

  • 主版本号:当你作了不兼容的 API 修改
  • 次版本号:当你作了向下兼容的功能性新增
  • 修订号:当你作了向下兼容的问题修正

经过执行,npm version xxx 来自动更新版本号。(须要将改动提交至 git ,而后再执行此命令。此命令,会自动打上 tag,并提交,须要手动 git push )

  • patch 1.0.0 => 1.0.1
  • minor 1.0.0 => 1.1.0
  • major 1.0.0 => 2.0.0

版本号更新好以后,就能够 npm publish 了。

注意: 首次 publish 只要有个版本号就能够,再次 publish 以前,必须更新版本号,也就是执行 npm version xxx 命令,否者会报错:

You cannot publish over the previously published versions: x.x.x;

package.json 属性概览

package.json 俗称 依赖配置文件(我本身取的名),最主要的做用就是,管理项目中所用到的依赖。它自己的做用是为 node.js 模块服务的,模块有不少属性,为了描述模块的特性,package.json 也被称做模块的 描述文件

name version

nameversionpackage.json 中最重要的两个属性,并且是必填的。这两个属性一块儿就造成了 npm 模块惟一标识符。分别表示 模块的 名称 和 版本。名称通常不会变,版本会随着模块的修改而更新变更。

description keywords

这两个字段都是用来在 npm 官网上搜索的, 区别是一个是字符串, 一个是字符串数组。

dependencies devDependencies

这两个属性,都是用来记录项目中所用到的依赖。区别是,一个是用来记录开发环境所用的依赖,一个是记录生产环境所用到的依赖。

好比,对于大多数前端项目来讲,gulp 等构件工具及插件,可能只在开发环境中使用,而在生产环境只关心最终生成的 dist 文件,因此,gulp 等插件 就应该放在 devDependencies 下。

经过 npm i xxx -savenpm i xxx -syarn add xxx -S 安装的依赖会添加到 dependencies 下;

经过 npm i xxx -save-devnpm i xxx -dyarn add xxx -D 安装的依赖会添加到 devDependencies 下;

peerDependencies

可让宿主环境拥有某个特定版本的依赖

探讨npm依赖管理之peerDependencies

前提项目X 依赖 模块A, 模块A 依赖 模块B

状况一:若是 模块B 定义在 模块Adependencies 字段中
结果模块B 只能被 模块A 引用
可能的好处:假如 项目X 也依赖 模块B,版本不同,则能够互不干扰。
可能的坏处:假如 项目X 也依赖 模块B,且版本同样,则会有两个如出一辙的 模块B

项目X
└──node_modules/
   └── 模块A
       └──node_modules/
          └── 模块B

状况二:若是 模块B 定义在 模块ApeerDependencies 字段中
结果项目X 也会下载 或 检查 模块b 的版本。
可能的好处:假如 项目X 也依赖 模块B,版本不同,则会在控制台以警告的形式提示版本问题。
可能的坏处:假如 项目X 也依赖 模块B,且版本同样,只用下载一遍。

项目X
└──node_modules/
   ├── 模块a
   └── 模块b

结论:定义在 peerDependencies 中的依赖,在宿主环境中,也会被下载 或 被检查版本。

files

files 是一个包含项目中的文件的数组。若是命名了一个文件夹,那也会包含文件夹中的文件。(除非被其余条件忽略了 .npmignore .gitignore)

npm publish 的时候,会依据这个配置 上传你的文件。

scripts

scripts 是一个由脚本命令组成的 kye value 对象。

相关文章
相关标签/搜索