TECHNICAL BLOG

2019/6/19 # Node.js # Lambda # TypeScript # AWS 2019/6 AWS LambdaのTypeScript化

2018/10 AWS Lambdaを使った雑務への取り組みで紹介しましたが、大阪事務所では雑務にLambdaを使っています。
Lmabdaは最近Node.js v10に対応したこともあり、アップデートを兼ねてTypeScript化しましたのでご紹介します。

フォルダ構成

以下のような構成で、srcフォルダで開発してビルドしたものがdist、dist.zipになるという構成です。

    ├─ package.json   # パッケージ設定ファイル
    ├─ tsconfig.json  # TypeScript設定ファイル
    │   
    ├─ src            # TypeScriptソース
    │   └─ index.ts   # 
    │   
    ├─ dist           # ビルド後のJSソース
    │   └─ index.js   # 
    └─ dist.zip       # zipアップロード用

設定ファイル

package.json

> npm install -g typescript

TypeScript自体はインストールしている前提で、以下のようにしました。

型補完用の@types/nodeやaws-sdk、TypeScript系のパッケージをインストールしています。

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "clean": "rimraf dist && rimraf dist.zip",
    "ts": " tsc -p tsconfig.json",
    "cp": "cp -f ./package.json ./dist",
    "install": "npm --prefix ./dist install --production ./dist",
    "zip": "cd dist/ && bestzip ../dist.zip *",
    "build": "npm run clean && npm run ts && npm run cp && npm run install && npm run zip"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^12.0.0",
    "aws-sdk": "^2.441.0",
    "bestzip": "^2.1.2",
    "rimraf": "^2.6.3",
    "ts-loader": "^5.4.3",
    "ts-node": "^8.1.0",
    "tsconfig-paths": "^3.8.0"
  },
  "dependencies": {
  }
}

tsconfig.json

TypeScript設定ファイルは基本的な設定だけです。
Node.js v10なのでtargetをes2017にしてみました。

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2017",
    "declaration": false,
    "removeComments": true,
    "sourceMap": false,
    "outDir": "./dist",
    "baseUrl": "./src"
  },
  "exclude": ["node_modules"]
}

ビルド&デプロイ

> npm run build

このビルドコマンドを実行すればpackage.jsonのscriptsに記載している

  • clean: distフォルダとdist.zipの事前削除
  • ts: TypeScriptビルド
  • cp: package.jsonのコピー
  • install: distフォルダ内でdependenciesパッケージのインストール
  • zip: dist.zipの作成

一連の処理が実行されdist.zipが出来上がるので、AWSの管理画面からdist.zipをアップロードする感じです。

コード

index.ts

雑務につかっているコード例です。引数Event型をわかりやすいように定義してあげて、hanlder関数内で用途に応じて分岐、async/await構文が使えるのでスッキリしました。

import { polling } from './cron';
import { hookSlack, hookBitbucket } from './webhook';

type Event = {
    // 機能
    mode: string;
    // Slack
    token?: any;
    team_id?: any;
    team_domain?: any;
    channel_id?: any;
    command?: any;
    text?: any;
    // Bitbucket
    push?: { changes: any[] };
    repository?: { name:string; };
};
export const handler = async(event: Event, context: {succeed: (a:string)=>void; fail: (a:any)=>void; }, callback:(a:any, b:any)=>void)=>{

    if(event.mode == 'polling'){
        await polling();

    // slack
    }else if(event.token && event.team_id && event.team_domain && event.channel_id){
        const message = await hookSlack(event.team_domain, event.channel_id, event.command, event.text);
        context.succeed(message);

    // bitbucket
    }else if(event.repository && event.push){
        await hookBitbucket(event.repository, event.push);
        context.succeed('complete bitbucket.');
    }
};

感想

LambdaをTypeScript化すると言うと大事に聞こえますが、実際やっていることは必要なパッケージをインストールしてtsconfig.jsonを整えてJSへビルドしてあげるだけの簡単な作業でした。