3
0

More than 3 years have passed since last update.

[Serverless Framework] yarn workspaceを使ったmonorepo

Last updated at Posted at 2020-12-28

はじめに

Serverless Frameworkはサーバレスなアプリケーションを簡単にデプロイできるOSSのフレームワークです。
Serverless Frameworkを使うときには、複数のパッケージを一つのリポジトリで管理する、いわゆるモノレポな構成にしたいことがあると思います。モノレポなプロジェクトの管理方法にはyarn workspaceやlernaなどがあります。

ここでは、yarn workspaceを使ったServerless Frameworkのモノレポを構築する方法を紹介したいと思います。サンプルには、AWSのAPIGatewayとLambdaを使います。

構築中にいろいろと問題が発生したので、誰かの参考になればと思います。
初心者なので、おかしいところがあれば是非指摘お願いします。

githubにもサンプルを残したので、よければ参考にしてください。

serverless-webpackを使う方法: https://github.com/allJokin/serverless-webpack-service
serverless-bundleを使う方法: https://github.com/allJokin/serverless-bundle-service

環境
serverless@2.16.0

yarn workspaceの設定

以下のようなディレクトリ構成でプロジェクトを作成します。
Serverless Frameworkではサービスという単位で環境を作っていきます。

├── packages # serviceで使うパッケージ
|   ├── package-1
|   └── ...
├── services # lambdaなど
|   ├── package-1
|   └── ...
├── package.json
└── yarn.lock

yarn workspaceを有効にするためにrootのpackage.jsonを以下のように記載します。

package.json
{
  "name": "root",
  "private": true,
  "workspaces": [
    "packages/*",
    "services/*"
  ]
}

Serviceの作成

公式サイトの手順を参考にAPIGatewayとLamdaのServiceを作っていきます。

aws-nodejs-typescriptのテンプレを使って、servicesの配下にapi(名前は何でもいい)を作成します。

serverless create --template aws-nodejs-typescript --path services/api

コマンドを実行するとapiの配下に以下のようなファイルが作成されていると思います。

├── .gitignore
├── handler.ts
├── package.json
├── serverless.ts
├── tsconfig.ts
└── webpack.config.js

handler.tsにはLambdaの中身、serverless.tsにはインフラの設定が書いてあります。

Serviceを用意したので、rootでyarn installしましょう。yarn workspaceを有効にしているので、apiにもモジュールがインストールされます。

モジュールをインストールしたら、services/apiにcdしてデプロイしてみましょう!
sls deploy

deployできない

deployしようとすると、以下のようなエラーが出ました…。

ERROR in ./handler.ts 1:0-37
Module not found: Error: Can't resolve 'source-map-support/register' in '/workspaces/services/serverless-webpack-service'

どうやら、serverless-webpackがyarn workspaceに対応していないようです。(2020年12月時点)

以下のissueを参考にwebpack.config.ts修正します。nodeExternalsにrootのnode_moduleを指定してあげると良いようです。

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

これでデプロイできるようになりました!
なぜこれでできるようになるのか、原理はわかりません…。

自作のpackageを追加

自作のpackageをpackagesフォルダに追加します。文字列を返すだけの簡単なサンプルです。

index.ts
export const mypackage = () => {
  return 'This is my pakcage.';
}

service/apiに自作パッケージを追加します。rootで以下のコマンドを実行します。(yarn addのworkspace版)
yarn workspace api add my-package

handler.tsでimportして、

handler.ts
import { APIGatewayProxyHandler } from 'aws-lambda';
import 'source-map-support/register';
import { mypackage } from 'my-package';

export const hello: APIGatewayProxyHandler = async (_event, _context) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: mypackage()
    }, null, 2),
  };
}

deployします!

deployできない Part2

今度は以下のようなエラー。

  Error: npm install failed with code 1
      at ChildProcess.<anonymous> (/workspaces/node_modules/serverless-webpack/lib/utils.js:91:16)
      at ChildProcess.emit (events.js:314:20)
      at ChildProcess.EventEmitter.emit (domain.js:483:12)
      at maybeClose (internal/child_process.js:1021:16)
      at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)

今度は、以下のissueの最後にある修正をします。allowlistにpackage名を入れてあげる。

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

デプロイできた!URLにアクセスすると、ちゃんと表示されているので動いてそう。なぜこれでできるようになるのか、これも原理はわかりません…。

deploy.png

もっと簡単な対処法

webpack.config.tsをいろいろ修正して、なんとかデプロイできました。実はもっと簡単な方法がありました。
それは、serverless-bundleを使う方法です。

これはwebpackのconfigを書かなくてもいい感じにやってくれるプラグインのようです。

導入はとても簡単で、

serverless create --template aws-nodejs-typescript --path services/api

をした後に、不要なファイル(webpack.config.ts)を削除して、以下のファイルを変更するだけです。

package.json
  "devDependencies": {
    "@serverless/typescript": "^2.12.0",
    "@types/aws-lambda": "^8.10.64",
    "@types/node": "^14.14.6",
    "serverless-bundle": "^4.1.0",
    "ts-loader": "^8.0.10",
    "ts-node": "^9.0.0",
    "typescript": "^4.0.5"
  }
serverless.ts
  custom: {
    bundle: {
      packager: 'yarn',
      tsConfig: './tsconfig.json',
      caching: false
    }
  },
tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".", // 追加
    "lib": ["es2017"],

これでデプロイできるようになると思います!
webnpackのconfigを細かく調整する必要がないならこれが楽でいいかもしれません。

結論

Serverless Frameworkでyarn workspaceを使う方法について紹介しました。serverless-webpackでいろいろエラーが出ましたが、なんとか動くようになりました。issueでも議論されているので、いつか対応されるかもしれません。issue通りに修正してなぜ動くのかは今後勉強したいと思います。

serverless-bundleは導入するだけでいい感じにbuildしてくれるので、それまではserverless-webpackではなく、こっちを使うのがいいかもしれません。

3
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
3
0