Serverless Frameworkで作ったNode.jsプロジェクトをTypeScriptへリプレイスする
基本的にServerless FrameworkでAPIや処理系等を実装しているのですが、同梱するライブラリが増えてくるとどうしてもデプロイサイズが気になってきます。 webpackでビルドしてサイズを減らすことも考えた […]
目次
基本的にServerless FrameworkでAPIや処理系等を実装しているのですが、同梱するライブラリが増えてくるとどうしてもデプロイサイズが気になってきます。
webpackでビルドしてサイズを減らすことも考えたのですが、どうせならTypeScriptに段階的に切り替えてみようかなと思ったのでトライしました。
準備
まずはマイグレーション対象のプロジェクトを作りましょう。
$ sls create -t aws-nodejs -p sls-migration
$ cd sls-migration
$ sls deploy
Service Information
service: sls-migration
stage: dev
region: us-east-1
stack: sls-migration-dev
api keys:
None
endpoints:
None
functions:
hello: sls-migration-dev-hello
素のままだとファイル削減の効果も見えにくいので、SDKをいくつか入れて重しにしておきます。
$ npm init -y
$ npm i -S ask-sdk watson-developer-cloud
$ sls deploy function -f hello
Serverless: Packaging function: hello...
Serverless: Excluding development dependencies...
Serverless: Uploading function: hello (11.34 MB)...
Serverless: Successfully deployed function: hello
11MB。いい感じです。選んだSDKはAWS SDK以外で使ったり興味があったりするもので、特に他意はありませんのでご了承ください。
$ sls invoke -f hello -d '{"key": "value"}'
{
"statusCode": 200,
"body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{\"key\":\"value\"}}"
}
動作も問題ない様子です。
TypeScriptを導入する
ここからいよいよTypeScriptを入れていきます。ここからはビルドしたものをデプロイする形になりますので、そのあたりの処理も入れる必要があります。
幸いsls create
のテンプレートにaws-nodejs-typescript
がありますので、ここから部品を取る形で進めます。
$ cd ../
$ sls create -t aws-nodejs-typescript -p ts-sls
$ cd ts-sls
$ tree -L 1 -I node_module
.
├── handler.ts
├── package.json
├── serverless.yml
├── source-map-install.js
├── tsconfig.json
└── webpack.config.js
0 directories, 6 files
source-map-install.js
, tsconfig.js
,webpack.config.js
が新しく追加されています。また、package.json
を見るといくつかのライブラリが含まれています。
$ cat package.json | jq .devDependencies
{
"@types/aws-lambda": "8.10.1",
"@types/node": "^8.0.57",
"serverless-webpack": "^5.1.1",
"source-map-support": "^0.5.6",
"ts-loader": "^4.2.0",
"typescript": "^2.9.2",
"webpack": "^4.5.0"
}
これらを先ほどのプロジェクトに入れていきましょう。
# プロジェクトに戻る
$ cd ../sls-migration
# ライブラリインストール(webpackは5系を入れるとうまく行かないので要注意)
$ npm i -D serverless-webpack source-map-support ts-loader typescript webpack@4
# ファイルをコピー
$ cp ../ts-sls/source-map-install.js ./
$ cp ../ts-sls/webpack.config.js ./
$ cp ../ts-sls/tsconfig.json ./
また、serverless.yml
を開いて以下の2行を追加しましょう。
plugins:
- serverless-webpack
これでTypeScript(+webpack)を使う準備ができました。この状態でデプロイすると、webpackによるビルドが実行されます。
$ sls deploy function -f hello
<中略>
@ multi ./source-map-install.js ./handler.js
Serverless: Packaging function: hello...
Serverless: Uploading function: hello (2.15 MB)...
Serverless: Successfully deployed function: hello
2.15MBまで減りましたね。およそ1/5。これだけでも十分に大きいのですが、せっかくなのでTypeScriptの力を借りてみましょう。
TypeScriptのハンドラーを追加する
ここまででは、TypeScriptをビルドに使用していますが対象となるファイルがない状態です。ですので.ts
ファイルを追加してみましょう。
$ vim handler2.ts
'use strict';
module.exports.hello = async (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event
}),
};
};
まずは先ほどのhandler.js
に書いている内容をそのままコピーします。これだけでは対象ファイルに含まれませんので、serverless.yml
にも定義を追加しましょう。
functions:
hello:
handler: handler.hello
hello2:
handler: handler2.hello
これでTypeScriptファイルもビルドされるようになります。また、tsconfig.json
を以下のようにすることでより厳密なチェックを受けることが可能です。
{
"compilerOptions": {
"sourceMap": true,
"target": "es6",
"lib": [
"esnext"
],
"strict": true,
"moduleResolution": "node"
},
"exclude": [
"node_modules"
]
}
strict
をtrueにすると、webpackのビルドがこけるようになります。
$ sls deploy
ERROR in /Users/develop/sandbox/sls-migration/handler2.ts
./handler2.ts
[tsl] ERROR in /Users/develop/sandbox/sls-migration/handler2.ts(2,31)
TS7006: Parameter 'event' implicitly has an 'any' type.
ERROR in /Users/develop/sandbox/sls-migration/handler2.ts
./handler2.ts
[tsl] ERROR in /Users/develop/sandbox/sls-migration/handler2.ts(2,38)
TS7006: Parameter 'context' implicitly has an 'any' type.
Error --------------------------------------------------
Webpack compilation error, see above
For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com
Your Environment Information -----------------------------
OS: darwin
Node Version: 10.1.0
Serverless Version: 1.32.0
「引数に型が付いてないぞ!」ということなので、追加してやりましょう。
$ npm i -D @types/aws-lambda @type/node
handler2.ts
も以下のように変更します。
import { APIGatewayEvent, Handler } from 'aws-lambda';
export const hello: Handler = async (event: APIGatewayEvent) => ({
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event
})
})
eventに設定する型は使用するイベントによって変わります。今回のサンプルはAPI Gatewayのバックエンドとして利用するものを設定しました。
これで再度deployを実行すると、今度はエラーなくビルドが成功します。
おわりに
allowJs
の設定をしていない状態ですが、今のところこの状態のままでJS / TypeScriptの共存が可能な様子です。
段階的に移行するということが可能ですので、ファイルサイズが気になったり型が欲しいなと思った方はぜひお試しください。