Open8

nx・turborepoを調査する

N.WayamaN.Wayama

◎ npm workspace

nxに入る前にnpm workspaceの基本説明が入っている

package.json

{
    "workspaces": ["packages/*", "apps/*"]
}

パッケージインストール

プロジェクトルートでコマンド叩く。
workspacesに記載していたディレクトリ配下のpackage.jsonをインストールしてくれるみたい。

npm install

Build

app単体のビルドコマンドは失敗する。
packages/*のビルドが出来ていないからだ。依存関係が発生している。

npm run build -w @tuskdesign/demo

-wは後にワークスペース名を入れる。ワークスペース名はpackage.jsonnameに記載してある。

{
    "name": "@tuskdesign/demo"
}

全部ワークスペース対象にするなら--wsオプションにする。
package.jsonworkspacesに記載してある順にビルドしてくれる。

npm run build --ws

これでビルドが成功する。依存関係の調整に弱点があるのがnpm workspaceなのかも
nxだと管理できますよ〜的な流れかも

N.WayamaN.Wayama

◎ Add Nx

ここからが本番。nx導入する。

npx nx@latest init

選択肢はチュートリアルに指定されている通りにする。

package.json

初期化するとpackage.json2つの変化が起きる

  • ルートにnxパッケージがインストールされる
  • 各フォルダにnx項目が追加される。
./
{
    "devDependencies": {
        "nx": "18.2.1"
      }
}
app & packages
{
  "nx": {
    "includedScripts": [
      "typecheck",
      "build",
      // lintはappだけ
      "lint"
    ]
  }
}

nx.json

ルートにnx.jsonが作成される

nx.json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "targetDefaults": {
    "build": {
      "dependsOn": [
        "^build"
      ],
      "outputs": [
        "{projectRoot}/dist"
      ],
      "cache": true
    },
    "typecheck": {
      "cache": true
    },
    "lint": {
      "cache": true
    }
  },
  "defaultBase": "main"
}

.gitignore.nx/cacheが追加される。nxのCacheを溜めるディレクトリかな。

N.WayamaN.Wayama

◎ Nx graph

初期化完了後、次のコマンドを実行するとアプリごとの依存関係が分かる図が表示される。すごい。

npx nx graph

graph

nxはこの依存関係を理解しているのが分かる図だ。
スクリプトコマンドが実行されるといい感じに依存関係を解決してくれるのかな

N.WayamaN.Wayama

Nx Caching

Buildしてみる
npm workspaceでは単体指定は失敗したが、Nxは成功した。依存関係を理解しているっぽい。

npx nx build @tuskdesign/demo

typecheckしてみる。run-many-tで指定した種別package.json::nx::includedScriptsに存在しているところだけ実行してくれる。優秀だ。

npx nx run-many -t typecheck

ここからがNxの本領。Cache機能
Buildコマンドをもう一度実行する。

npx nx build @tuskdesign/demo
# Nx read the output from the cache instead of running the command for 3 out of 3 tasks.

爆速で終わった。どうやらCache機能をONにしていると変更がない箇所はCacheを採用するみたい。

N.WayamaN.Wayama

Nx Pipeline

タスクは依存関係を参照してPipelineで構築しているみたい。
nx.jsonのbuildを見てみる

nx.json
{
  "targetDefaults": {
    "build": {
      "dependsOn": [
        "^build"
      ],
      "outputs": [
        "{projectRoot}/dist"
      ],
      "cache": true
    }
}

^buildプロジェクトの依存関係のビルドタスクを意味する。Buildで指定されたタスクの依存関係が終わってから自分のbuildを行うということ。

実際のPipelineはnx graphで確認するとよい

因みにBuildしたディレクトリ(ここではdist)を削除してもう一度実行すると、Cacheを採用して爆速で終了&distディレクトリを復元してくれる。すごい。

Pipeline作成

タスクPipelineを追加してみる。buildタスクにtypecheckを追加

nx.json
{
  "targetDefaults": {
    "build": {
      "dependsOn": [
        "^build",
        "typecheck"
      ],
      "outputs": [
        "{projectRoot}/dist"
      ],
      "cache": true
    }
}

これで実行すると依存関係buildと指定タスクのtypecheckが実行された後にbuildが行われる。

N.WayamaN.Wayama

◎Nxチュートリアルまとめ

簡単にまとめる

Nxはnpm workspaceで弱点だった依存関係の管理をいい感じにやってくれる。
npx nx@latest initで導入可能

nx.jsonにPipelineを書いて、その通り実行。依存関係を先にやってもらうには^{type}とする
Cacheを有効にした場合、実行結果を保存してくれる。次回以降はCacheを再利用

所感

npm workspace使っているプロジェクトへの導入は案外楽そう。
プラグインを追加することでもう少し多機能になるっぽい。要調査

Pipelineあるなら、buildにlint入れておけばCIに組み込めそう。
チュートリアルあるから後で確認してみる。

https://nx.dev/ci/intro/tutorials/github-actions

N.WayamaN.Wayama

Turborepo

こちらの記事を見ながら構築
https://zenn.dev/uttk/articles/create-pnpm-monorepo

使い心地はNxと変わらん。
今の使い方想定だとどっち選んでも変わらないかなあ。

どっちかっていうと、pnpm使っているのが気になる。
npm, yarn, pnpmどれが最適解なのか悩む。