Help us understand the problem. What is going on with this article?

SSR する時にフロントエンドからバックエンドのエンジニアに最小限伝えておきたい Nuxt.js の挙動

More than 1 year has passed since last update.

というわけで

実際に手を動かしてもらった方が早いので Tutorial を用意しました。

準備

vue-cli がなければ install しておく

% npm install -g vue-cli

デモプロジェクトを用意する

mkdir practice-nuxt-docker && cd $_
vue init nuxt-community/starter-template myapp 
touch myapp/Dockerfile docker-compose.yml
cd myapp
yarn init -y
yarn
yarn nuxt build # 重要
cd ..

create myapp/Dockerfile

RUN yarn add nuxt
WORKDIR /app
ENV HOST 0.0.0.0
EXPOSE 3000
CMD yarn nuxt start

create Dockerfile

version: '3' 
services:
  nuxt:
    build: myapp
    tty: true
    volumes:
      - "./myapp:/app"
    ports:
      - "3000:3000"
docker-compose build
docker-compose up

http://localhost:3000 へアクセスして動作確認します。nuxt build が必要ですのでデプロイツールを構築する人にちゃんと伝えておきましょう。

最初の Request は Node.js が HTML を返しますが、その直後にブラウザ側でレンダリングされている

以下のように修正します。

% git diff                                                               [master ~/samurai/practice-nuxt-docker/myapp]
diff --git a/myapp/pages/index.vue b/myapp/pages/index.vue
index cf60434..2e2e2b5 100644
--- a/myapp/pages/index.vue
+++ b/myapp/pages/index.vue
@@ -8,6 +8,8 @@
       <h2 class="subtitle">
         Nuxt.js project
       </h2>
+      <h3 v-if="isClient()">Client</h3>
+      <h3 v-else>Server</h3>
       <div class="links">
         <a
           href="https://nuxtjs.org/"
@@ -28,6 +30,11 @@ import AppLogo from '~/components/AppLogo.vue'
 export default {
   components: {
     AppLogo
+  },
+  methods: {
+    isClient() {
+      return (typeof window !== 'undefined' && window.document)
+    }
   }
 }

Nuxt.js のアプリを起動します。(以下の例は docker を経由しない例です)

cd myapp
yarn nuxt build
yarn nuxt start

この状態で http://localhost:3000 を Reload すると一瞬 Server と表示されますが、直後に Client に置き換わる挙動を確認する事ができます。これ以降はブラウザ側で JavaScript が実行されます。

最初のリクエストの段階では Node.js が Javascript を処理するため、このタイミングでは localStorage へのアクセスはできません。access_token の保持などは cookie を使うと良いでしょう。素直に @nuxtjs/axios を使っていれば Header の情報はそのままバックエンドに渡されるはずです。たぶん。

https://axios.nuxtjs.org/options#proxyheaders

nuxt build が生成しているファイルの行方

nuxt build を実行すると以下のように圧縮された js ファイルが生成されます。

Hash: 893dbac70d5b02802558
Version: webpack 4.22.0
Time: 6225ms
Built at: 2018-10-23 12:02:07
                  Asset       Size  Chunks             Chunk Names
41297c5455157e9ca810.js   2.18 KiB       3  [emitted]  runtime
714f38d18aae84388e71.js   3.84 KiB       2  [emitted]  pages/index
               LICENSES  422 bytes          [emitted]  
a136c91fe4110122940e.js   31.1 KiB       0  [emitted]  app
ca15e729f68a6493bcb3.js    134 KiB       1  [emitted]  commons.app

これは以下の場所に配備されます。

% ls -l myapp/.nuxt/dist/client                                                
total 360
-rw-r--r--  1 okamuuu  staff    2228 10 23 12:02 41297c5455157e9ca810.js
-rw-r--r--  1 okamuuu  staff    3928 10 23 12:02 714f38d18aae84388e71.js
-rw-r--r--  1 okamuuu  staff     423 10 23 12:02 LICENSES
-rw-r--r--  1 okamuuu  staff   31824 10 23 12:02 a136c91fe4110122940e.js
-rw-r--r--  1 okamuuu  staff  137438 10 23 12:02 ca15e729f68a6493bcb3.js

そして以下の URL で配信されます。このファイルを nuxt start で動いているプロセスが返すのは効率が悪い気がするのでどうやってデプロイしてキャッシュしたりするかなどをインフラエンジニアに相談してみてください。

http://localhost:3000/_nuxt/41297c5455157e9ca810.js
http://localhost:3000/_nuxt/714f38d18aae84388e71.js
http://localhost:3000/_nuxt/LICENSES
http://localhost:3000/_nuxt/a136c91fe4110122940e.js
http://localhost:3000/_nuxt/ca15e729f68a6493bcb3.js

asyncData

非同期処理を SSR する場合、Nuxt.js では asyncData に記述するだけで簡単に実装できます。

mkdir myapp/pages/posts
touch myapp/pages/posts/index.vue

create pages/posts/index.vue

<template>
  <div class="container">
    <h1>Posts</h1>
    <ul>
      <li v-for="(post, index) in posts" :key="index">
        <nuxt-link :to="{ name: 'posts-id', params: { id: post.id } }">{{ post.title }}</nuxt-link>
      </li>
    </ul>
    <p><nuxt-link to="/">Back to home page</nuxt-link></p>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  asyncData({ req, params }) {
    return axios.get('https://jsonplaceholder.typicode.com/posts')
      .then((res) => {
        return { posts: res.data.slice(0, 5) }
      })  
  }
}
</script>

nuxt あるいは nuxt build && nuxt start でプロセスを起動してから以下の curl コマンドを実行してください。非同期処理で取得している情報が HTML で記述されてる事を確認できます。

curl -s http://localhost:3000/posts

他にも何かあれば

追記します。

  • 非同期処理であっても Node.js のプロセスで rendering して HTML を返す挙動が若干イメージしづらいようなので asyncDate について を追記しました。
okamuuu
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした