LiBz Tech Blog

LiBの開発者ブログ

真のフロントエンドエンジニアになるために、まずはNuxt.js + Firebaseを使って簡易メモ帳を作ってみた

目次

はじめに

こんにちは!
11月にLiBに入社したアベと申します。
アラサー子持ちのエンジニア(エンジニアと名乗るのは憚れる...)です。

社会人3年目からWebの世界へ転身し、webデザイン、コーディング、wordpress、ちょっとバッグエンドやったりと、
器用貧乏な状態です(実際は器用ではなく広く浅くやってる感じ)。

転職する際、フロントエンドエンジニアとして動いていたのですが、
とある企業からは「jsフレームワークやっていないとフロントエンドエンジニアとしての技術が低い」と言われ、
jsフレームワークを経験していないとフロントエンドエンジニアと名乗ってはいけないのか...と思った次第です。

趣味でやっていたものの、業務では経験がなかったので、
LiBでは積極的にjsフレームワークを使用して行きたいと思い、
まずはvue/nuxt.jsでメモ帳を作ってみましたのでそれを晒します(でもまだ途中...)

前提条件

  • node インストール済み(brewでのインストールが望ましい)
  • vue.jsがどんなものか知っている
  • 黒い画面(ターミナル)がほんの少し使える
  • npmを使用

Nuxtってなに?

Vueアプリケーションを作成するフレームワークです。
サーバーサイドレンダリング、SPA、静的ファイルの生成等で作成することができます。
Vue-Router,Vuex,vue-loader等も入っているのでvueで使うようなモジュールがすでに組み込まれているという認識で問題ないかと思います。webpackbabelも含まれています。

環境構築も特に必要はなく、後述するnuxtのコマンドで一発でOKです。

個人的に楽に感じたのはルーティングの設定をこちらでする必要がないという点ですね〜
pageフォルダにファイルを追加していけば勝手にルーティングを設定してくれます。

https://ja.nuxtjs.org/

Nuxtの主な機能

公式サイトからまま引用います。

Vue ファイルで記述できること(*.vue)
コードを自動的に分割すること
サーバーサイドレンダリング
非同期データをハンドリングするパワフルなルーティング
静的ファイルの配信
ES6/ES7 のトランスパイレーション
JS と CSS のバンドル及びミニファイ化
head要素(title、meta など)の管理
開発モードにおけるホットリローディング
プリプロセッサ: Sass, Less, Stylus など
HTTP/2 push headers ready
モジュール構造で拡張できること

はじめに - Nuxt.js

Nuxt.jsやってみる

Nuxt.jsのインストール

まずはNuxt.jsをインストールします。 ターミナルにて、

$ npm install -g create-nuxt-app

Nuxt.jsでアプリ作成

自分がNuxtのアプリを作成したいディレクトリに移動して以下を実行します。

$ create-nuxt-app appName

なんかいろいろ聞かれるので以下のように答えます。

f:id:ab_y:20181113162019p:plain

これで少しまてば初期設定状態のアプリが作成されました。
下の方に以下のような表示がされてるはずですが、
こちら後ほど使用しますので頭の片隅に入れておいてください。

f:id:ab_y:20181113162143p:plain

さきほど、アプリ作成の時に、

Use a custom UI frameworkelement-ui
Use axios moduleyes

と選択していますが、

element-uiは、 UIライブラリーで、CSSやJS(モーダル,ツールチップ等々)が用意されています。
結構綺麗に作れるのでオススメで今回のアプリでも使用しています。

axiosは、いわゆるAPIをajax通信で使用するためのライブラリみたいな認識で良いかと思います。
(jQueryのajax,getJsonとかその辺の代わりです)
今回はfirebaseを使用していますのでそのデータの扱いのためaxiosを使用するためyesとしました。

nuxt.config.jsによる設定いろいろ

nuxt.config.jsが直下にあると思いますのでまずはそれをみてみましょう。

const pkg = require('./package')

module.exports = {
  mode: 'spa',

  /*
  ** Headers of the page
  */
  head: {
    title: pkg.name,
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: pkg.description }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

  /*
  ** Customize the progress-bar color
  */
  loading: { color: '#fff' },

  /*
  ** Global CSS
  */
  css: [
    'element-ui/lib/theme-chalk/index.css'
  ],

  /*
  ** Plugins to load before mounting the App
  */
  plugins: [
    '@/plugins/element-ui'
  ],

  /*
  ** Nuxt.js modules
  */
  modules: [
    // Doc: https://github.com/nuxt-community/axios-module#usage
    '@nuxtjs/axios'
  ],
  /*
  ** Axios module configuration
  */
  axios: {
    // See https://github.com/nuxt-community/axios-module#options
  },

  /*
  ** Build configuration
  */
  build: {
    /*
    ** You can extend webpack config here
    */
    extend(config, ctx) {
      
    }
  }
}

element-uiがpluginsとcssに、
axiosがmodulesに記述されていますね。(axiosという項目もありますがこれは後述します)

cssの'element-ui/lib/theme-chalk/index.css'は、node_moduleフォルダの中にあります。
pluginsの'@/plugins/element-ui'はappName直下のpluginsにjsがありそこからさらに必要なファイルを読み込んでいます。

@は、ソースディレクトリを指しており、今回でいえばappNameまでになります。
ですので、'@/plugins/element-ui'は'appName/plugins/element-ui.js'ということになります。

ちなみにpluginには外部のjsプラグインや自作のプラグインを読み込む時に書きます。
modulesは公式サイトではシンプルな関数とありますが、 個人的にはNuxt側ですでに用意してあるモジュールを使用する時にここに記述するというイメージです。

headtitle部分は、package.jsonの"name"を参照しており、
変更したい場合はpackage.jsonの"name"を変更するのではなく、 pkg.nameを変更してください。
meta部分でdescription,keywordを追加したり、
link部分で,googleフォントとかを読み込んだりすることができます。

Nuxtの構成

  • pages
    ビュー及びルーティングファイルを入れます。 ここにファイルを入れると自動的にルーティングが作られます。
    ルールはこちら

  • layouts
    アプリケーションのレイアウトファイルを入れます。 初期でdefault.vueが入っており、大きくレイアウトを変更する場合は別に作った方が良いです。

  • components
    Vueのコンポーネントファイルを入れます。
    (header.vue,footer.vueなど汎用的に使えるコンポーネント)

  • assets
    cssやjs,images等のファイルを入れます

  • middleware
    アプリケーションのミドルウェアを入れます。
    ミドルウェアを使って、ページやページグループ(レイアウト)をレンダリングするよりも前に実行される処理をしたい時に使います。
    (例:ユーザーがログイン中か否かを確認)

  • plugins
    ルートの Vue.js アプリケーションをインスタンス化する前に実行したい JavaScript プラグインを入れます。
    (公式サイトの文のままです)

  • static
    静的ファイルを入れます。デフォルトでicoファイルが入っており、robot.txt等を入れたりするそうです。

  • store
    Vuex ストアを実行させるためのファイルを入れます。
    基本はindex.jsを入れることから始まり、規模が大きくなってきたら別々のファイルに分離していく形になります。

Nuxtでアプリ実行

ながながとつまらない説明をしてきてしまいましたが、
Nuxtを実行しブラウザで確認してみましょう!

$ cd appName  //appNameディレクトリに移動
$ npm run dev

localhost:3000で開きます。
(他の件で3000を使用している場合は開けないのでご注意ください)
(エラーがおきてしまう場合は、nodeを最新状態にしてみてください)

以下のような画面で表示されたらOKです!

f:id:ab_y:20181113173228p:plain

結局、4行ぐらいの実行で初期状態の表示をすることができましたね。
素晴らしいですね、Nuxt.js。
あとは自由にアプリを作るのみです。

ポート(3000の部分)を変更したい場合

3000はよく被るので変更したいという場合は、
package.jsonに、下記を追加すればOKです。
(scriptの上あたりで良いです)

"config": {
    "nuxt": {
      "host": "0.0.0.0",
      "port": "3333"
    }
},

これでlocalhost:3333で表示できます。

アプリの説明/解説

今回作成した簡易メモ帳の制作背景としては、
なにか調べていたり、コードをちょっと保存し、その後にまとめたりする必要がある時に、
とりあえず記述できるものが欲しいと思ったのがきっかけです。
後々共有するためにmarkdownで記載する必要があるのでその機能だけはつけようと思って作っていたら、
どんどんいろいろつけたくなったという感じです。

大まかな機能/概要は以下になります。

  • markdown記述(highlight.js)
  • Googleログイン
  • firebaseへ保存(ログインしていないとlocalstorage)
  • jsonダウンロード
  • element使用

作成アプリはこちら

(googleアカウントでログインできますが、情報を知ってしまいますのでログインオススメはしません)

レイアウト・コンポーネントの作成

実際に作成したファイルをgistから貼ります。

その前に、nuxt.config.jsを貼ります。
(余計なコメントは消してます)

追加したのは、
google fontと、
highlightのためのcss、
axiosのベースとなるURLです。

レイアウト(layouts)

default.vue

<template>
  <div>
    <nuxt />
  </div>
</template>

ページ(pages)

今回UIを作るのに、element-uiを使用しています。

Element

el-から始まるタグを使用することでそれに対応したhtmlを生成してくれます。
cssを追加したい場合はインラインで追記することができます。
最初(というか今でも)は公式サイトとにらめっこしながら作ることになると思いますが、
例がけっこうあるのですぐ慣れると思います。

コンポーネント(components)

コンポーネントはもっと分解できると思いますが、
今回はモーダルを一緒にしてしまいました。

edit.vueの中で、 marked,highlight.jsのプラグインを読み込んでいるので、 npmでインストールしておきます。

$ npm install marked highlight.js

markdownのcssは、下記から拝借させていただきました。

github.com

データの扱い/保存

今回のメモ帳では、 firebaseでデータを保存し、そのデータを主にVuexで扱っています。

firebase

firebaseはmBaaSと呼ばれるバックエンドのサービスで、
データベース、ホスティング、ストレージ、認証機能、等々様々な機能があります。

今回はデータベース(Realtime Database)、認証機能を利用しています。
僕みたいなバックエンドようわからんというフロントの方々からすると、
DB用意する必要もないうえに、
json形式で保存でき、取得できるので非常にやりやすいです。
まだまだ実案件として使用されることはあまりないですが、
ちょっと試しに作ってみるという点では非常にオススメです。 (試し程度であれば無料プランで十分いけます)

firebase.google.com

firebaseでdatabase作成

Googleアカウントを持っていればそれでログインをして、
「コンソールへ移動」で移動します。

f:id:ab_y:20181114151500p:plain
こんな画面が表示されるので、
「プロジェクトを追加」をクリックしてください。

そうすると、ポップアップが表示されるので、
プロジェクト名を任意のものにして作成してください。 f:id:ab_y:20181114151632p:plain

作成すると、そのプロジェクトの管理画面に入ります。
サイドメニューの開発 > Database でスクロールすると以下のように
Realtime Databaseのデータベースを作成するボタンが出てきます。

f:id:ab_y:20181114151845p:plain

クリックするとセキュリティルールを聞かれるので、
取り急ぎテストモードで開始してください。

f:id:ab_y:20181114152405p:plain

作成できたら以下のような画面に遷移します。

f:id:ab_y:20181114152511p:plain

firebaseには独自のタグ、関数があるのでそれを利用することで
データを登録、取得することができますが、
今回は今後を鑑みてそれを使わずにaxiosでAPIとして扱うようにしました。

nuxt.config.jsaxiosの箇所に、先ほどの画面で発行されているURLを記述します。

また、firebaseをプラグインとして使用するので、
plugins配下にfirebase.jsを作成し、下記のように記述します。

import firebase from 'firebase'

if (!firebase.apps.length) {
  firebase.initializeApp({
    apiKey: "xxxxxxxxxxxxxxxxxxxx",
    authDomain: "xxxxxxxxxxxxxxxxxxxx",
    databaseURL: "xxxxxxxxxxxxxxxxxxxx",
    projectId: "xxxxxxxxxxxxxxxxxxxx",
    storageBucket: "xxxxxxxxxxxxxxxxxxxx",
    messagingSenderId: "xxxxxxxxxxxxxxxxxxxx"
  })
}

export default firebase

xxxxxxxxxxxxxxxxxxxxの部分は、

以下の画面のようにfirebaseの管理画面の設定 > 全般に行き、 f:id:ab_y:20181114154507p:plain

「ウェブアプリに Firebase を追加」をクリックすると、 それぞれ情報が表示されるのでコピペしてください。

f:id:ab_y:20181114155350p:plain

firebaseで認証設定

firebaseでは認証機能を簡単に実装できるAuthenticationがあります。
メールでのログインをはじめ、Google,facebook,Twitter等のアカウントも扱うことができます。

今回は、Googleでアカウントでログインできるようにしているので、
設定をする必要があります。

管理画面のAuthentication > ログイン方法にする進み、 Googleの箇所を有効にします。(メールアドレスを設定するだけでOK!)

以下の画面のように有効になったらOKです! f:id:ab_y:20181114193223p:plain

store(Vuex)

Vuex は「Vue.js アプリケーションのための 状態管理パターン + ライブラリ」ということで、Fluxという概念のvue版みたいな感じです。 基本、親子のコンポーネントだと値を引き継がせるのですが、
あまりにもコンポーネントが多くなると複雑でわけわからなくなるので、
どこかで管理しようというのが狙いです。 Vuexの場合その管理する場所がstoreになります。

多くのコンポーネント、ページで使われるデータ(今回はメモ情報とユーザー情報)は、
storeで管理するのが良いです。

この状態管理の概念は僕もはっきりとは理解できていないのですが、 適切な管理をすることにより、適切な構造、保守性が担保されるとのことです。 概念としては、以下の図のようになります。

f:id:ab_y:20181114160708p:plain
引用:Vuex とは何か? | Vuex

今回のメモ帳ではvuex使わなくても実装できるかと思いますが、
試しに使用してみました。

index.jsを作成します。

state(ステート)
上述してあるstoreで管理すると言っていた情報が、ここのステートにあります。
アプリで共通で持たせたい情報がここにすべて集約しているというイメージです。

mutations(ミューテーション)
Vuex のストアの状態を変更できる唯一の方法は、ミューテーションをコミットすることで、
ミューテーションはコンポーネントから呼び出すことはできず、アクションからのみの呼び出しになります。
また、非同期処理をすることも禁じられています。

actions(アクション)
アクションは、状態を変更するのではなく、ミューテーションをコミットします。
ミューテーションとは違い、任意の非同期処理を含むことができます。

コンポーネントから受けた値を加工してミューテーションに投げるみたいな認識かと思います。

今回では、ユーザーのログイン有無により、firebaseかlocalstorageを分けています。

コンポーネントからアクションを呼び出す方法

this.$store.dispatch('xxxxxxxx',値);
//例
this.$store.dispatch('init');
this.$store.dispatch('editMemo',this.memos[this.memoIndex]);

getters(ゲッター)
stateのデータを変更(フィルタリング,カウント)して取得したい場合、ゲッターを利用します。 今回ではメモ情報がステートにfirebaseで取得したデータが入っているので、
ログイン中のユーザーの情報にフィルタリングしています。

コンポーネントからゲッターを呼び出す方法

this.$store.getters.xxxxxxxx
//例
this.$store.getters.memos
this.$store.getters.user

デバッグ

vueもそうですが、vuexになると、処理が実行されているか、値はどう変化しているか等はわからないので、 Chromeの拡張機能で便利なデバッガーがあります。

chrome.google.com

通常のディペロッパーツールを開き直す(Chromeも再起動)と、vueというタブが追加されてるので、 こちらで以下のように確認することができます。

f:id:ab_y:20181115094654p:plain

ビルド

アプリが完成した、もしくはどこかにアップしたいと思ったらビルドしてみましょう。

通常のビルドは以下になります。

$ npm run build

//これだと静的ファイルが生成されるとのことだがあまり違いがわからない...
$ npm run generate

するとdistというフォルダにファイル等が生成されます。

f:id:ab_y:20181114164945p:plain ※上記は初期状態のアプリをビルドした場合です。

これをどこかのサーバーにアップするだけで、
表示することができます。 (index.htmlのそれぞれのリンクがルートパスになっているので注意してください) 今回はherokuにアップしてみたいと思います!

herokuにデプロイ

昔からよくheroku,herokuと聞いてきたのですが、一度も利用したことがありませんでした。 なので今回試しということでherokuを利用してみました。

jp.heroku.com

herokuアカウントを作成したら、 ターミナルでデプロイするために、 CLIをダウンロードします。

The Heroku CLI | Heroku Dev Center

Macであれば以下コマンドでもインストールできます。

$ brew install heroku/brew/heroku

インストールができたら

//アプリのディレクトリに移動し
$ heroku login

//herokuのプロジェクト作成、appNameは任意です(管理画面でもできます)
$ heroku create appName

//Nuxt.jsの場合以下が必要
$ heroku config:set NPM_CONFIG_PRODUCTION=false
$ heroku config:set HOST=0.0.0.0
$ heroku config:set NODE_ENV=production

package.json にheroku-postbuildを追記

"scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "heroku-postbuild": "npm run build"
  },

最後に以下のコマンドを実行していきます。

$ git add .
$ git commit -am "何かしらのコメント"
$ git push heroku master

これでデプロイ完了です!

以下を実行すると、ブラウザで開いてくれます。

$ heroku open

やってみて

  • すぐ環境諸々作れるのが素晴らしい
  • コンポーネントでhtml,js,css完結できるの素晴らしすぎる
  • ただコンポーネントが多すぎると受け渡し面倒くさそう(多いようならvuexで管理した方が良さそう)
  • とはいえまだコンポーネントに切り分けるの慣れない...
  • インラインでcss書くのは今までNGだったがvueでならありと感じてしまった
  • セミコロンつけたりつけなかったりがひどい
  • 必要ない処理をすぐ消さないと残りがち(今もあると思います)

Nuxt/Vueにまだ慣れておらず、Vuexの扱い方、コンポーネント間の受け渡しがおかしいところもあると思います。 その際は優しく教えていただけると幸いです。

真のフロントエンドを目指して、 次はReactに挑戦してみたいと思います...