2020年09月28日追記
Slackより有識者から「ログインなど機能はフロントに持たせないのがベターだと思います。フロントとバックの役割分担を明確にして、フロントはあくまでも"表現"UIに徹するべきだと考えます。」と言ったご意見をいただきました。
理由として下記2点です。
- ログイン後のページ情報(JSファイル)が_nuxtディレクトリ以下で誰でも確認できるため(下画像)、ログイン後のページ情報が解析されるリスクがある。
- ログインという本来の意図を無視できしまう可能性があること自体がアプリケーションの信頼性・品質を低くしてしまう恐れがある。
今回のアプリでは、ログイン後のページ情報を解析されても、そこにユーザー情報や機密情報がないため、大きな驚異に繋がる訳ではありません。
しかし、2の意見にあるように、そもそも「ログイン前とログイン後のフロントは切り分けるべきだ」という考えが認証アプリケーションの常識のようです。
この記事はNuxtの知識を深めることを目的としたサンプルアプリケーションの実装で、「実務で使えるNuxtの完璧なログイン機能」ではありません。
この記事を読み、「これでログイン機能ができるのか!」と勘違いされた皆さまにはこの場で謝罪します。申し訳ありません。
なお、具体的なログイン実装方法は
- ウェルカムページ、ログインぺージ、パスワードリセットページなどのログイン前ページを表示するフロントと
- ログイン後のページを表示するフロントを
切り分ける必要があります。
別アプリを用意してドメインを分ける方法、エントリポイントを分ける方法などがあるようです。
このあたりは筆者は未経験であり、今は詳しく説明することができません。また、知見を得た時にこの場所で紹介できればと考えています。
プログラミング技術はweb上に多数ありますが、考え方は実務でしか得られないものもあります。そう言った点でも有識者の方には、本当に貴重なご意見をいただきました。感謝いたします。
(追記終了)
_nuxtディレクトリ以下のログイン後のページ情報
【2019/12/07追記】ログイン後のfooter.vueは使用しないとしました。
ログイン後のfooter.vueは、2つの理由で使用しない事としました。
- 重要性がないこと
<v-navigation-drawer>
と併用した時に下に固定表示され、ユーザーが見る画面領域が狭まる事
この変更に伴い、レイアウトファイルの
frontend/layouts/default.vue
<template>
<v-app>
<login-header />
<nuxt />
<!-- <my-footer /> 削除 -->
<my-footer v-if="!$store.state.loggedIn" /> <!-- 追加 -->
</v-app>
</template>
なお、記事は修正済みの内容となっています。
今回達成すること
今回はNuxt.jsのlayout
プロパティを使って、ログイン前と後でレイアウトを切り替えていきます。
完成イメージのgif
レイアウトファイルの設計
レイアウトファイルは、ログインの前後でこのように切り替えます。
なお、default.vue以外のファイルは全て作成します。
ログイン前 | ログイン後 | |
---|---|---|
レイアウトファイル | home.vue | default.vue |
ヘッダーコンポーネント | shared/header.vue | shared/loginHeader.vue |
フッターコンポーネント | shared/footer.vue |
ブランチを作成しときましょ
新しい作業に入るのでブランチを作成しておきましょう。
myapp $ git checkout -b login_layouting
作業に移る前に
今回の記事は全てNuxt.js上での作業となります。
ターミナルは、Rails内のNuxt.jsプロジェクト(筆者の場合、myapp/frontend)に移動しておいてください。
froutend $ # ここに移動しておく
それでは実装に移りましょう。
Eslintのルールを緩和する
まず、実装の前にEslintのルールを変更します。
確認のたびにエラーを吐き出されると困る2つのルールを緩和します。
-
no-console
console.logがある時にエラーを吐きます。
warn
(警告)に変更します。 -
vue/no-unused-components
template内で使われていないコンポーネントがある時にエラーを吐きます。
warn
(警告)に変更します。
frontend直下rules
プロパティにルールを追加します。
ちなみにルール付けは、error
(エラー)、warn
(警告)、off
(何もしない) の3つを設定する事ができます。
frontend/.eslintrc.js
module.exports = {
...
rules: {
'no-console': 'warn', // 追記
'vue/no-unused-components': 'warn' // 追記
}
}
componentsファイルの作成
componentsディレクトリにsharedディレクトリを作成し、その下3つのファイルを作成します。
- loginHeader.vue
- header.vue
- footer.vue
frontend $ mkdir components/shared && touch components/shared/{loginHeader.vue,header.vue,footer.vue}
-
touch {file1, file2, file3}
touch
コマンドで同じディレクトリ内に複数のファイルを一度に作成するテクニックです。
componentsディレクトリはこのようになります。
components
├── README.md
└── shared
├── footer.vue
├── header.vue
└── loginHeader.vue
デフォルトで入っているlogo.vueは、必要ないので削除しました。
componentファイルの編集
作成した3つのファイルを以下のように編集しましょう。
frontend/components/shared/loginHeader.vue
<template>
<div>
ログイン後のloginHeader.vueを表示中
</div>
</template>
<script>
export default {
}
</script>
frontend/components/shared/header.vue
<template>
<div>
ログイン前のheader.vueを表示中
</div>
</template>
<script>
export default {
}
</script>
frontend/components/shared/footer.vue
<template>
<div>
footer.vueを表示中
</div>
</template>
<script>
export default {
}
</script>
これでコンポーネントファイルが整いました。
layoutファイルの作成
ログイン前のトップページとして利用する
layoutsディレクトリ内に作成しましょう。
frontend $ touch layouts/home.vue
layoutsディレクトリはこのようになります。
frontend/layouts
├── README.md
├── default.vue
└── home.vue
ログイン前のレイアウト(home.vue)を編集
ログイン前のトップページとして利用する
ログイン前のヘッダーは「header.vue」を利用するので間違わないようにしてください。
frontend/layouts/home.vue
<template>
<v-app>
<my-header />
このページはログイン前のレイアウト「home.vue」が使用されています。
<my-footer />
</v-app>
</template>
<script>
import myHeader from '~/components/shared/header.vue'
import myFooter from '~/components/shared/footer.vue'
export default {
components: {
myHeader,
myFooter
}
}
</script>
ログイン後のレイアウト(default.vue)を編集
ログイン後のレイアウトファイル
ログイン後のヘッダーは「loginHeader.vue」を呼び出します。
frontend/layouts/default.vue
<template>
<v-app>
<login-header />
<nuxt />
<my-footer v-if="!$store.state.loggedIn" />
</v-app>
</template>
<script>
import loginHeader from '~/components/shared/loginHeader.vue'
import myFooter from '~/components/shared/footer.vue'
export default {
components: {
loginHeader,
myFooter
}
}
</script>
-
<my-footer v-if="!$store.state.loggedIn" />
ログインフラグがfalse、つまりログインしていない場合に表示します。
ログインフラグを扱うindex.jsファイルを作成する
ログインフラグをVuexに作成します。
storeディレクトリ内に
frountend $ touch store/index.js
index.jsにloggedInを作成する
作成した
frontend/store/index.js
// 追記
export const state = () => ({
loggedIn: false
})
レイアウトを切り替えるテクニック
それでは、
と言っても簡単で、layout
プロパティに表示したいファイル名を文字列で渡します。
frontend/pages/index.vue
<script>
export default {
// layoutプロパティを追記
layout ({ store }) {
return store.state.loggedIn ? 'default' : 'home'
}
...
}
</script>
layout()
には、layoutsディレクトリ内にあるファイル名を文字列で渡します。
また、単にレイアウトを変更する場合は以下のように書くことができます。
export default {
layout: 'home'
}
ログインフラグを切り替えるリンクを作成する
ログインフラグを切り替えるリンクを作成していきましょう。
store/index.js
loggedIn
フラグを変更するactionメソッドを作成します。
frontend/store/index.js
export const state = () => ({
loggedIn: false
})
// 以下、追記
export const mutations = {
setLogin (state, payload) {
state.loggedIn = payload
}
}
export const actions = {
userLogin ({ commit }, payload) {
commit('setLogin', payload)
}
}
ログイン、ログアウトページの作成
pagesディレクトリに、ログイン、ログアウトページを新たに作成します。
frontend $ touch pages/{login.vue,logout.vue}
pagesディレクトリはこのような構成になります。
pages
├── README.md
├── index.vue
├── login.vue
└── logout.vue
ログインページにリダイレクト設定を行う
/login
に遷移するとトップページにリダイレクトする設定を行います。
frontend/pages/login.vue
<template>
<div />
</template>
<script>
export default {
fetch ({ store }) {
store.dispatch('userLogin', true)
},
created () {
this.$router.replace('/')
}
}
</script>
-
store.dispatch('userLogin', true)
ログインページには、引数にtrueを渡しています。
-
this.$router.replace('/')
ページ遷移と同時にトップページへ移動するよう設定しています。
ログアウトページにもリダイレクト設定を行う
こちらも同じく、/logout
に遷移するとトップページにリダイレクトする設定を行います。
frontend/pages/logout.vue
<template>
<div />
</template>
<script>
export default {
fetch ({ store }) {
store.dispatch('userLogin', false)
},
created () {
this.$router.replace('/')
}
}
</script>
-
store.dispatch('userLogin', false)
ログアウトページには、引数にfalseを渡しています。
トップページにリンクをセットする
home.vueには、/login
リンクをセットします。
frontend/layouts/home.vue
<template>
<v-app>
<my-header />
このページはログイン前のレイアウト「home.vue」が使用されています。
<!-- 追記 -->
<nuxt-link to="/login">
ログインする
</nuxt-link>
<!-- 追記終了 -->
<my-footer />
</v-app>
</template>
...
index.vueには、/logout
リンクをセットします。
frontend/pages/index.vue
<template>
<v-container fluid fill-height>
<v-row
justify="center"
class="text-center"
>
<!-- 追記 -->
<v-col cols="12">
<nuxt-link to="/logout">
ログアウト
</nuxt-link>
</v-col>
<!-- 追記終了 -->
...
</template>
最後に確認してみましょう
以上で実装は完了です。
Nuxt.jsを起動した後に"http://localhost:3333/"にアクセスして確認してみましょう。
frontend $ yarn dev
コミットしとこ
さて、ここまでの変更をコミットしておきましょう。
一度Railsプロジェクトに戻ります。
frontend $ cd ../
commitしましょう。
myapp $ git add -A
myapp $ git commit -m "add_layout_files"
まだ、masterブランチにはマージしません。
まとめ
今回は、ログイン前とログイン後に利用する、レイアウトファイルとコンポーネントファイルを作成しました。
ログイン前 | ログイン後 | |
---|---|---|
レイアウトファイル | home.vue | default.vue |
ヘッダーコンポーネント | shared/header.vue | shared/loginHeader.vue |
フッターコンポーネント | shared/footer.vue |
Nuxt.jsのレイアウトは、デフォルトで
この
頭の隅っこに覚えておいてください。
さて、次回は?
今のままだとかなりブサイクなので、次回はヘッダーとフッターを作り込んでいきます。
どうぞお楽しみに。