🚀

NxでCDKを使いたい

2023/01/02に公開

Nxとはnwrl社が開発するモノレポ環境用のビルドツールです。
とにかく高速に動作することを謳っています。

https://nx.dev/

今回はNxでAWS CDKを使うための設定を紹介しようと思います。

環境

  • OS
    • macOS 13.0.1(22A400)
% node -v
v18.12.1
% npm -v
8.19.2
% yarn -v
1.22.19
package.json(一部)
 "dependencies": {
    "@nrwl/next": "15.4.2",
    "aws-cdk": "^2.51.1",
    "aws-cdk-lib": "^2.51.1",
    "constructs": "^10.1.164",
  },
  "devDependencies": {
    "@ago-dev/nx-aws-cdk-v2": "^1.3.1",
    "@nrwl/workspace": "15.4.2",
    "nx": "15.4.2",
    "typescript": "~4.8.2"
  }
  • サンプルのリポジトリはこちら

https://github.com/tokku5552/nx-nextjs-workspace-poc

やってみる

まずはプラグインをインストールします。
プラグインは以下で検索できます。

https://nx.dev/community#plugin-directory

cdkで検索すると、現時点では2つしか存在せず、一つはcdk v1なので、v2で使おうと思ったら実質選択肢は一つしかありません。

https://github.com/adrian-goe/nx-aws-cdk-v2

これを使わなくても自分でgenerator等を作れば良いですが、今回はとりあえずこちらを使います。

yarn add -D @ago-dev/nx-aws-cdk-v2

プラグインがインストールできたら、project.jsonにコマンドが増えています。

project.json
...
targets": {
    "deploy": {
      "executor": "@ago-dev/nx-aws-cdk-v2:deploy",
      "options": {}
    },
    "destroy": {
      "executor": "@ago-dev/nx-aws-cdk-v2:destroy",
      "options": {}
    },
    "bootstrap": {
      "executor": "@ago-dev/nx-aws-cdk-v2:bootstrap",
      "options": {}
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/sample-app-cdk/**/*.ts"]
      }
    },
...

まずはcdk用のprojectを作ってみます。

yarn nx generate @ago-dev/nx-aws-cdk-v2:application sample-app-cdk

sample-appというアプリ用のcdk codeというイメージです。

cdk initで作ったときと比べると、package.jsonがなかったり、binがなかったりします。
srcのなかのmain.tsがエントリポイントになっていて、src/stacks/app-stack.tsに実際のリソースを定義せよということだと理解したので、こちらに適当にS3バケットとそこにNext.jsのアプリをデプロイする設定を書いてみます。

apps/sample-app-cdk/src/stacks/app-stack.ts
import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';

export class AppStack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props);

    const bucket = new s3.Bucket(this, 'Bucket', {
      removalPolicy: RemovalPolicy.DESTROY,
    });

    new s3deploy.BucketDeployment(this, 'BucketDeploy', {
      sources: [s3deploy.Source.asset('../sample-app/.next')],
      destinationBucket: bucket,
    });
  }
}

注意点としてはSource.asset('path')pathはこのcdkアプリケーションのプロジェクトルートから見たときの相対パスです。
現状apps/の下にsample-appsample-app-cdkが横並びになっているので、そこのパスは../sample-app/になります。

これをデプロイするには以下のコマンドを実行します。

yarn nx deploy sample-app-cdk

これで通常通りデプロイできます。

用意されているコマンド以外のコマンドを使いたいとき

CodePipelineに載せたかったので、それだとどうしてもsynthコマンドが使える必要があります。
はじめはpluginを拡張したり、自作する必要があるのかと思っていたんですが、単にコマンドを追加するだけならもっと簡単にできました。

cdkのproject.jsonに以下のように追記します。

apps/sample-app-cdk/project.json
  "targets": {
+    "synth": {
+      "executor": "nx:run-commands",
+      "options": { "command": "cdk synth", "cwd": "apps/sample-app-cdk" }
+    },
    "deploy": {
      "executor": "@ago-dev/nx-aws-cdk-v2:deploy",
      "options": {}
    },
    "destroy": {
      "executor": "@ago-dev/nx-aws-cdk-v2:destroy",
      "options": {}
    },

executornx:run-commandsを指定して、optionscommandに実行したいコマンドを渡してやると、package.jsonscriptsに追加する感覚でスクリプトを追加できます。
(公式ドキュメントを読んでもなかなか理解できなくて、小一時間ハマりました、、、)

あとは同じように

yarn nx synth sample-app-cdk

と実行してやると、無事cdk synthが行えました🎉
試していないですが、同様のことをすればcdk diffとかも実行できると思います。

まとめ

Nxに関しては、そもそもGoogleで検索しづらいし(車の記事が出てくる、、、)ドキュメントも分かりづらいし、QiitaやZennでも記事が少なく、結構ハマったときに抜け出しにくいなと思いました。
ただ、cdkはともかくNext.jsのプロジェクトを作ったり共通componentを追加したりする開発体験はとても良かったので、もうちょっと頑張って整えて使っていこうかなと思います💪

Discussion