Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
13
Help us understand the problem. What is going on with this article?
@kai_kou

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

More than 1 year has passed since last update.

Nuxt.jsのv2系でTypeScriptを利用しつつ、AWS Lambda+αにデプロイできるか確認してみました。

手順

GitHubにいい感じのコードをアップいただけている御方がおられたので、利用させてもらいます。

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

静的ファイルはS3、AWS LambdaのNode.jsでExpressを立ち上げて、SSRをして、API Gatewayがエンドポイント、ドメインはカスタムドメインを利用する構成です。

カスタムドメインを利用する前提でしたので、それを外してデプロイするようにしてみます。

Githubに上記リポジトリをフォークしたものがありますので、よければご参考ください。
https://github.com/kai-kou/nuxt-serverless

ソースの取得と環境構築

ローカル環境で構築します。

nodenpm がインストールされている前提です。

> node -v
v10.11.0

> npm -v
6.4.1
> git clone https://github.com/jeehyukwon/nuxt-serverless.git
> cd nuxt-serverless
コンテナ内
> npm install

動作確認

ローカルで動作するか確認します。

> npm run dev

()
✔ success Builder initialized
✔ success Nuxt files generated

 READY  Listening on http://localhost:3000

ブラウザでアクセスします。
http://localhost:3000
スクリーンショット 2018-11-13 11.07.17.png

スクリーンショット 2018-11-13 11.07.37.png

はい。
ソースを確認するとSSRしてますね。

デプロイ準備

API Gatewayのステージ対応

AWS Lambdaへデプロイする場合、HTTPアクセスにはAWS API Gatewayを利用することになります。
カスタムドメインを利用しない場合、API GatewayのURLはhttps://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/ のように、ステージ名dev が含まれます。

Nuxt.jsでこのステージ名をBaseURL として設定してやる必要があります。
詳細は下記記事で詳しく解説されています。感謝!

Nuxt.js on AWS Lambda with Serverless Framework - mya-ake com
https://mya-ake.com/posts/nuxtjs-on-aws-lambda/

nuxt.config.jsrouter.base を追加します。

nuxt.config.js(一部抜粋)
module.exports = {
  ()
  router: {
    base: '/dev/'
  },
  ()
}

Nuxt.jsの設定以外にExpressでも設定が必要となります。リクエストのURLにステージ名dev が含まれないため、強制的に含めてやります。BaseURLはNuxtの設定nuxtConfig.router.base から取得しています。

handler.js
app.use((req, res) => (
  setTimeout(() => {
    req.url = `${nuxtConfig.router.base}${req.url}`.replace('//', '/')
    nuxt.render(req, res)}
  , 0)
))

カスタムドメインを利用しない設定

カスタムドメインを利用しないので、package.jsonscripts に指定されているsls create_domainsls delete_domain を削除します。

package.json(一部抜粋)
  "scripts": {
    "dev": "nuxt",
    "build": "cross-env NODE_ENV=production nuxt build",
    "start": "nuxt start",
    "sls:local": "sls offline",
    "sls:create": "npm run build && sls deploy",
    "sls:delete": "sls remove",
    "sls:deploy": "npm run build && sls deploy"
  },

serverless.yml でもカスタムドメイン作成の定義を削除します。(ここではコメントアウトしています。)serviceregionBUCKET_NAMESPACE は任意で変更してください。

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
    BUCKET_NAMESPACE: nuxt-serverless  # 3. Specify a new AWS S3 bucket namespace for bundled assets and static assets (should be unique)
    ASSETS_BUCKET_NAME: ${self:provider.environment.BUCKET_NAMESPACE}-assets-${opt:stage, 'dev'}
    STATIC_BUCKET_NAME: ${self:provider.environment.BUCKET_NAMESPACE}-static-${opt:stage, 'dev'}
    ASSETS_BUCKET_URL: https://s3.${self:provider.region}.amazonaws.com/${self:provider.environment.ASSETS_BUCKET_NAME}
    STATIC_BUCKET_URL: https://s3.${self:provider.region}.amazonaws.com/${self:provider.environment.STATIC_BUCKET_NAME}

custom:
  # customDomain:
  #   domainName: service.mydomain.io  # 4. Specify a new domain name to be created
  #   stage: ${opt:stage, 'dev'}
  #   certificateName: mydomain.io  # 5. Enter the certificate name in AWS Certificate Manager (us-east-1) for https connection
  #   createRoute53Record: true
  serverless-offline:
    port: 4000
  s3Sync:
    - bucketName: ${self:provider.environment.ASSETS_BUCKET_NAME}
      localDir: .nuxt/dist/client
    - bucketName: ${self:provider.environment.STATIC_BUCKET_NAME}
      localDir: static

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

resources:
  Resources:
    AssetsBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:provider.environment.ASSETS_BUCKET_NAME}
    AssetsBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket:
          Ref: AssetsBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement: [
            {
              Action: ['s3:GetObject'],
              Effect: 'Allow',
              Resource: {
                Fn::Join: ['', ['arn:aws:s3:::', { Ref: 'AssetsBucket' }, '/*']],
              },
              Principal: '*'
            },
          ]
    StaticBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:provider.environment.STATIC_BUCKET_NAME}
    StaticBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket:
          Ref: StaticBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement: [
            {
              Action: ['s3:GetObject'],
              Effect: 'Allow',
              Resource: {
                Fn::Join: ['', ['arn:aws:s3:::', { Ref: 'StaticBucket' }, '/*']],
              },
              Principal: '*'
            },
          ]

plugins:
  - serverless-offline
  - serverless-s3-sync
  # - serverless-domain-manager

デプロイする

npm run sls:create またはnpm run sls:deploy することで、Nuxt.jsのビルドと、AWSへのデプロイがされます。

> npm run sls:create
()
Entrypoint app = 55e8f003a83a598dd113.js 5e45cc8df25adbaac94b.js 1d1bc122ddb9c7b7f271.css 6a943e90e669a1de7258.js
[13:27:00] Compiling server
[13:27:04] Compiled server in 4s

Hash: 2c7c34f6c1ea4aefd63d
Version: webpack 4.25.1
Time: 3924ms
Built at: 2018-11-13 13:27:04
             Asset     Size  Chunks             Chunk Names
server-bundle.json  213 KiB          [emitted]
Entrypoint app = server-bundle.js
✨  Done in 114.07s.
()
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
S3 Sync: Syncing directories and S3 prefixes...
....
S3 Sync: Synced.

デプロイができたら、ブラウザでアクセスしてみます。xxxxxxxxxx はご自身の環境に合わせてください。

Hello__Nuxt_Serverless_Template.png

Hello__TypeScript.png

view-source_https___vvb2o02739_execute-api_ap-northeast-1_amazonaws_com_dev_.png

なんとか動きました^^

はまりポイント

nuxt dev でホスト名に0.0.0.0 が指定できない

当初Dockerコンテナ内で実行させようとしたのですが、ホスト名に0.0.0.0 が指定できなかったので、ローカル環境で構築しました。

Host and Port - Nuxt.js
https://nuxtjs.org/faq/host-port

0.0.0.0 を指定すると、ランダムっぽいIPが振られてしまいます。。。
環境変数HOSTNUXT_HOSTpackage.json で指定も --hostname もだめ。むむぅ。なんでしょう。。。
ドキュメントには

Note: If port is assigned the string value of '0' (not 0, which is falsy), a random port will be assigned to your Nuxt application.

とありますので、ポートはわかるのですが、ホスト名でも同じような挙動です。。。ローカルでもDockerコンテナ内でも同じ挙動でした。

ローカル
INFO Building project

✔ success Builder initialized
✔ success Nuxt files generated

READY Listening on http://192.168.34.25:3001
Dockerコンテナ
INFO Building project

✔ success Builder initialized
✔ success Nuxt files generated

READY Listening on http://172.28.0.2:3001

API Gatewayのパスが面倒

Nuxt.jsとExpressと別でBaseURL の設定が必要だったのが非常にわかりにくかったです。今回Serverless-httpを利用していたのですが、いくつかIssueが上がっていました。どうにかならないものでしょうか^^

Correct path for non-custom endpoints by bsdkurt · Pull Request #42 · dougmoscrop/serverless-http
https://github.com/dougmoscrop/serverless-http/pull/42

Include baseUrl in request object · Issue #35 · dougmoscrop/serverless-http
https://github.com/dougmoscrop/serverless-http/issues/35

まとめ

ローカル環境の構築がさくっと終わったのでAWS Lambdaにもさくっと構築できるだろうと思って取り組んだら、思いの外ハマって時間がかかりました。Nuxt.jsもv2がリリースされたこともあり、かつTypeScriptを利用だったので、正しい情報・設定を見極めるのに試行錯誤することになりました。

デプロイできることは確認できましたので、ひとまずは

やったぜ^^

参考

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 on AWS Lambda with Serverless Framework - mya-ake com
https://mya-ake.com/posts/nuxtjs-on-aws-lambda/

Host and Port - Nuxt.js
https://nuxtjs.org/faq/host-port

Correct path for non-custom endpoints by bsdkurt · Pull Request #42 · dougmoscrop/serverless-http
https://github.com/dougmoscrop/serverless-http/pull/42

Include baseUrl in request object · Issue #35 · dougmoscrop/serverless-http
https://github.com/dougmoscrop/serverless-http/issues/35

13
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kai_kou
2004年からWeb系のシステムエンジニアとして開発、運用、マネジメントを経験。現在はアイレット(クラウドパック)に所属。 べ、別にいいね貰えたからってモチベーションが上がって記事とコードの品質があがるわけじゃないんだからね///
cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
13
Help us understand the problem. What is going on with this article?