おーばーびゅー
AWSでAPI Gateway/Lambdaの組み合わせでREST APIを運用しています。
以前はLambdaのdeployにApexを使用していたのですが、今回API Gatewayの設定も同時に記述したく、Serverless Frameworkへの移行を決めました。
その際serverless create --template aws-nodejs --path my-service
等のコマンドで生成されるディレクトリ構成が気に入らず...
この記事は私の望むディレクトリ構成を得るまでの軌跡です。
環境
macOS Sierra v10.12.6
node.js v9.2.0
yarn v1.3.2
Serverless Framework v1.25.0
いやなところ
--template aws-nodejs
で生成したプロジェクト
my-service
├── handler.js
└── serverless.yml
function増やすには...?と調べてみるとエントリポイントは全部handler.jsで、中身だけ別ファイルに書いて、それをhandler.jsでexportしている実装がちらほら
そもそもエントリポイントはfunction別にあったほうがよくない?
functionを増やすとトップレベルに沢山ファイルが出来そうだし...
babel-dynamically-entriesのプロジェクト例
babel-dynamically-entries
├── event.json
├── first.js
├── package.json
├── second.js
├── serverless.yml
├── webpack.config.js
└── yarn.lock
function分けられてるけど結局トップレベルかーい!
こうしたい
api
├── functions
│ └── hello
│ └── index.js
├── package.json
├── serverless.yml
├── webpack.config.js
└── yarn.lock
こんな感じでfunctions以下に関数毎にディレクトリを切りたい
どうやる
init
$ serverless create --template aws-nodejs --path my-best-sls-structure
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/XXXXX/my-best-sls-structure"
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v1.25.0
-------'
Serverless: Successfully generated boilerplate for template: "aws-nodejs"
$ # globalにserverlessがない場合は下記のコマンド等で適宜導入のほど
$ # npm install -g serverless
$ # yarn global add serverless --prefix /usr/local
$ cd my-best-sls-structure
$ yarn init -y
yarn init v1.3.2
warning The yes flag has been set. This will automatically answer yes to all questions which may have security implications.
success Saved package.json
✨ Done in 0.05s.
install dependencies
一応serverlessも入れてます
$ yarn add babel-core babel-loader webpack serverless serverless-webpack
edit files
service: my-best-sls-structure
provider:
name: aws
runtime: nodejs6.10
# コレが大事
#
# ref.: https://serverless.com/framework/docs/providers/aws/guide/packaging/#packaging-functions-separately
package:
individually: true
# webpackと連携するためにserverless-webpackを導入
plugins:
- serverless-webpack
functions:
hello:
handler: functions/hello/index.handler
const path = require('path');
const slsw = require('serverless-webpack');
module.exports = {
// Serverlessのpackage.individuallyを使用する場合にはentryをserverless-webpackに任せる必要がある(slsw.lib.entries)
// 基本的に問題は起こらないと思うが、entryが足りない!みたいなケースには下記の様なコードで対応しろとのこと(_はlodashなので適宜導入下さい)
// entry: _.assign({myCustomEntry1: './custom/path/something.js'}, slsw.lib.entries)
entry: slsw.lib.entries,
target: 'node',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
};
// このコードはServerless Frameworkのテンプレートに入ってるアレ
export function handler(event, context, callback) {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event
})
};
callback(null, response);
}
うごかす
ビルドだけ
$ serverless webpack
Serverless: Bundling with Webpack...
Time: 544ms
Asset Size Chunks Chunk Names
functions/hello/index.js 2.98 kB 0 [emitted] functions/hello/index
[0] ./functions/hello/index.js 257 bytes {0} [built]
localで叩く
$ serverless invoke local --function hello
Serverless: Bundling with Webpack...
Time: 647ms
Asset Size Chunks Chunk Names
functions/hello/index.js 2.98 kB 0 [emitted] functions/hello/index
[0] ./functions/hello/index.js 257 bytes {0} [built]
{
"statusCode": 200,
"body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":\"\"}"
}
うまくビルド出来ていますね
まとめ
api
├── functions
│ └── hello
│ └── index.js
├── package.json
├── serverless.yml
├── webpack.config.js
└── yarn.lock
の様な、任意のディレクトリ(functions)配下で、関数毎にディレクトリを切ってソースを配置するには、下記2点が大事
- serverless.yml
- package.individually
- webpack.config.js
entry: slsw.lib.entries
こちらからは以上です。
お疲れ様でした。