Nuxt.js ビギナーズガイド ch.3 Nuxt.jsの機能の活用
nuxt-beginners-guide.elevenback.jp
- layoutsディレクトリによるレイアウトの共通化
- Nuxt.jsのライフサイクル
- middlewareによるグローバルなフックの登録
- プラグインによるVue.jsプラグイン資産の有効活用
- Vuexのモジュールモードを活用したオートローディング
- より多くの機能を知りたい場合は
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のライフサイクル
- Incoming Request
- nuxtServerInit
- VuexストアのルートにnuxtServerInitが定義されているときのみ
- 必ず入れておきたいデータの格納
- 簡単な認証
- middleware
- マスタデータの取得
- 複雑な認証
- グローバルで動かすべき単一の専門的な機能
- validate()
- asyncData() & fetch()
- Vue.jsの通常のライフサイクル
middlewareによるグローバルなフックの登録
- ルーティングに割り込んで様々な処理を行う
- UAに合わせたリダイレクト
- 認証・認可
middlewareを利用した認証の必要なルーティングの実装
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"); } };
- /authed-routeにアクセス
- /loginにリダイレクトされる
- ログインボタン押下
- /に遷移
- /loginにアクセス
- /にリダイレクトされる
- /authed-routeにアクセス
- 「認証が必要なページ」が表示される
ミドルウェアの魅力と注意点について
- できること
- アプリケーション全域に記述したい処理を簡単に書ける
- Vuexストアの読み出し
- Responseオブジェクトの改変
- アプリケーション全域に記述したい処理を簡単に書ける
- ブートストラップロジックとアプリケーション本体のはざま
- 両方の情報にアクセスでき、柔軟な機能追加が可能
- 半面、責務をまたぐコードが生まれるので注意
- むやみに増やすとアーキテクチャが密結合になり見通しが悪くなる
プラグインによるVue.jsプラグイン資産の有効活用
プラグインの実装と登録
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の付け忘れ
- Vue.jsあるあるの解消
モジュールモードの仕組みについて
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); } } } } });