ペイの技術MEMO

文系大学生の技術メモ

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通知を予定) スクリーンショット 2019-12-09 21.23.10.png

積みたい本気になる本をデータベースから検索している画面 スクリーンショット 2019-12-09 21.24.27.png

スマホ表示

スクリーンショット 2019-12-09 21.42.38.png

スクリーンショット 2019-12-09 21.44.12.png

使った技術

フロントエンド

インフラ

実装していて良かったこと

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


  1. 自分を含め大学生3人でwebサービスなどを開発しているチーム名twitter.comtwitter.comtwitter.com

VSCodeでESLintを使う

はじめに

VSCodeでjsやtsを書いていましたが、ESLintを無視して自動的に修正される謎現象に苛立っていたのでこの記事を書いています。

今回はVSCode上でESLintのルールに沿ったjsとVueファイルを自動的に修正することを目標にします。

VSCodeの設定

私のようになぜかESLintを無視して、自動的に修正されるようでしたらVSCodeをアンインストールしてください。私の場合ココを参考にしてVS Codeに関連する設定やキャッシュを削除したら謎現象は止まりました。

そしたら、VSCodeマーケットプレイスこれをインストールします。

ファイルを保存したらESLintの構文チェックが自動的に修正してほしいのでVSCodeのsettings.jsonで以下のように記述します。

{
    // 参考にさせていただきました。
    // https://qiita.com/moriyuu/items/6bac1c75c61d9d359f96
    // https://qiita.com/neuwell/items/27ea4efee9f67b33e053
    "eslint.autoFixOnSave": true,
    "files.associations": {
        "*.vue": "vue"
    },
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        {
        "language": "vue",
        "autoFix": true
        }
    ]
}

上記設定を書いたら、VSCodeを再起動

ESLintを使う

公式に書いていますが、グローバルにインストールすることは推奨されていません。なのでローカルにインストールします。

npm install eslint --save-dev

初期設定するためにinitします。設定について何回か質問されるので選択してください。

./node_modules/.bin/eslint --init

終わったら.eslintrc.jsが作成されていると思います。

ルールを記述する

ルールは先ほど作られた.eslintrc.jsのrules内に書いていきます。沢山のルールがあるので、とりあえず今回は文字列はシングルクォーテーションに、セミコロンは無しの設定を書きたいと思います。

"rules": {
  "semi": ["error", "never", {"beforeStatementContinuationChars": "never"}],
  "quotes": ["error", "single"]
}
  • semi,quotesはESLintのルールの名前
  • off,warn,errorの三段階エラーレベルがある

とりあえずここまで設定したら、js,Vueファイルで上記のルールに沿った自動修正がされると思います。

結構ざっくりの説明なのであとは公式さんみてください。

eslint.org

Ruby 配列,ブロック,範囲

配列

配列の宣言

a = [1,2,3]
a, b = [1,2] 
c, d = [10] #dはnilになる

要素に追加

a[1] = 20

末尾に追加

a << 10

要素の削除

a.delete_at(3)

引数で指定した文字を削除

a.delete(2)

ブロック

Rubyでは一般的に使われるfor文ではなくeachメソッドが使われる

number = [1,2,3,4]
sum = 0
number.each do |n|
  sum += n
end
 # sum=10

条件を指定して値を削除

a = [1,2,3,1,2,3]

# 戻り値が真になったら削除する
a.delete_if do |n|
  # odd?で奇数判定している
  n.odd?
end
# a = [2,2]

do...endではなく{}で囲める

numbers.each {|n| sum += n }

map

mapではブロックの戻り値で配列が作れる。空の配列を宣言して末尾に追加するなどの代わりに短くかける

numbers = [1,2,3,4,5]
new_numbers = numbers.map {|n| n*2 }

#new_numbers = [2,4,6,8,10]

select

戻り値が真の値だけで配列を作る

numbers = [1,2,3,4,5,6]
event_numbers = numbers.select {|n| n.even? }
# event_numbers = [2,4,6]

reject

戻り値が偽の値だけで配列を作る

numbers = [1,2,3,4,5,6]
non_multiples_of_three = numbers.reject {|n| n%3==0}
# event_numbers = [1,2,4,5]

find

戻り値が真になった最初の要素を返す

numbers = [1,2,3,4,5,6]
event_number = numbers.find { |n| n.even?}
# event_numbers = 2

inject

繰り返し計算する

numbers = [1,2,3,4]
# ループ処理1回目はinjectの引数0がresultに入り、numbersの1がnに入りresult + nの結果1がresultに入る
# ループ処理2回目はresultが上記の結果1、nが2
# その繰り返し
sum = numbers.inject(0) {|result, n| result + n}
# sum = 10

範囲オブジェクト

値の範囲を表す範囲オブジェクト

range = 1..10(1<=10)
range2 = 1...10(1<10)

文字列の範囲を取り出す

a = 'abcdefg'
a[1..3]
# bcd

配列の範囲を取り出す

a = [1,2,3,4,5]
a[1..3]
#2,3,4

配列に直す

a = (1..10).to_a

# 以下のような書き方もある
a [*1..10]

参考

https://www.amazon.co.jp/exec/obidos/ASIN/4774193976/junic05-22/

ScalaのOption

Optionとは

  • 値があるかもしれない時に使う
  • 実行時ではなくコンパイル時に気づける(エラーを型で表現するため)
  • 使用する際はOptionでラップした(Optionで囲う)メソッドなどを定義する

Optionの値

  • Option[A]は抽象クラス
  • Some[A]はOptionを継承したクラス
  • 値がある時はOptionインスタンス、ない時はNoneオブジェクトを返す

Optionの値を使う場合

  • getで取り出せるがNoneに対して取り出す場合例外になる
  • getOrElseを使うとNoneの時の対応ができる
  • foreachを使うとSomeの時にのみ実行してくれる
  • matchを使ってSomeとNoneに対しての処理を書く

Optionの変換

  • OptionのIntからStringに変換する場合はmapを使う(A => B)
Option(1).map(_.toString)

mapについての説明

  • mapは変換したい場合に使用される
  • _.hogeはi => iの簡略版
  • 下記は同義
Seq(1,2,3).map(_ * 2)
Seq(1,2,3).map(i => i*2)

PostgreSQL 基本操作

はじめに

最近HerokuとPostgreSQLの組み合わせを使うことが増えた気がするので基本的なcliの操作をまとめたいとおもいます。

環境

macOS Mojave (10.14.5)

install

brew install postgresql

起動

macを起動するたびに自動的にpostgresqlが起動する

brew services start postgresql

確認

起動状況を確認する

brew services list

停止

brew services stop postgresql

接続

ターミナル等からpostgresqlに接続します

psql -d postgres

psql の後にオプションをつけてログインします。

上記の場合だと -dpostgresというデータベースを指定します。

ログイン時のオプションは

-h, --host=ホスト名      データベースサーバーのホスト
-p, --port=ポート番号    データベースサーバーのポート番号(デフォルト: "5432")
-U, --username=ユーザー名  データベースのユーザ名(デフォルト: "postgres")
-w, --no-password        パスワード入力を要求しない
-W, --password           パスワードプロンプトを強制表示する

参照

psql内コマンド

psql内というのはログインした後の操作のことです。

postgresでログインしたらシェル上では以下のような形になると思います。

postgres=#

デーベース一覧

\l

ユーザー 一覧

\du

別のデータベースに接続

hogeに接続

\connect hoge

データベース作成

hogeという名前で作成

;最後につけてください

create database hoge;

データベース削除

hogeデータベースを削除

;同じく

drop database hoge;

postgresを抜ける

\q

さいごに

最近DB周りの勉強不足を痛感することが多々あるので、積極的に触っていこうと思います。

今回は必要最低限のコマンドしか紹介できなかったので、ロールの作成等の記事も書けたらと思います。

参照

PostgreSql コマンドの覚え書き - Qiita

PostgreSQLの使い方

Python3学び直してみる その3

Python3学び直してみる - ペイの技術MEMO

Python3学び直してみる その2 - ペイの技術MEMO

if文

if 条件式:
    print('True')
else:
    print('False')
  • pass文
    • 何も行わない文
    • if以外でも使える
    • 文が必要で何も行わない時に置く
if n > 0:
    print('hoge')
elif n == 0:
    pass
else:
    print('hogemaru')
論理型

論理型(bool型)はFalse,True

  • Falseの規則

    • 0
    • 0.0
    • None
    • 空の値
  • Trueの規則

    • 上記以外
論理演算子
and演算子

pythonの場合and演算子は左のオペンランドを比較してfalseなら右オペンランドを比較しない

左がFalseなら、その値を生成し、左がTrueなら右を評価し、値を生成。

  • 下記の場合
    • bが0ならcはfalse
    • bが0でないならcはaとbの剰余
c = b != 0 and a % b
or演算子

左がTrueなら、その値を生成し、左がFalseなら右を評価して、その値を生成。

  • 下記の場合
    • bが0なら評価終了
    • bが0でないなら右を評価
b == 0 or print('a // b =', a // b)
not演算子
  • 反転

条件演算子

x if y else z

Python3学び直してみる その2

前回の続きです。

peei.hatenablog.com

画面への表示

画面への表示はprint()関数を使用する

print('hello python')

改行しないで表示

print('hello', end='')
print('python')

空の行を表示

print('hello')
print()
print('python')

表示途中で改行する

print('比屋定\n真帆') #\nは改行文字のエスケープシーケンス

キーボードからの読み込み

キーボードから文字列を読み込むにはinput()関数を使用する

hoge = input() 
print(hoge)

表示させ、なおかつ、文字列受け取り

hoge = input('入力せい') 
print(hoge)

複数の文字列をスペースなしで表示するにはsep=''(+で連結するのでも可能)

hoge = input()
print('入力したもじは', hoge, 'です', sep='')

文字列から数値へ

数値へ変換するにはint()関数を使う

hoge = input()
print(int(hoge))

浮動小数点数へ変換するにはfloat()関数を使う

hoge = input() 
print(float(hoge))

読み込みと変換をまとめる

hoge = int(input())
print(hoge)

formatメソッド

文字列と整数は連結できないのでformatメソッドを使用します

文字列.format()

文字列には{}を書く必要があり、format関数内で{}に入る値を書きます

hoge = int(input())
print('受け取った数値は{}です'.format(hoge))

定数を表す変数

定数とはその名の通り、定まった数であるため、一箇所変更するだけど、その定数を書いている部分も変更されます。

そして定数を表す変数は大文字と下線記号(_)で表記するのが慣習です。