Vue.jsでSPA、Vuex使用するなら Nuxt.jsが超絶便利な件。
2018.12.23
この記事は最終更新日から1年以上が経過しています。
どもです。
Vue.jsはかれこれ、使用して2年くらい経つのかも、経たないかも。
ガッツリと使用してきたのですが、主にwebゲーム作成での使用でした。
今回、所謂一般的な「Webサービス(Webアプリケーション)」を作成することもあって、色々漁っては見たものの
やっぱりVue.jsが実装も楽だなと言うことで、どうせならモダンなフロントエンド実装が良いなと思って
改めてNuxt.jsをガッツリ触り始めたのですが、やっぱり「超絶便利」ですね!
前回、こちらの記事で、軽く紹介させていただいたのですが(もう1年以上前なのかw)、改めて使用し始めたのですが、やはり便利ですね。
バージョンも2.3.4という事で、1年前よりもメジャーバージョンが上がったのではないのでしょうか?
今まであまり使用してこなかったのは、やはりWebゲームともなると、1画面で多ければ20個くらいAPIの非同期リクエストが発生したり、
インタラクションの為、恐ろしくDOMを動かしたり、勿論画面の状態管理が必要となってきたりして(ステートマシーンを利用したり)細かい調整が多々必要とされてきます。
そのため、一般的な「Webサービス(Webアプリケーション)」向けのフルスタックなフレームワークだと使用しない余分なパッケージが入ってきたりするので、nodeパッケージも個別で選定してインストールを行ったりし、リソースも最小限にします。
また、アーキテクチャも共通認識が持てる、枯れた設計であるOOP(オブジェクト指向)などを用いて作成したほうが無難に制作を進められたりします。
OOP(オブジェクト指向)と言えば、クラスに「状態」「処理」を持ったオブジェクトが疎結合の関係で設計されていくのですが、
通常の「Webサービス(Webアプリケーション)」のフロントエンド実装で用いようとすると、冗長に感じてしまうこともしばしばありました。
API通信も画面に対して1、2個。多くても5個とかではないでしょうか?
その様な場合、1方向データフロー設計であるFluxやRedux、Vue jsでは Vuexの設計を用いると、大きすぎず、比較的シンプルに状態管理が行えるように感じました。
と、まぁ、前置きはさておき、「Nuxt.js」が、「非常に楽だ。」と感じたところと、注意点を軽くピックアップしてみました。
「Nuxt.js」のインストール方法などは、公式のこちらを参考に、割愛させていただきます。
webpack、nodeパッケージ管理が超絶楽
通常 Vue jsを使用して nodeパッケージをインストールしてくと、こんな感じで増えていき、(一部)管理も辛くなってきます。。
... "autoprefixer": "9.3.1", "aws-sdk": "2.353.0", "babel-eslint": "10.0.1", "babel-loader": "8.0.4", "babel-plugin-lodash": "3.3.4", "browser-sync": "2.26.3", "cfonts": "2.2.3", "chalk": "2.4.1", "check-engines": "1.5.0", "chokidar": "2.0.4", "colors": "1.3.2", "commander": "2.19.0", "concurrently": "4.0.1", "css-loader": "1.0.1", "eslint": "5.9.0", "eslint-config-airbnb-base": "13.1.0", "eslint-config-prettier": "3.3.0", "eslint-plugin-import": "2.14.0", "eslint-plugin-prettier": "3.0.0", "fs-extra": "7.0.1", "glob": "7.1.3", "html-loader": "0.5.5", "html-webpack-plugin": "3.2.0", "htmlhint": "0.10.1", "husky": "1.1.3", "json-server": "0.14.0", "lint-staged": "8.0.4", "lodash-webpack-plugin": "0.11.5", "mini-css-extract-plugin": "0.4.4", "node-sass": "4.10.0", "optimize-css-assets-webpack-plugin": "5.0.1", "postcss-loader": "3.0.0", "postcss-syntax": "0.34.0", "prettier": "1.15.2", "prettier-stylelint-formatter": "0.5.1-beta.2", "progress-bar-webpack-plugin": "1.11.0", "pug": "2.0.3", "pug-loader": "2.4.0", "sass-loader": "7.1.0", "shelljs": "0.8.2", "style-loader": "0.23.1", "stylelint": "9.8.0", "stylelint-config-prettier": "4.0.0", "stylelint-config-recommended-scss": "3.2.0", "stylelint-scss": "3.4.0", "uglifyjs-webpack-plugin": "2.0.1", "webpack": "4.25.1", "webpack-build-notifier": "0.1.30", "webpack-bundle-analyzer": "3.0.3", "webpack-cli": "3.1.2", "webpack-merge": "4.1.4", "axios": "0.18.0", "dom-helpers": "3.4.0", "lodash-es": "4.17.11", "vue": "2.5.17", "vue-class-component": "6.3.2", "vue-iscroll-view": "1.0.3", "vue-touch": "2.0.0-beta.4", "ts-loader": "4.1.0", "ts-node": "^7.0.0", "tslint": "^5.9.1", "tslint-config-airbnb": "^5.8.0", "tslint-config-prettier": "^1.10.0", "tslint-plugin-prettier": "^1.3.0", "typescript": "2.8.1", "typings": "^2.1.1", "webidl-conversions": "^4.0.2", "iscroll": "^5.2.0", "countdown-timer-js": "^1.0.3", "vue-iscroll-view": "^1.0.3", ...
プロジェクト毎に考えるのを少々辛くなってくるのですが、「Nuxt.js」だと、この辺も最初のcreate-nuxt-appで選択すれば、 「Nuxt.js」側がインストール「Nuxt.js」内で閉じてくれているので、管理も楽です。
また、冗長になりやすい webpackの設定・エコシステムなど、ビルドプロセスも「Nuxt.js」が隠蔽(ラップ)してくれてて超絶楽です。
とは言え、アプリケーションの設定は必要です。
アプリケーション側にパッケージ、プラグイン設定を行う場合は、すべて「nuxt.config.js」に設定すればオッケーです。
「Atomic Design」のCSSフレームワークである「atomic-package」を使用したい場合。
npm installコマンドでインストール
$ npm install @atomic-package/css
nuxtの設定ファイルである「nuxt.config.js」を修正
nuxt.config.js
/* ** Global CSS */ css: [ '@/@atomic-package/css/dist/atomic-package.css', '... ],
ボタンを表示される要素の記述。
Vueファイル
<p class="btn" />
これでもう、Atomic Design ベースの CSSボタンが表示されます。
超絶楽ですね。
ルーティングが超絶楽
「nuxt.config.js」の modeで「SPA」か「SSR」を選択できます。
こちらを spaに設定。
mode: 'spa'
「pages」ディレクトリ以下の「Vueファイル(〇〇.vue)」は、「Nuxt.js」がページと認識し、自動的にVue Routerの設定を行ってくれます。
例えば、以下の様に、pages/recipe があるとすると
{ path: "/recipe/detail", component: _24157e40, name: "recipe-detail" }, { path: "/recipe/edit", component: _52345939, name: "recipe-edit" }, { path: "/recipe/:id", component: _021e4a4a, name: "recipe-id" }
と言った具合に自動的に、Vue Routerの設定を行ってくれます。
「Nuxt.js」は、_〇〇.vue と、アンダースコア以降の名前をプロパティ名と認識するようで、
自動的に「params」に代入されます。
これらの仕組みがありますので、サクッとSPAページを作成する場合。
対象のファイルを「pages」ディレクトリ以下に作成。
ルーティングのリンクの設定は「nuxt-link」で設定。
<nuxt-link to="/recipe/detail"></nuxt-link>
idをパラメータに渡したい場合は、以下のように「name」「params」を「:to」でバインドさせます。
<nuxt-link :to="{ name: 'recipe-id', params: { id: recipe.id }}">
わざわざ、Vue Routerも個別にインストールしなくて良いので、非常に楽です。
Reduxが超絶楽
「Nuxt.js」では、「store」ディレクトリ以下のファイルを「Vuex」のファイルとして認識します。
ネットでもちょこちょこ見かけるのですが、storeディレクトリ以下に「index.js」を作成し、
以下の様に記述。
クラシックモード記述
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
とこれら、Vuexの「クラシックモード」での記述となります。
こちらでも問題なく動作するかと思いますが、より Nuxtを便利に扱いたいのであれば
「new Vuex.Store(..)」の記述も必要ない「モジュールモード」を活用すると良さそうです。
export const state = () => ({ state: { count: 0 } }) export const mutations = () => ({ increment (state) { state.count++ } })
こちら何が便利かというと、ファイル単位でモジュール化を行えることができます。
todo.jsを作成し以下を記述。
store/todos.js
export const state = () => ({ list: [] }) export const mutations = { add (state, text) { state.list.push({ text: text, done: false }) }, remove (state, { todo }) { state.list.splice(state.list.indexOf(todo), 1) }, toggle (state, todo) { todo.done = !todo.done } }
以下のようにクラシックモードの記述と同等となります。
自動で「modules」を作成してくれるので管理もしやすいですね。
new Vuex.Store({ state: () => ({ counter: 0 }), mutations: { increment (state) { state.counter++ } }, modules: { namespaced: true, todos: { state: () => ({ list: [] }), mutations: { add (state, { text }) { state.list.push({ text, done: false }) }, remove (state, { todo }) { state.list.splice(state.list.indexOf(todo), 1) }, toggle (state, { todo }) { todo.done = !todo.done } } } } })
Vueファイルから呼び出す場合
export default { computed: { todos () { return this.$store.state.todos.list } }, methods: { addTodo (e) { this.$store.commit('todos/add', e.target.value) e.target.value = '' }, ...mapMutations({ toggle: 'todos/toggle' }) } }
componentとpageの違い
公式サイトより引用
components ディレクトリには Vue.js のコンポーネントファイルを入れます。Nuxt.js は components ディレクトリ内のコンポーネントの data メソッドについては手を加えません(訳注: 一方、Nuxt.js は
pages
ディレクトリ内のコンポーネントの data メソッドには非同期データを扱えるよう手を加えます)
どうやら、componentsディレクトリは通常のVue.js として扱われそうな感じです。
実際に、pages以下で使用できる非同期データ取得の
export default { asyncData (context) { return { project: 'nuxt' } } }
は、component以下のVueファイルでは使用できない様子でした。
また、Storeをvueファイルから「this.$store」で参照できるのも、pageディレクトリ以下のvueファイルに限られている様子です。
pages以下のVueファイルでStoreを参照
this.$store.state.user
と、言った感じで「Nuxt.js」の便利さをざっとではありますが、ピックアップしてみました。
次回は、「Nuxt.js」で、サクッとSNSを作成でも書ければと思います。
ではでは。