Nuxt.js + firebaseで「積ん読防止」アプリを作ってみた
この記事は「JX通信社Advent Calendar 2019」の14日目の記事です。
はじめに
こんにちは。JX通信社でエンジニアインターンシップをしているペイと申します。
1ヶ月ほど前からKI-develop1で積ん読を防止できるアプリBookMotionを開発しています。
今回はBookMotionでWebフロントとfirebaseを担当したので作っていて良かったこと(主にWebフロント)など紹介できればと思います。
開発環境や具体的なコードの記述はないので知らなかったことが知れると思ってお読みください。
作ったもの
ランディングページ / BookMotion WEB(β版)
BookMotionは積ん読を防止する為に、読みたい本を簡単に登録、
読書のモチベーションを維持することできるようになっているアプリです。
特にエンジニアの方は,技術書を沢山積んでいるのではないでしょうか?
BookMotionはweb版でβ版として一般公開, iOS, Androidは準備中です。
WEB版の様子
積み本のリストを表示している画面。
読書開始日、読書終了予定日を設定することができます。(モバイル版ではpush通知を予定)
積みたい本、気になる本をデータベースから検索している画面
スマホ表示
使った技術
フロントエンド
Nuxt.js (v2.9.2)
- Vueのフレームワーク
- 今回はSPAモードで使用
TypeScript(vue-property-decorator)
- VueをTypeScriptで書くためにvue-property-decorator使用
Atomic Design
- iView UI
- UIフレームワーク
- JX通信社Advent Calendar 2019 7日目の記事 で 渡辺さんが紹介しています。
インフラ
- Firebase Authentication
- 認証に使用
- Cloud Firestore
- クラウドホストの NoSQL データベース
- 登録した本のデータなどを保存する際に使用
- Cloud Functions for Firebase
- OCRから本のタイトル等を抽出しオーバーレイした画像を返す
- Slackに利用額を通知する際に使用
- Google Cloud Vision API
- 本のタイトルなどを検出・抽出する際に使用
実装していて良かったこと
Nuxt(SPA)のここが良い
前提: SPAモードで実装した場合の話をしています。
1. middlewareが便利
Vueを触っている人なら一度は見たことがある、ライフサイクルの図があると思います。
vueではインスタンスが生成されてからDOMが構築されるまでに順序があります。
例えば頻繁に使用される、createdはインスタンスが生成された後に実行される為、コンポーネントが呼ばれて最初に走らせたい処理などを呼ぶことができます。
しかし、インスタンスが生成されてから、API等でサーバーにリクエストする時、ログインの情報からドメインとなる情報まで複数持ってくるのは難しいです。
キャッシュさせたり、ローカルストレージに保存する方法などもあると思いますが、ブラウザ上でデータを持っておくのはあまり好ましくなかったりします。
そこでコンポーネントが呼ばれる(インスタンスが生成される)前にミドルウェアを挟んで、そこでログインの状態などがわかると便利じゃないですか?()
Nuxt.jsではmiddleware が使えます。実装の方法によっては本当に便利です。
実装
middlewareの処理を書く
middlewareディレクトリの配下に任意のファイルを作成
今回はauthenticated.js
というファイルで作成する
export default function({ route, redirect, store }) { /** 任意の処理 route.nameでpathを取得できる store.state.hoge のようにvuexにアクセス可能 redirect('/login')でリダイレクトしてくれる */ }
nuxt.config.jsにmiddlewareの名前追加する
middleware/authenticated.jsというファイル名の場合は、以下のように記述します。
authenticatedはミドルウェアのファイル名によって変わるので適宜変更してください。
export default { mode: 'spa', // ~省略~ router: { middleware: ['authenticated'] } }
firebaseでのログインを実装する場合は以下の記述で現在ログインしているユーザーを取得することができるので実装の方法によってはミドルウェアに挟めてログインの状態を各ページが呼ばれる前に確認することができます。
import { auth } from '~/plugins/firebase' auth.onAuthStateChanged((user) => {})
2. pluginを使ってモジュールを呼び出せる
NuxtのpluginはNuxt.jsで作っているインスタンスが生成される前に呼ばれるので外部モジュールなどを呼ぶ時に便利です。
上記で紹介したmiddlewareは各ページが呼ばれる前に実行したい関数がある場合などが適していますが、
pluginはルートのアプリケーションがインスタンス化される前に実行されるのでページ転移する度に関数を実行したいという時には適していません。
例えばfirebaseのイニシャライズ処理をしたい時などにおすすめです。
import * as firebase from 'firebase/app' import config from '~/firebase.config' if (!firebase.apps.length) { firebase.initializeApp(config) } export const auth = firebase.auth()
また、全てのVueコンポーネントで特定の関数を使用することができます。 下記はインスタンスへ注入する場合です。
import Vue from 'vue' Vue.prototype.$hoge = foo => console.log(foo)
export default { mounted () { this.$hoge('hello') } }
またNuxtにはInject
という機能があり、共通の関数を定義することができます。
Injectを使ってDIをしている方の記事も上がっているので興味がある方は調べてみてください。
vue-property-decoratorを使ってコードを見やすく
VueをTypeScriptで書く為のライブラリです。
jsで書くVueでは、Propsなどを除いて型安全ではないで今回使いました。
また、素のVueは,
カンマが多く登場するので、コードの見通してもよくありません。
以下jsで書いた場合
export default { data: () => ({ hoge: false, }), computed: { foo: { get() { return ['menu-icon', this.hoge ? 'rotate-icon' : ''] } }, }, created() { this.hoge2() }, methods: { bar() { this.$refs.foo2 } } }
以下はvue-property-decoratorを使って上記のコードをリファクタしたコードになります。
<script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator' @Component export default class Index extends Vue { hoge: boolean = false get foo(): Array<string> { return ['menu-icon', this.hoge ? 'rotate-icon' : ''] } created() { this.hoge2() } bar(): void { this.$refs.foo2 } }
無駄な,
がなく、スッキリしたコードになりました。また、戻り値を書くことで型安全になりました。
特にAPIを叩いてデータを流し込む際は型がないと、正しい値を入っていると保証できないので、型をしっかり定義してあげることは重要です...
詳しい書き方はvue-property-decoratorで調べると記事が結構出てくるので調べてみてください。
Firebase UIで認証の見た目を実装
今回はログイン認証をFirebase Authenticationを使って実装しました。
Vueで実装する場合はとても簡単でFirebase UIのプラグインを読み込んで,インスタンスを生成したらtemplate内のタグに埋め込むだけで使用できます。
公式のページを読むだけで実装できたので、機能の開発に集中したい時や、ログインの実装を任せたい時はおすすめです。
現状の課題
Atomic Designの粒度があっているのか分からない。
現状Atomic Designもどきで実装しています。
Atomic Designは機能によって粒度を分けるのですが、moleculesとorganismsの境目が本当に正しいのかどうか、
再利用性の低いコンポーネントをわざわざmoleculesに分ける必要があるのか、
など気になる点が多くあり、今後の課題です。
今後について
webフロントでは実装が増えるごとに手動でのデザインの確認やロジックの確認をすることに限界を感じているのでそろそろテスト導入していかないといけないなーって感じています。
また、コンポーネントが増える毎に自分が実装したAtomic Designに幻滅するのでリファクタを重ねていかないとなーって感じです。
さいごに
firebaseを使うことで、各自メインの機能を作ることに集中できました。
Firestoreのデータモデルに最初は苦戦しましたが使ってみるとRDBより楽なのでは?と感じたりもするの色々触ってみるのも大事だなと感じました。
BookMotionはweb版でβ版として一般公開, iOS, Androidは準備中なので、積ん読しちゃっている人は是非使ってみてください!!
参考文献
https://blog.shimar.me/2018/03/31/nuxt-firebase-authentication.html
https://tech.cydas.com/entry/nuxt-inject
https://qiita.com/ryo2132/items/4d43209ea89ad1297426
-
自分を含め大学生3人でwebサービスなどを開発しているチーム名twitter.comtwitter.comtwitter.com↩