30
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Serverless + Webpack + TypeScript + tslint メモ

Last updated at Posted at 2016-12-27

: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 の一覧が取れるはずですね!

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

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

30
29
3

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
30
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?