というわけで
実際に手を動かしてもらった方が早いので 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 の情報はそのままバックエンドに渡されるはずです。たぶん。
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 について
を追記しました。