はじめまして、ゆと(@utoc11)と申します。
普段はPdM(プロダクトマネージャー)が本業なのですが、自分でも創れるようになりたい! そんな思いでプログラミングを学びはじめ、小さくWebアプリを作ったのでその超基本的事項をシェアできればと思います。
今回のVue、Nuxt、firebaseに関しては全くのど素人です。かつ、以下のように他のスキルも精通しているわけではないです。(だからこそ、初歩の初歩でつまずく方への参考になれば嬉しいです)
本記事は利用した技術の紹介から、多くの人に必要な知識/技術のところを中心に絞って解説していく流れになります。
1つ強調して伝えたいのは、Nuxt.js+firebaseでの開発はとても楽しいです。公式ドキュメントも、Qiitaやブログも充実しつつあります。Nuxt.jsとかfirebaseに興味を持ってるんだよねーと言うかたはぜひ触ってみることをお勧めします。
##利用した技術など
- Nuxt.js
- firebase auth
- firebase Realtime Database
- Vuetify
- pug
##完成したもの
URL:ハッシュタグカウンター
##ソースコード
Github
##使った機能や実装した機能などざっくり全体像
- pugを使いこなす
- Vuetifyを使いこなす
- Nuxt.jsのコンポーネント間での値受け渡し
- firebase authによるSNSログイン
- firebase authによるメールアドレスで新規登録/ログイン
- Nuxt.jsのstore機能でログイン状態の保持
- firebase Realtime Databaseへの保存
- firebase Realtime Databaseからログインしているユーザーの投稿を読み取る
- 「#~~ #×× #▲▲」のハッシュタグの数をリアルタイムに数えて表示する
- 入力内容をコピーする
- 入力内容をクリアする
- 半角スペースを入力する
- 退会
- サイトマップ作成
- @nuxtjs/google-tag-manager を利用したPV計測
- 各種メタタグ、favicon、PWAなどの設定
- 利用規約/プライバシーポリシーなど個人開発で漏れがちなところを作成
- 独自ドメインの取得
- firebase Hostingでホスティング
##共通で使えそうな部分を中心にご紹介
###1. Pugを使いこなす
こちらは以下の参考記事のおかげでものすごいスムーズに導入ができました。開発中も、その後はあまり参照することもなかったですね。強いて言うならば、コメントアウトくらいでした。
- 【pug導入編】今流行りの「Nuxt.js」を使ってサーバーサイドレンダリング(SSR)をしてみよう【Vue.js】
- nuxt.js(v2)でpug/stylusを利用する
- Pug(Jade)の基本記法について
- Vue.js製のポートフォリオサイトをPugで書き換えました
- Pugでコメントアウトをする
###2. Vuetifyを使いこなす
Vuetifyは、導入には苦戦してないですがひたすら参照はし続けましたね。 ただ最近知ったのですがVScodeにはプラグインでいい感じに予測を出してくれるものがあるらしいので、そちらを利用すると良いかもしれません。(ちなみに私はAtomです)
独自でCSSはほとんど書いておらず、マージンやレイアウト、ほぼ全てがVuetifyでサクッと書かれております。
###3. Nuxt.jsのコンポーネント間での値受け渡し
Vue.js自体が初めてと言うこともあり、コンポーネント間の値受け渡しもここで初めて試しました。 親→子のイメージはすぐにできたのですが、子→親の感覚がなかなかしっくりこず、以下の記事を何度読み返したかわかりません。
ただし私のコードでは結局動くことを優先して、子コンポーネントから親の変数を直接書き換えているので、正直あまりいいコードではありません・・・!(もっとスマートな書き方ができるようになりたいものです)
###4. firebase authによるSNSログイン/5. メールアドレスで新規登録/ログイン
firebaseのSNSログインは、本当に簡単です。以下の記事を参考にすれば、プログラミング初心者の鬼門でもあるログイン機能を、全てfirebaseに任せて実装することができます。
ただし、考慮しなきゃいけなかったなあと後半に気づいて見送っているのが、パスワード変更やリセットなどの機能です。TwitterなどのSNS認証の場合にはパスワードが未設定で、メールアドレス認証の場合にはパスワードが設定済みと言う状況なので、場合分けしてコードを記述する必要があります。
私のハッシュタグカウンターではパスワード変更機能を実装した後にそのことに気づき、若干不自然な挙動になってしまっているのが反省です。
###6. Nuxt.jsのstore機能でログイン状態の保持
Vuexが実はロード(リロード)をするとデータが消えてしまうとのことで…
vuex-persistedstateというものを使い、消さないように、ユーザのlocalStorageを用いてよきに保存できるようにしておきました。
以下の記事を参考に、
- npm install vuex-persistedstate --save でインストール
- persistedstate.js の作成、
- nuxt.config.js内の設定変更
を行いました。
本当にこの記事の通りにやればOKです。感謝。
###7. firebase Realtime Databaseへの保存
データベースはfirebaseのRealtime Databaseを利用してみました。以下の記事を参考に実装を進め、書き込みはなんなくできたのですが、どうしてもリアルタイム読み込みのコードがうまくいきませんでした。
###8. firebase Realtime Databaseからログインしているユーザーの投稿を読み取る
そこで読み込むべきタイミングだけ更新するように、以下の記事を参考に調整してみることで問題を回避しました。
firebase realtime databaseのon()(リアルタイム連携)
const sampleRef = firebase.database().ref('sample')
sampleRef.on('value', function(snapshot){
console.log('value', snapshot.val())
})
firebase realtime databaseのonce()(1度だけ読み込む)
const sampleRef = firebase.database().ref('sample')
sampleRef.once('value', function(snapshot){
console.log('value', snapshot.val())
})
上記参考記事でもあるように、リアルタイム同期って意外といらなかったりするんですよね。必要なタイミングを見極めて、once()を使うことがむしろ良い場合も多いということです。
私のハッシュタグカウンターも、once()の機能で十分だったので、結果オーライとなりました。
###9. 「#~~ #×× #▲▲」のハッシュタグの数をリアルタイムに数えて表示する
<template lang="pug">
v-textarea(
id="hashtag_input"
ref="r"
v-model="content"
@input="updateValue"
auto-grow
solo
)
div
p {{ now_hashtag_count }}
</template>
<script>
export default {
data () {
return {
now_hashtag_count:0,
content:'',
input_text:'',
};
},
methods:{
// 入力内容が1文字変わる度に、ハッシュタグの数を数える
updateValue(){
var input_text = this.content
var hashtag_count = input_text.match(/#\S/g)
if(hashtag_count){
var now_hashtag_count = hashtag_count.length
return this.now_hashtag_count = now_hashtag_count;
}else{
var now_hashtag_count = 0
return this.now_hashtag_count = now_hashtag_count;
},
},
},
</script>
<style>
//省略
</style>
textareaをv-model='content'
として、ハッシュタグのカウントはmatch(/#\S/g)
をしているだけのコードです。
厳密にはもう少し違う正規表現があり、
https://rubular.com/
ではうまく抽出で規定なのですが、JSでなんともうまく拾えず…
泣く泣く、match(/#\S/g)
で抽出しています。
Instagramのハッシュタグは、「#」のみではハッシュタグにはならず、「#gragagag #garjgairga」のように
「#」の後になんらかの文字列が並ぶ必要があります。
「#が1文字あって、その後任意の文字が1文字以上続いて、空白または次の#がくるまでを1つのハッシュタグとする」
が正しいのですが、match(/#\S/g)
では、
「#が1文字あって、任意の空白ではない文字が1文字以上続く」という抽出の仕方となっています。
この場合にはマッチしているのは「#テスト1 #テスト2#テスト3 #」
のような場合、
#テ、#テ、#テの3つということになります。
使ったハッシュタグを保存していくまでを想定していく場合にはこれではNGですが、有効なハッシュタグの個数を数えるという今回の用途ではこれでOKだったということです。
###10. 入力内容をコピーする
nuxt-clipboard2
というライブラリをインストールすると、以下のように書くだけでテキストをコピーすることができます。
// 入力内容をコピーする
copyHashtag(content) {
this.$copyText(content)
}
###11. 入力内容をクリアする
this.content = ""
をするだけです。簡単ですね。
###12. #と半角スペースをワンタップで入力する
Instagramの####の流れでよく使うのがこの、「#」と半角スペースです。これをPCなら簡単ですが、スマホだと慣れていないと手間に感じる人も多いですよね。
なので、ボタンをワンタップすると、カーソルの位置に「#」や半角スペースを追加できるように試みました。
<script>
addHashtag(content) {
//入力内容をtext_valに
var text_val = this.content
//文字数抽出
var all_len = text_val.length
//カーソルの位置
var select_len = this.$refs.r.$el.querySelector('textarea').selectionStart
//元の入力内容のカーソルの前部分を抽出
var first = text_val.substr(0, select_len)
//「#」をいい感じの箇所に入れる
var insert = '#'
//元の入力内容のカーソルの後ろ部分を抽出
var latter = text_val.substr(select_len, all_len)
//#を間に入れた形で元のテキストと統合する
text_val = first + insert + latter
this.content = text_val
},
</script>
ただこれでは#を入力した後にフォーカスが外れてしまい、以下の記事を参考に$nextTickを利用してみました。
しかしそれでもうまくはいかず、半ば強制的にDOMを操作してフォーカスし直しました。
原因は厳密にはわかっていませんが、どうやらVuetifyが悪さを起こしているようでした。
<script>
addHashtag(content) {
//入力内容をtext_valに
var text_val = this.content
//文字数抽出
var all_len = text_val.length
//カーソルの位置
var select_len = this.$refs.r.$el.querySelector('textarea').selectionStart
//元の入力内容のカーソルの前部分を抽出
var first = text_val.substr(0, select_len)
//「#」をいい感じの箇所に入れる
var insert = '#'
//元の入力内容のカーソルの後ろ部分を抽出
var latter = text_val.substr(select_len, all_len)
//#を間に入れた形で元のテキストと統合する
text_val = first + insert + latter
this.content = text_val
//ここを追加
this.$nextTick(() => {
this.$refs.r.focus();
this.$refs.r.$el.querySelector('textarea').setSelectionRange(select_len + 1, select_len + 1)
});
},
</script>
###13. 退会
firebaseの公式の通りに従うのみです。
var user = firebase.auth().currentUser;
user.delete().then(function() {
console.log('User deleted.')
}).catch(function(error) {
// An error happened.
alert('ユーザーデータを削除できませんでした。再度お試しください。')
});
###14. サイトマップ作成
@nuxtjs/sitemap
というライブラリを用いて、一瞬で対応ができます。ありがたや。
サイトマップは簡単にいうとGoogleさんなどの機械にサイト構造を教えてあげるものでして、SEO対策の1つですね。
###15. @nuxtjs/google-tag-manager を利用したPV計測
@nuxtjs/google-tag-manager
を用いて、GoogleAnalyticsでページごとにPVを計測できるように設定しました。
ぼくはディレクターとしてアナリティクスやタグマネをゴリゴリ使っていたこともありすんなりいけましたが、そちらが初めての場合は少しきついかもしれません。
とはいえ上記の参考記事に丁寧に沿って作業をすればできるはず、ではあります。
###16. 各種メタタグ、favicon、PWAなどの設定
各種設定については、以下の参考記事にスーパー感謝。
今回はOGPなど一部は見送りましたが、それらも含めて記事に沿えば実現が可能です。
###17. 利用規約/プライバシーポリシーの策定
利用規約やプライバシーポリシーなど、漏れがちなところは以下の記事を思いっきり参考にさせていただきました。
###18. 独自ドメインの取得
僕は独自ドメインをいつも使っているエックスドメインから取得しましたが、基本的な流れはどのサイトでも同じのはずです。
参考にした以下の記事は、お名前.comの場合です。
###19. firebase Hostingでホスティング
お疲れ様でした。firebase deployで完です。
##おわりに
ブックマークはしていたり、Qiitaでいいねやストックはしていましたが、意外と改めて読み返すことって少ないですよね。
本記事を書くに当たって、自分自身の復習にもなりました。
繰り返しにはなりますが、Nuxt.js+firebaseはとても楽しいです。ご興味ある方は是非、触ってみてください!
Twitter(@utoc11)もやっているので、こちらからも絡んでいただけると嬉しいです。