JS奮闘記【yarn workspaceを使ったモノレポ管理】

JS奮闘記 yarn workspace

こんにちは。
エンジニアの辻です。

今回はタイトル通り、yarn workspaceを使ってみました。
とても良い機能でしたので、備忘録を兼ねてブログにまとめてみました。

yarn workspaceとは?

yarn workspaceとは、複数のプロジェクトを1つのリポジトリでまとめて管理できる機能です。
いわゆるモノレポと呼ばれる環境を作れます。

例えば、あるプロジェクトAがあるとします。
プロジェクトAは、もともとクライアントとサーバーの2つのリポジトリがあるだけでした。
…が、プロジェクトの拡張に伴い、新機能用に新しいリポジトリを立てたり、メジャーバージョンアップのために新しいリポジトリを立てたりなど…、
時間が経過するにつれて、管理するリポジトリが増えてしまう…といった事、よくあると思います。

こういった時にyarn workspaceは、非常に便利です。
1つのリポジトリの中で、各プロジェクトを一括管理できます。

実現したかったこと

yarn workspace を使って、実現したかったのがTypeScriptの関数や型を各ワークスペースで共有する事です。
構成は以下のようになります。
この構成にすることで、/packages/common/ の中に格納してあるコードをclient01 / client02 / serverで共有できます。

今回は、TypeScriptのコードだけを各ワークスペースで共有しますが、やろうと思えば、CSS(SCSS)やコンポーネント、テストコードの共有なども可能です。(環境構築に時間がかかるかもですが…。)

より高度な事を実現したい場合は、NxLernaなどのモノレポ作成ツールがありますので、そちらを活用してみると良いでしょう。

yarn workspace によるモノレポ作成の手順

では、実際にモノレポ環境を作成していきます。
以下に大まかな手順をまとめました。これに沿っていくとモノレポ環境を作成できます。

  1. ルートプロジェクトの用意
  2. packagesディレクトリを作成
  3. packagesディレクトリ内に各ワークスペースを作成
  4. packagesディレクトリ内にcommonディレクトリを作成
  5. ルートディレクトリのpackage.jsonにprivate/workspaceを追加
  6. クライアントサイドワークスペース(client01/client02)を整備
  7. サーバーサイドワークスペース(server)を整備
  8. ルートディレクトリのpackage.jsonにscriptを追加
  9. 最終調整をして完成

ルートプロジェクトの用意

まずプロジェクトのルートディレクトリを作成しましょう。
そして、作成したディレクトリに移動して、プロジェクトを初期化しましょう。
以下のコマンドを順に実行していけばOKです。

packagesディレクトリを作成

次に、rootディレクトリ直下にpackagesディレクトリを作成します。
packages作成後は、packagesに移動しましょう。

packagesディレクトリ内に各ワークスペースを作成

packagesディレクトリ内に、各ワークスペースを作成していきましょう。

まずクライアントサイドワークスペース(その1)を作成します。
今回はNext.jsを使用します。以下のコマンドを実行します。

上記のコマンドが完了しましたら、クライアントサイドワークスペース(その2)を作成しましょう。
以下のコマンドを実行します。

さて、上記のコマンドが完了しましたら、次はサーバーサイドワークスペースを用意します。

まずserverディレクトリを作成して、その中に入ります。

次にサーバーサイドワークスペースを初期化します。

packagesディレクトリ内にcommonディレクトリを作成

クライアントサイド/サーバーサイドで共通のコードを格納するcommonディレクトリを作成します。

commonディレクトリの中に、typesとfunctionsディレクトリを作成します。
typesには共通の型ファイルを格納し、functionsには共通の関数を格納していきます。

では、共通化するファイルを用意していきましょう。
root/packages/common/typesにuser.tsを用意します。内容は以下の通りです。

▼root/packages/common/types/user.ts

root/packages/common/functionsには、getHello.tsを用意します。内容は以下の通りです。
なんてことはない。ただ「Hello!!」を返すだけの関数ですね。

▼root/packages/common/functions/getHello.ts

ルートディレクトリのpackage.jsonにprivate/workspaceを追加

ここまで来ましたら、一度rootディレクトリに戻りましょう。
そして、root直下のpackage.jsonに項目を追記していきます。

▼root/package.json

追加した項目は、privateworkspacesです。
yarn workspace を使う場合は、ルートディレクトリ直下のpackage.jsonに必須で記述しなければなりません。

privateは必ずtrueにしてください。
workspacesにはワークスペースとするプロジェクトを指定します。
今回の場合は、packages/client01、packages/client02、packages/serverを直接指定しても良いのですが…、
workspacesはワイルドカードが使用できるため、”packages”: [ “packages/*” ] としています。
これで、packages配下のディレクトリがワークスペースとして扱われます。

ちなみに、workspacesには、packagesの他にnohoistも指定できます。
nohoistに指定したnodeモジュールは、各ワークスペースごとに個別で管理されます。
nohoistがない、もしくはnodeモジュールを指定していない場合は、各ワークスペースでnodeモジュールが共有化されます。

クライアントサイドワークスペース(client01/client02)を整備

今度は、クライアントサイドワークスペース2つ分を調整していきます。

まず、next.config.jsの内容を以下のように変更します。
やっている事は、next.js内で使用するパスのエイリアスの指定です。
「^@」でroot/packages/common/配下のファイルを参照するように設定します。

▼root/packages/client01/next.config.js・root/packages/client02/next.config.js

tsconfig.jsonにbaseUrl、pathsを追記します。
追記した内容は、next.config.jsと同様で、パスエイリアスの設定です。

▼root/packages/client01/tsconfig.json・root/packages/client02/tsconfig.json

次に、root/packages/client01/pages/index.tsxとroot/packages/client02/pages/index.tsxを編集していきます。
Next.jsアプリを作成した時に、用意されているページですね。

▼root/packages/client01/pages/index.tsx

先程、クライアントサイドのnext.config.jsとtsconfig.jsonを調整したおかげで、common配下のファイルをimportできるようになっています。
以下のように、import文で呼び出して、ページ内で使っていますね。

また、useEffectを使ったコードも実装していますね。
この部分は後ほど解説します。

root/packages/client02/pages/index.tsxも同様に変更します。
内容はほぼ一緒ですが、client01との違いがわかるように、h1の中身を「{getHello()} This is client02.」としておきます。

▼root/packages/client02/pages/index.tsx

これで、クライアントサイドワークスペースの調整は完了です。

サーバーサイドワークスペース(server)を整備

次にサーバーサイドワークスペースを調整していきます。
まずカレントディレクトリをrootにします。その後に、以下のコマンドを実行しましょう。
このコマンドを実行すると、root/packages/serverにnodeモジュールがインストールされます。

 

yarn workspace を使う場合、コマンドの形式は以下のようになります。
サーバーサイドワークスペース(serverディレクトリ配下)に、Expressをはじめとしたnodeモジュールをインストールしたかったので、上記のようなコマンドになったわけです。

ちなみに、クライアントサイドワークスペースへ何かのnodeモジュールを追加したい・削除したい場合は、以下のようになります。

▼client01へnodeモジュールを追加

▼client01のnodeモジュールを削除

 

さて、nodeモジュールインストールが完了しましたら、サーバーサイドワークスペースのファイルを整備していきましょう。
まずtsconfig.jsonを作成します。
srcにTypeScriptファイルを配置するので、includeは忘れないように記述しておきましょう。

▼root/packages/server/tsconfig.json

次に、server直下にsrcディレクトリを作成し、その中にmain.tsを格納しまししょう。
内容は以下の通りです。

▼root/packages/server/src/main.ts

root/packages/server/src/main.ts でやっている事はシンプルです。
expressを使って、http://localhost:4000/へGETで叩くと、ユーザー一覧を返すだけのコードです。

先程、クライアントサイドワークスペースのindex.tsxで後ほど解説すると言っていた点がここです。
サーバーサイドでは、http://localhost:4000/(GET)でユーザー一覧を返すようになっています。
クライアントサイドでは、useEffectを使って初期表示時に、http://localhost:4000/を叩いてユーザー一覧を取得して、ページに表示するようにしています。

 

クライアントサイドワークスペース同様、packages/commonから、UserType・getHelloをimportして、それぞれ使っています。
これでクライアントサイドとサーバーサイドでコードの共有化ができましたね。

さて、次は、server直下のpackage.jsonを編集します。
以下のように、scriptsを入れましょう。

▼root/packages/server/package.json

ルートプロジェクトのpackage.jsonにscriptを追加

あともうちょっとです。
ルートディレクトリ直下のpackage.jsonにscriptsを追記します。

▼root/package.json

先程、チラッと解説しましたが、yarn workspace を使った時のコマンドは以下のようになります。

ですので…、
yarn workspace client01 devを実行すると、packages/client01のNext.jsのdevコマンドを実行されます。
同じように、yarn workspace client02 devは、packages/client02のNext.jsのdevコマンドが。
yarn workspace server devは、packages/serverのdevコマンドが実行されます。

これらのコマンドをルートディレクトリのpackage.jsonに登録しておくことで、ルートディレクトリから各ワークスペースのコマンドを実行できるようにしています。
クライアントサイド(その1)のdevを実行したいなら、yarn cl01:dev
サーバーサイドのdevを実行したいなら、yarn se:devを使えばOKです。

最終調整をして完成

さて、ここまでくれば完成!…と言いたいのですが、
各ワークスペースのpackage.jsonに足りない項目があると、yarn workspaceコマンドがうまく実行されない場合があります。

私が環境構築した際は、各ワークスペースのpackage.jsonに「version」がないために、yarn workspaceコマンドがうまく動作しませんでした。

また、package.jsonの「name」も重要な項目です。
ここまで触れませんでしたが、実はpackage.jsonのnameは、yarn workspaceコマンドのworkspace名と一致させる必要があります。
でないと、yarn workspaceコマンドがうまく動作しません。

他にもいろいろありそうですが、とりあえず…、
各ワークスペースのpackage.jsonにWARNINGが出ないようにする。
各ワークスペースのpackage.jsonのnameは、yarn workspaceコマンドのworkspace名と一致させる。
…の2つをクリアしていれば問題はないかと思います。

一度、各ワークスペースのpackage.jsonを見直しましょう。

 

最終調整が終わりましたら、これでモノレポ環境作成作業は完了です!
お疲れさまでした。

ルートディレクトリをカレントとして、yarn cl01:devとyarn se:devのコマンド2つ分を実行してみましょう。
その上で、http://localhost:3000/を開くと、サーバーサイドからレスポンスが返され、ユーザー一覧が画面に表示されると思います。
また、yarn cl02:devでも同じように表示できるようになっていると思います。

 

このようにyarn workspaceを使うと、モノレポ環境を作成することができます。
各ワークスペースで簡単にコードを共有できますので、大変便利な機能です。

今回はここまで。
では、また!



❏❏ TOPIC ❏❏ ------------------------------------------------------------

カスタム自由!フリーECサイトパッケージ
チャットボット導入サービス
WEBシステム開発・スマホアプリ開発はSRIAへ