4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Firebase v9 + Vue3 + Vite + Vuetify3 beta で firebase auth のメール認証でログインしてみるの、TypeScript版

Last updated at Posted at 2022-08-22

Firebase v9 + Vue3 + Vite + Vuetify3 beta で firebase auth のメール認証でログインしてみるの、TypeScript版

元のQiita:Firebase v9 + Vue3 + Vite + Vuetify3 beta で firebase auth のメール認証でログインしてみる をTypeScript版でうまくいくようにやってみましょうという事です。

ちなみに筆者は、Vue2とVuetify2を少し触ってたら、時代がVue3になっていて驚いている人、世間様があまりにもTypeScriptというもんだから、TypeScriptを学習初めたばかりのものです。つまりはどちらも慣れてはおりません。これから学んで慣れていければと思っております。

変更した所のまとめ

js ts
アプリ作成 vue-create app yarn create vite
vue-routerインストール vue add router yarn add vue-router@4
各種ファイル firebase.js, router.js firebase.ts, router.ts

Vue関連のインストール

Vue3のアプリの作成

参考:Vite + Vue3にESLintとPrettierを導入する

vue-createでなく、yarn create viteを使う

yarn create vite
? Project name: vue-ts-app
? Select a framework > vue
? Select a variant > vue-ts

cd vue-ts-app
yarn
yarn dev

Vuetify3の追加

vue add vuetify
? Choose a preset: > Vite Preview (Vuetify 3 + Vite)
yarn dev

Welcome to Vuetify 3 Beta Vite Previewというページを見ることができました。

vue-routerのインストール

参考:Vue3 + TypeScript + Vue RouterからはじめるWebアプリケーション開発

vue add routerは使わない

yarn add vue-router@4

yarn以外のパッケージマネージャーを使うと

  • npmを使った場合、vue add vuetify後は、なぜかnpm install がエラーとなる場合がありました。
  • pnpmだとvue add vuetify自体でエラーが出てしまいそこから進めなくなりました。他のvue addでも同様とのIssueがあがっていました。
  • すべてvue addが鬼門のもようです。

routerの設定

src/router.tsの作成

ViteのCLIがrouterをインストールしたら色々設定してくれるということは無いので、色々手作業で設定する必要があります。

ここでは、'/'にアクセスされると、現在はまだ存在しないファイルsrc/views/HomeView.vueを読むという設定にしています。

参考:Vite で作成したアプリのVue-routerの設定方法

src/router.ts
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('./views/HomeView.vue'),
  },
]

const router = createRouter({
  history: createWebHistory(), // HTML5 History モード
  routes,
})

export default router

src/main.tsに追加する

src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
import router from './router' // この行を追加

loadFonts()

// ここらへ.use(router)を追加
createApp(App)
  .use(vuetify)
  .use(router)
  .mount('#app')

App.vueの変更

routerで飛ばされるだけの存在にしてみます。

src/App.vue
<template>
  <v-app>
    <router-view />
  </v-app>
</template>

src/views/HomeView.vueを作る

mkdir -p src/views

src/views/HomeView.vue
<template>
  <v-app>HOME(HomeView)</v-app>
</template>

routerの動作確認

yarn dev

出てきたリンクにアクセスしてHOME(HomeView)のみ表示されるシンプルなものが見えたら動作確認完了です。

firebase

初期化

firebase initして、必要なサービスを選び、Firebaseのプロジェクトに紐付ける。そしてそのプロジェクトでは、initした時に選択したサービスはFirebase consoleで開始しておく必要がある。Authenticationではログインプロバイダで、メール/パスワードは使えるようにしておく必要がありました。

firebase init
? Which Firebase features do you want to set up for this directory?...
Hosting: Set up GitHub Action deploys以外を全部選択してみました
? Please select an option: > Use an existing project
? Select a default Firebase project for this directory: vue3ts-123456 (Vue3ts)
? What file should be used for Realtime Database Security Rules? database.rules.json
? What file should be used for Firestore Rules? firestore.rules
? What file should be used for Firestore indexes? firestore.indexes.json
? What language would you like to use to write Cloud Functions? TypeScript
? Do you want to use ESLint to catch probable bugs and enforce style? Yes
? Do you want to install dependencies with npm now? Yes

Hosting Setupの? What do you want to use as your public directory? だけはデフォルトとは全然違う回答をしているので注意、distにしています。

Emulators Setupは全部選択しました。
Emulatorsのportは全部デフォルトでエンターを押しました

? What do you want to use as your public directory? dist
? Configure as a single-page app (rewrite all urls to /index.html)? No
? Set up automatic builds and deploys with GitHub? No
? What file should be used for Storage Rules? storage.rules
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm your choices. 全部
EmulatorsのPortは全部デフォルトに
? Would you like to enable the Emulator UI? Yes
? Which port do you want to use for the Emulator UI (leave empty to use any available port)?
? Would you like to download the emulators now? No
? What file should be used for your Remote Config template? remoteconfig.template.json

APIキーなどの登録

環境変数を使う

参考:【Vue.js】VueCLI3.x 4.xで環境変数を扱う場合は .env ファイルに VUE_APP_ の接頭語をつける

  • プロジェクトルートに.env.localというファイルを作成し、そこに環境変数を書きFirebaseのAPIキーなど、外部に渡したくないものを書くと、Vue3は自動的に.env.localを読み込み、環境変数に設定しました。

  • 環境変数の接頭辞はVUE_APP_としないと読み込みません。

  • .env.localファイルを.gitignoreに登録しました。

この辺りを手で書いても良いのですがそれを楽にするツールを使うことにします。firebaseで使うプロジェクトから、web app's Firebase configurationをコピーまたはファイルに保存します。

そして、npmによるcliツール@hkj_50/firebase-configを実行して質問に答え、src/firebase.tsと.env.localファイルを生成します。

npx @hkj_50/firebase-Config

? Where is the root dir of the your App? ./
? Enviroment Variables file name? .env.local
? Do you use firebase's emulator? Yes
? In which format should the contents of firebaseConfig be entered? file
? Where is the path to the file containing firebaseConfig? ../firebaseConfig.js

上記の場合は、プロジェクトルート上でnpx @hkj_50/firebase-configを実行し、web app's Firebase configurationを../firebaseConfig.jsという名前で保存していたので、それを指定しています。エミュレータを使うと指定しました。その結果、src/firebase.ts.env.localという二つのファイルが生成されました。

src/firebase.ts
import { initializeApp } from 'firebase/app';
import { getFunctions, connectFunctionsEmulator } from "firebase/functions";
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";

import { getStorage, connectStorageEmulator } from "firebase/storage";
import { getAuth, connectAuthEmulator } from "firebase/auth";

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: 'process.env.VUE_APP_API_KEY',
  authDomain: 'process.env.VUE_APP_AUTH_DOMAIN',
  databaseURL: 'process.env.VUE_APP_DATABASE_URL',
  projectId: 'process.env.VUE_APP_PROJECT_ID',
  storageBucket: 'process.env.VUE_APP_STORAGE_BUCKET',
  messagingSenderId: 'process.env.VUE_APP_MESSAGING_SENDER_ID',
  appId: 'process.env.VUE_APP_APP_ID',
}

const firebase = initializeApp(firebaseConfig);
const isEmulating = window.location.hostname === "localhost";
if (isEmulating) {

    const auth = getAuth();
    connectAuthEmulator(auth, "http://localhost:9099");

    const storage = getStorage();
    connectStorageEmulator(storage, "localhost", 9199);

    const db = getFirestore(firebase);
    connectFirestoreEmulator(db, 'localhost', 8080);

    const functions = getFunctions(firebase);
    connectFunctionsEmulator(functions, "localhost", 5001);
}

export const firebaseApp = () => { return firebase };

export default firebase;

肝心な情報は環境変数から読み込まれ、このファイルには書かれていないので、gitに含めたり、githubにて公開されても問題ありません。

.env.local
VUE_APP_API_KEY="YourApiKey"
VUE_APP_AUTH_DOMAIN="yourAuthDomain.firebaseapp.com"
VUE_APP_DATABASE_URL="https://yourdomain.firebaseio.com"
VUE_APP_PROJECT_ID="yourID-12345"
VUE_APP_STORAGE_BUCKET="youID-12345.appspot.com"
VUE_APP_MESSAGING_SENDER_ID="123456789012"
VUE_APP_APP_ID="1:123456789012:web:a11bbcc123456ab1a1b23b"

こちらは肝心な情報なので、.gitignoreに入っていない場合は登録します。

echo '*.local' >> .gitignore

tsconfig.jsonの設定

参考:TypeScript に対応した Vue 3 プロジェクト の作成

その項目が無ければ、"compilerOptions"以下に、"baseUrl"と"paths"の設定を追加します。

tsconfig.json
{
  "compilerOptions": {
    ...
    ...
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  ...
  ...
}

firebase関連のインストール

yarn add firebase

確かにこれは忘れやすいと、私も思いました。

src/App.vueにfirebaseApp登録を追加

src/App.vue
<template>
  <v-app>
    <router-view/>
  </v-app>
</template>
<script setup lang="ts">
import { firebaseApp } from './firebase';
const app = firebaseApp()
</script>

このfirebaseApp()を呼ばないとfirebaseを初期化していないと怒られる現象が後に起こります。

Firebaseを使った機能の実装例

Homeview.vueに実装してみます。元々の書き方がComposition APIっぽくない書き方をしていたので、Composition API風に書き替えています。<script setup lang>を使う事によって、余計な呪文を排除して、scriptとtemplateとstyleのみとなったすっきりした書き方ができるようになります。

Refで動的に変更する変数を定義します。constで定義していますが、refのオブジェクトになり、変数.valueという形で実際の値を使い、そのvalueは変更可能です。

mounted()はonMounted()内に書きます。

v-if="currenUser.value === null"と書きたかったのですが、nullである可能性があるとなってエラーとなりました。v-if="currentUser === null"であれば、エラーとならず、動作の目的には叶いました。しかし、本当にこれで良いのかは良く分かっておりません。

src/views/HomeView.vue
<script setup lang="ts">
import { ref, Ref, onMounted } from 'vue'
import {
  getAuth,
  signOut,
  onAuthStateChanged,
  signInWithEmailAndPassword,
  createUserWithEmailAndPassword,
  User,
} from 'firebase/auth'

const emailText: Ref<string> = ref('')
const passwordText: Ref<string> = ref('')
const message: Ref<string> = ref('')
const currentUser: Ref<User | null> = ref(null)

onMounted(() => {
  const auth = getAuth()
  onAuthStateChanged(auth, (user) => {
    if (user != null) {
      currentUser.value = user
    } else {
      currentUser.value = null
    }
  })
})

const signIn = () => {
  // エラーなどメッセージをクリア
  message.value = ''
  if (emailText.value == '' || passwordText.value == '') return
  const auth = getAuth()
  signInWithEmailAndPassword(auth, emailText.value, passwordText.value)
    .then((userCredential) => {
      // Sign In
      const user: User = userCredential.user
      console.log(user)
    })
    .catch((error) => {
      message.value = error.message
      console.log(error.code, error.message)
    })
}

const createAccount = () => {
  message.value = ''
  if (emailText.value == '' || passwordText.value == '') return
  const auth = getAuth()
  createUserWithEmailAndPassword(auth, emailText.value, passwordText.value)
    .then((userCredential) => {
      const user: User = userCredential.user
      console.log(user)
    })
    .catch((error) => {
      message.value = error.message
      console.log(error.code, error.message)
    })
}

const logOut = () => {
  const auth = getAuth()
  signOut(auth)
    .then(() => {
      currentUser.value = null
    })
    .catch((error): void => {
      console.log(error)
    })
}
</script>

<template>
  <v-container>
    <div v-if="currentUser === null">
      <v-card width="400px" class="mx-auto mt-5">
        <v-card-actions>
          <v-col>
            <v-text-field
              v-model="emailText"
              label="E-MAIL"
            >
            </v-text-field>
            <v-text-field
              v-model="passwordText"
              label="PASSWORD"
              type="password"
            >
            </v-text-field>
            <v-btn @click="signIn" color="primary"> E-Mail Sign In </v-btn>
            <v-btn color="primary" @click="createAccount">Sign Up</v-btn>
            <div class="message">{{ message }}</div>
          </v-col>
        </v-card-actions>
      </v-card>
    </div>
    <div v-else>
      <h2>Success to sign in with firebase auth!</h2>
      <v-btn @click="logOut">Sign Out</v-btn>
    </div>
  </v-container>
</template>

<style scoped>
.message {
  color: red;
}
</style>

Functionsの設定

必要なライブラリが入ってないのとビルドがされていないので実行

cd functions
yarn
yarn build

buildで

rc/index.ts:1:1 - error TS6133: 'functions' is declared but its value is never read.

1 import * as functions from "firebase-functions";
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

と怒られました。現時点ではfunctionsは使わないので、コメントアウトしておきます。

// import * as functions from "firebase-functions";
そこで再びbuild
yarn build
エラーが出ずに完了しました。

Firebase Emulatorの実行と確認

firebase emulators:start

とやってから違うターミナルで

yarn dev

とやってください。E-MAILとPASSWORDの所に入れて初めてであれば、SIGN UP、そうでなければ、E-MAIL SIGN INを選んでいただいて、Success to sign in with firebase auth!と出て、SIGN OUTボタンを押せば元に戻れば成功です。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?