Slide 1

Slide 1 text

ローコードサービスの進化のためのモノレポ移⾏ 2025-3-18 NEWT Tech Talk vol.15 サービスの成⻑に合わせたフロントエンドの進化 株式会社ベースマキナ ⼤⻄太郎(taro)

Slide 2

Slide 2 text

はじめに

Slide 3

Slide 3 text

モノレポ使っていますか?

Slide 4

Slide 4 text

モノレポを使う目的 ● 複数のマイクロサービスの⼀元管理 ● クライアント/サーバー間の型の共有 ● 複数のサービス間での関数や処理の共通化 などなど はじめに

Slide 5

Slide 5 text

モノレポを使う目的 ● 複数のマイクロサービスの⼀元管理 ● クライアント/サーバー間の型の共有 ● 複数のサービス間での関数や処理の共通化 などなど はじめに

Slide 6

Slide 6 text

Webクライアント APIサーバー リクエスト はじめに

Slide 7

Slide 7 text

Webクライアント APIサーバー リクエスト Node.jsクライアント リクエスト 新機能追加!! はじめに

Slide 8

Slide 8 text

Webクライアント APIサーバー リクエスト Node.jsクライアント リクエスト モノレポで処理を共通化したい! はじめに

Slide 9

Slide 9 text

目次 ● ⾃⼰紹介&サービス紹介 ● モノレポ移⾏の背景 ● モノレポの構成 ● モノレポ移⾏の流れ ● モノレポで共通化しているもの ● まとめ ⽬次

Slide 10

Slide 10 text

自己紹介 ● ⼤⻄太郎 ● taro( @taroro_tarotaro) ● 株式会社ベースマキナのソフトウェアエンジニア ● ローコードで管理画⾯を作れるサービスを作ってます ⾃⼰紹介

Slide 11

Slide 11 text

リクエストの情報を設定 APIやDBを呼び出す フォームが出来る! サービス紹介 設定画⾯ 実⾏画⾯

Slide 12

Slide 12 text

モノレポ移⾏の背景

Slide 13

Slide 13 text

Webクライアント APIサーバー リクエスト Node.jsクライアント リクエスト モノレポで処理を共通化したい! モノレポ移⾏の背景

Slide 14

Slide 14 text

リクエストの情報を設定して、 APIを呼び出す処理を作成 フォームから実⾏! 設定画⾯ 実⾏画⾯ モノレポ移⾏の背景

Slide 15

Slide 15 text

フォームで実⾏していた処理を JavaScriptから実⾏できる機能を追加! モノレポ移⾏の背景

Slide 16

Slide 16 text

事前に作成した APIやSQLを呼び出す処理の実⾏ JavaScriptでワークフローを作成できる機能 モノレポ移⾏の背景

Slide 17

Slide 17 text

事前に作成した APIやSQLを呼び出す処理の実⾏ JavaScriptでワークフローを作成できる機能 モノレポ移⾏の背景 アクション ※重要な機能で以降の 話で何度か登場します

Slide 18

Slide 18 text

モノレポ移⾏の背景 フォームで実⾏していたアクションを JavaScriptから実⾏する機能が追加!

Slide 19

Slide 19 text

Webクライアント APIサーバー アクション実⾏ リクエスト Node.jsクライアント ワークフローの JSコードの実⾏環境 モノレポ移⾏の背景

Slide 20

Slide 20 text

Webクライアント APIサーバー Node.jsクライアント 同じ機能の別環境のクライアント間 のモノレポの話 アクション実⾏ リクエスト モノレポ移⾏の背景

Slide 21

Slide 21 text

モノレポの構成

Slide 22

Slide 22 text

root/ ├─ packages/ │ ├─ web/ # Webクライアント │ ├─ js-executor/ # Node.jsクライアント │ └─ lib/ # 共有ライブラリ ├─ pnpm-workspace.yaml └─ package.json モノレポの構成 モノレポの構成

Slide 23

Slide 23 text

モノレポ移⾏の流れ

Slide 24

Slide 24 text

① モノレポのキャッチアップ ② Webクライアントのみのモノレポに移⾏ ③ 開発ツールの設定をモノレポに移⾏ ④ Node.jsクライアントを追加 ⑤ 順番に共有ライブラリに移⾏する モノレポ移行の流れ モノレポ移行の流れ

Slide 25

Slide 25 text

モノレポ移行の流れ モノレポ移行の流れ ① モノレポのキャッチアップ ② Webクライアントのみのモノレポに移⾏ ③ 開発ツールの設定をモノレポに移⾏ ④ Node.jsクライアントを追加 ⑤ 順番に共有ライブラリに移⾏する

Slide 26

Slide 26 text

● pnpmのWorkspaceのドキュメント ○ pnpm.io/workspaces ● Turborepoのガイド(おすすめ) ○ turbo.build/repo/docs/crafting-your-repository ○ ⼀般的なモノレポの構成のことがだいたいわかる ○ Next.jsのstandaloneでのDockerfileとかも書いてある ○ (結局Turborepoは使ってないけど…) モノレポのキャッチアップ モノレポ移行の流れ

Slide 27

Slide 27 text

モノレポ移行の流れ モノレポ移行の流れ ① モノレポのキャッチアップ ② Webクライアントのみのモノレポに移⾏ ③ 開発ツールの設定をモノレポに移⾏ ④ Node.jsクライアントを追加 ⑤ 順番に共有ライブラリに移⾏する

Slide 28

Slide 28 text

root/ ├─ packages/ │ ├─ web/ ├─ pnpm-workspace.yaml └─ package.json root/ ├─src/ │ ├─features/ │ ├─pages/ └─ Dockerfile └─ tsconfig.json └─ next.config.js └─ package.json 移⾏前 移⾏後 稼働中のアプリかつ他の開発ライ ンも動いているので、できるだけ 影響を⼩さく段階的に移⾏した モノレポ移行の流れ

Slide 29

Slide 29 text

root/ ├─ packages/ │ ├─ web/ ├─ pnpm-workspace.yaml └─ package.json root/ ├─src/ │ ├─features/ │ ├─pages/ └─ Dockerfile └─ tsconfig.json └─ next.config.js └─ package.json 移⾏前 移⾏後 src/配下は差分なし それ以外の差分も、ほぼパスに packages/webをつけるだけ モノレポ移行の流れ

Slide 30

Slide 30 text

モノレポ移⾏の流れ npm scriptsも⼀旦今まで同様に動くようにして、 モノレポが⼀通り整うまでは 他のメンバーがこれまでと同じ⽅法で開発できる状態を維持 rootのpackage.json

Slide 31

Slide 31 text

差分のほとんどがlockファイルで、 それ以外もほぼパスにpackages/webがついただけで、 あんまり怖がらずにデプロイできた! モノレポ移行の流れ

Slide 32

Slide 32 text

モノレポ移行の流れ モノレポ移行の流れ ① モノレポのキャッチアップ ② Webクライアントのみのモノレポに移⾏ ③ 開発ツールの設定をモノレポに移⾏ ④ Node.jsクライアントを追加 ⑤ 順番に共有ライブラリに移⾏する

Slide 33

Slide 33 text

● tsconfig ● Jest(当時、今はVitest) ● ESlint ● GraphQL Codegen ● GitHub Actions を共通化できる形式に移⾏(詳細は割愛) 開発ツールの設定をモノレポに移行 モノレポ移行の流れ

Slide 34

Slide 34 text

モノレポ移行の流れ モノレポ移行の流れ Node.jsクライアントの開発を進めつつ、 必要なものをWebクライアントから共有ライブラリに移動していった ① モノレポのキャッチアップ ② Webクライアントのみのモノレポに移⾏ ③ 開発ツールの設定をモノレポに移⾏ ④ Node.jsクライアントを追加 ⑤ 順番に共有ライブラリに移⾏する

Slide 35

Slide 35 text

root/ ├─ packages/ │ ├─ web/ # Webクライアント │ ├─ js-executor/ # Node.jsクライアント │ └─ lib/ # 共有ライブラリ ├─ pnpm-workspace.yaml └─ package.json モノレポの構成 モノレポの構成

Slide 36

Slide 36 text

モノレポの構成 root/ ├─ packages/ │ ├─ web/ # Webクライアント │ ├─ js-executor/ # Node.jsクライアント │ └─ lib/ # 共有ライブラリ ├─ pnpm-workspace.yaml └─ package.json モノレポの構成 運⽤中のアプリでも 意外と簡単にモノレポ移⾏できた!

Slide 37

Slide 37 text

モノレポで共通化しているもの

Slide 38

Slide 38 text

● 特定の機能に依存しないもの ○ 汎⽤の定数、関数、型 ○ 開発ツールの設定(tsconfig, ESLint, etc.) ○ 外部ライブラリの初期化関数 ● 特定の機能に依存するもの ○ 「アクションの実⾏機能」に依存する処理 ○ 「ユーザーがコードを書く機能」に依存する処理 モノレポで共通化しているもの モノレポで共通化しているもの

Slide 39

Slide 39 text

● 特定の機能に依存しないもの ○ 汎⽤の定数、関数、型 ○ 開発ツールの設定(tsconfig, ESLint, etc.) ○ 外部ライブラリの初期化関数 ● 特定の機能に依存するもの ○ 「アクションの実⾏機能」に依存する処理 ○ 「ユーザーがコードを書く機能」に依存する処理 モノレポで共通化しているもの モノレポで共通化しているもの

Slide 40

Slide 40 text

Day.jsの初期化関数 外部ライブラリの初期化関数 ● 各クライアント ● テストのセットアップ で使う

Slide 41

Slide 41 text

モノレポで共通化しているもの モノレポで共通化しているもの ● 特定の機能に依存しないもの ○ 汎⽤の定数、関数、型 ○ 開発ツールの設定(tsconfig, ESLint, etc.) ○ 外部ライブラリの初期化関数 ● 特定の機能に依存するもの ○ 「アクションの実⾏機能」に依存する処理 ○ 「ユーザーがコードを書く機能」に依存する処理

Slide 42

Slide 42 text

① アクションの取得 ② 実⾏できるアクションか判定 ③ フォームの表⽰ ④ ⼊⼒値のバリデーション ⑤ APIサーバーへのリクエスト ⑥ 結果の表⽰ アクションの実行 Web 「アクションの実⾏機能」に依存する処理

Slide 43

Slide 43 text

アクションの実行 Node 「アクションの実⾏機能」に依存する処理 ① アクションの取得 ② 実⾏できるアクションか判定 ③ フォームの表⽰ ④ ⼊⼒値のバリデーション ⑤ APIサーバーへのリクエスト ⑥ 結果の表⽰

Slide 44

Slide 44 text

Web Node ①アクションの取得 「アクションの実⾏機能」に依存する処理 GraphQLでアクションの取得

Slide 45

Slide 45 text

Web Node ②実⾏できるアクションか判定 共通のisExecutableAction関数を使⽤ 「アクションの実⾏機能」に依存する処理

Slide 46

Slide 46 text

Lib

Slide 47

Slide 47 text

Lib GraphQL Fragment

Slide 48

Slide 48 text

https://graphql.org/ GraphQL

Slide 49

Slide 49 text

「アクションの実⾏機能」に依存する処理 Lib Node GraphQL Fragment query内で参照する

Slide 50

Slide 50 text

query内で参照する 「アクションの実⾏機能」に依存する処理 Lib Node Fragment Colocation 関数とその関数で必要な値のFragmentを ⼀緒に定義する

Slide 51

Slide 51 text

Node Web 各クライアントでlibの関数と⼀緒にFragmentを参照すると…

Slide 52

Slide 52 text

Node Web GraphQLのFragment Colocationを使うと、モノレポで 「関数」とその関数のためにサーバーから取得する情報まで 共通化できる!

Slide 53

Slide 53 text

Node 他の処理も、ほぼlibの関数と そのFragmentを使うだけ

Slide 54

Slide 54 text

Node モノレポとGraphQLのおかげで、ほぼ追加実装なしで Nodeクライアントからのアクション実⾏を追加できた!

Slide 55

Slide 55 text

モノレポで共通化しているもの モノレポで共通化しているもの ● 特定の機能に依存しないもの ○ 汎⽤の定数、関数、型 ○ 開発ツールの設定(tsconfig, ESLint, etc.) ○ 外部ライブラリの初期化関数 ● 特定の機能に依存するもの ○ 「アクションの実⾏機能」に依存する処理 ○ 「ユーザーがコードを書く機能」に依存する処理

Slide 56

Slide 56 text

「ユーザーがコードを書く機能」に依存する処理 Node

Slide 57

Slide 57 text

TODO アクションを実⾏する画⾯を JSXで作れる「ビュー」機能 Web

Slide 58

Slide 58 text

Node JavaScriptの実⾏環境は違うが、 関数でアクション実⾏などの ベースマキナの機能を呼ぶのは共通 Web

Slide 59

Slide 59 text

stringの引数に数値を渡してしまっている Node 「ユーザーがコードを書く機能」に依存する処理

Slide 60

Slide 60 text

引数の値を検証する zodのスキーマ Node Web 「ユーザーがコードを書く機能」に依存する処理

Slide 61

Slide 61 text

Lib

Slide 62

Slide 62 text

Lib zodのエラーを頑張って整形

Slide 63

Slide 63 text

● 関数の引数のバリデーション機構 「ユーザーがコードを書く機能」に依存する処理 「ユーザーがコードを書く機能」に依存する処理で、 モノレポで共通化しているもの

Slide 64

Slide 64 text

● 関数の引数のバリデーション機構 モノレポで共通化しているもの 「ユーザーがコードを書く機能」に依存する処理で、 モノレポで共通化 しているする予定のもの もうすぐ共通化を終わらせ て、ビュー機能でも同じ機構 が使えるようになる予定🙏

Slide 65

Slide 65 text

モノレポで共通化しているもの モノレポで共通化しているもの ● 特定の機能に依存しないもの ○ 汎⽤の定数、関数、型 ○ 開発ツールの設定(tsconfig, ESLint, etc.) ○ 外部ライブラリの初期化関数 ● 特定の機能に依存するもの ○ 「アクションの実⾏機能」に依存する処理 ○ 「ユーザーがコードを書く機能」に依存する処理

Slide 66

Slide 66 text

モノレポで共通化しているもの 別環境のクライアント間のモノレポだと、 ⼤きい(機能)単位で、処理を共通化できて嬉しい!

Slide 67

Slide 67 text

モノレポで共通化しているもの 別環境のクライアント間のモノレポだと、 ⼤きい(機能)単位で、処理を共通化できて嬉しい! 共通で使える実装にするのを、実は結構がんばってる🔥 (単位が⼤きい分、⾊々複雑で難しかったりする…)

Slide 68

Slide 68 text

まとめ

Slide 69

Slide 69 text

● 運⽤中のアプリでも、意外とさくっとモノレポ始められた ● GraphQLだと関数と⼀緒に取得する情報も共通化できて嬉 しい ○ モノレポとGraphQL Fragment Colocationはいいぞ ● 別環境のクライアント間のモノレポだと、機能単位で処理 を共通化できる(できるように頑張ってる🔥) まとめ まとめ

Slide 70

Slide 70 text

ありがとうございました! (ぜひベースマキナ使ってください!!)