【Windows】AmplifyのLambda function(+Layer)をTypeScriptで書きたい(ローカルでTS→JSする)
実現したいこと
前回の記事では、
Amplify CLIを使ってLambda関数をTypeScriptでコーディングする方法について書きました。
しかし、以下のような課題がありました。
- Lambdaのソースコードをzip化する際に、TSファイル本体・tsconfig.json等の余計なファイルも含まれてしまう
- GitHubと接続してCI/CD環境を構築する場合、ソースコードをPushしたときに自動でバックエンドのビルドも走ってしまうので、Amplify Console側でのTSコンパイルの考慮が必要
そこで、以下の方針を検討します。
- TSファイルは関数の「src」フォルダーとは別で管理する
- TS→JSのコンパイルはローカルでやる(これはこれで別の問題がありそうだけど。。)
今回の記事ではローカルでTSファイルからJSファイルにコンパイルする方法について手順を残しておきます。
環境
本記事では、以下の環境で実施しています。
- バージョン
- OS: Windows 11
- Node.js: v14.16.1
- npm: 6.14.12
- AWS CLI: 2.1.38
- Amplify CLI: 8.0.0
- Lambdaランタイム: nodejs14.X
- ネーミング
- Amplify Project Name:
app
- Lambda Layer Name:
layer
※識別用としてAmplify Project Name + Lambda Layer Nameのapplayer
になります - Lambda Function Name:
func
- Amplify Project Name:
- エディタ
- Visual Studio Code(以下、VSCode)
- ターミナル
- PowerShell
手順
Step1. Lambda Layerを作成する
amplify add function
で追加
1. $ amplify add function
? Select which capability you want to add: Lambda layer (shared code & resource used across functions)
? Provide a name for your Lambda layer: layer
? Choose the runtime that you want to use: NodeJS
? The current AWS account will always have access to this layer.
Optionally, configure who else can access this layer. (Hit <Enter> to skip) Specific AWS accounts
? Provide a list of comma-separated AWS account IDs: <AWSアカウントID>
✅ Lambda layer folders & files created:
amplify\backend\function\applayer
2. TSファイル群を管理するフォルダーを作成
次のフォルダーに移動
$ cd amplify\backend\function\applayer
tsフォルダーを作成し、その中にtsconfig.jsonを作成します
$ New-Item ts -ItemType Directory
$ cd ts
$ tsc --init
以下のように書き換えます。
{
"compilerOptions": {
"target": "es2017",
"noImplicitAny": false,
"allowJs": true,
"noImplicitUseStrict": true,
"types": ["node"],
"moduleResolution": "node",
"module": "CommonJS"
},
"include": ["."],
"exclude": ["node_modules", "**/*.spec.ts"]
}
次に、(layerのフォルダー)/lib/nodejsの下にある「package.json」をコピーして
上記で作成した「ts」フォルダーの中に貼り付けします。
PowerShellのコマンドで実行する場合は以下のようになります。
Copy-Item -Path ..\lib\nodejs\package.json -Destination .\
コピーしたpackage.jsonを開いてmainを適宜書き換えます。
この後に「layer.ts」ファイルを作成するので、ここでは「layer.js」としておきます。
{
"version": "1.0.0",
"description": "",
"main": "layer.js",
"dependencies": {},
"devDependencies": {}
}
続けて、(tsフォルダ内で)共通利用するパッケージをインストールします。
今回は「date-fns」をインストールしてみます
$ npm install date-fns
次に、(tsフォルダ内で)tsファイルを新規に作成します。
$ New-Item layer.ts
TSで好きに記述します。
import { format as _format } from "date-fns";
import ja from "date-fns/locale/ja";
export const formatJa = (date: Date, format: string): string => {
return _format(date, format, { locale: ja });
};
3. 中間フォルダ構成
ここまでのフォルダ構成
<プロジェクルート>\amplify\backend\function\applayer
│ applayer-awscloudformation-template.json
│ layer-configuration.json
│ parameters.json
│
├─lib
│ └─nodejs
│ package.json
│ README.txt
│
├─opt
└─ts
│ layer.ts
│ package-lock.json
│ package.json
│ tsconfig.json
│
└─node_modules
└─date-fns
Step2. Lambda Functionを作成する
amplify add function
で追加
1. ? Provide existing layers or select layers in this project to access from this function
のところで、Step1で作成したLambda Layer(ここではapplayer
)を選択する
$ amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: func
? 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? Yes
? Do you want to access other resources in this project from your Lambda function? No
? Do you want to invoke this function on a recurring schedule? No
? Do you want to enable Lambda layers for this function? Yes
? Provide existing layers or select layers in this project to access from this function (pick up to 5): applayer
? Do you want to configure environment variables for this function? No
? Do you want to configure secret values this function can access? No
? Do you want to edit the local lambda function now? Yes
Edit the file in your editor: <プロジェクトルート>amplify\backend\function\func\src\index.js
? Press enter to continue
Successfully added resource func locally.
2. TSファイル群を管理するフォルダーを作成
次のフォルダーに移動
$ cd amplify\backend\function\func
tsフォルダーを作成し、その中にtsconfig.jsonを作成します
$ New-Item ts -ItemType Directory
$ cd ts
$ tsc --init
後でTSファイルを作成するので、先にtsconfig.jsonを作成しておく
$ tsc --init
中身は適宜書き換え
{
"compilerOptions": {
"target": "es2017",
"noImplicitAny": false,
"allowJs": true,
"noImplicitUseStrict": true,
"types": ["node"],
"module": "CommonJS",
"baseUrl": ".",
"paths": {
"/opt/layer": ["../../applayer/ts/layer"],
"*": [
"../../applayer/ts/node_modules/@types/*",
"../../applayer/ts/node_modules/*"
]
}
},
"include": ["."],
"exclude": ["node_modules", "**/*.spec.ts"]
}
次に、(lambda関数のフォルダー)/srcの下にある「package.json」をコピーして
上記で作成した「ts」フォルダーの中に貼り付けします。
PowerShellのコマンドで実行する場合は以下のようになります。
Copy-Item -Path ..\src\package.json -Destination .\
3. index.tsを作成
次に、TSファイルを作成(ここではPowershellのコマンドで新規作成しています)
$ New-Item index.ts
index.tsの処理を書きます
import { formatJa } from "/opt/layer";
import { Callback, Context, Handler } from "aws-lambda";
interface IEvent {
arguments: {
input: {
message: string;
};
};
}
interface IResult {
statusCode: number;
body: string;
}
/**
* @type {import('@types/aws-lambda').APIGatewayProxyHandler}
*/
export const handler: Handler<IEvent, IResult> = async (
event: IEvent,
context: Context,
callback: Callback<IResult>
) => {
const { message } = event.arguments.input;
return {
statusCode: 200,
body: `${message} ${formatJa(new Date(), "yyyy-MM-dd")}`,
};
};
aws-lambdaでTSエラーが出ると思いますが、(tsフォルダ内で)npm install
することで解消出来るかと思います。
ここまでのフォルダ構成
<プロジェクトルート>\amplify\backend\function\func
│ custom-policies.json
│ func-cloudformation-template.json
│ parameters.json
│
├─src
│ event.json
│ index.js
│ package.json
│
└─ts
│ index.ts
│ package-lock.json
│ package.json
│ tsconfig.json
│
└─node_modules
Step3. ローカルでTSファイルをコンパイルする
最後に、上記で作成したTSファイルをJSファイルにコンパイルします。
プロジェクトルートにある「package.json」に以下のようなスクリプトを追加しておきます。
...
"scripts": {
...
"layer-tsc": "cd amplify\\backend\\function\\%npm_config_folder%\\ts && tsc && move /Y %npm_config_file%.js ..\\opt && xcopy package.json ..\\lib\\nodejs /Y && cd ..\\lib\\nodejs && del package-lock.json && npm install --production && npm prune --production",
"lambda-tsc": "cd amplify\\backend\\function\\%npm_config_name%\\ts && tsc && move /Y index.js ..\\src && xcopy package.json ..\\src /Y && cd ..\\src && del package-lock.json && npm install --production && npm prune --production"
},
...
上記のようにしておくことで、プロジェクトルートから各TSファイルをコンパイル出来ます。
layerをコンパイルする場合
npm run layer-tsc -folder=applayer -file=layer
lambda関数をコンパイルする場合
npm run lambda-tsc -name=func
あとはGitHub等と連携すれば、ソースコードをPushしたタイミングで関数の作成を自動でやってくれます。
Discussion