Server Side Rendering を Serverless Framework と Nuxt.js でやる Tutorial


## 対象読者

* Node.js で express を使った事がある。
* async, await 書ける。
* `sls deploy` したことある
* `nuxt build` したことある

## STEP0: 準備

必要なファイルとディレクトリを用意して起きます。

```
sls create --template aws-nodejs --path tutorial-serverless-nuxt && cd $_
yarn init -y
yarn add express serverless-http
yarn add -D serverless-offline
touch server.js
```

以下は Nuxt.js で使用します

```
yarn add nuxt
touch nuxt.config.js
mkdir -p app/pages
touch app/pages/index.vue
```

## STEP1: Express Server を用意する

create `server.js`

```javascript
const express = require('express');
const app = express();
const port = process.env.PORT || 3000

app.get('/api/ping', (req, res) => {
  res.json({ ping: 'pong' }); 
});

function listen() {
  app.listen(port, '0.0.0.0')
  console.log('Server listening on `localhost:' + port + '`.')
}

if (!module.parent) {
  listen()
}

module.exports = app;
```

起動する

```
% node server.js
Server listening on `localhost:3000`.
```

`curl http://localhost:3000/api/ping` で動作確認する。

なお、require して使う場合は以下のように実行します。Serverless Framework で動かす場合は require しますのでこのようにしています。

```
% node -e "require('./server').listen(3000)"  
```

## 用意した Express Server を Serverless Framework で使う

edit `serverless.yml`

```javascript
service: tutorial-serverless-nuxt

plugins:
  - serverless-offline

provider:
  name: aws 
  runtime: nodejs8.10
  stage: dev 
  region: ap-northeast-1

functions:
  server:
    handler: handler.server
    timeout: 30
    events:
      - http:
          method: ANY 
          path: '/' 
      - http:
          method: ANY 
          path: '{proxy+}'
```

edit `handler.js`

```javascript
'use strict';

const serverless = require('serverless-http');
const server = require('./server');

module.exports.server = serverless(server);
```

動作確認。以下の実行するとローカル環境で Lambda が実行できます。

```
% sls offline
```

## STEP2: 最小限の Nuxt.js を用意する

動作させるだけなので、最小限の `nuxt.config.js` と `app/pages/index.vue`を用意します。

edit `nuxt.config.js`

```javascript
module.exports = { 
  head: {
    titleTemplate: "%s - Nuxt.js"
  },  
  srcDir: 'app'
}
```

create `app/pages/index.vue`

```vue
<template>
  <div>
    <h1>Hello, Nuxt.js</h1>
  </div>
</template>
```

動作確認をします。

```
% yarn run nuxt --port 3001
```

`srcDir` は参考にした記事によると deploy するときにアップロードするファイルを除外する為だそうです。素直に真似をしています。

## STEP3: Nuxt.js を express の middleware として使う

edit `server.js`

```javascript

const { Nuxt, Builder } = require('nuxt')

const express = require('express');
const app = express();
const isProd = (process.env.NODE_ENV === 'production')
const port = process.env.PORT || 3000

const config = require('./nuxt.config.js')
config.dev = !isProd
const nuxt = new Nuxt(config)

app.get('/api/ping', (req, res) => {
  res.json({ ping: 'pong' });
});

app.use(nuxt.render)

// Build only in dev mode with hot-reloading
if (config.dev) {
  new Builder(nuxt).build()
  .then(listen)
  .catch((error) => {
    console.error(error)
    process.exit(1)
  })
}

function listen() {
  // Listen the server
  app.listen(port, '0.0.0.0')
  console.log('Server listening on `localhost:' + port + '`.')
}

module.exports = app;
```

開発する時は以下のように実行します。

```
% PORT=3002 node server.js
```

この状態で `app/pages/index.vue` を書き換えて hot-reloading が動作していることを確認してください。

## STEP4: Lambda に deploy する

最後に deploy します。 以下のコマンドを実行して必要なファイルを生成します。

```
% yarn nuxt build
```

次に deploy するときにファイルの容量が増えないように工夫します。これはb

edit `serverless.yml` 

```yml
service: serverless-tutorial-one

plugins:
  - serverless-offline

package:
  excludeDevDependencies: true
  exclude:
    - .**
    - .**/*
    - app/**
    - LICENSE
    - README.md
    - package.json
    - yarn.lock
  include:
    - handler.js
	- server.js
	- nuxt.config.js

provider:
  name: aws 
  runtime: nodejs8.10
  stage: dev 
  region: ap-northeast-1

functions:
  nuxt:
    handler: handler.server
    timeout: 30
    environment:
      NODE_ENV: production
    events:
      - http:
          method: ANY 
          path: '/' 
      - http:
          method: ANY 
          path: '{proxy+}'
```

それでは deploy してみましょう。`sls offline` だと上手く動かなかったので実際に deploy しています。

```
% sls deploy
```

`/api/ping` は json が返ってきて、それ以外は Nuxt.js が画面を返していることを確認します。

動作確認が終わったら以下のコマンドでお掃除します。

```
% sls remove
```

以上です。お疲れ様でした。

## ちなみに

実を言うと serverless.yml の `exclude` と `include` の設定に関してはこれで合っているのかよく調べていません。その辺りは後日追記・修正するかもしれません。

色々ハマった点がありましが、とても参考になる記事を書いてくれていた人がいのたでなんとかゴールする事ができました。ありがとうございました。

https://mya-ake.com/posts/nuxtjs-on-aws-lambda/