JavaScriptはオワコン!とまでは言いたくないんですが、やはり普段からTypeScriptを利用していると極力JavaScriptは避けたいところ。
ということで基本JavaScriptで開発されているであろうAWS LambdaのNode環境ですが、TypeScriptで開発を始めるまでをまとめておきます。
Serverless Frameworkを使えば比較的容易にTypeScript環境を構築できるようですが、またそれは別途試してみます。
今回はSAM CLIで対応します。
(デプロイはJavaScriptと変わらないので割愛します)
SAM開発環境を整える
SAM CLIのインストール
まずはSAM CLIをインストールする必要があります。
Dockerのインストールも必要になってきますが、基本的には公式ドキュメント(Installing the AWS SAM CLI)に一通り書いてあるのでそちらを参照して下さい。
最終的に
sam --version
がきちんと動作すれば問題ないと思います。
(補足)IAMユーザー情報の登録
AWS CLIを普段利用していない方などはIAMユーザーの認証情報をPCにセットアップする必要があります。
AWSを利用していてLambdaだけしか使わない人も珍しいと思いますので、詳細は割愛しますが公式ドキュメント(Setting Up AWS Credentials)にAWS CLIを利用しない認証情報のセットアップも掲載されておりますのでご参照ください。
個人的にはAWS CLIをセットアップすることをオススメしますが。
SAM CLIでプロジェクトを作成する
SAMでプロジェクトを作成します。
とりあえずはHello World的なものを生成する所まではJavaScriptで対応します。
sam init --runtime nodejs10.x --name hello-sam
上記コマンドのオプションをとりあえず説明しておきますと、
--runtime
:Lambdaの実行ランタイムを選択します。(python3.7とか)ホントはv12を使っていきたいんですが、一応安牌をとってv10で進めて行きます。
--name
:プロジェクトのディレクトリ名です。Lambdaの関数名などは別途修正する必要があります。
上記コマンドを実行すると対話形式でウィザードが進みます。
とりあえず今回は1, 1をチョイスしました。
Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git AWS quick start application templates: 1 - Hello World Example 2 - Quick Start: From Scratch 3 - Quick Start: Scheduled Events 4 - Quick Start: S3 5 - Quick Start: SNS 6 - Quick Start: SQS 7 - Quick Start: Web Backend Template selection: 1 ----------------------- Generating application: ----------------------- Name: hello-sam Runtime: nodejs10.x Dependency Manager: npm Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./hello-sam/README.md
S3などの処理を書きたいときはその辺を選んだりするのが良いんでしょう。
とりあえず今回は無難なチョイスを選択しましたが、ウィザードが完了すると--name
で指定したディレクトリにファイルが出力されていると思います。
テストを実行する
SAM CLIでセットアップすると、mocha+chaiがセットアップできるようになっています。とりあえず走らせる為にpackage.json
の情報でセットアップします。
cd .\hello-sam\ cd .\hello-world\ yarn
ドキュメントではnpm
コマンドを利用している例が多いですが普段はyarn
を利用しているのでそのまま使います。
基本問題無いのでそのままテストを走らせます。
yarn test yarn run v1.22.0 $ mocha tests/unit/ Tests index √ verifies successful response 1 passing (7ms) Done in 0.34s.
問題無さそうです。
ローカルで関数を実行する
SAMを利用すればローカルで関数を実行するのは非常に簡単です。
一応sam local invoke
で関数を実行する方法と、sam local start-api
で実行する2種類の方法がありますが、大体後者かと思いますので後者で動かしてみます。
(Dockerが起動してないと怒られますので起動しておきましょう)
cd .. sam local start-api
問題が無ければブラウザでhttp://127.0.0.1:3000/hello
を入力するか、curl
コマンドでGETリクエストを投げると{"message":"hello world"}
が返ってきます。
基本的にJavaScriptのファイル群はここで不要となりますので、hello-world
ディレクトリはこの段階で削除してしまって構いません。
ちなみに、Dockerをセットアップしただけの状態だとC:\Users
以下以外のディレクトリは権限がなくてマウントされないので、プロジェクトのディレクトリがC:\Users
以下でない場合はsam local Error: Cannot find module 'app' docker toolbox
のようなエラーが発生します。
対処法としましてはDokcer Toolboxでは下記のサイトを参考にさせていただきました。
ToolboxでないDokcerでは警告が出てきちんと設定していた気がします。
TypeScript
tsconfig.jsonの作成
まずはプロジェクトのルートディレクトリにtsconfig.json
を作っておきます。
特にこだわりのない人は
tsc --init
でtsconfig.json
を作成するのが良いと思います。
一応今回用意しているtsconfig.json
は下記の通りにしました。
{ "compilerOptions": { "module": "commonjs", "target": "es6", "noImplicitAny": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "outDir": "./built", "allowJs": true, "moduleResolution": "node", "resolveJsonModule": true, "esModuleInterop": true }, "include": [ "./src/**/*" ], "exclude": ["node_modules"] }
入力対象を./src/
以下、出力先を./built
にしています。
パッケージを追加
TypeScriptを使っているので型が必要です。開発用の型をまずは追加していきます。
yarn add -D @types/aws-lambda
最小限のパッケージはこれだけでOKです。
index.tsを編集
index.ts
を編集します。基本的にはデフォルトのapp.js
を踏襲して作成してみます。
import {APIGatewayEvent, Context} from "aws-lambda" const lambdaHandler = async (event: APIGatewayEvent, context: Context) => { let response: any try { response = { 'statusCode': 200, 'body': JSON.stringify({ message: 'hello ts world', }) } } catch (err) { console.log(err) return err } return response } export {lambdaHandler}
とりあえずという意味ではevent
とcontext
もany
で受けてしまえばいいんですが、まぁそんぐらいは・・・
これでコンパイルしてみます。tsconfig.json
を設定してるのでルートディレクトリでtsc
コマンドを実行します。
tsc
これでbuilt
ディレクトリが作成され、index.js
が生成されたかと思います。
template.yamlの修正
JavaScriptの時との差異はコンパイル後のファイル名
とファイルの場所
です。
これをtemplate.yaml
に修正していきます。
~ Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: built/ Handler: index.lambdaHandler ~
CodeUri
とHandler
を修正しました。
ローカルで関数を実行する
これでローカル関数を実行してみます。
sam local start-api
JavaScriptの時と同様にブラウザかcurl
コマンドで確認してみて下さい。
返ってくるのが{"message":"hello world"}
のままの人はもしかするとsam build
して.aws-sam
ディレクトリに履歴が残ってる可能性がありますので消しちゃって下さい。
無事{"message":"hello ts world"}
が返ってきたら最低限度の環境構築はできたのではないでしょうか。
その他
ESLint + Prettier
基本的にはReactの設定と同じなのですが、ReactのJSXなどは不要です。
一応eslintrc
などを掲載しておきます。
パッケージの追加
yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin yarn add -D prettier @types/prettier @types/eslint-plugin-prettier eslint-config-prettier eslint-plugin-prettier
eslintrc.js
module.exports = { env: { browser: true, node: true, es6: true }, parser: '@typescript-eslint/parser', parserOptions: { sourceType: "module" }, plugins: [ 'prettier', '@typescript-eslint' ], extends: [ "eslint:recommended", 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'prettier/@typescript-eslint' ], rules: { 'prettier/prettier': [ 'error', { 'semi': false, 'trailingComma': "all" } ] }, };
.eslintignore
node_modules/ *.config.js built/
webpack
今回はwebpack
+ts-loader
で構成します。
パッケージの追加
yarn add -D ts-loader webpack webpack-cli dotenv
今回は.env
で環境変数を管理する想定でdotenvを利用しています。
直で書いたりする場合はこの辺は必要無いと思います。
とりあえず.env
を作っておきます。
NODE_ENV=development
webpack.config.js
const path = require("path") const dotenv = require("dotenv") dotenv.config() const BUILT_PATH = path.resolve(__dirname, "./built") const BUILD_VARIANT = process.env.NODE_ENV module.exports = { target: "node", mode: BUILD_VARIANT === "production" ? "production" : "development", resolve: { extensions: [".ts", ".js"], }, entry: "./src/index.ts", output: { filename: `${BUILD_VARIANT}.js`, path: BUILT_PATH, library: "[name]", libraryTarget: "commonjs2", }, module: { rules: [ { test: /\.ts$/, loader: "ts-loader", }, ], }, }
これで、ファイルを分割して開発することができます。