LoginSignup
7

More than 5 years have passed since last update.

Serverless Framework + webpack-pluginでTypeScriptなwebサイト基盤

Last updated at Posted at 2016-12-03

このページは Wanoグループ Advent Calendar 2016 の3日目の記事となります。
ギリギリになってしまった。

Serverless Framewok v1.1 でtypescript & babelなベースを整えるとこまでやったのでメモっておきます。
S3の静的サイトホスティング以外でのどケチなサイト運営を模索していきたい。
今回は jsonを返すデモ と HTMLを返すデモを作るとこまで目指します。

serverless frameworkでのプロジェクトセットアップ

serverless create プロジェクト名

でプロジェクトのひな形を作っておきます。

プロジェクトの設定で、webpackプラグインやbabel,typescriptを適用するためのモジュールをインストールします。


npm install babel-loader babel-core babel-preset-es2015 ntypescript serverless-webpack ts-loader

serverless コマンドでプロジェクトを作ったあと、serverless.ymlで
プロジェクトの設定を行います。
書いてないけどLambda関数のタイムアウト時間やメモリ設定もここ。


service: serverless-webpack-advent-demo

plugins:
  - serverless-webpack # ここでプラグインを指定します

provider:
  name: aws
  runtime: nodejs4.3
  stage  : production
  profile: xxxx # aws-cliにおけるprofileを設定します。
  regeon : ap-northeast-1


functions:
  apiDemo:
    handler: handler.apiDemo  # 動かすlambda関数名
    events:
      - http:
          method: get
          path: apiDemo
          response:
            headers:
              Content-Type: "'application/json'"
            template: $input.path('$')
  htmlDemo:
    handler: handler.htmlDemo # 動かすlambda関数名
    events:
      - http:
          method: get
          path: htmlDemo
          response:
            headers:
              Content-Type: "'text/html'"
            template: $input.path('$')

webpack設定

serverless-webpack
webpackプラグインが入ったので、ビルド段階で typescriptやbabelを通して、AWS lambda上のnodejs4.3で使えない段階の機能にも対応できるようにしておきます。

個人的にgulpやgrunt等のタスクランナーはすぐに使わなくなりましたが、
webpackはビルド速度の速さや cssの多段sourcemap作成のためにもとても便利なので、しばらく離れられそうにないです。

また,serverless-webpackは

serverless webpack serve

してサーバーを動かすことで、ローカルでapi gateway + lambdaのテストもできます。

development.webpack.config.js


const path = require('path');

module.exports = {
    entry: './ts/handler.ts',
    output: {
        libraryTarget: 'commonjs',
        path: path.join(__dirname, '.webpack'),
        filename: 'handler.js'
    },
    target: 'node',
    resolve: {
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js']
    },
    module: {
        loaders: [
            {
                test: /\.ts(x?)$/, // .ts or .tsx にフックさせてbabelやtypescriptを動かす
                exclude: /node_modules/,
                loader: 'babel-loader?presets[]=es2015!ts-loader'
            }
        ]
    },

    ts: {
        compiler: 'ntypescript'// 最新版のtypescriptもts-loaderで使えるように入れておきます
    }
};


typescript設定

tsconfig.json を書きます。webpackでts-loaderを書く場合、コンパイル時の設定としてここを見に来るようになります。

{
    "compilerOptions": {
        "module": "commonjs",
        "removeComments": true,
        "target" : "es6",
        "allowJs" : true,   
        "pretty" : true,
        "noImplicitThis" : true,
        "jsx" : "react",
        sourceMap": true"
    }
}

エントリーポイントになるhandler.ts

serverless.ymlで定義したLambda関数の実装を作ってみます。
非同期チェーンの記述に便利な async/await も使えるようになったので意味もなく試しておきます。
TypeScriptって言っといて今回は型がガバガバです。


export const apiDemo = (event, context, callback) => {
    const response = {
        headers: {
            "Content-Type":"application/json"
        },
        statusCode: 200,
        body: JSON.stringify({
            message: 'TypeScriptでコンパイルしますた'
        }),
    };

    if (context.succeed != null){
        context.succeed(response); //<= LAMBDA-PROXYとしてAPIを作成するときはこっちを使わないといけない。

    } else {
        callback(null , JSON.parse(response.body));
    }


};

export const htmlDemo = (event , context , callback) => {
    const response = {
        headers: {
            "Content-Type":"text/html"
        },
        statusCode: 200,
        body: `
            <html>
                <head>
                    <meta charset="utf-8">
                    <title>lambda html sample</title>
                </head>
                <body>
                    <div id="content">
                      デモ
                    </div>
                </body>
            </html>
        `
    };

    // test
    (async()=>{
        await new Promise((resolve)=>{
            setTimeout(resolve, 1);
        });

        if (context.succeed != null){
            context.succeed(response);
        } else {
            callback(null , response.body); // <-- でもHTML返すときはこっち使うみたい
        }
    })();
};

ローカルでのテスト

前述の serverless-webpack の機能を使ってローカルでコンパイルの自動化とブラウザ上のテストができるようにしておきます。
この手のシェルスクリプトは npm scriptとしてpackage.jsonに記述して便利にしておきます。

package.json

{
  ....()
  "scripts": {
    "watch": "./node_modules/.bin/webpack --watch",
    "serve": "serverless webpack serve",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ....()

これで

npm run watch

でコードの自動的な差分ビルドができ、

npm run serve

でローカルサーバーが立ち上がります。
あとはこのみで livereload など入れれば、自動でコード変更後のブラウザリロードも行うようになります。

これで

http://localhost:8000/htmlDemo
http://localhost:8000/apiDemo

にアクセスすることで、それぞれの api gateway / lambda function が ローカルで動くようになりました。

デプロイは

serverless deploy

を叩くだけです。

今回はここまでですが、今後 URLのルーティング や テンプレートの読み込み、DynamoDBなどとの連携も模索していこうかと考えています。(Reactのサーバーサイドレンダリングとかもね)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7