2
0

More than 3 years have passed since last update.

ServerlessFrameworkのテンプレをYarn Workspacesで扱うチュートリアル

Posted at

概要

複数のServerlessFrameworkプロジェクトをYarn Workspacesを利用して1リポジトリに収めた際の備忘録です。

GitHubにコードサンプルを上げています:https://github.com/shu000/serverless-ts-monorepo-sample

Dependencies

  • Node.js v14.15.1
  • Yarn v1.22.5
  • ServerlessFramework v2.52.1

Step 1. テンプレートのインストール

まずは、ServerlessFrameworkのテンプレートを利用して、helloパッケージを作成します。

sls create --template aws-nodejs-typescript --path hello

複数のパッケージを用意したいので、同様にbyeパッケージも作成します。

sls create --template aws-nodejs-typescript --path bye

これでディレクトリはこのような状態です(一部ファイル省略)。

bye/
    src/
        functions/
        libs/
    package.json
    serverless.ts
    webpack.config.js
hello/
    src/
        functions/
        libs/
    package.json
    serverless.ts
    webpack.config.js

(以下、helloパッケージのコードサンプルが登場しますが、byeパッケージでも同一の変更が必要です。)

Step 2. モノレポ化

ここまでで1リポジトリ内に2つのnpmパッケージを設置しました。
ここからYarn Workspacesを活用してモノレポと呼べる構成にしていきます。

packages/
    bye/
        src/
            functions/
            libs/
        package.json
        serverless.ts
        webpack.config.js
    hello/
        src/
            functions/
            libs/
        package.json
        serverless.ts
        webpack.config.js

次にルートディレクトリにpackage.jsonを作成して、Yarn Workspaces設定を記述します。
また、今回は子パッケージのdevDependenciesは共通依存と見做し、ルートのpackage.jsonに書き写してします。

/package.json
{
  "name": "monorepo-sample",
  "version": "1.0.0",
  "private": true,
  "workspaces": [
    "packages/bye",
    "packages/hello"
  ],
  "devDependencies": {
    "@serverless/typescript": "^2.23.0",
    "@types/aws-lambda": "^8.10.71",
    "@types/node": "^14.14.25",
    "json-schema-to-ts": "^1.5.0",
    "serverless": "^2.23.0",
    "serverless-webpack": "^5.3.5",
    "ts-loader": "^8.0.15",
    "ts-node": "^9.1.1",
    "tsconfig-paths": "^3.9.0",
    "tsconfig-paths-webpack-plugin": "^3.3.0",
    "typescript": "^4.1.3",
    "webpack": "^5.20.2",
    "webpack-node-externals": "^2.5.2"
  }
}

ルートにdevDependenciesを記述したので、byeおよびhelloのpackage.jsonも編集します。

/packages/hello/package.json
{
  "name": "hello",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "@middy/core": "^1.5.2",
    "@middy/http-json-body-parser": "^1.5.2",
    "source-map-support": "^0.5.19"
  }
}

これで一旦モノレポにはなりました。
ルートディレクトリでyarnを実行すると、共通するライブラリがルートに巻き取られることが分かります。

Step 3. webpack.config の修正

ここまででは、まだデプロイはうまくいきません。
デフォルトのwebpack.config.jsでは親のnode_modulesを解決できないためです。

従ってwebpack-node-externalsに親のnode_modulesを教えてやります。

/packages/hello/webpack.config.js

  externals: [nodeExternals({
    modulesDir: path.resolve(__dirname, '../../node_modules')
  })],

これで、各パッケージ内でsls deployの実行に成功するようになります。

Step 4. 共通パッケージの作成

せっかくモノレポにしたので、重複ソースを共通パッケージとして切り出しましょう。
まずはpackages/my-libsディレクトリを作成します。

mkdir packages/my-libs

テンプレートに含まれるsrc/libsを共通パッケージにしてみます。

mv packages/hello/src/libs packages/my-libs/src
rm -rf packages/bye/src/libs
/packages/my-libs/package.json
{
  "name": "my-libs",
  "version": "1.0.0",
  "private": true,
  "main": "src/index.ts",
  "dependencies": {
    "@middy/core": "^1.5.2",
    "@middy/http-json-body-parser": "^1.5.2"
  }
}
/packages/my-libs/src/index.ts
export * from './apiGateway'
export * from './handlerResolver'
export * from './lambda'

上記ではmy-libsのmainをts(src/index.ts)にしています。 今回の構成では、byeやhelloのビルド時に、ts-loaderがmy-libsのtsも併せてビルドしてくれるためです。 通常、他者のパッケージからも呼ばれる場合は、ちゃんとトランスパイルしてからjsをmainに設定しましょう。

これでディレクトリ構成はこんな感じ。

package.json
packages/
    my-libs/
        src/
            index.ts
            apiGateway.ts
            handlerResolver.ts
            lambda.ts
        package.json
    bye/
        src/
            functions/
        package.json
        serverless.ts
        webpack.config.js
    hello/
        src/
            functions/
        package.json
        serverless.ts
        webpack.config.js

ではmy-libsをworkspacesに追加しましょう。

/package.json
  "workspaces": [
    "packages/my-libs",
    "packages/bye",
    "packages/hello"
  ]

続いてbyehelloからmy-libsを利用してみます。

/packages/hello/package.json
  "dependencies": {
    "my-libs": "*",
    "source-map-support": "^0.5.19"
  }
/packages/hello/src/functions/handler.ts
import type { ValidatedEventAPIGatewayProxyEvent } from 'my-libs';
import { formatJSONResponse } from 'my-libs';
import { middyfy } from 'my-libs';
/packages/hello/src/functions/index.ts
import { handlerPath } from 'my-libs';

最後に、このままではServerlessFrameworkがmy-libsをバンドルする際にエラーになるため、webpack.configに設定を追加します。

/packages/hello/webpack.config.js

  externals: [nodeExternals({
    modulesDir: path.resolve(__dirname, '../../node_modules'),
    allowlist: ['my-libs']
  })],

これで、ルートディレクトリでyarnを再実行すれば、sls deployが成功するようになります!

以上、当方初学者のため、マサカリ募集中です。

参考記事

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0