1つのReactプロジェクトで複数のサイトに対応する

![eyecatch_2105ReactMultipleProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/88511b0f-3243-1f66-b58e-cb5e40da1ba2.png)

※ 本稿は <a href="https://tech.drecom.co.jp/?_src=qiita">Tech Inside Drecom</a> に掲載された記事、「<a href="https://tech.drecom.co.jp/one-react-project-for-maltiple-sites/?_src=qiita">1つのReactプロジェクトで複数のサイトに対応する</a>」の Qiita 出張版です。

---

# はじめに
こんにちは、DRIP部でフロントエンドエンジニアをやっている福井です。 DRIPはDrecom Invention Project の略称で、ドリコムが発明を生み続けるためのプロジェクトです。 今回は、「キャンペーンを実施するたびにリポジトリが増えてしまう」という問題に対して、「1つReactプロジェクトで複数のサイトに対応する」と方針転換し実装方法について検討・実装したことについてまとめました。 https://drip.drecom.co.jp/

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/7b8a30c9-b8d3-5368-a6e1-d9753f6e6b68.png)

## Rooot（ルート）
DRIPでは「Rooot（ルート）」というサービスの開発・運用をしています。「Rooot」とは、ファンの方によりファンになっていただくために、Twitter上でユーザー同士（ファン同士）で盛り上がれるキッカケや、ユーザー同士（ファン同士）で繋がるキッカケを与えるサービスです。Twitter上で特定のハッシュタグがついたツイートに「いいね」や「RT」をしたユーザーはRoootのWebサイト内で「ポイント」を獲得することができます。ユーザーは「ポイント」を利用して、景品交換やグッズ等への抽選に応募などができます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/f728b3f1-d611-b8a4-1cfd-609f8606fe3a.png)
サービス概要

## React
RoootのWebサイトはモバイルアプリケーションのような快適な操作性をユーザーに提供することが可能なSingle Page Application(SPA)となっています。このSPAを実現するためにReactを利用しています。 Reactとは、ユーザーインターフェイスを構築するJavaScriptのライブラリです。Facebookとコミュニティによって開発されており、React.jsまたは、ReactJSの名称でも知られています。

# 本題

## 既存の構成と問題点
Roootのキャンペーンを実施するにあたり、ユーザーが取得している「ポイント」の確認や、景品交換などをする場所として特設されたRoootのWebサイト（以降、特設サイト）を用意する必要があります。この特設サイトは、キャンペーンごとに作成します。各キャンペーンごとに用意する特設サイトは画像やテキストを変えるものの、ページの大まかな構成や、表示するコンテンツはよく似ています。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/ffa06aec-9133-2ef3-4ab8-a5d28346b444.png)
特設サイトの例

そのため、サイト作成では、雛形となるReactプロジェクトのGitリポジトリ（以降、リポジトリ）を事前に作成し、
新キャンペーン用に雛形リポジトリから新キャンペーン用リポジトリにデータをコピー
新キャンペーン用リポジトリにデザインを入れていく
特設サイト用に準備したインフラ環境へデプロイする
という開発をしていました。 しかしこの開発では、キャンペーンを実施するたびにリポジトリが増えていき、管理が大変になってきます。また、新キャンペーン用リポジトリで発見した修正を雛形リポジトリにも適用する作業があるなど、無視できないコストが発生していました。

## 問題点の解決に向けての検討
これを解決するために、今までの雛形から新キャンペーン用にデータをコピーするという開発方法をやめ、「1つのReactプロジェクトで複数のサイトに対応する」ように方向転換しました。 これを実現する方法として2案ありました。

* 案(1): 表示に必要なデータを都度DBから取得・解析して表示する
* 案(2): 裏側で事前にビルドしたものを取得して表示する

案(1)では、表示に必要なデータをデータベースなどに保存しておき、フロントエンド側はAPIを通してデータを取得し、内容を解析して表示物を整形していくという方法です。フロントエンド側が解析エンジンを持つため、実装が大変であり、SEO対策として、index.htmlのメタデータなどをキャンペーン毎に書き換える必要があります。 案(2)では、表示に必要なデータをデータベースなどに保存するところまでは案(1)と同じです。さらに、バックエンド側がビルドを実施し、表示情報をもとにWebサイトで表示するフロントエンドアセットを完成させてストレージに配置します。フロントエンド側はストレージにあるフロントエンドアセットを取得し表示するだけという方法です。バックエンドがビルドを実施している分だけ、表示に必要なデータから実際のページが表示されるまでに時間がかかります。 エンジニアチームで吟味した結果、案(1)で進めることにしました。 理由としては、雛形リポジトリで作成してきたコンポーネントやノウハウを流用しやすいことに加え、今後、複数の特設サイトを同時期に作成し出した時、バックエンドのビルドがボトルネックになってしまい、開発速度に影響が出ると考えたためです。

## 表示に必要なデータを都度DBから取得・解析して表示する
コンセプトは次のようなものになります。 ブラウザでRoootの特設サイトにアクセスすると、Reactで作成されたWebサイト（Roootアセット）を返却します。この時点では真っ白なページのみを表示します。 その後ページを構成するために必要な「設計図」のリクエストを行い、バックエンド側からリクエストに応じた「設計図」をブラウザに返却します。 ブラウザでは、Reactで作成されたWebページが、受け取った「設計図」を読み取り、表示したいページ等を構成します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/6262b02c-0991-5852-1994-57b7f8307252.png)
大まかな流れ

最初に渡されるRoootアセットは、特設サイトで利用するある程度デザインの入ったReactコンポーネントを複数持っています。例えば、ボタンやチェックボックス、水平線や画像を表示するコンポーネントなどです。 Roootアセットは設計図を読み込み、そこに記載されているコンポーネント名と用意されているReactコンポーネントを突き合わせながらページを構成します。 Roootアセットには、Reactコンポーネント以外にも、ユーザー情報などの取得をしたり、URLを見て必要な設計図をリクエストしたりする処理も含みます。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/12e2ae3b-1641-27a3-a211-4ffca2e026c0.png)
Roootアセット

「設計図」とは以下のようなjson形式のデータです。「設計図」には事前に決められたReactコンポーネントの名前やパラメータ、そのコンポーネントのchildren要素が入れ子になって記載されています。 また、「設計図」にはparameterというキー名に、あらかじめ決められたキーで値を渡すことによって、表示されるコンポーネントのテキスト、色、形状などを変更することができます。例えばButtonというコンポーネントはcolorというキーをparameterに渡すことができます。このcolorへ値を入れることでボタンの色を変更することができます。 他にもchildrenというキー名に、オブジェクトを配列で渡す子によって、より柔軟な表現を可能にしています。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218415/b482fc97-4111-ac4b-fef8-8c1287969043.png)
ボタンを生成する例

このように「設計図」と解析器を持ったRoootアセットに二分することによって、次のようなメリットが得られます。
Roootアセットで、ある程度デザインを制限するため、統一の取れたサイト構築ができる
Reactの知識がなくても、設計図の作り方を知っていればデザイン作成が可能
ロジックと切り分けられているので、比較的安全にデザインや文言の変更ができる

## 解決したいことは解決できたのか
最初に解決したかった「キャンペーン毎にリポジトリを増やさないようにする」は解決することができました。代わりにキャンペーン毎に「設計図」が増えていくことになりますが、こちらは、別途管理しています。 この辺りの話や、「設計図」とReactアセットのより詳しい動作など、書き始めるとキリがないので次の機会に執筆しようと思います。

# まとめ
今回は、「キャンペーンを実施するたびにリポジトリが増えてしまう」という問題に対して、「1つReactプロジェクトで複数のサイトに対応する」と方針転換し実装方法について検討・実装したことについてまとめました。その結果、キャンペーンを実施するたびにリポジトリが増えることはなくなり、管理が複雑になっていくことを防ぐことができました。 また機会があれば、Roootアセット内でどのように設計図を展開しているのかなど記述できればと思います。 最後まで読んでくださりありがとうございます。またいつか。

---

Tech Inside Drecom の最新の情報は Facebook や Twitter からお届けしています、フォローよろしくおねがいします！

* Twitter: <a href="https://twitter.com/DRECOM_TECH" target="_blank">@DRECOM_TECH</a>
* Facebook: <a href="https://www.facebook.com/tech.inside.drecom" target="_blank">tech.inside.drecom</a>

---

※ その他の Tech Inside Drecom の記事は、<a href="https://tech.drecom.co.jp/?_src=qiita">コチラ</a>からお探しいただけます！!