開發本身的react-native組件併發布到npm[轉]

原文連接:https://www.jianshu.com/p/091a68ea1ca7

寫在前面

在作react-native開發的時候,咱們常常會找到一些第三方組件,而且經過npm install的方式很方便的安裝使用。在使用的同時,你是否想過,咱們本身應該如何開發併發佈一個組件呢?不論是給本身的多個項目共用,或者開源給到別人用,這都是一件很酷的事情。javascript

那麼今天,我就以我本身開發的一個在iosandroid通用的CardView組件爲例來說一下,如何開發一個本身的組件,並開源到github、發佈到npm上去css

一個說明java

個人組件名爲react-native-rn-cardview。教程裏若是出現react-native-cardview組件名,視爲同一意思。node

1 建立並實現

1.1 建立自定義組件模版項目

1.1.1 安裝react-native-create-library

$ npm install -g react-native-create-library

1.1.2 建立模板項目

咱們用命令react-native-create-library建立項目,並指定平臺爲ios,android,指定android中的package,其餘參數能夠自行參考在react-native-create-librarygithub 上的文檔說明,這裏就不贅述react

$ react-native-create-library --package-identifier com.quenice.cardview --platforms android,ios cardview

咱們重命名一下項目名android

$ mv cardview react-native-cardview

有人可能會說,樓主爲何不直接生成react-native-cardview的項目,而要先生成cardview再重命名。其實這是一個小技巧,由於利用react-native-create-library生產的項目,一些跟組件相關的名稱或者類會默認加上react-native或者RN前綴。
例如,若是你的初始項目名是react-native-card-view,那麼package.json中定義的組件名將是react-native-react-native-card-view,android模塊中定義的相關類會是RNReactNativeCardviewModule.java,這顯然比較醜啊。ios

ok, 咱們繼續。git

如今的目錄結構:github

$ tree
└── react-native-cardview
    ├── README.md
    ├── android
    │   ├── build.gradle
    │   └── src
    │       └── main
    │           ├── AndroidManifest.xml
    │           └── java
    │               └── com
    │                   └── reactlibrary
    │                       ├── RNCardviewModule.java
    │                       └── RNCardviewPackage.java
    ├── index.js
    ├── ios
    │   ├── RNCardview.h
    │   ├── RNCardview.m
    │   ├── RNCardview.podspec
    │   ├── RNCardview.xcodeproj
    │   │   └── project.pbxproj
    │   └── RNCardview.xcworkspace
    │       └── contents.xcworkspacedata
    └── package.json

生成好組件項目後,就能夠開始編寫實現代碼了npm

2 編寫代碼

編寫代碼分爲三部分,一部分是android原生代碼,一部分是iOS原生代碼,一部分是react-native(或者javascript)代碼。因爲react-native-cardview只涉及到android原生模塊,因此本篇文章暫不涉及到iOS原生模塊開發,若是你們感興趣,我能夠另開一篇文章專門講一下iOS原生模塊相關內容

2.1 編寫Android Native Module

編寫android原生代碼,通常如下三個類是必須的:

2.1.1 RNxxxModule

這個類主要做用是定義原生模塊名,能夠直接在javascript中經過React.NativeModules.xxx來訪問,其中xxx是在RNxxxModule類中定義的getName方法返回值。如下爲我組件react-native-cardview中的Module類

RNCardViewModule.java

package com.quenice.reactnative;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

public class RNCardViewModule extends ReactContextBaseJavaModule {

  private final ReactApplicationContext reactContext;

  public RNCardViewModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
  }

  @Override
  public String getName() {
    return "RNCardView";
  }
}

2.1.2 RNxxxManager

Manager類主要是組件的原生實現,而且把react-native組件的屬性映射到原生屬性

RNCardViewManager.java

package com.quenice.reactnative;

import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.view.View;

import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.view.ReactViewGroup;

public class RNCardViewManager extends ViewGroupManager<CardView> {
    @Override
    public String getName() {
        return "RNCardView";
    }

    @Override
    protected CardView createViewInstance(ThemedReactContext reactContext) {
        CardView cardView = new CardView(reactContext);
        cardView.setUseCompatPadding(true);
        cardView.setContentPadding(0, 0, 0, 0);
        ReactViewGroup reactViewGroup = new ReactViewGroup(reactContext);
        cardView.addView(reactViewGroup);
        return cardView;
    }

    @ReactProp(name = "cardElevation", defaultFloat = 0f)
    public void setCardElevation(CardView view, float cardElevation) {
        view.setCardElevation(PixelUtil.toPixelFromDIP(cardElevation));
    }
...
}

2.1.3 RNxxxPackage

Package類主要用於註冊原生模塊、原生組件實現,也就是註冊上面的Module和Manager類

RNCardViewPackage.java

package com.quenice.reactnative;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;
public class RNCardViewPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
      return Arrays.<NativeModule>asList(new RNCardViewModule(reactContext));
    }

    // Deprecated from RN 0.47
    public List<Class<? extends JavaScriptModule>> createJSModules() {
      return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
      return Arrays.<ViewManager>asList(new RNCardViewManager());
    }
}

2.2 編寫iOS原生代碼

react-native-cardview
iOS的實現方式直接利用react-nativeshadow相關屬性就能夠實現,因此本文暫不涉及

2.3 編寫ReactNative代碼

編寫好了android/iOS原生模塊後,須要編寫javascript代碼來橋接react-native與原生模塊。

RNCardView.android.js

import PropTypes from 'prop-types';
import {requireNativeComponent, View} from 'react-native';

const iface = {
    name: 'CardView',
    propTypes: {
        cardElevation: PropTypes.number,
        maxCardElevation: PropTypes.number,
        backgroundColor: PropTypes.string,
        radius: PropTypes.number,
        ...View.propTypes, // include the default view properties
    },
};

module.exports = requireNativeComponent('RNCardView', iface);

3 代碼上傳與組件發佈

3.1 代碼上傳到github

編寫完代碼後,咱們須要把它上傳到github上,以後在組件發佈到npm的時候也須要用到代碼的github地址
。若是你沒有作github相關的配置,能夠參考我另外一篇文章:安裝GIt並配置鏈接GitHub

執行如下命令把代碼同步到你github對應的repository中:

$ git add .
$ git commit -a -m "initial commit"
$ git push -u origin master

同步以後能夠到github中看下是否push成功:

https://github.com/YourGithubAccount/YourRepository

3.2 組件發佈

開發好組件以後,想在其餘的項目(或者提供給其餘人安裝使用)中經過npm install的方式安裝你的組件,那麼你的組件必須發佈到npm registry中。

3.2.1 npm registry

npm registry 是什麼

簡單來講,npm registry就至關於一個包註冊管理中心。它管理着全世界的開發者們發佈上來的各類插件,同時開發者們能夠經過npm install的方式安裝所須要的插件。

npm官方registry爲:http://registry.npmjs.org/

國內速度較快的爲:https://registry.npm.taobao.org/

查看

你能夠查看當前使用的registry:

$ npm config get registry

切換

固然也能夠經過命令切換當前使用的npm registry

# 全局切換
$ npm config set registry http://registry.npmjs.org/

有時候你可能只想在執行某些npm命令時臨時切換,這個時候,可使用--registry來指定臨時切換的registry,好比在npm發佈

$ npm publish --registry http://registry.npmjs.org/

就能夠臨時指定,固然,在命令執行結束以後,registry仍然會恢復到原來的registry

3.2.2 建立/登錄npm registry帳戶

要發佈組件到npm registry,你必需要是npm registry的註冊用戶,經過:

$ npm adduser

來新增一個用戶,或者你已經在官網註冊了一個用戶,能夠經過:

$ npm login

來登錄npm registry帳戶。

利用如下兩種方式來確認你是否建立/登錄成功npm registry

  1. 命令$ npm whoami確認本地是否成功登錄認證成功
  2. 在線打開 https://npmjs.com/~username 查看是否建立帳戶成功

3.2.3 發佈前準備

3.2.3.1 .gitignore 和 .npmignore

  1. .gitignore中定義哪些文件不上傳到github中
  2. .npmignore中定義哪些文件發佈時不打包
  3. 若是有.gitignore可是沒有.npmignore文件,那麼.gitignore能夠充當.npmignore的做用
  4. 具體規則能夠參照:npm-developers, .gitignore or .npmignore pattern rules

3.2.3.2 package.json

package.json文件定義了發佈的全部信息,包括:組件名、版本、做者、描述、依賴等等關鍵信息。具體能夠參照 Working with package.json

下面是react-native-cardview的package.json文件內容:

{
  "name": "react-native-rn-cardview",
  "version": "1.0.0",
  "description": "A ReactNative CardView Component for android and iOS",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "react-native",
    "react-component",
    "react-native-component",
    "react",
    "mobile",
    "ios",
    "android",
    "cardview"
  ],
  "author": {
    "name": "quenice",
    "email": "qiubing.it@gmail.com"
  },
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git@github.com:quenice/react-native-cardview.git"
  },
  "devDependencies": {
    "react": "^16.2.0",
    "react-native": "^0.53.0"
  },
  "peerDependencies": {
    "react": "^16.2.0"
  },
  "dependencies": {
    "prop-types": "^15.6.0"
  }
}

3.2.3.3 編寫readme.md

能夠在readme.md文件中詳細說明組件的使用方法、注意事項等。通常使用Markdown語法來編寫

3.2.4 發佈

作好以上準備以後,就能夠發佈了。這裏須要注意,首次發佈跟後面更新發布是不同的。

首次發佈

第一次發佈的話,直接執行命令:

$ npm publish

就搞定了,能夠在線查看確認是否發佈成功。訪問連接(<package>是你發佈的npm package名):
https://www.npmjs.com/package/<package>
看看是否已經有內容了,有內容說明發布成功了。

更新發布

若是不是首次發佈,須要執行兩個命令

$ npm version <update_type>
$ npm publish

$ npm version命令是用來自動更新版本號,update_type取值有patch minor major。那麼在什麼場景應該選擇什麼update_type呢?看下錶

update_type 場景 版本號規則 舉例
- 首次發佈 版本號1.0.0 1.0.0
patch 修復bug、微小改動時 從版本號第3位開始增量變更 1.0.0 -> 1.0.1
minor 上線新功能,而且對當前版本已有功能模塊不影響時 從版本號第2位開始增量變更 1.0.3 -> 1.1.3
major 上線多個新功能模塊,而且對當前版本已有功能會有影響時 從版本號第1位開始增量變更 1.0.3 -> 2.0.0

注意

若是首次發佈版本號不是1.0.0的話,那麼用$ npm version <update_type>
來更新會報錯,由於你沒有按照它約定的版本規則來,這個時候,你能夠手動修改package.json中的version字段爲符合約定規則的版本號,而後直接執行$ npm publish就能夠,而後下次再增量更新的時候,就能夠直接使用$ npm version <update_type>的方式來自動更新版本號了

4 測試

組件從開發到最終發佈的過程當中,須要不斷進行測試,確保功能正常,那如何進行測試呢?

4.1 建立一個react-native項目

首先咱們建立一個叫作example的react-native項目

$ react-native init example

example項目目錄能夠和組件項目目錄react-native-cardview同級,固然你也能夠放在任何你想放的位置,這裏爲了操做方便,咱們就把兩個目錄放在同級目錄。也就是說,如今的目錄是這樣

$ tree
.
├── example
└── react-native-cardview

而後咱們要作的就是把本地或者已發佈的組件安裝到example項目中進行測試

4.2 本地代碼測試

在組件未發佈以前,咱們能夠直接安裝本地代碼到example項目中進行測試,有如下幾種方式均可以作到

4.2.1 yarn link

$ cd react-native-cardview
$ yarn link
$ cd ../example
$ yarn link react-native-cardview
$ react-native link react-native-cardview

說明幾點:

  1. yarn link是把當前目錄中的本地代碼用yarn註冊爲react-native-cardview的一個本地組件,組件名字react-native-cardview實際上是根據package.json中的name字段的值來的,跟目錄名無關,只不過這裏正好等於目錄名
  2. yarn link react-native-cardview命令是把這個本地組件react-native-cardview安裝到了example的項目中,你能夠在example/node_modules中找到這個組件
  3. react-native link react-native-cardview這個你們應該知道,就是作了android/iOS的原生模塊link
  4. 其實yarn link這種方式簡單來講,就是作了一個symbol link,也就是說,example/node_modules/react-native-cardview/目錄中的內容是指向react-native-cardview/目錄內容,你改動react-native-cardview/目錄下的代碼,至關於直接改動example/node_modules/react-native-cardview/這個目錄中的代碼,這樣就可以達到邊修改組件代碼邊看效果的目的了

4.2.2 package.json中配置本地路徑

直接在examplepackage.json中增長dependencies

example/package.json

{
  "name":"example",
  ...
  "dependencies": {
    "react-native": "^0.55.4",
    "react-native-cardview":"file:../react-native-cardview",
    ...
  }
  ...
}

而後執行

$ react-native link react-native-cardview

yarn link同樣,也至關於作了symbol link,直接修改react-native-cardview/目錄下的代碼,至關於直接改動example/node_modules/react-native-cardview/這個目錄中的代碼

4.2.3 直接copy本地代碼

這種方式就比較簡單粗暴了,直接copyreact-native-cardview/目錄中內容到example/node_modules/react-native-cardview/這個目錄中

$ cp -rf react-native-cardview/ example/node_modules/

而後執行

$ react-native link react-native-cardview

這種方式缺點就是每次在react-native-cardview/改完代碼後,須要手工copy到example/node_modules/react-native-cardview/

4.3 已上傳/發佈代碼測試

已上傳到github或者發佈到npm registry的組件,測試方式就跟普通咱們安裝一個第三方組件同樣了。

4.3.1 經過github

加入你的代碼經過git上傳到了github倉庫上,那麼,你能夠直接經過npm install來安裝你的組件

npm install --save https://github.com/quenice/react-native-cardview.git

或者

npm install --save git@github.com:quenice/react-native-cardview.git

注意:根據你本身ghthub上的URL替換以上的HTTPS或者SSH

而後執行

$ react-native link react-native-rn-cardview

4.3.2 經過npm

這種方式就跟按照第三方組件沒有區別了

$ npm install --save react-native-rn-cardview

而後執行

$ react-native link react-native-rn-cardview

結語

至此,一個react-native組件完整的開發-測試-發佈的生命週期就講完了。

因爲是結合我本身開發的組件react-native-rn-cardview的實際開發過程,因此不免有遺漏,確定也有許多不足的地方。若是你們有什麼問題,或者發現哪裏有錯誤,歡迎你們在評論區給我留言,咱們一塊兒探討、一塊兒解決。

另外若是在react-native中有須要用到CardView的,歡迎使用react-native-rn-cardview

相關文章
相關標籤/搜索