この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
背景
Lambda Functionでサーバーレスアプリケーションを作ったり、公式のAlexa Skills Kit SDKを使ってコードを書く機会が増えています。
ある程度の規模や複雑さを超えると、以下のような問題に直面するでしょう。
- FlowやBabelなどの開発ツールを使いたい
- npmを使って独自の機能を使おうとすると、Lambda Functionにアプロードするzipファイル容量が大きくなるので、抑制したい
このような問題は、webpackを使うことで解決できます。
今回は、有名なLambda FunctionデプロイツールApexと、webpackを併用する方法をご紹介します。
本文
前提
Lambdaに合わせたNode.js(v6.10.3)と、npmまたはyarnが利用可能であることを前提とします。
今回のファイルは以下のようなディレクトリ構成です。
.
├── .apexignore
├── .eslintrc
├── .gitignore
├── README.md
├── functions
│ └── entrypoint
│ └── src
│ └── index.js <== Lambda Functionのエントリポイント
├── package.json
├── project.json
├── webpack.config.js
└── yarn.lock
package.json
webpackはdevDependenciesに加えます。
以下のpackage.json
にあるとおり、今回はeslintの設定も加えてみます。また、実行時エラーでスタックトレースを追えるように、source mapも追加してみます。
{
"private": true,
"license": "UNLICENSED",
"engines": {
"node": "6.10.3"
},
"scripts": {
"lint": "eslint functions/entrypoint/"
},
"dependencies": {
"source-map-support": "^0.5.0"
},
"devDependencies": {
"eslint": "^4.3.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-node": "^5.1.1",
"webpack": "^3.3.0"
}
}
webpack.config.js
webpack.config.js は、webpackの動作オプションを設定するファイルです。各設定項目の詳細は公式ドキュメントをご覧ください。
const path = require('path');
const Webpack = require('webpack');
exports.default = {
entry: './src/index.js',
target: 'node',
output: {
path: path.join(process.cwd(), 'build'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
externals: ['aws-sdk'],
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true,
failOnError: true,
failOnWarning: true,
emitError: true
},
exclude: [/node_modules/]
}
]
},
plugins: [
new Webpack.NoEmitOnErrorsPlugin(),
new Webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production') // 環境変数はwebpackで展開されるので、ここで設定します
}
}),
new Webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
})
],
devtool: 'inline-source-map',
bail: true
};
Apex設定ファイル
デプロイツールApexの設定ファイルです。詳細は公式ドキュメントをご覧ください。
project.json
{
"name": "myapp",
"description": "",
"memory": 128,
"timeout": 10,
"role": "arn:aws:iam::01234567890123:role/lambda_basic_role",
"runtime": "nodejs6.10",
"handler": "build.handler",
"hooks": {
"build": "../../node_modules/.bin/webpack --config ../../webpack.config.js",
"clean": "rm -rf build"
},
"environment": {
}
}
.apexignore
apexで作成するzipファイルには、webpackを通したファイルのみを含めるので、ソースコードそのものは除外します。
src/
index.js
'use strict';
require('source-map-support').install();
exports.handler = function(event, context, callback) {
// do something
};
apex deploy
時の動作
apex deploy
コマンドを実行する際、project.json
のhooks.buildで設定したフックが実行されます。今回の場合、「index.jsがあるビルドフック実行時のカレントディレクトリから2つ上の/node_modules/.bin/webpack を実行する」となります。
webpack実行時に指定した設定ファイルのoutputにもとづき、 functions/entrypoint/build/index.js
がビルド結果としてwebpackにより出力されます。
これでビルドフックが終了したので、apexはzipファイルを作成してAWSにアップロードし、バージョンとエイリアスの処理を行います。
その後、cleanフックで指定したとおり、webpackの出力用ディレクトリ(build/)を削除します。
まとめ
私の経験ですが、webpackを使うことで、zipファイルのサイズが10MBから500KB程度に削減され、開発時の快適な動作確認環境を作ることができました。
webpackの設定によっては、FlowTypeやBabelなどのトランスパイラを使用して、複雑なFunctionを作ることができます。
参考: https://github.com/apex/apex/tree/master/_examples/babel-webpack2