モノリポ(monorepo)での開発について 備忘録
モノリポとは
chatgpt曰く。。。。
モノリポ monorepoとは?
モノリポは複数のプロジェクトを1つのリポジトリで管理するアプローチです。
この方法は、コードの再利用性を高め、依存関係を一元管理しやすくするなど、多くのメリットがあります。
言葉で説明してもわかりづらいので、このディレクトリ構造図を見てみましょう。
これは僕のモノリポから作ったサンプルのツリーです。
ディレクトリ構造🌲
your-monorepo/
├─ @your-org/ //共有ライブラリ
│ ├─ assets/
│ │ ├─ src/
│ │ ├─ package.json
│ │ └─ README.md
│ ├─ next-app/
│ │ ├─ src/
│ │ ├─ package.json
│ │ └─ README.md
│ └─ .....
├─ apps/ //個別アプリ
│ ├─ project-a/ //個別プロジェクト
│ │ ├─ category-a/ //プロジェクト内のカテゴリ
│ │ │ ├─ app-a/ //個別アプリ
│ │ │ │ ├─ public/
│ │ │ │ ├─ src/
│ │ │ │ ├─ .eslintrc.json
│ │ │ │ ├─ .gitignore
│ │ │ │ ├─ next-env.d.ts
│ │ │ │ ├─ next.config.mjs
│ │ │ │ ├─ package.json
│ │ │ │ ├─ README.md
│ │ │ │ └─ tsconfig.json
│ │ │ └─ app-b/
│ │ │ ├─ public/
│ │ │ ├─ src/
│ │ │ ├─ .eslintrc.json
│ │ │ ├─ .gitignore
│ │ │ ├─ next-env.d.ts
│ │ │ ├─ next.config.mjs
│ │ │ ├─ package.json
│ │ │ ├─ README.md
│ │ │ └─ tsconfig.json
│ │ └─ category-b/
│ │ └─ [同様のアプリケーション構造]
│ └─ project-b/
│ ├─ category-a/
│ │ └─ [同様のアプリケーション構造]
│ └─ category-b/
│ └─ [同様のアプリケーション構造]
├─ node_modules/
├─ .gitignore
├─ package-lock.json
├─ package.json
├─ README.md
└─ tsconfig.json
つまりyour-monorepo
という単一のディレクトリの中に複数のnextjsアプリを作っていくことが可能なのです。
良い点
良い点、というかこういう開発環境を求めていて、全然知らなくて損したな、という感じなんですが。
上の例では、your-monorepo
の中に@your-app
とapps
というフォルダを作っています。
@your-app
には、apps
内の複数のnextjsアプリで共有して使えるライブラリを作っていくことができます。現状では@your-app/next-app
があって、これは自分のnextjsアプリで共通して使う雛形を入れています。
これまでは、自分でライブラリをまとめても、コードを使い回すためにnotionにおいておくか、過去に作ったプロジェクトから持ってこないとダメだったのが、モノリポ内で共有することができるのです。そして、別のアプリを作っているときに独自のライブラリを変更しても、常に全てのアプリで同じ状態のライブラリが使えるのです。
初期設定方法
まずは、ローカルにディレクトリを作ります。
例えばyour-monorepo
これが、モノリポのルートになるのです。
●npm init
your-monorepo
をvscodeで開きます。
そして以下のコマンドを実行します。単純に、npm initです。
npm init -y
●package.jsonの設定
次にpackage.jsonの設定です。
{
"name": "your-monorepo",
"version": "1.0.0",
"private": true,
"workspaces": [
"apps/*",
"apps/*/*",
"apps/*/*/*",
"@your-app/*"
],
"scripts": {
"build": "next build",
"b": "next build",
"start": "next start",
"s": "next start",
"lint": "next lint",
"dev": "run-p dev:next dev:scss",
"d": "run-p dev:next dev:scss",
"dev:next": "next dev",
"dev:scss": "typed-scss-modules src --watch",
"typegen:scss": "typed-scss-modules src"
},
"dependencies": {
"@vercel/edge": "^1.1.1",
"next": "14.1.0",
"react": "^18",
"react-dom": "^18",
"sass": "^1.71.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.1.0",
"npm-run-all": "^4.1.5",
"typed-css-modules": "^0.9.1",
"typed-scss-modules": "^8.0.0",
"typescript": "^5"
}
}
scripts
dependencies
devDependencies
は現状こんな感じ、ということなので、各々よしなに。
workspaces
注目すべきはここで、どのディレクトリを個別のアプリとして認識するかを決めます。 僕の場合は@youre-app
配下に独自ライブラリ、apps
配下に個別のアプリを作っていくことにしています。
この部分です。
"workspaces": [
"apps/*",
"apps/*/*",
"apps/*/*/*",
"@your-app/*"
],
- ``というのは
全て
という意味で、apps/*
というのはapps/以下の全てのディレクトリ
という意味です。
また、
"apps/*/*", "apps/*/*/*",
も設定しています。
配下のアプリも階層グループ分けしていくことがあるので、apps/以下の全ての階層/以下の全ての階層/以下の全ての階層
ということになっています。
apps/your-app-name
を作る方法
●新しい個別アプリ新しい個別アプリを作るには、そのアプリを配置するディレクトリに入る、もしくはそのディレクトリをvscodeで開いて、以下のコマンドを実行します。
cd apps/
npx create-next-app@latest your-app-name —use-npm —no-git
前半は普通のnextjsの作り方ですが、最後の—no-git
は「.git
を生成しない」という指定
ちなみに.gitignore
は必要っぽい。
.next/
などを不要不適切なものをgitにアップしないために。
@your-app/your-lib-name
を作る方法
●新しいライブラリこれに関しては、なんだか正確じゃない気もするのですが、
基本は個別アプリを作る方法と同じです。
cd @your-app/
npx create-next-app@latest your-lib-name —use-npm —no-git
ライブラリはnextアプリじゃないので、エントリポイントを自分でpackage.jsonに書きます。
package.json
{
"name": "@your-app/your-lib-name",
"version": "0.1.0",
"private": true,
"main": "index.ts",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^18",
"react-dom": "^18",
"next": "14.1.0"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.1.0"
}
}
このjsonの"main": "index.ts",
この部分です。 "index.ts"
内では、以下のようにライブラリ内の全ての機能をインポート/エクスポートします。
import * as Components from "./components/Components";
import * as Utils from "./utils/Utils";
import * as Const from "./constants/Constants";
import * as Functions from "./utils/Functions/Functions";
import * as Styles from "./styles/Styles";
export { Components, Utils, Const, Functions, Styles };
@your-app/your-lib-name
のライブラリの読み出し方
●独自ライブラリを個別のアプリにインストールする方法です。
ここまでの設定がきちんと済んでいれば、以下のように普通のnpm installの方法で可能です。
cd ./apps/your-app-name //インストールしたいアプリに移動する
npm i @your-app/your-lib-name //普通のインストール
@your-app/your-lib-name
はライブラリのpackage.json
のname
で設定している名前です。
Tips & Trouble Shoot
node_modules/
はルートのみに存在する
モノレポでは、node_modules/はルート(ここではyour-app/
)にのみ存在します。
なので、個別アプリの中にnode_modules/が存在しちゃっている場合は、モノレポのpackage.json
のworkspaces
にその個別アプリのディレクトリが指定されていない可能性があります。その場合は、きちんとpackage.json
のworkspaces
に該当する個別アプリのディレクトリを指定しましょう。apps/*
みたいな書き方がよくわからないのであればapps/your-app-name
というようにきちんと指定することも可能です。
vercelでのデプロイ🌐
ここまでの設定がうまくいっていれば、vercelでデプロイする際のプロジェクトを作る時の画面で、root directoryをどこにするか、自動でvercelが確認してくれます。
その他は、普通のvercelのデプロイ方法と同じです。
別のライブラリをライブラリから使用する
例えば@your-app/assetsにアセット類をまとめて、@your-app/next-appから使いたい場合。
●scssのfont-faceのurlとして使いたい。
@font-face {
font-family: "Helvetica Neue LT W05 25 Ult Lt";
src: url("~@your-app/assets/fonts/xxxxxx/ec6281a0-c9c4-4477-a360-156acd53093f.woff2")
format("woff2"),
url("~@your-app/assets/fonts/xxxxxx/11066b40-10f7-4123-ba58-d9cbf5e89ceb.woff")
format("woff");
unicode-range: U+0030-0039, U+0041-007A, U+0025-00FF, U+0021, U+2381, U+0332,
U+FF3F, U+005F, U+0022, U+0027, U+2018, U+2019, U+201C, U+201D, U+0023,
U+FF03, U+0024, U+FE69, U+FF04, U+1F4B2, U+00B7, U+0387, U+2022, U+2219,
U+22C5, U+30FB, U+FF65, U+0080 –U + 00FF, U+2122;
}
// ちなみにこれは合成フォントを実現するためのscss
url部分で”@your-app/assets/*********”
とするとパスが解決されない。
こういう場合は”~@your-app/assets/*********”
みたいに~
を最初に持ってくる必要があるみたい。
sakamoto-appを作る上で便利だなと思ったもの。
npm i typed-scss-modules —save-dev
これは、*.module.scss
の型定義*.d.ts
を自動で生成してくれるもの
これによってscssモジュールの使い回しが楽になり、重複を減らせる。
設定ファイルtyped-scss-modules.config.ts
はモノレポ./
に置いちゃっていいと思う。多分。
typed-scss-modules.config.ts
export const config = {
exportType: "default",
nameFormat: "none",
implementation: "sass",
};
npm i npm-run-all —save-dev
これはnpmコマンドを複数自動で実行できるようにするもの。
npm run dev
した後に 自動でtyped-scss-modules src --watch
を実行する。みたいな
package.jsonではこんな感じに設定する。
Discussion