前回、以下のリポジトリからカスタムドメインの利用を外した構成で、Nuxt.js(v2.2.0)+TypeScriptのアプリがAPI Gateway+AWS Lambdaにデプロイできることを確認しました。

Nuxt.js(v2.2.0)+TypeScriptなアプリをAWS Lambda+αにデプロイしてみた
https://cloudpack.media/44795

jeehyukwon/nuxt-serverless: Nuxt.js Serverless SSR Starter on AWS (Lambda + API Gateway + S3) with Serverless Framework
https://github.com/jeehyukwon/nuxt-serverless

今回は、以下のような記事を発見してしまったので、S3を外した構成を試してみます。発見したからには仕方がないです。やってみます。

Serverless-Side Rendering With AWS Lambda & NuxtJS
https://medium.com/@fernalvarez/serverless-side-rendering-with-aws-lambda-nuxtjs-b94d15782af5

手順

環境構築

GitHubに今回のソースをアップしていますので、よければご参考ください。
https://github.com/kai-kou/nuxt-serverless/tree/feature/no-use-s3

前回フォークしたリポジトリを利用します。
kai-kou/nuxt-serverless: Nuxt.js Serverless SSR Starter on AWS (Lambda + API Gateway + S3) with Serverless Framework
https://github.com/kai-kou/nuxt-serverless

> git clone https://github.com/kai-kou/nuxt-serverless.git
> cd nuxt-serverless
> npm install

必要となるライブラリのインストールと、不要となるライブラリをアンインストールします。

> npm install --save-dev serverless-apigw-binary
> npm install --save aws-serverless-express

> npm uninstall --save serverless-http
> npm uninstall --save-dev serverless-s3-sync

serverless.yaml を編集します。S3に関する定義を削除、LambdaとAPI Gatewayで静的ファイルが返せるように定義を追加しています。serviceregion は任意でどうぞ。

serverless.yml

service: nuxt-serverless # 1. Edit whole service name

provider:
  name: aws
  runtime: nodejs8.10
  stage: ${opt:stage, 'dev'}
  region: ap-northeast-1 # 2. Edit AWS region name
  environment:
    NODE_ENV: production

custom:
  serverless-offline:
    port: 4000
  apigwBinary:
    types:
      - '*/*'

package:
  exclude:
    - src/**
  include:
    - serverless.yml

functions:
  nuxt-renderer:
    handler: handler.render
    memorySize: 512
    timeout: 30
    events:
      - http:
          path: /
          method: ANY
          cors: true
      - http:
          path: /{proxy+}
          method: ANY
          cors: true

plugins:
  - serverless-offline
  - serverless-apigw-binary

実装

handler.js の実装を分割します。

ほぼ、記事通りの実装となります。

handler.js

const awsServerlessExpress = require('aws-serverless-express')
const app = require('./server')

const binaryMimeTypes = [
  'application/javascript',
  'application/json',
  'application/octet-stream',
  'application/xml',
  'font/eot',
  'font/opentype',
  'font/otf',
  'image/jpeg',
  'image/png',
  'image/svg+xml',
  'text/comma-separated-values',
  'text/css',
  'text/html',
  'text/javascript',
  'text/plain',
  'text/text',
  'text/xml'
]
const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes)

module.exports.render = (event, context) => awsServerlessExpress.proxy(server, event, context)

server.js にExpressの実装を引っ越しました。ポイントは/_nuxt/static へのアクセス時にS3にリダイレクトさせていたのを、直接ファイルを返すようにしている点です。

前回同様に、ステージ名のパス対応も入れています。

server.js

const express = require('express')
const {Nuxt} = require('nuxt')
const path = require('path')
const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')

const app = express()

app.use(awsServerlessExpressMiddleware.eventContext())

app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist', 'client')))

app.use('/static', express.static(path.join(__dirname, 'static')))

let config = require('./nuxt.config.js')
const nuxt = new Nuxt(config)

app.use((req, res) => {
  req.url = `${config.router.base}${req.url}`.replace('//', '/')
  nuxt.render(req, res)
})

module.exports = app

デプロイ

デプロイしてみます。

> npm run sls:create
(略)
Entrypoint app = 55e8f003a83a598dd113.js 5e45cc8df25adbaac94b.js 1d1bc122ddb9c7b7f271.css 1417c3d6af1ef683305c.js
[15:20:26] Compiling server
[15:20:31] Compiled server in 5s

Hash: f66c1442df8e32ec8ab4
Version: webpack 4.25.1
Time: 4754ms
Built at: 2018-11-13 15:20:31
             Asset     Size  Chunks             Chunk Names
server-bundle.json  213 KiB          [emitted]
Entrypoint app = server-bundle.js
(略)
Serverless: Stack update finished...
Service Information
service: nuxt-serverless
stage: dev
region: ap-northeast-1
stack: nuxt-serverless-dev
api keys:
  None
endpoints:
  ANY - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/
  ANY - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/{proxy+}
functions:
  nuxt-renderer: nuxt-serverless-dev-nuxt-renderer

動作確認

デプロイができたら、ブラウザでアクセスしています。

https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/

やったぜ。

ハマりどころ

API Gatewayのパス指定に気をつけよう

今回は参考にした記事だと、serverless.yml eventshttp 設定が1つだけですが、それだとhttps://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/ にアクセスしても、API GatewayからAWS Lambdaへイベントが発火せず、{"message":"Missing Authentication Token"} となりました。ここは前回参考にした記事の設定のままだとうまくいきました。

OK

 events:
      - http:
          path: /
          method: ANY
          cors: true
      - http:
          path: /{proxy+}
          method: ANY
          cors: true

だめ。1時間くらい悩んだ

events:
      - http:
          path: /{proxy+}
          method: ANY
          cors: true

これもだめ。もうだめだ

events:
      - http: ANY {proxy+}

タイムアウトエラーが発生したらyarn を利用する

npm でライブラリをインストールしていると、デプロイできても、URLへアクセスするとタイムアウトエラーになることがありました。その場合には、yarn でライブラリをインストールし直すとうまく動きました。

> rm -rf node_modules/
> npm install -g yarn # yarnがインストールされていなかったら
> yarn
> yarn build
> sls deploy

注意点

注意点としては、静的ファイルが多くなるとAWS Lambdaのアップロード制限に引っかかる可能性があるかもしれません。

AWS Lambda の制限 – AWS Lambda
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/limits.html

AWS Lambda デプロイメントの制限

Lambda 関数デプロイパッケージのサイズ (圧縮 .zip/.jar ファイル) : 50 MB
リージョンあたりの、アップロードできるすべてのデプロイパッケージの合計サイズ : 75 GB
デプロイパッケージ (非圧縮 .zip/.jar サイズ) に圧縮できるコード/依存関係のサイズ: 250 MB

まとめ

シンプルなSSR対応のサービスを提供するにはこちらのほうがシンプルですね。
プロジェクト次第で使い分けが良さそうです。

参考

Serverless-Side Rendering With AWS Lambda & NuxtJS
https://medium.com/@fernalvarez/serverless-side-rendering-with-aws-lambda-nuxtjs-b94d15782af5

Nuxt.js(v2.2.0)+TypeScriptなアプリをAWS Lambda+αにデプロイしてみた
https://cloudpack.media/44795

jeehyukwon/nuxt-serverless: Nuxt.js Serverless SSR Starter on AWS (Lambda + API Gateway + S3) with Serverless Framework
https://github.com/jeehyukwon/nuxt-serverless

元記事はこちら

Nuxt.js(v2.2.0)+TypeScriptなアプリをAWS Lambda+αにデプロイしてみた(S3なし版)