Nuxtjsでプロダクトを開発して得た知見

米川桂氏:はじめまして。株式会社ITプロパートナーズの米川と申します。本日はNuxt.jsを使ってプロダクト開発して得た知見等を発表していきたいと思っています。

今日のアジェンダなんですが、簡単に自己紹介したあと、Nuxt.jsを導入したことによるメリット・デメリット、あとはNuxt.jsを作って工夫した点やまとめ等を発表していきます。

まず自己紹介なんですけど、名前は米川と申します。所属は株式会社ITプロパートナーズになりまして、エンジニアをやってます。

もともと新卒で入社した会社が金融系のSIerで、主に上流工程に携わっていました。その後、SESに転向して、JavaとかSpring Bootとか使って、競馬のポータルサイトといったWebアプリの開発を経験してきました。

去年の4月にITプロパートナーズとご縁があって、いまはフロントエンドをNuxt.js、サーバーサイドをLaravel使用して、自社サービスの「Graspy」を開発しています。

簡単にGraspyの説明なのですが、Graspyは「学び」と「出会い」を作り出すキャリア形成プラットフォームになります。

具体的に何ができるのかというと、ユーザーは新規会員登録後、企業が掲載している求人に応募、企業からスカウトを受け取ることができるいわゆる転職サイトです。ただ、普通の転職サイトと違って、オンラインでプログラミング学習ができたり、あとは著名人の方が主催する勉強会にも参加できます。

このような点から、Graspyは「学び」と「出会い」をユーザーに提供していくサービスになっております。

現在プログラミングのカリキュラムは、HTML/CSS、JavaScript、Ruby on Rails、AI、UI designのカリキュラムを無料で提供しています。もし興味ある方がいらっしゃいましたら、登録してみてください。

そんなGraspyですが、去年の8月にβ版をリリースしました。12月に正式リリースし、現在の登録者数は9,000名以上になっています。あとは日経MJっていう新聞にも掲載されたりしています。

転職を考えている人も、転職を考えてない人も、もし興味がある方がいらっしゃいましたら、ぜひご登録をお願いいたします!

Nuxt.jsを導入したメリット

こちらから技術的な話になるんですけど、Graspyのサーバー構成はこちらのスライドのとおりになっていて、フロントはNuxt.js、サーバーサイドはLaravelでAPIとして使っています。

開発体制は、現在社員3名と業務委託4名、計7名で開発しています。

うちデザイナー2名で、エンジニアはフロントとサーバーサイド隔てなく、フロントとサーバサイド両方に携わって開発しています。

続いて、Nuxt.jsを導入したことによるメリットです。技術的メリットはさっきのリビルドさんと少し被っちゃっているのですが、実際私も開発していて思ったのが、規約による開発の生産性向上になります。

具体的にどういったことかというと、ディレクトリ構成とか設計がしっかりしていて、その規約に沿ってコードを記述することで、複数人で開発していてもファイルが散らばらない。あと、技術的負債になりにくいといったことが、私自身実装してみて感じました。かといって、ガチガチに制約が厳しいというわけではないです。

storeディレクトリに配置したファイルが自動的にVuexとして読み込まれたり、あとはpagesディレクトリに*.vueファイルを配置することで、自動でルーティングの定義をしてくれる。あとは、middlewareとして読み込むファイルはmiddlewareディレクトリ直下に置かないといけない、といった規約があります。

続いて技術的メリットの2つ目として、middlewareの機能になります。

middlewareはページの最初に読み込まれて、SSR処理などが行われる前に処理が実行されます。例えば認証許可が必要なページだったり、ログイン後のリダイレクトパスを保存するといった設定が容易にできます。

middlewareには2種類ありまして、自動のmiddlewareと手動のmiddlewareがあります。

自動のmiddlewareに関しては、nuxt.config.jsにmiddlewareプロパティに記載することで、すべてのページで有効になるmiddlewareを設定できます。手動のmiddlewareに関しては、各ページでmiddlewareを定義することによって、ページ単体で適用されるmiddlewareを作ることができます。

具体的にどういったものを作ったかというと、認証が必要なページにつけるmiddlewareで、authRedirect.jsっていうのを作ってみました。

cookieからauthTokenを取ってきて、authTokenが存在していればそのまま処理を実行して、authUserのVuexのisLoginっていうのをtrueにして処理を継続してます。もし存在しなかったらunAuthorizationっていうエラーをスローして、VuexのisLoginをfalseにして、/loginにリダイレクトします。

こういったmiddlewareとかも簡単に設定できるっていうのがメリットだと私は感じています。

あとは、setPath.jsっていうのも作ってみました。

これはアクセスしたページのURLをcookieに保存してるだけなのですが、ログイン処理後にログイン画面にリダイレクトされる直前のURLに遷移させたい場合とか、もしリダイレクトパスが存在していれば、ログイン後そちらのパスに遷移させたくこのようなmiddlewareを作ってみました。

技術以外のメリットと、導入のデメリット

続いて技術以外のメリットなんですが、1つ目は技術ブランディングの向上になります。

昨年、「VueFesJapan2018」というイベントがあったのですが、行った方はいらっしゃいますか?

(会場挙手)

あ、けっこういますね。ITプロパートナーズはゴールドスポンサーとして協賛し、Graspyのブースを出展してました。

このように、Nuxt.jsを導入して、こういったVueFesJapanとかゴールドスポンサーに協賛することによって、社内でモダンな技術を取り入れて開発してるということの技術的なブランディングにもつながっています。

それによってNuxt.jsとかLaravelで開発したいエンジニアから、応募が来ることが多くなり、エンジニア採用にもつながっています。

簡単にまとめると、技術的メリットに関しては、規約による開発の生産性向上とmiddleware機能。技術以外のメリットに関しては、会社の技術ブランディングの向上やエンジニアの採用にもつながっているっていうのが、メリットだと感じています。

続いてNuxt.jsを導入したことによるデメリットなんですが、特段そこまで強いて言うものがなかったです。

挙げるとすると、けっこうSSRのときだけとか、SPAのときだけ、よくわからないバグが発生したり、asyncDataが2回呼ばれてしまうとかがあったりしました。あと、リロードしたときに発生するバグとかもあったりして、テスト工数が少し増えたなとか。あとは、なんだかんだVue.jsの学習コストもあったり、不具合とかあったときも、Nuxtの情報がまだちょっと少ないなっていうふうに感じています。

プロダクト開発において工夫したこと

続いて、工夫した点を発表します。

工夫した点なんですが、GraspyはPCとSP版でデザインが大きく異なり、PCとSP版でcomponentを分けました。具体的にどのようにしたかというと、componentのディレクトリのパスを引数に受け取るmixinsを作りました。

mixinsのなかでasyncDataを呼び、そのasyncData内でデバイスの判定を行い、SPのcomponetを使うのかPCのcomponentを使うのかを出し分けて、元のpagesのディレクトリに返すというのをやってました。

componentのディレクトリの下は、component/pages。変数のところがcomponent直下のパスになります。

具体的に呼び出し方はどうやってたかっていうと、pages直下のディレクトリの各Vueファイルに、先ほど作ったmixinsを指定します。それで、mixinsはasyncDataに返却されたcomponentを、PCかSPのcomponentかを動的に切り替えることをGraspyの開発ではやりました。

mixinsでasyncDataは基本呼べないんですけど、それを呼べるようにするためにnuxtendっていうライブラリを使用しました。nuxtendを使えば、mixinsのなかでもasyncDataを呼べるようになります。使うためには、nuxtendをインポートして、nuxtendでcomponent自体をwrapするみたいな感じになります。

なので、Graspyのpagesディレクトリ直下のVueファイルは、全部これだけの記述になっていて、componentディレクトリのなかでPCとSPを動的にcomponentを切り替えるような感じの構成になっています。

クライアント側とサーバー側でCookieのライブラリを分けた

工夫した点の2つ目なんですけど、クライアント側とサーバー側でcookieのライブラリを分けました。

クライアント側に関してはuniversal-cookieっていうcookieのライブラリを使用して、サーバー側に関してはcookie-universal-nuxtっていうライブラリを使用しました。

これはけっこう賛否両論あって、「なんで分けたのか?」っていう話なんですけど、結論から言うと、クライアント側はuniversal-cookieのほうが使い勝手がいい、サーバー側に関してはcookie-universal-nuxtのほうが使い勝手がいいからになります。

それぞれのライブラリの特徴なんですけど、universal-cookieの特徴は、new Cookiesみたいな書き方で、クライアントのcookieをどこのコードでも取得できるっていうのがメリットです。cookie-universal-nuxtに関しては、app.$cookiesみたいな感じで、Vueのcomponentを必ず経由するかたちで取得できます。

それぞれの特性を踏まえて、クライアント側はappっていうのをけっこうコンテキストで渡していくのが大変で、Vuexのactionとか深いところで使う場合とかコンテキストを引数で渡していくのがすごい大変です。クライアント側はappを渡さずに、cookieのインスタンスを作れるuniversal-cookieというのを使っています。

サーバー側に関しては、サーバー側でcookieを取得してくるには、必ずapp、Vueのcomponentが必要になるので、app経由で取得できるcookie-universal-nuxtを使ったほうがいいと思っています。例えばnew Cookie().get(’XX')みたいな感じで、サーバー側でこのような間違いを防げるのがメリットで、それぞれの観点から、各ライブラリの長所を採用するようにしました。

使い分け方

実際にどのように使い分けたかっていうと、servicesのディレクトリにcookie.jsっていうcookieのライブラリのラッパークラスを作りました。

ClientCookiesのほうはnew Cookiesみたいな感じで明示的にわかるようにして、SSRCookiesのほうは、cookie-universal-nuxtを使っているので、app.$cookiesみたいな感じでexportをしてます。

利用する側なんですが、serviceからimportするときに、明示的に両者を使い分けるようにしました。process.serverで、サーバー側に関してはSSRCookiesを使用して、クライアント側はClientCookiesみたいな感じです。

このようにすることで、サーバー側なのかクライアント側なのか、どちらのcookieを使ってるのかわかるように、明示的にしてます。

工夫したことのまとめなんですが、1つ目がnuxtendを使用して、mixinのasyncData内でデバイス判定して、動的にcomponentの切り替えを行ったこと。あとは、クライアント側とサーバー側で使用するcookieのライブラリを分けて、明示的に使い分けるようにしたっていう点です。

最後に、弊社もまだ4年目の会社で、スタートアップの開発スピード重視のフェーズでNuxtを導入した結果、componentの再利用だったりとかNuxtの規約によって、複数人で開発していてもファイルやディレクトリが散らばらなかったり、技術的負債が生まれにくいといったことや、コミュニケーションコストも減って開発スピードも上がるといったメリットを感じています。

あと、「学習コストが低い」って言われるけど、なんだかんだ理解しないといけないことが多いと思っており、特にVueのライフサイクルとNuxtのライフサイクルは、けっこう開発をしていて何回も見直したりしました。

弊社はNuxt(Vue.js)とLaravelでエンジニア主体にモダンな開発をしております。もしNuxtやLaravelで開発したいエンジニアの方がいらっしゃれば、お声をかけ頂ければと思います。ご清聴ありがとうございました!

(会場拍手)