iku8blog - 考えない為に考える

npx create-nuxt-appコマンドでNuxt.jsのSSRとSSGを使ってみた

date: 2021-03-16

Nuxt.jsにはSPAで動作させる意外に、SSRとSSGというものがある。

今回はこれをプロジェクト作成から実際に動かすまでを行う。

  1. npx create-nuxt-appコマンドでプロジェクト生成
  2. APIサーバを作っておく(api通信してデータをレンダリングする用)
  3. SSR化
  4. SSRのアプリケーションしたものをSSGとして静的ファイルを生成

こんな感じ

アプリケーションの作成

nuxtプロジェクトはcreate-nuxt-appというコマンドを通して行うと楽。

npx create-nuxt-app nuxt-ssr-app

プロジェクト名はnuxt-ssr-appとした

コマンド実行後対話モードで色々聞かれるので、以下のように選択。

universalを選択するとSSR,SSGが使えるようになるらしい ただ、ここはあとから修正できるので、余り神経質にならなくてよい。

APIサーバを準備する

SSRでもSSGでもAPIサーバに通信した結果をレンダリングするということをしたいので、予めAPIサーバとしてjson型式でデータを返すサーバを立てておく。

npmのjson-serverを使う

https://www.npmjs.com/package/json-server

db.json

{
  "users": [
    { "id": 1, "name": "bob", "age": 20 },
    { "id": 2, "name": "tom", "age": 30 },
    { "id": 3, "name": "takeshi", "age": 70 }
  ]
}

json-serverがnpmでインストールされていれば以下コマンドで、サーバを起動出来る

./node_modules/json-server/lib/cli/bin.js --watch db.json -p 9000

エンドポイントはこうなるhttp://localhost:9000/users

以上でAPIサーバが準備できた

SSRで起動する

axiosの設定

axiosは事前にインストールして使えるように設定しておく

npm install @nuxtjs/axios

nuxt.config.jsにmoduleとしてaxiosを追加

export default {
...,
    modules: ['@nuxtjs/axios'],
...

これでvue内からthis.$axiosとしてアクセス出来るようになる

ただのaxiosをインストールして使ってもよいが、vueファイルごとにimportしないといけなくなるので、nuxtjs/axiosが使えるならこの方が良さそう

asyncDataでaxiosを使う場合は、thisは使えないので、このようにアクセスする必要がある

asyncData({ $axios }) {
    ...
}

asyncDataを使ってSSRにする

通常データの取得などはcreatedやmountedで行うが、 それではSPAの動きをしてしまうので、サーバサイド側でデータを取得するためにasyncDataを使用する。

pages/index.vueを以下のように書き換える

<template>
  <div class="container">
    <div>
      <Logo />
      <h1 class="title">
        nuxt-ssr-app
      </h1>
      <ul>
        <li v-for="user in users">
          {{ user.id }}
          {{ user.name }}
          {{ user.age }}
        </li>
      </ul>
      <button @click="resetUser()">reset</button>
      <button @click="fetchUser()">fetch user</button>
    </div>
  </div>
</template>

<script>
export default {
  asyncData({ $axios }) {
    return $axios.get("http://localhost:9000/users").then(res => {
      return {
        users: res.data
      }
    })
  },
  data() {
    return {
      message: "hello nuxt ",
    }
  },
  methods: {
    resetUser: function () {
      this.users = []
    },
    fetchUser: function () {
      this.$axios.get("http://localhost:9000/users").then(res => {
        this.users = res.data
      })
    },
  }
}

重要なのは、asyncDataの箇所。ここで9000ポートに対して、リクエストを飛ばしユーザデータを取得している。 このようにすることで、SPAではなくSSRとして動作するようになる。

では起動してみる

npm run dev

リストとしてユーザ情報が表示されたので、実際の通信をみてみると

ちゃんとDocとしてユーザ情報が入っているHTMLが返されている

念の為Xhrもみてみると、API通信している箇所はなかったのでSSRは成功している

今回ついでにresetとfetchメソッドを作成したので、こちらを使用してみると

fetchUserしたタイミングで、API通信が行われているのが確認できる

このように、今まで通りの何らかのアクションをしたときにAPIをコールすることもできる。HTMLを一気にレンダリングした結果を返したい場合は、asyncDataで事前に取得すれば良い。

今までのSPAの開発とほぼ同じなので、SSRで実装する場合も特段意識することは少なそう。

SSGに切り替えてみる

では先程のページをSSGにしてみる。

とは言ってもかなり簡単にSSG化することができ、

nuxt generate

とするとSSGが完了する。

nuxtコマンドが使えない場合はpackage.jsonに以下追記すると良い

  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "export": "nuxt export",
    "serve": "nuxt serve",
    "generate": "nuxt generate"  ←追加
  }

これでnpm run generateとして実行できる generateコマンドにより、asyncDataに記述されているAPIをコールしてHTMLが作成されdistディレクトに静的ファイルが配置される。

このdistをホスティングすると静的サイトとして稼働させることが出来る。

生成されたdist/index.htmlをみてみると、HTMLファイル内にAPI経由で取得したユーザデータがきちんと追加されていた。

ホスティングするのが面倒だったので、PHPのビルドインサーバ使用して起動してみた

php -S localhost:8000

すると問題なく表示され、メソッドであるresetやfetchなども効いていた。

SSGの際のnuxt.config.jsについて

公式サイトではSSGにするときはtarget: 'static'にすることが推奨されているので、それに従っていた方が良さそう。

何やらmodeというオプションが廃止されるようで、ssrというオプションになり、今後はtrue,falseを指定するようになるらしい

現状target: 'server'出会ってもnuxt generateコマンドだけで、SSGは可能だが、警告も出ていたので、やはりstaticとして指定していたほうが無難だろう。

stackoverflowでこれに対する質問もされていた

[https://stackoverflow.com/questions/63336570/whats-the-real-difference-between-target-static-and-target-server-in-nuxt:embed:cite]

date: 2021-03-16