ハイパーマッスルエンジニア

Vim、ShellScriptについてよく書く

NestJSとNext.jsをlernaでモノレポ化する

f:id:rasukarusan:20210323232210p:plain

最近流行りのフレームワークたちをlernaを使ってモノレポ化する。
構成はこんな感じになる想定。

.
├── lerna.json
├── package.json
└── packages
    ├── client   <-------- Next.js
    │     └── package.json
    └── server   <-------- NestJS
          └── package.json

どこまでやるか

今回モノレポ化したい一番の目的が、package.jsonのscriptsコマンドの一括操作。
つまりリポジトリ直下でyarn devと実行したら、クライアント側とサーバー側の両方のyarn devが実行される形。
node_modulesの共通化はやらない。

クライアントとサーバーを作成する

各自Next.jsとNestJSのコマンドを使って作成する。もうすでにclientとserverのディレクトリが作成済みの人はここの作業は不要。別にNext.jsやNestJSじゃなくても全く構わない。 まずはclientとserverをまとめるためのmonorepoディレクトリを作成する。

mkdir monorepo
cd monorepo

今後の作業はこのmonorepoディレクトリの中でおこなっていく。

Next.jsでクライアントの作成

# クライアントの作成 @See https://nextjs.org/docs
npx create-next-app

コマンドを実行するといくつか質問を聞かれるが全部ENTERでOK。最初に聞かれるプロジェクト名だけclientと入力する。

create-next-appで作成すると自動的にgit管理になるが、今回は邪魔になるので.gitを削除しておく。

rm -rf client/.git

yarn devを実行した後、http://localhost:3000にアクセスしてページが表示されたらOK。

cd client
yarn dev

NestJSでサーバーの作成

# サーバーの作成 @See https://docs.nestjs.com/first-steps
# 'server'という名前で作成する
nest new server

ここもコマンドを実行するといくつか質問を聞かれるが全部ENTERでOK。
nest newで作成すると自動的にgit管理になるが、今回は邪魔になるので.gitを削除しておく。

rm -rf server/.git

yarn start:devを実行した後、http://localhost:3000にアクセスしてページが表示されたらOK。

cd server
yarn start:dev

ただ、このままだとクライアント側とポート番号が3000で衝突して同時に環境を立ち上げることができないのでポート番号を変更しておく。

$ vim src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3001); // <------- 3001に変更
}
bootstrap();

また、クライアントとサーバー側でscriptsコマンドの名前を同じにしておきたいので、package.jsonも編集しておく。yarn devで環境を立ち上げられるようにする。

$ vim package.json

...略
"scripts": {
  "dev": "nest start --watch",

lernaを導入してモノレポ化する

さっそくlernaでモノレポ化する。現在のディレクトリ構造は下記。

monorepo
  ├── client
  │     └── package.json
  └── server
      └── package.json

lernaの導入

npm install -g lerna

npxでその場だけでlernaをインストールしてもいいが、今回はグローバルでインストールしておく。

lerna initで初期環境を構築

cd monorepo
lerna init

実行するとlerna.json,package.json,packagesの3つが作成される。

monorepo
  ├── lerna.json
  ├── package.json
  ├── packages
  ├── client
  └── server

client、serverをパッケージ化する

lerna createコマンドでパッケージの作成とともにディレクトリを生成されるが、今回はすでにclient, serverを作ってあるので、それをpackages配下に移動させてからコマンドを実行する。

mv server packages
mv client packages
lerna create @monorepo/server ./packages/server
lerna create @monorepo/client ./packages/client

@monorepoの部分がパッケージ名となるが、あとから変更可能なので気軽につける。 また、lerna createをすると各パッケージ配下にいくつかファイルが作成される。

f:id:rasukarusan:20210323230824p:plain:w500
testsやREADMEが作成される
__tests__README.mdは不要なので削除してもOK。libは必要なので消さないでおく。

scriptsコマンドの一括操作

ディレクトリ直下のpackage.jsonにscriptsコマンドを追加する。

vim package.json

{
  "name": "root",
  "private": true,
  "scripts": {
    "dev": "lerna run dev --parallel --stream --scope=@monorepo/{client,server}"
  },
  "devDependencies": {
    "lerna": "^4.0.0"
  }
}

ディレクトリ直下でyarn devを実行すると、clientとserverの両方が立ち上がる。

f:id:rasukarusan:20210323230543p:plain:w500
clientとserverどちらも起動できている

これで終了

コマンドまとめ

mkdir monorepo
cd monorepo

# クライアント作成
npx create-next-app
rm -rf client/.git

# サーバー作成
nest new server
rm -rf server/.git

# モノレポ化
lerna init
mv server packages
mv client packages
lerna create @monorepo/server ./packages/server
lerna create @monorepo/client ./packages/client

終わり

ただ、node_modulesの共通化はyarn workspaceとlernaをセットで使ったりと、少し複雑になってきそうだったのでやらなかったけど、モノレポ化と言ったらリポジトリの軽量化みたいなところもあるので別の機会でちゃんとやる。