LoginSignup
41
29

More than 5 years have passed since last update.

nuxt.js を serverless framework と一緒に使う

Last updated at Posted at 2017-12-16

まだまだ検証段階だが、手法を載せる。

追記: nuxtjs 1.0 がリリースされましたが、残念ながら node.js 8 以降のサポートとなり、2018年2月26日現在、AWS Lambda上で動かすことができません。動かしたい場合は、node.js 6 で動作する、RC版の利用が必要そうです。早く、AWS Lambda に、node.js 8 Runtime が来てほしいですね。

追記2: 2018年4月 に AWS Lambda 上に、node.js 8 ランタイムが実装されました。https://aws.amazon.com/jp/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/ 同様の方法で nuxtjs 1.4 が動作することを確認済みです。

追記3: 2018年8月16日以前の記事では、 S3 に server-bundle.json を転送する挙動があったため、CDN側でこちらのファイルを見えないようにする設定がない場合、ソースコードが漏洩する可能性があります。 Nuxtのサーバで動かした場合は、公開されないような挙動になっています。 https://github.com/nuxt/nuxt.js/issues/916

目的

たいしてリクエストのないアプリなので、serverless framework 上で、nuxt.js を動作させたい。

参考にしたもの

手順

nuxt.config.js の調整

js や css などのアセットに関しては、Lambda 経由でのアクセスではなく、CDNで配信したいため、publicPath の設定を変更する。ローカル開発 (nuxt dev) では、publicPath を設定しても反映されないので、ファイルを分けたり分岐を作る必要はない。

また、Lambda上で動作させる場合は、gzip圧縮をしてしまうとうまく動かないことがわかっている。この点は、手前にCloudFrontのCDNを挟み圧縮をかけることでなんとかなると思う。

nuxt.config.js
module.exports = {
  build: {
    // CSSについても別ファイルになるようにする。こちらも開発環境では反映されない。
    extractCSS: true,
    publicPath: `https://xxxxxxx.cloudfront.net/nuxt/`,
  },
  render: {
    gzip: false
  }
}

ビルドを行う

yarn run build 

.nuxt/dist ディレクトリにある中身をCDNで配信する。
自分は、S3に上げて CloudFront から参照しているので、以下のように同期かけてます。

server-bundle.json に関しては、SSRのみで利用するため除外します。

aws s3 sync ./.nuxt/dist/ s3://$ASSET_BUCKET/nuxt/ --acl public-read --cache-control "public, max-age=31557600" --exclude "server-bundle.json"

サーバを組み立てる

aws-serverless-express を使う。

yarn add aws-serverless-express
server.js
import express from 'express'
import { Nuxt } from 'nuxt'
import awsServerlessExpress from 'aws-serverless-express'
import awsServerlessExpressMiddleware from 'aws-serverless-express/middleware'

const app = express()
const config = require('./nuxt.config')
config.dev = false
config.mode = 'universal'
const nuxt = new Nuxt(config)

app.use(nuxt.render)
app.use(awsServerlessExpressMiddleware.eventContext())

const server = awsServerlessExpress.createServer(app)

export function render (event, context) {
  awsServerlessExpress.proxy(server, event, context)
}

babel と backpack 使ってビルド

yarn add -D backpack-core babel-core babel-plugin-dynamic-import-node babel-plugin-transform-es2015-modules-commonjs babel-preset-stage-2 babel-preset-env
.babelrc
{
  "presets": [
    ["env", {
      "modules": false
    }],
    "stage-2"
  ],
  "plugins": ["transform-runtime"],
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": ["transform-es2015-modules-commonjs", "dynamic-import-node"]
    }
  }
}
backpack.config.js
module.exports = {
  webpack: (config, options, webpack) => {
    config.entry.server = './server.js'
    return config
  }
}
package.json
{
  "scripts": {
    "build": "nuxt build && backpack build"
  }
}
yarn run build

serverless.yml を作る

service:
  name: ${self:custom.name}

provider:
  name: aws
  region: ap-northeast-1
  runtime: nodejs6.10
  stage: ${opt:stage, 'dev'}
  memorySize: 2048

custom:
  name: sample

package:
  include:
    - .nuxt/**
    - build/**
  exclude:
    # 要らないファイルが結構あるので除去しまくる
    - .git/**
    - .idea/**
    - README.md
    - backpack.config.js
    - components/**
    - layouts/**
    - nuxt.config.js
    - pages/**
    - scripts/**
    - store/**
    - assets/**
    - middleware/**
    - plugins/**
    - server/**
    - static/**
    - test/**

functions:
  render:
    handler: build/server.render
    events:
      - http:
          path: '/'
          method: 'get'
          private: false
      - http:
          path: '{proxy+}'
          method: 'get'
          private: false

これで、 sls deploy で出来上がったエンドポイントにアクセスすればいい感じに展開された。
serverless-domain-manager などを使ってやり、ドメイン割当をすれば、より良い感じに使うことができそう。

41
29
0

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
41
29