コンポーネント共有ツールBitを試してみた

コンポーネント共有ツールの`Bit`を使ってみて、非常に便利に感じたため、紹介します。
本記事は、`Atomic Design`の手法に則り、チュートリアル形式で使い勝手などを紹介していきます。

## 作成するもの （デモページ）

https://thirosue.github.io/bit-react-tutorial/

![bit-react-tutorial.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/31f786f1-e6b0-a000-73b2-0f82f15a460d.png)

## GitHub

https://github.com/Thirosue/bit-react-tutorial

## Bitを利用した開発プロセス

公式の以下のデモが非常にわかりやすいので、是非参照してみてください。

[Bit Dev 2019 - Share code components to build apps faster as a team https://bit.dev](https://youtu.be/E5lgoz6-nfs) 

## チュートリアル手順
1. 前準備
2. Atoms（原子）の作成・公開
3. Molecules（分子）の作成・公開
4. Organisms（有機体）の作成・公開
5. Templates（テンプレート）の作成・公開
6. Pages（ページ）の編集・公開

## 1. 前準備

#### Bit CLIセッティング

以下や公式のチュートリアルを参考に`bit init --package-manager yarn`まで進めましょう。

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

[サルでもわかるBit入門 〜Reactのコンポーネントをbit.devにエクスポートするまで〜](https://qiita.com/yahooshiken/items/fec4670211662e54bf93) 

#### Collection作成

Bitにてアカウントを作成後、以下流れでコレクションを作成してください。

* 「+ New」 を選択

![スクリーンショット 2021-02-02 14.18.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/fd9dac1a-eb2b-aa53-2920-e5331851c30b.jpeg)

* コレクション名 / 公開区分を設定

![スクリーンショット 2021-02-02 21.10.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/b0b1017a-6853-b3b0-cb3f-67411c532b46.png)

上記まで完了した後は、対象レポジトリをcloneするか、自身で同じ流れにそってコンポーネントを作成してみてください。

```bash
# 対象レポジトリのクローン
$ git clone git@github.com:Thirosue/bit-react-tutorial.git
```

## 2. Atoms（原子）の作成・公開

本ステップでは、原子レベルのコンポーネントを作成し、公開します。
本ステップで作成したコンポーネントを利用して、ヘッダ・フッター（有機体レベル）などのコンポーネントを作成します。

+ 対象ブランチ

https://github.com/Thirosue/bit-react-tutorial/tree/step1/addAtoms

* 対象ブランチをチェックアウト

```bash
# 対象ステップのブランチをcheckout
% git checkout step1/addAtoms
```

* 対象のコンポーネントを追加(`git add`に相当)

```bash
% bit add src/components/atoms/textField
tracking component atoms/text-field:
added src/components/atoms/textField/index.js
```

* ステータス確認（`git status`に相当）

```bash
% bit status
new components
(use "bit tag --all [version]" to lock a version with all your changes)

     > text-field ... ok
```

* コンパイラ追加

```
% bit import bit.envs/compilers/react@1.0.21 --compiler
the following component environments were installed
- bit.envs/compilers/react@1.0.21
```

* ビルド

```bash
% bit build
⢀⠀ building components(node:15748) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
✔ building component - text-field
text-field
/Users/hirosue/workspace/bit-react-tutorial/dist/src/components/atoms/textField/index.js.map
/Users/hirosue/workspace/bit-react-tutorial/dist/src/components/atoms/textField/index.js
```

* タグを付与

```bash
% bit tag --all 0.0.1
⡀⠀ importing components(node:15797) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
✔ building component - text-field
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)
     > text-field@0.0.1
```

* ステータス確認

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

     > text-field. versions: 0.0.1 ... ok
```

* コンポーネント公開

```
% bit export thirosue.react-tutorial
exported 1 components to scope thirosue.react-tutorial
```

この状態でブラウザにログインすると、対象のコンポーネントが公開されているのが確認できるはずです。

![スクリーンショット 2021-02-03 8.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/9abc50c6-d84e-ca5b-ad84-61fa1658dbd1.png)

上記と同様の手順で、`typography`コンポーネントも公開します。
公開後、以下の状態になっていることを確認し、次に進みましょう。

![スクリーンショット 2021-02-03 8.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/3e7e1090-87a8-05ec-ae26-f5f0f264a5de.png)

## 3. Molecules（分子）の作成・公開

本ステップでは、分子レベルのコンポーネントを作成し、公開します。
本ステップで作成したコンポーネントを利用して、Pageコンポーネントを作成します。

+ 対象ブランチ

https://github.com/Thirosue/bit-react-tutorial/tree/step2/addMolecules

* 対象ブランチをチェックアウト

```bash
# 対象ステップのブランチをcheckout
% git checkout step2/addMolecules
```

* 対象のコンポーネントを追加

```bash
% bit add src/components/molecules/card
tracking component thirosue.react-tutorial/card@0.0.1:
added src/components/molecules/card/index.js
```

以降は、2.と同じ手順で、コンポーネントを公開します。

![スクリーンショット 2021-02-03 8.54.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/27e33cef-b0a8-b883-3a6f-291a7e71398a.png)

公開し、正常にプレビューされていることを確認して、次に進みましょう。

## 4. Organisms（有機体）の作成・公開

本ステップでは、有機体レベル（ヘッダー、フッターなど）のコンポーネントを作成し、公開します。
本ステップで作成したコンポーネントを利用して、Templateコンポーネントを作成します。

+ 対象ブランチ

https://github.com/Thirosue/bit-react-tutorial/tree/step3/addOrganisms

* 対象ブランチをチェックアウト

```bash
# 対象ステップのブランチをcheckout
% git checkout step3/addOrganisms
```

* 利用するコンポーネントのインポート

本ステップで、2.で作成したコンポーネントを利用するため、インポートします。

```bash
# bit cliを利用する場合
% bit import thirosue.react-tutorial/text-field

successfully ran yarn install at /Users/hirosue/workspace/bit-react-tutorial

successfully imported one component
- up to date thirosue.react-tutorial/text-field
```

```bash
# yarnを利用する場合、package jsonに追加されるため、自動ビルド設定する場合は、こちらの方がやり易い
% yarn add @bit/thirosue.react-tutorial.text-field
```

上記同様の手順で、typographyコンポーネントも追加します。

```bash
$ yarn add @bit/thirosue.react-tutorial.typography
```

コンポーネントを追加後、ヘッダー（`src/components/organisms/top-bar/index.js`）、フッター（`src/components/organisms/footer/index.js`）を2.と同様の手順で公開しましょう。

```jsx:src/components/organisms/footer/index.js
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Link from '@material-ui/core/Link';
import Container from '@material-ui/core/Container';
import Typography from '@bit/thirosue.react-tutorial.typography'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import TextField from '@bit/thirosue.react-tutorial.text-field'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集

(...中略...)

                    <Grid item xs={6} sm={8} md={4}>
                        <Typography variant="h6" marked="left" gutterBottom>
                            Language
                        </Typography> {/* 公開したコンポーネントを利用 */}
                        <TextField
                            select
                            SelectProps={{
                                native: true,
                            }}
                            className={classes.language}
                        >
                            {LANGUAGES.map((language) => (
                                <option value={language.code} key={language.code}>
                                    {language.name}
                                </option>
                            ))}
                        </TextField>　{/* 公開したコンポーネントを利用 */}
                    </Grid>
```

フッターを公開した後

![スクリーンショット 2021-02-06 15.11.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/1d6900e6-b95f-8d4e-0912-02ff3012777f.png)

ヘッダーを公開した後

![スクリーンショット 2021-02-03 9.17.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/95b6c9c0-44d1-4ab3-6b37-ede039cf16ea.png)

* Pageコンポーネント (App.js) を編集し、ローカルサーバ起動

ヘッダー、フッターの両コンポーネントをインポートして、Pageコンポーネント (App.js) を編集し、ローカルで動作確認してみましょう。

```bash
# ヘッダー、フッターをインポート
$ yarn add @bit/thirosue.react-tutorial.footer
$ yarn add @bit/thirosue.react-tutorial.top-bar
```

```jsx:src/App.js
import React from 'react';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import DialogContent from '@material-ui/core/DialogContent';
import TopBar from '@bit/thirosue.react-tutorial.top-bar'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import Footer from '@bit/thirosue.react-tutorial.footer'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import theme from './theme';

function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <>
        <TopBar className="top-bar" /> {/* 公開したコンポーネントを利用 */}
        <DialogContent>
          Content
        </DialogContent>
        <Footer /> {/* 公開したコンポーネントを利用 */}
      </>
    </ThemeProvider>
  );
}

export default App;
```

* ローカルサーバ起動

```bash
$ yarn start
```

問題なく設定できていれば、以下URLにブラウザで接続すると、ヘッダー、フッターを利用した画面が表示されるはずです。

http://localhost:3000

![スクリーンショット 2021-02-03 9.22.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/c61fbe77-a13f-3af6-a410-aa6b283bef3c.png)

## 5. Templates（テンプレート）の作成・公開

本ステップでは、Template（ページテンプレート）コンポーネントを作成し、公開します。
本ステップで作成したコンポーネントを利用して、6.のPageコンポーネントを作成します。

+ 対象ブランチ

https://github.com/Thirosue/bit-react-tutorial/tree/step4/addTemplates

* 対象ブランチをチェックアウト

```bash
# 対象ステップのブランチをcheckout
% git checkout step4/addTemplates
```

手順通りに進めていると、ヘッダー、フッターはインポート済みなので、このコンポーネントをTemplateコンポーネントに反映し、公開（`bit export`）します。

* Templateコンポーネント作成

```jsx:src/components/templates/base-template/index.js
import React from 'react';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import DialogContent from '@material-ui/core/DialogContent';
import TopBar from '@bit/thirosue.react-tutorial.top-bar'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import Footer from '@bit/thirosue.react-tutorial.footer'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import theme from './theme'; //<---- テンプレートにデザイン （theme） を適応する

function App({ children }) {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <>
        <TopBar className="top-bar" /> {/* 公開したコンポーネントを利用 */}
        <DialogContent>
          {children} {/* 子コンポーネントの内容を表示 */}
        </DialogContent>
        <Footer /> {/* 公開したコンポーネントを利用 */}
      </>
    </ThemeProvider>
  );
}

export default App;
```

コンポーネント作成後、`bit add` -> `bit build` -> `bit tag --all 0.0.x` -> `bit export`し、コンポーネントを公開します。

正常に公開できると、プレビューの見た目は崩れますが、ヘッダー、フッターを利用したTemplateコンポーネントが確認できます。

![スクリーンショット 2021-02-06 15.16.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/840f99ce-043c-4df4-47fa-274af764474f.png)

## 6. Pages（ページ）の編集・公開

本ステップでは、今まで作成したコンポーネントを利用して、画面（Pageコンポーネント）を作成します。
本チュートリアルでは、テンプレートと分子コンポーネントを利用します。

+ 対象ブランチ

https://github.com/Thirosue/bit-react-tutorial/tree/step5/modifyPage

* 対象ブランチをチェックアウト

```bash
# 対象ステップのブランチをcheckout
% git checkout step5/modifyPage
```

まず、前ステップで公開した、Tempateコンポーネントをインポートしましょう。

```bash
# yarn or bit or npm でインポートする
$ yarn add @bit/thirosue.react-tutorial.base-template
```

次に、インポートしたコンポーネントを利用して、Pageコンポーネント git (`App.js`) を編集し、ローカルで動作確認してみましょう。

```jsx:src/App.js
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import BaseTemplate from '@bit/thirosue.react-tutorial.base-template'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集
import Card from '@bit/thirosue.react-tutorial.card'; //<---- 公開したコンポーネントを利用 ※自身の設定に応じて編集

// アイテム一覧
export const items = [
  {
    id: 1,
    title: 'Phone XL',
    imagePath: 'https://thirosue.github.io/hosting-image2/bit-react-tutorial/1.jpg',
    description: 'A 1st phone with one of the best screens'
  },
  {
    id: 2,
    title: 'Phone Mini',
    imagePath: 'https://thirosue.github.io/hosting-image2/bit-react-tutorial/2.jpg',
    description: 'A 2nd phone with one of the best cameras'
  },
  {
    id: 3,
    title: 'Phone Standard',
    imagePath: 'https://thirosue.github.io/hosting-image2/bit-react-tutorial/3.jpg',
    description: 'A 3rd phone with one of the best cameras'
  }
];

// ...(省略)...

function App() {
  const classes = useStyles();

  return (
    <BaseTemplate> {/* 公開したコンポーネントを利用 */}
      <Grid className={classes.root} container spacing={3}>
        {items.map(item =>
          <Grid key={item.id} item xs={12} sm={4} md={3}>
            <Card
              title={item.title}
              imagePath={item.imagePath}
              description={item.description}
            /> {/* 公開したコンポーネントを利用 */}
          </Grid>
        )}
      </Grid>
    </BaseTemplate>
  );
}

export default App;
```

* ローカルサーバ起動

```bash
$ yarn start
```

ローカルサーバ起動後、以下URLにブラウザで接続すると、テンプレート、分子コンポーネントを利用した一覧画面サンプルが表示されるでしょう。

http://localhost:3000

![bit-react-tutorial.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/31f786f1-e6b0-a000-73b2-0f82f15a460d.png)

なお、今まで作成したコンポーネントは、yarnコマンドを通して、`/path/to/directory/node_modules`下に展開されているので、
作成したコンポーネン群を削除しても、表示する一覧画面に影響はありません。

```
# これまで作成したコンポーネント群を削除
% rm -rf src/components
```

## 感想

Bitを利用した開発プロセスは、プライベートレポジトリ（*1）とStoryBook(*2)のいいとこ取りした環境をSaaS形式で平易に利用でき、かつ、GitライクでインタラクティブなCLI(`bit cli`)を通じて、より直感的に操作できるため、非常に魅力に感じました。

マイクロサービス開発、チーム開発などが盛んになっている昨今、非常に強力なツールに映りましたが、まだ利用事例が少なそうなのは、それなりにコストが掛かるからなのでしょうか。
利用する人が増えて、よりリーズナブルに利用できる日を気長に待ちたいと思います。

[*1 AWS CodeArtifact でプライベートリポジトリを作ろう](https://qiita.com/hayao_k/items/d55576a2920cb859901c) 
[*2 Build bulletproof UI components faster](https://storybook.js.org/) 

### メリット
 - CLIがGitと同じ感覚で使え、直感的で分かり易い
 - `private repository`によるコンポーネント共有（複数レポジトリ・複数チームでの共有）の障壁がかなり下がり、生産性の向上が見込める
 - 開発プロセスにコンポーネント公開プロセスの導入することで、コンポーネント設計力の向上（再利用性・テスタビリティの向上）が見込める
 - Storybookより平易に導入できる（フルマネージド、SaaS形式）

### デメリット
 - 少々、お高い (*3)
 - 単一プロジェクトだと、導入効果が薄い

[*3 Bit - Pricing](https://bit.dev/pricing) 

## おまけ

### 単体テスト

* `bit add` (testsオプション付き)

```bash
$ bit add src/components/atoms/submit --tests src/components/atoms/submit/index.test.js
```

* テストコンパイラの追加 (`bit import`)

```bash
$ bit import bit.envs/testers/jest --tester
the following component environments were installed
- bit.envs/testers/jest@22.4.3
```

* test

```bash
 bit test
⢀⠀ building components(node:8545) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
✔ building component - submit

submit
tests passed
file: src/components/atoms/submit/index.test.js
total duration - 1335ms

✔ can render - 1335ms
✔ can render with Text - 1335ms
✔ can be clicked when not in proccessing - 1335ms
```

後は、通常通り公開（`bit export`）すると、テスト結果が追加された形で公開される。

![スクリーンショット 2021-02-21 18.30.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73176/74d82837-a73b-ff90-c9fb-1a3be53db6aa.png)


### コンポーネント削除 / 登録解除

* remote

```bash
% bit remove thirosue.react-tutorial/base-template@0.0.2 --remote
are you sure you would like to proceed with this operation? (yes[y]/no[n])':  Y
successfully removed components from the remote scope: thirosue.react-tutorial/base-template
```

* local

```bash
# 上記から--remoteオプションのみ外す
% bit remove thirosue.react-tutorial/base-template@0.0.2
are you sure you would like to proceed with this operation? (yes[y]/no[n])':  y
successfully removed components from the local scope (to remove from the remote scope, please re-run the command with --remote flag): thirosue.react-tutorial/base-template
```

### 自動ビルド設定（`GitHub Action`）

以下ファイルを作成し、GitHubページ設定すると、簡単にインターネットに公開できます。
Bitを使う場合の自動ビルドの注意点は以下です。

```bash
# 取得レジストリに、bit registryを追加する
      - run: npm config set @bit:registry https://node.bit.dev
```

* 全量

```yml:.github/workflows/gh-pages.yml
name: github pages

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2

      - name: Setup Node
        uses: actions/setup-node@v1
        with:
          node-version: "12.x"

      - run: node -v
      - run: yarn -v
      - run: npm config set @bit:registry https://node.bit.dev # 取得レジストリに、bit registryを追加する
      - run: yarn
      - run: yarn build

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./build
```

## 参考
  - [Bit for React](https://docs.bit.dev/docs/tutorials/bit-react-tutorial) 
  - [サルでもわかるBit入門 〜Reactのコンポーネントをbit.devにエクスポートするまで〜](https://qiita.com/yahooshiken/items/fec4670211662e54bf93)