搭建 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 對象。

相關文章
相關標籤/搜索