Closed26

AWS Amplify CLIとTypeScriptでLambda関数の開発環境を構築する手順を学ぶ

okomeworldokomeworld

まずはAWS Amplify CLIをインストール(バージョンは5.2.0だった)

npm i -g @aws-amplify/cli
okomeworldokomeworld

適当にディレクトリ作って amplify init する

mkdir ~/amplify-sample && cd $_
amplify init
okomeworldokomeworld

プロジェクト名とか使うエディタとか使うAWS Profileとかとか色々聞かれるけど一旦適当に選択しておく。最悪 amplify delete すればまた1からやり直せるし。。

okomeworldokomeworld

処理が終わったら↓みたいな構成ができあがった

.
├── .gitignore
├── amplify
│   ├── #current-cloud-backend
│   │   ├── amplify-meta.json
│   │   └── tags.json
│   ├── .config
│   │   ├── local-aws-info.json
│   │   ├── local-env-info.json
│   │   └── project-config.json
│   ├── README.md
│   ├── backend
│   │   ├── amplify-meta.json
│   │   ├── backend-config.json
│   │   └── tags.json
│   ├── cli.json
│   └── team-provider-info.json
└── src
    └── aws-exports.js

5 directories, 13 files
okomeworldokomeworld

amplify add function でプロジェクトにLambda関数を追加できるみたいなので実行する
実行したらまた色々聞かれたのでとりあえず今は↓みたいな感じにした

$ amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: samplefunction
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? No
? Do you want to edit the local lambda function now? No
Successfully added resource jobboardnotifier locally.
okomeworldokomeworld

TypeScriptはローカルインストールにしてみる

npm init
npm i -D typescript

npm init で色々聞かれるやつはとりあえずEnterキー連打

okomeworldokomeworld

amplify/backend/function/samplefunction/src にトランスパイルしたjsを突っ込みたいので、tsファイルは amplify/backend/function/samplefunction/lib に置くことにしてみる

cd amplify/backend/function/samplefunction

mkdir lib

# 一旦削除
rm src/event.json src/index.js
okomeworldokomeworld

公式ドキュメントの例では tsconfig.jsonamplify/backend/function/samplefunction の直下に置けとなってるのでそれに倣ってみる

npx tsc --init
okomeworldokomeworld

公式ドキュメントに倣って tsconfig.json を編集して一旦↓みたいな内容になった

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["DOM", "ESNext"],
    "outDir": "./src",
    "rootDir": "./lib",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "src": ["./lib"]
    },
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  }
}

構成ファイル '.../tsconfig.json' で入力が見つかりませんでした。指定された 'include' パスは '["**/*"]' で、'exclude' パスは '["./src"]' でした。 みたいなエラー出てるけど一旦無視

okomeworldokomeworld

とりあえずまず動かしたいので Hello World 吐くだけのコードを書く

lib/index.ts
export const handler = () => {
    console.log('Hello World');
}
okomeworldokomeworld

公式ドキュメント見てると、プロジェクトルート(今回で言うと~/amplify-sampleディレクトリ)の package.jsonamplify:functionの名前 で実行できるnpm-scriptsを定義しておくと、amplify push 実行時に合わせて実行してくれるらしい。のでnpm-scriptsを追加する

プロジェクトルートのpackage.json
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "amplify:jobboardnotifier": "cd amplify/backend/function/jobboardnotifier && tsc -p ./tsconfig.json && cd -"
  },
okomeworldokomeworld

amplify push でトランスパイルできる的なことが書いてあるけど、とりあえずローカルで動かしたいので amplify mock を試す

$ amplify mock function samplefunction
? Provide the path to the event JSON object relative to {プロジェクトルートのパス}/amplify/backend/function/samplefunction
>> Provide a valid unix-like path to a .json file

event.jsonどうしますか的なこと聞かれたので空にしてみたらjsonファイル指定しろと怒られた。。
のでevent.jsonを改めて追加する

echo "{}" > ~/amplify-sapmle/amplify/backend/function/samplefunction/src/event.json
okomeworldokomeworld

再度 amplify mock を試してみる

$ amplify mock function samplefunction
? Provide the path to the event JSON object relative to {プロジェクトルートのパス}/amplify/backend/function/job
boardnotifier src/event.json
Ensuring latest function changes are built...
Starting execution...
Hello World
samplefunction failed with the following error:
Error: Lambda execution timed out after 10 seconds. Press ctrl + C to exit the process.
    To increase the lambda timeout use the --timeout parameter to set a value in seconds.
    Note that the maximum Lambda execution time is 15 minutes:
    https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-functions-that-can-run-up-to-15-minutes/

    at Timeout.<anonymous> (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-util-mock/src/func/index.ts:82:42)
    at listOnTimeout (node:internal/timers:557:17)
    at processTimers (node:internal/timers:500:7)
Finished execution.

おー動いた。が、エラーが出てる。

okomeworldokomeworld

エラーが出てるのは関数がasync(Promise)でないといけないようで、そのPromiseが解決しないとタイムアウトになってしまうっぽい。のでasyncにして適当に解決させて再度 amplify mock してみる

export const handler = async () => {
    console.log('Hello World');

    return {
        statusCode: 200,
        body: JSON.stringify({
            message: 'Hello World'
        })
    };
}
$ amplify mock function samplefunction
? Provide the path to the event JSON object relative to {プロジェクトルートのパス}/amplify/backend/function/job
boardnotifier src/event.json
Ensuring latest function changes are built...
Starting execution...
Hello World
Result:
{
  "statusCode": 200,
  "body": "{\"message\":\"Hello World\"}"
}
Finished execution.
okomeworldokomeworld

tsconfig.jsonのエラー解決やlintしたりできるようにしたいので、後日続きやる

okomeworldokomeworld

amplify/backend/function/samplefunction/src 以下のjsも管理するのは煩わしいので .gitignore に追記

@@ -17,4 +17,6 @@
 amplify-build-config.json
 amplify-gradle-config.json
 amplifytools.xcconfig
 .secret-*
-#amplify-do-not-edit-end
\ No newline at end of file
+#amplify-do-not-edit-end
+
+amplify/backend/function/jobboardnotifier/src/**/*.js
\ No newline at end of file
okomeworldokomeworld

tsconig.json でエラーがでる件については include フィールドを追加すれば消えた。

…けどそれ以降includeフィールド消したりしてもエラーがでなくなったので謎。どうもVSCodeが出力するエラーっぽいのでまぁ一旦よしとする

@@ -16,5 +16,6 @@
     "skipLibCheck": true,
     "forceConsistentCasingInFileNames": true,
     "resolveJsonModule": true
-  }
+  },
+  "include": ["./lib/**/*.ts"]
 }
okomeworldokomeworld

ここまでやってみて、どうせプロジェクトルートの tsc 使うなら tsconfig.json もプロジェクトルートに置いてしまったほうが良いのかもしれないと思った。けどまぁあとで考える

okomeworldokomeworld

lint周りの環境を整えようと思って、とりあえずeditorconfigを入れるために editorconfig-cli というnpmモジュールが便利そうだったので使ってみた。インデントをスペースにしたくらいであとはEnter連打で良かったので楽。

$ npm i -g editorconfig-cli

$ ec init
? charset? utf-8
? indent style? space
? indent size? 2
? end of line? lf
? trim trailing whitespace? Yes
? insert final newline? Yes

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

? Ok? Yes
okomeworldokomeworld

まずは eslint 環境整えるためにインストール

$ npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
okomeworldokomeworld

eslint--init オプションで設定ファイル生成してくれるのでそれを実行する。TypeSciprt使いますか?みたいな質問もあってYesにしたら関連プラグインをインストールしてくれたので、もしかしたらとりあえずeslintだけインストールしてinitしたら概ね出来上がってしまうのかもしれない。便利ー。

$ npx eslint --init
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · none
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · standard
✔ What format do you want your config file to be in? · JSON
Checking peerDependencies of eslint-config-standard@latest
The config that you've selected requires the following dependencies:

@typescript-eslint/eslint-plugin@latest eslint-config-standard@latest eslint@^7.12.1 eslint-plugin-import@^2.22.1 eslint-plugin-node@^11.1.0 eslint-plugin-promise@^4.2.1 || ^5.0.0 @typescript-eslint/parser@latest
✔ Would you like to install them now with npm? · No / Yes
Installing @typescript-eslint/eslint-plugin@latest, eslint-config-standard@latest, eslint@^7.12.1, eslint-plugin-import@^2.22.1, eslint-plugin-node@^11.1.0, eslint-plugin-promise@^4.2.1 || ^5.0.0, @typescript-eslint/parser@latest

added 80 packages, and audited 229 packages in 5s

55 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Successfully created .eslintrc.json file
okomeworldokomeworld

prettiereslint--init では考慮されないみたいなので素直に入れる

$ npm i -D prettier eslint-config-prettier
.eslint.json
@@ -4,7 +4,10 @@
         "es2021": true
     },
     "extends": [
-        "standard"
+        "standard",
+        "plugin:@typescript-eslint/recommended",
+        "prettier",
+        "prettier/@typescript-eslint"
     ],
     "parser": "@typescript-eslint/parser",
     "parserOptions": {
okomeworldokomeworld

VSCodeでファイル保存時に勝手にフォーマットしてほしいので .vscode/settings.json を↓の内容で追加

.vscode/settings.json
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

okomeworldokomeworld

試しに lib/index.ts を保存してみたらちゃんと自動フォーマットされたので、とりあえず求めてた環境構築はできた!

apmlifyでfunction開発する場合のDefinedTypeがないか探してみたけど、具体的に言及されてるような記事等は見つからなかった。ので一旦 @types/aws-lambda を導入して開発してみようと思う

このスクラップは2021/07/29にクローズされました