Nuxt.js ビギナーズガイド ch.3 Nuxt.jsの機能の活用

JavaScriptNuxt.js勉強メモ

出典: 

layoutsディレクトリによるレイアウトの共通化

  • 本格的なアプリケーション開発を行っていく前にNuxt.jsの機能について理解しておこう

レイアウト構築機能について

  • 共通レイアウト

    • Vue.jsによるSPA開発の悩みの種
  • 共通レイアウトについての規約がある

    • 簡単な切り分け
    • 宣言的
    • 複雑な管理いらず

レイアウトのルールとdefault.vueの編集

  • default.vue

    • 特にレイアウト指定のない場合のフォールバック
  • <nuxt />タグのところにpages内のVueコンポーネントが入る

複数のレイアウトの管理

  • アプリケーション全体ではなく、カテゴリ別のテンプレートを設けられる
  • pagesの中のVueコンポーネントでlayoutを指定する

layouts/single.vue

<template>
  <div>
    <span>
      single layout
    </span>
    <AppNavigation />
    <hr />
    <nuxt />
    <nuxt-link to="/">
      トップに戻る
    </nuxt-link>
    <hr />
    <footer>
      footer
    </footer>
  </div>
</template>

<script>
import AppNavigation from "~/components/AppNavigation.vue";

export default {
  components: {
    AppNavigation
  }
};
</script>

pages/child.vue

<script>
export default {
  layout: "single"
};
</script>

いま見ているページのレイアウトはVue.js Devtoolsでも確認可能

レイアウトファイル設計のベストプラクティス

  • default.vueにはアプリケーション全体で使われるレイアウトを

    • フォールバック
    • いちいち書かなくていいのでミスが減る・管理が楽に
  • 特別なものには名前付きのものを

    • トップページとか
    • 完全に隔離

Nuxt.jsのライフサイクル

  1. Incoming Request
  2. nuxtServerInit

    • VuexストアのルートにnuxtServerInitが定義されているときのみ
    • 必ず入れておきたいデータの格納
    • 簡単な認証
  3. middleware

    • マスタデータの取得
    • 複雑な認証
    • グローバルで動かすべき単一の専門的な機能
  4. validate()
  5. asyncData() & fetch()

    • asyncData

      • SSRでつかうやつ(前章)
    • fetch

      • asyncDataと同様の機能で、Vueコンポーネントのローカルステートに影響がないやつ
      • ページ単位のミドルウェア的な
  6. Vue.jsの通常のライフサイクル

middlewareによるグローバルなフックの登録

  • ルーティングに割り込んで様々な処理を行う

    • UAに合わせたリダイレクト
    • 認証・認可

middlewareを利用した認証の必要なルーティングの実装

  • universal-cookie

    • フロントエンド・サーバーサイド両方でCookieを扱えるUniversalなライブラリ
import Cookies from "universal-cookie";

export default {
  methods: {
    login() {
      const cookies = new Cookies();
      cookies.set("credential", "true", { maxAge: 90 });
      this.$router.push("/");
    }
  }
};

ミドルウェアの作成とグローバルへの登録

middleware/auth.js

export default () => {
  if (process.browser) {
    console.log("console.log() on browser");
  } else {
    console.log("console.log() on SSR server");
  }
};
  • 関数をデフォルトエクスポートするjs

nuxt.config.js

      }
    },
   
+   router: {
+     middleware: ["auth"]
+   }
+ };
  • ページ更新すると、サーバーに下記ログが出力される
console.log() on SSR server                                           08:20:55

ミドルウェアの認証の実装

import Cookies from "universal-cookie";

export default ({ req, route, redirect }) => {
  console.log(route.path);
  if (["/"].includes(route.path)) {
    return;
  }

  const cookies = req ? new Cookies(req.headers.cookie) : new Cookies();
  const credential = cookies.get("credential");

  // 認証済でログインページにアクセスしたらrootにリダイレクト
  if (credential && route.path === "/login") {
    return redirect("/");
  }
  // 未認証でroot・ログインページ以外にアクセスしたらloginにリダイレクト
  if (!credential && route.path !== "/login") {
    return redirect("/login");
  }
};
  1. /authed-routeにアクセス
  2. /loginにリダイレクトされる
  3. ログインボタン押下
  4. /に遷移
  5. /loginにアクセス
  6. /にリダイレクトされる
  7. /authed-routeにアクセス
  8. 「認証が必要なページ」が表示される

ミドルウェアの魅力と注意点について

  • できること

    • アプリケーション全域に記述したい処理を簡単に書ける

      • Vuexストアの読み出し
      • Responseオブジェクトの改変
  • ブートストラップロジックとアプリケーション本体のはざま

    • 両方の情報にアクセスでき、柔軟な機能追加が可能
    • 半面、責務をまたぐコードが生まれるので注意

      • むやみに増やすとアーキテクチャが密結合になり見通しが悪くなる

プラグインによるVue.jsプラグイン資産の有効活用

  • pluginsディレクトリが用意されている
  • 自前でutilsディレクトリとかを掘るのに比べての利点

    • Nuxt.jsの規約に則って開発できる

      • CoCなフレームワークなので、規約に則ってこそ生産性が上がる
    • SSR時に呼び出すか否かをオプションで切り替え可能

      • SSR時はwindowやdocumentオブジェクトがないため使えないものがある
      • process.browserで分岐するよりもキレイ

プラグインの実装と登録

plugins/logger.js

export default ({ app }) => {
  app.router.beforeEach((to, from, next) => {
    console.log(`[ROUTER] move to '${to.fullPath}'`);
    next();
  });
};

nuxt.config.js

    router: {
      middleware: ["auth"]
    },
+   plugins: ["~/plugins/logger"]
+   // 同じ意味
+   // plugins: [
+   //   {
+   //     src: "~/plugins/logger",
+   //     ssr: true
+   //   }
+   // ]
  • ssrオプション

    • デフォルトtrue
    • windowやdocument等、browserでないと存在しないものに依存している
      = サーバサイドで動かすとエラーになる場合はssr: falseとする
    • SPAモードではサーバサイドで動かさないので、明示的にfalseと指定する必要はない
  • 今回はページ遷移でログを仕込んだ
  • 実際の開発では、Google Analyticsやmixpanel等を仕込むことが多くある
  • 既存のVue.jsプロジェクトのプラグイン資産を活用したい場合などに有用

Vuexのモジュールモードを活用したオートローディング

  • 前章ではクラシックモードでVuexを利用した

    • deprecated
    • Nuxt.js ver3から使えなくなる
  • 規約に沿ってファイル名をつけ記述し、適切にexportを行うだけで、名前空間付きVuexモジュールができあがる

    • Vue.jsあるあるの解消

      • モジュールの読み込み漏れ
      • namespacedの付け忘れ

モジュールモードの仕組みについて

index.js

export const state = () => ({
  isLoading: false
});

export const mutations = {
  setIsLoading(state, isLoading) {
    state.isLoading = isLoading;
  }
};

users.js

export const state = () => ({
  list: []
});

export const mutations = {
  addUser(state, user) {
    state.list.push(user);
  }
};

export const actions = {
  addUser({ commit }, { user }) {
    commit("addUser", user);
  }
};

下記Vuexストアと等価

new Vuex.Store({
  state: {
    isLoading: false
  },

  mutations: {
    setIsLoading(state, isLoading) {
      state.isLoading = isLoading;
    }
  },
  modules: {
    users: {
      state: {
        list: []
      },

      mutations: {
        addUser(state, user) {
          state.list.push(user);
        }
      },

      actions: {
        addUser({ commit }, { user }) {
          commit("addUser", user);
        }
      }
    }
  }
});

より多くの機能を知りたい場合は