20200207のvue.jsに関する記事は5件です。

ローカルホストにスマホからアクセスできたのでメモ

localhost:8080へスマホでアクセスしたかった

正確に言うと
現在のpcのipアドレス:8080にスマホでアクセスしたかった。
自分の場合失敗はnpm run devのタイミング、
jsonの書き換え+Ctrl+Sタイミングが間違っていたこと。
最大の原因は無線ルーターがアクセスポイントとなっているため
「スマホ」と「pc」で別のssidに入っていたこと。
これらを手順通り行っていけばきちんと通信してスマホで見れたのだ。

この手順は

・ファイアウォール・セキュリティ無効
・同じアクセスポイントに入る
・jsonの書き換え
・npm run dev
・ブラウザ表示失敗
・ターミナルでCtrl+Cして一旦カレントディレクトリへ戻る
・ipconfig でipv4アドレス確認
・npm run dev
・先ほどのブラウザ画面のアドレスバーにipv4アドレス:8080を入力しリロード
・パソコンでipv4の自作app.vue画面が表示成功
・スマホのブラウザのアドレスバーに先ほどのipv4アドレス:8080を入力しリロード
・スマホでipv4の自作app.vue画面の表示成功

なぜ手順飛ばしたら表示されない部分があるのかはわかりません!
間違っていたらすいません!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue CLIでFirebase SDKとFirebaseUIを外部から読み込みたい!

Firebase SDKはデカい!

Web用のFirebase SDKは、Node.jsモジュール、CDN、Hosting URLからの3つの方法で導入できます。
https://firebase.google.com/docs/web/setup#add-sdks-initialize

しかし、Node.jsモジュールをwebpackでバンドルすると、ビルドされたファイルの大半をFirebase SDKが占める、なんてこともあります。

加えて、FirebaseUIの日本語版のNode.jsモジュールは1.0.0で止まっちゃってるので最新版を使いたいときはCDNを使うしかなさそうです。

そこでCDNから読み込みたいのですが、Vue CLIを使ってビルドする際、CDNとwebpackを共存させる方法で詰まったので記録しておきます。

webpackに外部ファイルの存在を告げる

webpackに「外部ファイルを使うからビルドファイルにはこのモジュールはいらないよ」と教える必要があります。

そのためにはwebpack.config.jsexternalsというプロパティを追加します。
https://webpack.js.org/configuration/externals/

Vue CLIの場合、vue.config.jsに追加できます。
https://cli.vuejs.org/guide/webpack.html#simple-configuration

vue.config.js
module.exports = {
    configureWebpack: {
        externals: {
            firebase: 'firebase',
            firebaseui: 'firebaseui'
        }
    }
}

index.htmlにリンクを追加する

Node.jsモジュールの場合、

main.js
import firebase from 'firebase/app'
import 'firebase/firestore'
import 'firebase/auth'

このように必要な機能を部分的にimportしますが、CDNの場合、

public/index.html
<head>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>タイトル</title>

    <script src="https://www.gstatic.com/firebasejs/7.8.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.8.0/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.8.0/firebase-firestore.js"></script>

    <script src="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth__ja.js"></script>
    <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth.css" />
</head>

index.htmlに必要なSDKのCDNリンクを追加して、

main.js
import firebase from 'firebase'

このようにimportすれば、必要な機能だけ導入できます。

Hosting URLを使いたい!

これでCDNからの読み込みは出来るはずですが、Firebase Hostingを使っている場合、予約済みURLから読み込んだ方がパフォーマンスが向上するようです。
https://firebase.google.com/docs/hosting/reserved-urls

これもCDNと同様にindex.htmlに追加すれば使えます。

public/index.html
<head>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>タイトル</title>

    <script src="/__/firebase/7.8.0/firebase-app.js"></script>
    <script src="/__/firebase/7.8.0/firebase-auth.js"></script>
    <script src="/__/firebase/7.8.0/firebase-firestore.js"></script>
    <script src="/__/firebase/init.js"></script>

    <script src="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth__ja.js"></script>
    <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth.css" />
</head>

/__/firebase/init.jsを追加すれば、初期化処理をコピペする必要はありません。

ローカルサーバーでも使いたい!

npm run serveで立ち上げたローカルサーバーでは/__/firebase/にアクセスしても「そんなもん無いよ?」と言われてしまいます。
npm run build + firebase serveではfirebase-toolsが/__/firebase/にアクセスできるようにしてくれるのですが、ファイルを変更するたびにビルドしていたら開発効率が落ちてしまうでしょう。

解決するのは簡単で、/__/firebase/の頭にFirebase HositingのURLを付けるだけです。

public/index.html
<head>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>タイトル</title>

    <script src="https://~.firebaseapp.com/__/firebase/7.8.0/firebase-app.js"></script>
    <script src="https://~.firebaseapp.com/__/firebase/7.8.0/firebase-auth.js"></script>
    <script src="https://~.firebaseapp.com/__/firebase/7.8.0/firebase-firestore.js"></script>
    <script src="https://~.firebaseapp.com/__/firebase/init.js"></script>

    <script src="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth__ja.js"></script>
    <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth.css" />
</head>

絶対パスでは速度が落ちるらしいので環境変数を使って開発環境だけで使うといいと思います。

.env
VUE_APP_FIREBASE_URL=
.env.development
VUE_APP_FIREBASE_URL=https://~.firebaseapp.com
public/index.html
<head>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>タイトル</title>

    <script src="<%= VUE_APP_FIREBASE_URL %>/__/firebase/7.8.0/firebase-app.js"></script>
    <script src="<%= VUE_APP_FIREBASE_URL %>/__/firebase/7.8.0/firebase-auth.js"></script>
    <script src="<%= VUE_APP_FIREBASE_URL %>/__/firebase/7.8.0/firebase-firestore.js"></script>
    <script src="<%= VUE_APP_FIREBASE_URL %>/__/firebase/init.js"></script>

    <script src="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth__ja.js"></script>
    <link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.4.0/firebase-ui-auth.css" />
</head>

環境変数については以下を参照
https://cli.vuejs.org/guide/mode-and-env.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FirebaseでSMS認証(Nuxt, Vue.js)

ドキュメント見るの辛い人向けに置いておきます。

1.Firebaseのコンソールで電話番号認証を許可

AuthenticationタブからONにするだけです

これでアプリケーションで使えるようになります

料金体系

Sparkプランは1万/月でいけるので、試しにテストしてみたかったり小規模なサービスではこれで十分かと思います

1万を超過するようなログイン、登録が発生する場合はBlazeプランにあげたほうが確実です。

Blazeプランの場合は従量課金制度で1万を超過した分に対して1件あたりの金額がかかってきます。

料金を確認

スクリーンショット 2020-02-07 13.17.02.png

2.reCAPTCHAで認証を設定

主に不正行為を防止する目的でこれ設定する必要があります。

例えばよくある画像を選んでロボットではないことを確認するアレです。

//任意の言語を渡すとreCAPTCHAの言語が自動的に変わります
firecase.auth().languageCode = 'jp'

最近ではユーザーの操作を必要としないreCAPTCHAもあるのですが、firebaseはそれもサポートしています

今回はチェックボックスにチェックするいつものreCAPTCHAを使います

<template>
  <div>
    <a
      id="sign-in-button"
      @click="sendMessage()">
      <span>ログイン</span>
    </a>
    <div id="recaptcha-container"/>
  </div>
</template>

<script>
import firebase, { auth } from 'firebase'

export default {
  data () {
    return {
      recaptchaVerifier: null,
      recaptchaWidgetId: null,
      confirmationResult: null,
      verificationCode: null
    }
  },
  mounted () {
    this.recaptchaVerifier = window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
      'size': 'normal',
      'callback': responseToken => {
         // reCAPTCHA solved
       }
    })

    this.recaptchaWidgetId = await this.recaptchaVerifier.render()
  }
}

これでreCAPTCHAのdivがrenderingされます

この recaptchaVerifier は signIn時の引数で利用するので保持しておきます

スクリーンショット 2020-02-07 16.13.30.png

3.SMSへのコード送信処理

電話番号は国際番号(+81) + 電話番号で入力されたものを利用します

ここでは決め打ちしていますが、本来はinputタグを用意してそこに入力したものをv-modelなどを利用して取得してきます

async sendMessage() {
  // ダッシュボードからホワイトリストにいれてテストすることが可能です
  const phoneNumber = "+818099999999"
  try {
    this.confirmationResult = await firebase.auth().signInWithPhoneNumber(
      phoneNumber, this.recaptchaVerifier) // ここで先ほどのreCAPTCHA認証を利用します
  }
}

問題なく送信された場合はconfirmationResultにverificationIdが返ってくるのでそれをユーザー認証に使います

4.SMSで届いたコードを入力させてログイン

3で実施したcofirmationResultとSMSに送信されたコードを利用して実際にユーザーを認証させます

※htmlにはないですが、認証コード入力欄と確認ボタンみたいなものがある前提です

// verificationCodeはv-modelなどで指定しているユーザーが入力した認証コード
if (this.confirmationResult && this.verificationCode) {
  try {
    const result = await this.confirmationResult.confirm(this.verificationCode)
    const user = result.user // これでユーザーを取得できる
   } catch (e) {
     // 認証コードが間違っている
   }
}

以上で電話番号で認証をとることが可能です

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nuxt.js(v2) meta情報を1つのjsonに集約、各ページに反映されるようにする

こちらの記事、nuxt.js(v2)でSEOに必要なmeta(OGP)で入力漏れの事故をなくす で紹介されていた、metaまわりの実装をスッキリさせる方法を元に
meta情報を一箇所で管理する方法をまとめます。

予め、この記事のもと設定が終わっている条件とします。

実現したいこと

  • meta情報の一覧性を高めるため、メタ情報を一箇所で管理できるようにしたい。
  • 各ページでmeta情報を定義するのをやめて、すべてのページのメタ情報が含まれるjson形式の定義ファイルを1つ作成しそこにまとめて書いたものが反映されるようにしたい

手順

  • メタ情報をまとめた定義ファイルをjsonで作成
  • nuxt.config でそれを読み込みを定義し、どこからでも参照できるように
  • jsonで定義されたmeta情報は、ファイルパスに基づいて各ページに反映されるように

準備

1. meta情報定義ファイル metadata.jsonを作成

ファイルパスに基づいてmetaデータを切り分けられるような構造にした。
独自のフォーマット。
例は、about、activity、works、projectsページがある場合の定義例。

metadata.json
{
    "/about": {
        "title": "about title",
        "description": "about no description"
    },
    "/activity": {
        "title": "activity title",
        "description": "activity no description"
    },
    "/works": {
        "title": "works title",
        "description": "works no description"
    },
    "/projects": {
        "title": "projects title",
        "description": "projects no description"
    },
}

ファイルはasset内に配置した。

@/assets/data/metadata.json

2. プロジェクト内で使用できるように、nuxt.config.js に読み込み設定

nuxt.config.js
import metaData from './assets/data/metadata.json'

export default {
  env: {
    metaData: metaData
  },

これで、

context.env.metaData

でアクセスできるようになった。

metaに反映

記事 の本題と紹介されている部分 assets/mixins/meta.js の箇所に手を加えていきます。

mixin内で、metaData 値でアクセスできるようにする

metaData 値でアクセスできるように、asyncDataの箇所を追加します。

assets/mixins/meta.js
export default {
  asyncData (context) {
    return {
      baseName: context.env.baseName,
      baseDesc: context.env.baseDesc,
      baseUrl: context.env.baseUrl,
      baseOgp: context.env.baseOgp,
      metaData: context.env.metaData, //←追加
    }
  },
.
.
.

head 関数内の調整

次に、head 関数内を調整していきます。
書くページのファイルのパスは、

const path = `${this.$router.history.base}${this.$route.path}`;

で取れるようなので
やや雑な感じですがこのような感じにします。

assets/mixins/meta.js
    head() {
        const head = { meta: [] }

        if (this.$route.path === '/') {
            head.meta.push({ hid: 'og:type', property: 'og:type', content: 'website' })
        }

        // ページPath
        const path = `${this.$router.history.base}${this.$route.path}`

        if (this.metaData[path]) {

            // タイトル
            if (this.metaData[path].title) {
                const title = `${this.metaData[path].title} - ${this.baseName}`
                head.title = title
                head.meta.push({ hid: 'og:title', property: 'og:title', content: title })
            }

            // ディスクリプション
            if (this.metaData[path].description) {
                const description = `${this.metaData[path].description}`
                head.meta.push({ hid: 'description', name: 'description', content: description })
                head.meta.push({ hid: 'og:description', property: 'og:description', content: description })
            } else if (!this.metaData[path].description && this.metaData[path].title) {
                const description = `${this.baseName}サイトの${this.metaData[path].title}ページです。${this.baseDesc}`
                head.meta.push({ hid: 'description', name: 'description', content: description })
                head.meta.push({ hid: 'og:description', property: 'og:description', content: description })
            }

            // ページタイプ
            if (this.metaData[path].type) {
                head.meta.push({ hid: 'og:type', property: 'og:type', content: this.metaData[path].type })
            }

            // OGP画像URL
            if (this.metaData[path].image) {
                const imageUrl = `${this.baseUrl}${this.$router.history.base}${this.baseOgp}${this.metaData[path].image}`
                head.meta.push({ hid: 'og:image', property: 'og:image', content: imageUrl })
            }

        }

        // ページURL
        const url = `${this.baseUrl}${this.$router.history.base}${this.$route.path}`
       head.meta.push({ hid: 'og:url', property: 'og:url', content: url })

        return head
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Vue.js] どうしてVue.set()で配列の更新が検知できるの?

[Vue.js]配列の変更が検知できない理由の「JavaScriptの制限」って何よ! - Qiita

こちらの記事で配列の更新検知にはVue.setを使うと記載したのですが、
どうして検知できるのかな?って思って調べました。

結論

内部ではsplice()をしているだけだった。

実装を見てみる

公式GitHubを見てみましょう! :eye: :eye:

export function set (target: Array<any> | Object, key: any, val: any): any {
// 中略
  if (Array.isArray(target) && isValidArrayIndex(key)) {
     target.length = Math.max(target.length, key) 
     target.splice(key, 1, val) //ここだ!
     return val 
  } 
...

ありました!
内部でtarget.splice(key, 1, val)をしていることが確認できました!
だから検知できるんですね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む