Edited at

Serverless + Webpack + TypeScript + tslint メモ

More than 1 year has passed since last update.


:pray::pray:

Getting Started With Serverless and TypeScript


用意するもの


  • Node.js


    • あんまり古くないやつ




Hello World まで


repo を作る

$ mkdir oreno-sls-ts

$ cd oreno-sls-ts
$ git init


依存物をインストール

$ npm init

$ npm install --save-dev serverless serverless-webpack ts-loader tslint typescript webpack

今回はあえて serverless をグローバルに入れないパティーンでやってみる。 package.jsonserverless のバージョンを管理できるメリットがある(serverless.yml の中にバージョン固定する設定もできるけど)。


雛形を作り、いらないものを一旦捨てる

$ node_modules/.bin/serverless create --template aws-nodejs

$ node_modules/.bin/tslint --init
$ rm handler.js serverless.yml # このあと手動でつくる


いろいろ作る


.gitignore

node_modules

.serverless
.built


serverless.yml

service: oreno-sls-ts

provider:
name: aws
runtime: nodejs4.3
plugins:
- serverless-webpack
functions:
hello:
handler: index.hello
events:
- http:
path: hello
method: get


tsconfig.json

{

"compilerOptions": {
"target": "es5",
"module": "commonjs"
},
"exclude": [
"node_modules"
]
}


webpack.config.js

var path = require('path');

module.exports = {
entry: './index.ts',
target: 'node',

module: {
loaders: [
{
test: /\.ts(x?)$/,
loader: 'ts-loader',
},
],
},

resolve: {
extensions: [
'.ts',
'.js',
'.tsx',
'.jsx',
'',
],
},

output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, '.built'),
filename: 'index.js',
},
};



index.ts

export * from './functions/hello';



functions/hello.ts

export function hello(event, context, callback): void {

const response = {
statusCode: 200,

headers: {
},

body: JSON.stringify({
"message": "Hello TypeScript!!!!"
})
};

callback(null, response);
};



ローカルで動作確認

$ node_modules/.bin/serverless webpack serve

うまく動いていれば http://localhost:8000/hello で動作確認できるはず。


デプロヰ

$ node_modules/.bin/serverless deploy                                                                                                                              

$ curl https://********.execute-api.us-east-1.amazonaws.com/dev/hello | jq

うまくいけば {"message": "Hello TypeScript!!!!"} が表示されるはず。


せっかくの TypeScript なので


型定義を使ってみる

Lambda Function に渡される context オブジェクトを型定義してみます。 event はめちゃくちゃ長くてアレだったので、ちゃんと書くときには定義します…

追記: context の型定義は自分でしなくても @types/aws-lambda パッケージを使えます。


types.d.ts

export interface LambdaExecutionContext {

callbackWaitsForEmptyEventLoop: boolean
logGroupName: string
logStreamName: string
functionName: string
memoryLimitInMB: string
functionVersion: string
invokeid: string
awsRequestId: string
invokedFunctionArn: string
}

さっきの hello function を少し変更してこれを使ってみます。


functions/hello.ts

import {LambdaExecutionContext} from '../types';

export function hello(event, context: LambdaExecutionContext, callback): void {
const response = {
statusCode: 200,

headers: {
},

body: JSON.stringify({
"message": `Hello!!!! I am a function named "${context.functionName}"`
})
};

callback(null, response);
};


さてさて型定義されているということは。 Visual Studio Code なら補完が効きますし、

hello_ts_-_serverless-ts.png

ありえないプロパティを指定するとちゃんとエラーを指摘してくれます。

hello_ts_-_serverless-ts.png

すてき!!!!!


AWS SDK で async/await してみる

パッケージを追加する。

$ npm install --save-dev aws-sdk @types/aws-sdk json-loader

@types/aws-sdkDefinitelyTyped にある AWS SDK 用の型定義。 TypeScript の型定義管理はちょうざっくり変遷を辿ると



  1. tsd っていう型定義管理ツールがあるぞ


  2. tsd はオワコン。 typings の時代だぜ

  3. 型定義インストール専用のツールなんてもういらん。 npm@types/foo って入れればおk

…という流れらしく、従って npm で入れる。

json-loader は AWS SDK の中で require('foo.json') してるの(たぶん)を Webpack で処理するのに必要。

ちょっと昔は AWS SDK と Webpack の組み合わせに問題があり、みんな困ってたけど直った模様。マジ感謝。


index.ts

export * from "./functions/hello";

export * from "./functions/listfunctions";


functions/listfunctions.ts

import * as AWS from "aws-sdk";

import {LambdaExecutionContext} from "../types";

const lambda = new AWS.Lambda();

export async function listfunctions(event, context: LambdaExecutionContext, callback): Promise<void> {
const functions = [];
let nextMarker = null;

do {
const response: AWS.Lambda.ListFunctionsResponse = await lambda.listFunctions({Marker: nextMarker}).promise();

functions.push(...response.Functions);
nextMarker = response.NextMarker;
} while (nextMarker);

callback(null, {
statusCode: 200,
headers: {},
body: JSON.stringify({functions}),
});
};


を追加します。 AWS の API によくある NextMarker での判断を含んだ非同期 N 回ループがこんなに簡単に書けちゃいます。最高。

他のファイルも微変更が必要なのですが、後述の repo に全部あげておくのでそちらを参照してください。

再度デプロイして…

$ node_modules/.bin/serverless deploy                                                                                                                              

実行してみます。

$ curl https://********.execute-api.us-east-1.amazonaws.com/dev/listfunctions | jq

うまくいけばデプロイされたこれ自体を含む Lambda Function の一覧が取れるはずですね!


ここまでやったのがこちら

どうぞご笑覧ください。その後、諸々を見直してこの記事の内容とだいぶ違いがあったりします、ご注意を。