最近のAWS Lambda開発環境

最近は以下の組み合わせでLambda関数を書いている

* AWS Lambda (Node 4.3)
* [Serverless Framework](https://serverless.com/)
* [serverless-webpack](https://github.com/elastic-coders/serverless-webpack) + babel + eslint
* Yarn

# 参考

ベースは以下のリポジトリを参考にした。
https://github.com/americansystems/serverless-es6-jest

# package.json

テンプレはこんな感じ。

```json:package.json
{
  "name": "your-service",
  "version": "0.0.1",
  "dependencies": {
    "babel-polyfill": "^6.20.0",
    "babel-runtime": "^6.20.0",
  },
  "devDependencies": {
    "babel-core": "^6.21.0",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-transform-async-to-generator": "^6.16.0",
    "babel-plugin-transform-runtime": "^6.15.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-stage-0": "^6.16.0",
    "eslint": "^3.14.1",
    "eslint-loader": "^1.6.1",
    "json-loader": "^0.5.4",
    "serverless-webpack": "^1.0.0-rc.3",
    "webpack": "^1.14.0",
    "webpack-node-externals": "^1.5.4"
  },
  "license": "MIT",
  "engines": {
    "node": ">=4.3.0"
  }
}
```

# Serverless

デプロイにはServerlessを使用している。Lambdaに特化しているという点でApexも気になるが、今のところはServerlessで不自由していない上にTerraformに馴染みがないのでこちらを使用している。

設定のテンプレは大体下のような感じ。

```yaml:serverless.yml
service: your-service-name
frameworkVersion: ">=1.4.0"

plugins:
  - serverless-webpack

provider:
  name: aws
  runtime: nodejs4.3
  stage: prod
  region: ap-northeast-1
  iamRoleStatements: # IAMの権限が必要であれば
    - Effect: "Allow"
      Action:
        - "cloudwatch:GetMetricStatistics"
      Resource: "*"

custom:
  webpackIncludeModules: true # enable auto including modules

functions:
  yourFunctionName:
    handler: handler.main
    description: Your function description.
    events:
      - schedule: # 定期的に実行したい場合
          name: your-schedule
          description: 'Your schedule description'
          rate: cron(0/10 22-15 * * ? *)
          enabled: true
    memorySize: 128
    environment: # 環境変数はコンソール側から指定している。
      SLACK_WEBHOOK: set_slack_webhook
```

Lambdaの環境変数を設定する箇所については[ローカルの環境変数から動的に設定する](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-in-other-files)ことも可能そうだが、今のところそこまでやっていない。

よくIAMのPolicyにCloudWatch Logsの権限を振り忘れてログ出ね―ってハマる人がいるらしいが、[serverlessはデフォルトのIAM Roleに設定してくれる](https://github.com/serverless/serverless/blob/d56024ecdd386fdfde7cf459305bca160b6e25a1/docs/providers/aws/guide/iam.md#the-default-iam-role)ようで、幸いそこにハマったことはなかった。

# Webpack

[serverless-webpack](https://github.com/elastic-coders/serverless-webpack)というプラグインがあるのでこれを使用している。webpack(babel)を通している理由はasync-awaitを使いたいだけ。なのでnpmも可能な限りPromise対応のものを選ぶ。
eslintも入れておくとJSの構文エラーや使用していない変数や関数を教えてくれたりするので便利。

なお、serverless-webpackを使用するとLambda関数毎にデプロイする `serverless deploy --function` は使えなくなるらしい。(1つのJSファイルにまとめられることに起因すると思われる。)

```js:webpack.config.js
var nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: './handler.js',
  target: 'node',
  externals: [nodeExternals()],
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: [
          'babel',
          'eslint-loader'
        ],
        include: __dirname,
        exclude: /node_modules/,
      },
      {
        test: /\.json$/,
        loaders: ['json']
      }
    ]
  }
};
```

```json:.babelrc
{
  "plugins": [
    "transform-runtime",
    "transform-async-to-generator"
  ],
  "presets": ["es2015", "stage-0"]
}
```

```js:.eslintrc
module.exports = {
  "parser": "babel-eslint",
  "extends": ["eslint:recommended"],
  "plugins": [],
  "parserOptions": {
    "ecmaVersion": 6
  },
  "env": {
    "node": true,
    "es6": true
  },
  "globals": {},
  "rules": {
    "no-console": "off",
    "strict": 0
  }
};
```