サルでもわかるBit入門 〜Reactのコンポーネントをbit.devにエクスポートするまで〜

## はじめに
今どきのフロントエンドのトレンドを調べていたら、この記事に出会いました。
[7 FrontEnd JavaScript Trends and Tools You Should Know for 2020](https://hackernoon.com/7-frontend-javascript-trends-and-tools-you-should-know-for-2020-fb1476e41083)

その中で、コンポーネント単位での共有ツールとしてBitが「今、アツい！」と紹介されており、前々から個人的に気になっていたのと、日本語の情報が少なかったので、公式ドキュメントにあるチュートリアルをやってみました。

ということで、この記事は以下のBit公式ドキュメントの翻訳記事です。

[Bit for React - Bit](https://docs.bit.dev/docs/bit-react-tutorial.html)

よしなに意訳したり、重要そうな部分を太字にしたりしていますが、基本的に内容は変えていません。
少しでも、皆さんのBitの理解の助けになれば幸いです。

---

## Bit for React

### 概要
Bitを使用すると、異なるプロジェクトやアプリケーション間でコンポーネントを共有および同期することができます。
**このチュートリアルでは、２つのプロジェクト間でReactコンポーネントを共有することを目指します。**

### 事前知識
このチュートリアルでは、次の知識があることを前提としています。

- TerminalとCLI操作
- nodeとnpm（またはyarn）
- Reactでの開発、create-react-app
- Git

### What do you need?
Nodeがバージョン10.9以上であることを確認してください（React 8の前提条件）。
また、このチュートリアルでは、以下のリポジトリをクローンして用いることにします。
https://github.com/teambit/bit-react-tutorial

```sh
$ git clone https://github.com/teambit/bit-react-tutorial
$ cd bit-react-tutorial
$ yarn install # or $ npm install
$ yarn start   # or $ npm start
```

`yarn start`で実行すると、以下のようなサンプルアプリケーションが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185956/c7201823-2b1d-9de8-3303-30e458df3481.png)


### What will you learn? 学べること
このチュートリアルでは、次のようなことを学習します。

* Bitのセットアップ
* 既存のプロジェクトからReactコンポーネントを共有する
* Bit cloudでエクスポートされたファイルをプレビューする
* 他のプロジェクトでコンポーネントをインストールする
* 新しいプロジェクトでReactコンポーネントを修正する
* コンポーネントの変更をオリジナルのプロジェクトに反映する

## Bitのセットアップ

まずはじめに、Bitの設定をしましょう！

### bit.devのアカウントを作成する

[bit.dev](https://bit.dev/)へ行き、アカウントを作成します。
ユーザー名とパスワードを入力するか、GitHubアカウントによる認証を行ってください。

**Welcome to Bit!** 

このチュートリアル内では、`<username>`という表記を用いることがありますが、適宜、ご自身のユーザー名に読み替えてください。

### コレクションを作成する

bit.devにログインできたら、**コレクション**を作成します。**コレクションは、リモートでホスティングされたコンポーネントの集合を意味し、それぞれのコンポーネントは共有可能で異なるアプリケーション間で利用することが出来ます。**

1. ヘッダーにある**New**ボタンをクリックし、**Collection**を選択します
2. コレクションに`react-tutorial`などの名前をつけます
3. コレクションをPrivateにするか、Publicにするか設定します

■ Public: 誰でも見るこどができる
■ Private: 招待した人のみ見ることができる

ヘッダーにある**New**ボタンをクリックし、**Collection**を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185956/4a476eb8-3a85-64be-1b58-91f0923d4235.png)

コレクションに`react-tutorial`などの名前をつけ、コレクションをPrivateにするか、Publicにするか設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185956/9e192226-9733-dce5-70b6-e31498705cd7.png)

**Create Collection**ボタンを押すと、コレクションが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185956/7e86f43f-ed52-27be-74e1-fbfb849e4c65.png)



### Bit CLIをインストールする
BitのCLIツールをインストールします。
無事にBitがインストールされたか`$ bit --version`コマンドで確認してみましょう。


```sh
$ npm install bit-bin -g
# もしくは yarn global add bit-bin
# もしくは brew install bit

$ bit --version

# 14.2.5

```

### CLIからBitのアカウントでログインする

コマンドラインから以下を実行し、bit.devアカウントの認証を行います。

```sh
$ bit login

# already logged in
```

実行すると、ブラウザが立ち上がってログインすることが可能です。すでにログインしている場合は`already logged in`と表示されます。さぁ、これでBitを使う準備が整いました！

ログイン処理の最中にBitはローカルの設定を行います。以下を実行することで設定を閲覧することができます。

```sh
$ bit config

# analytics_id                  xxxxxxxxxxxxxxxxx
# analytics_reporting           true
# user.token                    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

さらに、Bitで用いるnpmのレジストリ構成が`.npmrc`に追加されます（デフォルトでは`$HOME/.npmrc`で、OSに応じて変わります）。

```sh
$ cat ~/.npmrc

# @bit:registry=https://node.bit.dev
# //node.bitsrc.io/:_authToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# //node.bit.dev/:_authToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

### Bit workspaceの初期化

`react-bit-tutorial`リポジトリをクローンしたディレクトリに行き、次のコマンドを実行しましょう！

```sh
$ bit init

# successfully initialized a bit workspace.
```

これにより、2つの変化が起こります。

* **`.bitmap`という名前の新しいファイルがルートディレクトリに作成されます。このファイルは、Bitのコンポーネントをトラッキングするための、Bitのバージョンのみが書かれたファイルです。**
* `package.json`に`bit`のセクションが作成されます。

```json:package.json
"bit": {
  "env": {},
  "componentsDefaultDirectory": "components/{name}",
  "packageManager": "npm"
}
```

> 実際のプロジェクトでは、これらの変更はバージョン管理ツールにコミットする必要があります。

## Reactのコンポーネントを共有する

さあ、まずはこのチュートリアルプロジェクト内にある`product-list`コンポーネントをBitを用いてトラッキングしてみましょう。現在のディレクトリ構成は次のようになっています。

```
src/
├── App.css
├── App.js
├── App.test.js
├── components
│   ├── product-list
│   │   ├── index.js
│   │   ├── product-list.css
│   │   └── products.js
│   └── top-bar
│       └── index.js
├── index.css
├── index.js
└── serviceWorker.js
```


### 新しいコンポーネントをトラッキングする

`product-list`コンポーネントをトラッキングするためには、Bitに対してコンポーネントとそれに関連するファイルを伝える必要があります。すべてのファイルは`product-list`ディレクトリに存在しているため、`src/components/product-list`ディレクトリ内のすべてのファイルをコンポーネントとして追加します。

```sh
$ bit add src/components/product-list

# tracking component product-list:
# added src/components/product-list/index.js
# added src/components/product-list/product-list.css
# added src/components/product-list/products.js
```

追加されたファイルはそれぞれ以下のように記述されています。

```jsx:index.js
import React, { Component } from 'react';
import { products } from './products';
import './product-list.css';

export default class ProductList extends Component {
    share() {
        window.alert('The product has been shared!');
    }

    getProduct(product, index) {
        return (
            <div key={index}>
                <h3>
                    <a title={product.name + ' details'} href="/">{product.name}</a>
                </h3>
                <p>Description: {product.description} </p>
                <button className="btn" onClick={this.share}>Share</button>
            </div>
        )
    }

    render() {
        return (
            <>
                <h2>Products</h2>
                <br/>
                <div>
                    {
                        products.map((product, index) => {
                            return this.getProduct(product, index);
                        })
                    }
                </div>
            </>
        );
    }
}
```

```css:product-list.css
.btn {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    border-radius: 2px;
    font-size: 14px;
    cursor: pointer;
    background-color: #68bb5d;
    color: white;
    border: none;
  }
  
  .btn:hover {
    opacity: 0.8;
    font-weight: normal;
  }
  
  .btn:disabled {
    opacity: 0.5;
    cursor: auto;
  }
```

```js:products.js
export const products = [
    {
        name: 'Phone XL',
        price: 799,
        description: 'A large phone with one of the best screens'
    },
    {
        name: 'Phone Mini',
        price: 699,
        description: 'A great phone with one of the best cameras'
    },
    {
        name: 'Phone Standard',
        price: 299,
        description: ''
    }
];
```

新しいコンポーネントを作成したら、コンポーネントに必要なすべてのファイルが追加されているかを確かめる必要があります。これを行うには、コンポーネントのステータスを`bit status`で確認します。

```sh
$ bit status

# new components
# (use "bit tag --all [version]" to lock a version with all your changes)
#
#      > product-list ... ok
```

> 今回は`products.js`ファイルも追加しました。このデモアプリでは、product-list componentによってのみ使用されるため許容されますが、複数のコンポーネントで使用されている場合は、product-listコンポーネントや他のコンポーネントの依存関係となる別のコンポーネントとしてファイルを作成した方がいいかもしれません。

### React Compilerをインストールする

Reactコンポーネントをビルドするには、React Compilerが必要です。次のコマンドでコンパイラをインストールしましょう！

```sh
$ bit import bit.envs/compilers/react --compiler

# the following component environments were installed
# - bit.envs/compilers/react@1.0.2
```

これにより、React CompilerがこのBitワークスペースのデフォルトコンパイラとして設定されます。`package.json`を確認してみましょう。

```json
"env": {
  "compiler": "bit.envs/compilers/react@1.0.2"
}
```

### Reactのコンポーネントをビルドする

コンパイラがインストールできたら、コンポーネントをビルドします。コンポーネントをビルドするのは２つの目的があります。

* コンポーネントを他のプロジェクトから直接利用できるようにするため。
* コンポーネントが、共有に必要なすべての部品を含んでいるかを確認するため。

```sh
$ bit build

# product-list
# bit-react-tutorial/dist/src/components/product-list/index.js.map
# bit-react-tutorial/dist/src/components/product-list/index.js
# bit-react-tutorial/dist/src/components/product-list/products.js.map
# bit-react-tutorial/dist/src/components/product-list/products.js
# bit-react-tutorial/dist/src/components/product-list/product-list.css
```

### コンポーネントをエクスポートする

コンポーネントが正常にビルドされたら、次はいよいよそれを共有します。
コンポーネントは、semver（Semantic versioning）の標準に従ってバージョン管理されます。コンポーネントにバージョンをタグ付けするには、次のコマンドを実行します。

```sh
$ bit tag --all 0.0.1

# 1 component(s) tagged
# (use "bit export [collection]" to push these components to a remote")
# (use "bit untag" to unstage versions)

# new components
# (first version for components)
#      > product-list@0.0.1
```

※ このコマンドは、現在Bitで`add`されているすべてのコンポーネントにタグ付けします。

```sh
$ bit status

# staged components
# (use "bit export <remote_scope> to push these components to a remote scope")

#      > product-list. versions: 0.0.1 ... ok
```

**ステータスを確認すると、`staged components`と表示されますが、これはコンポーネントをエクスポートする準備が整ったことを意味します。**

コンポーネントをbit.devにあるコレクションにエクスポートするには、`bit export`コマンドとコレクションのフルネームを使用して、`bit export <username>.<collection>`のように指定します。

```sh
$ bit export <username>.react-tutorial

# exported 1 components to scope <username>.react-tutorial
```

おめでとう！これで、コンポーネントがbit.devのコレクションに追加されました！`https://bit.dev/<username>/react-tutorial` にアクセスして確認してみてください！

コンポーネントのステータスを確認すると、リモートコレクションでホスティングされているため、ステータスは表示されなくなります。そのため、所有しているすべてのコンポーネントを表示するには、`bit list`コマンドを実行します。

```sh
$ bit status

# nothing to tag or export (use "bit add <file...>" to track files or directories as components)

$ bit list

# found 1 components in local scope
# 
#   ┌──────────────────────────────────────────────────────────────────────┬─────────┬─────────┐
#   │ component ID                                                         │ local   │ used    │
#   │                                                                      │ version │ version │
#   ├──────────────────────────────────────────────────────────────────────┼─────────┼─────────┤
#   │ yahooshiken.react-tutorial/product-list                              │ 0.0.1   │ 0.0.1   │
#   └──────────────────────────────────────────────────────────────────────┴─────────┴─────────┘
```

現在、コンポーネントのソースコードはローカルプロジェクトに存在するため、ソース管理にコミットする必要がありますが、コンポーネントは他のプロジェクトでも使用することができます。

### Reactコンポーネントをプレビューする

エクスポートしたコンポーネントはbit.dev cloudでも利用可能です。https://bit.dev にアクセスし、ログインします。

1. 左側のパネルで、**Collections**を選択します
2. `react-tutorial`コレクションを選択すると、`product-list`コンポーネントが表示されます
3. `product-list`コンポーネントを選択して、Playgroundを確認します

また、直接次のURLのページにアクセスすることもできます。 `https://bit.dev/<username>/react-tutorial/product-list`

コンポーネントのPlaygroundは、コンポーネントが既に含まれている基本的なReactアプリを提供します。新しいファイルを追加することができます。

新しく`styles.css`という名前のファイルを作成しましょう。

```css:styles.css
#anchor {
	flex-direction: column;
}
```

Playground内の`index.js` ファイルの中でインポートします。


```js:index.js
import './styles.css';
```
数秒間待つと、Playground内にコンポーネントがレンダリングされます。[こちら](https://bit.dev/bit/react-tutorial/product-list)からexampleを見ることもできます。

### もう一つのプロジェクトでコンポーネントをインストールする

#### 新しくReactのアプリケーションを作る

ここで、別のReactアプリケーションを作成し、`product-list`コンポーネントを使用してみましょう。
新しいディレクトリに切り替えて、`create-react-app`を利用してアプリケーションを作成しましょう。

```shell
$ npx create-react-app my-new-app
```

#### コンポーネントをインストールする

npmまたはyarnを使用して、コンポーネントをインストールします。
コンポーネントは`@bit`レジストリに格納されるため、コンポーネントへのフルパスは次のようになります。

`@bit/<username>.<collection name>.<component name>`

```sh
$ npm install @bit/<username>.react-tutorial.product-list --save

# もしくは yarn add @bit/<username>.react-tutorial.product-list
```

`package.json`を見るとコンポーネントが追加されたことが分かります。

```json:package.json
"@bit/<username>.react-tutorial.product-list": "0.0.1"
```

#### アプリケーション内でコンポーネントを使用する

これで、JavaScriptの`import`構文を用いて作成したコンポーネントを使用できます。

```jsx:App.js
import React from "react";
import ProductList from "@bit/yahooshiken.react-tutorial.product-list";

function App() {
  return (
    <div className="App">
      <ProductList />
    </div>
  );
}

export default App;
```

```css:App.css
.App {
  flex-direction: column;
  margin: 20px;
}
```

```sh
$ npm start
```

** Voila!（出来上がり！）**
これで、新しく作成されたアプリケーション内のコンポーネントリストを別のアプリケーションから確認することができます！


#### コンポーネントを修正する

次に、コンポーネントに変更を加えて、再度コレクションにエクスポートします。`product-list`に表示ボタンを追加します。簡単にするために、製品が表示されたことを示すアラートのみが表示されます。


#### コンポーネントをインポートする

これまで、`product-list`コンポーネントはプロジェクトに（ビルドされた形式で）インストールされていました。

次に、コードをプロジェクトにインポートして、変更を加えます。

コンポーネントをインポートするには、`my-new-app`ワークスペースをBitワークスペースとして初期化します。

```sh
$ bit init
$ bit import yahooshiken.react-tutorial/product-list

# successfully imported one component
# - added yahooshiken.react-tutorial/product-list new versions: 0.0.1, currently used version 0.0.1
```

ここで起こったことを説明します。

* ルートディレクトリに`components`ディレクトリが生成されます（コンポーネントのコードとそのコンパイル済みコードおよび`node_modules`を含む）。
* `.bitmap`ファイルは、コンポーネントへの参照を含むように変更されました。
* `package.json`ファイルは、リモートパッケージではなくファイルを指すように変更されます。

```json:package.json
"@bit/<username>.react-tutorial.product-list": "file:./components/product-list"
```

product-listコンポーネントを変更しましょう。`components/product-list/index.js`を変更して、`view`メソッドを含めます。また、`getProduct`関数を変更して新しく「View」ボタンを追加します。

```js:components/product-list/index.js
view() {
    window.alert('The product has been viewed!');
 }

getProduct(product, index) {
  return (
    <div key={index}>
      <h3>
        <a title={product.name + " details"} href="/">
          {product.name}
        </a>
      </h3>
      <p>Description: {product.description} </p>
      <button className="btn" onClick={this.share}>
        Share
      </button>
      <button className="btn" onClick={this.view}>
        View
      </button>
    </div>
  );
}
```

```css:components/product-list/product-list.css
.btn {
  margin: 4px;
}
```

Reactアプリケーションを実行します。

```sh
$ npm start
```

アプリケーションはまだ変更されていません。

Bitコンポーネントは、Bitコンパイラによってコンパイルされます。
別のターミナルで、`bit build`コマンドを実行して変更をコンパイルしましょう。
コンパイラがインストールされていることがわかります。

```sh
$ bit build

# successfully installed the bit.envs/compilers/react@1.0.2 compiler
```

その後、すべてのファイルが正常にコンパイルされたことを確認し、`my-new-app`を再実行すると、変更されたコンポーネントを確認することができます！

### 変更をエクスポートする

次に、コンポーネントに加えられた変更をエクスポートしてbit.devに戻してみましょう。

```sh
$ bit status

# modified components
# (use "bit tag --all [version]" to lock a version with all your changes)
# (use "bit diff" to compare changes)
# 
#      > product-list ... ok

$ bit diff

# -----------------------------------------------------------------
# showing diff for yahooshiken.react-tutorial/product-list
# -----------------------------------------------------------------
# --- index.js (0.0.1 original)
# +++ index.js (0.0.1 modified)
# @@ -1,37 +1,45 @@
#  export default class ProductList extends Component {
# +  view() {
# +    window.alert("The product has been viewed!");
# +  }
# ...
```
`product-list`コンポーネントが変更されていることがわかります。

コンポーネントを新しいバージョンとしてタグ付けしてエクスポートします。デフォルトでは、patchバージョンが更新されます。

```sh 
$ bit tag product-list

# 1 component(s) tagged
# 
# changed components
# (components that got a version bump)
#      > yahooshiken.react-tutorial/product-list@0.0.2

$ bit export <username>.react-tutorial

# exported 1 components to scope yahooshiken.react-tutorial
```

bit.devのコンポーネントページに移動します。ここで、コンポーネントに新しいバージョンがあることがわかります。変更は、コンポーネントのプレイグラウンドにも反映されます。

### 元のプロジェクトのコンポーネントを更新する

#### 変更をインポートする
`react-bit-tutorial`リポジトリをクローンしたディレクトリに戻りましょう。`bit import`を実行して、コンポーネントが変更されたかどうかを確認します（`git pull`を実行してgitの変更を確認するのと同様）。

```sh
$ bit import

# successfully imported one component
# - updated yahooshiken.react-tutorial/product-list new versions: 0.0.2
```

`product-list`コンポーネントが変更され、新しいバージョンが存在することがわかります。

コンポーネントはダウンロードされますが、まだ変更は反映されていません。ワークスペースのステータスを`bit status`で確認すると、次のものが得られます。

```sh
$ bit status

# pending updates
# (use "bit checkout [version] [component_id]" to merge changes)
# (use "bit diff [component_id] [new_version]" to compare changes)
# (use "bit log [component_id]" to list all available versions)
# 
#     > yahooshiken.react-tutorial/product-list current: 0.0.1 latest: 0.0.2
```

#### チェックアウトする

コンポーネントに加えられた変更をプロジェクトにマージします。コマンドの構造はbit checkout <version> <component>です。

```sh 
$ bit checkout 0.0.2 product-list

# updated src/components/product-list/index.js
# updated src/components/product-list/product-list.css
# updated src/components/product-list/products.js
```

Bitは`git merge`を実行しているため、更新されたコンポーネントのコードはマージされます。アプリケーションを再度実行すると、更新されたコンポーネントが適切に機能していることを確認できます。

以上です！２つのプロジェクト間でコンポーネントの変更を行うことができました。アプリケーションは、更新されたコンポーネントで実行されています。

**Happy coding!!**

## 感想

BitがGitみたいにコンポーネントを管理できて知っておくと便利だなーと思いました！
業務内アプリケーションで用いるのはすぐには難しいかもしれないけれど、個人的なアプリであれば、よく使い回すコンポーネントなどをスニペット的に登録したり、他のbitコンポーネントをインポートして使えそうだなという印象です。

Bitの詳しい概念や、CIなどとのコラボレーションについてはまだまだ理解できていないので、もうちょっと勉強してみることにします。

## 参考
- [Discover Components · Bit](https://bit.dev/)
- [Bit for React - Bit](https://docs.bit.dev/docs/bit-react-tutorial.html)