0
0

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 3 years have passed since last update.

Nuxt.js+Firebaseで2回目の新しいプロジェクトを作る

Last updated at Posted at 2020-11-13

Nuxt.js+Firebaseを勉強しています。

プロジェクトを作成し、Webサービスをデプロイすることができました。本記事は、もう一つプロジェクトを作成してSNS認証を実装するところまでのメモです。

環境

  • Firebase 8.0.1
  • Vue 2.6.11
  • Nuxt 2.10.2
  • 開発環境 WindowsPC

実施手順

Firebaseコンソール で新規プロジェクトを作成

  • 「このプロジェクトで Google アナリティクスを有効にする」を有効
    • 「Google アナリティクスの構成」はデフォルトを選択

作成が完了し、プロジェクトのコンソールを見れるようになった。

Firebaseコンソールでウェブアプリを作成

プロジェクトのコンソールで開始するアプリ(ウェブ)を追加する。

  • 「アプリのニックネーム」は自由に決める。
  • Firebase Hostingの設定は後からでもできるとのことなので、このタイミングではしない。

「アプリを登録」ボタンを押下する。

Nuxtでプロジェクトを作成する

Nuxtでプロジェクトを作成するコマンド
npx create-nuxt-app (プロジェクト名)

コマンドを実行したディレクトリに指定したプロジェクト名のディレクトリが作られる。

Vuetifyで簡単に作りたかったので、設定はこんな感じ。

- ? Project name: (プロジェクト名)
	- デフォルトでいいので未入力で Enter
- ? Programming language: (Use arrow keys)
	- > JavaScript
	-   TypeScript
- ? Package manager: (Use arrow keys)
	-   Yarn
	- > Npm
- ? UI framework: (Use arrow keys)
	-   None
	-   Ant Design Vue
	-   Bootstrap Vue
	-   Buefy
	-   Bulma
	-   Chakra UI
	-   Element
	-   Framevuerk
	-   iView
	-   Tachyons
	-   Tailwind CSS
	-   Vuesax
	- > Vuetify.js
- ? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
	- >( ) Axios
	-  ( ) Progressive Web App (PWA)
	-  ( ) Content
	- ※ 選択無しでEnter
- ? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
	- >( ) ESLint
	-  ( ) Prettier
	-  ( ) Lint staged files
	-  ( ) StyleLint
	-  ( ) Commitlint
	- ※ 選択無しでEnter
- ? Testing framework: (Use arrow keys)
	- > None
	-   Jest
	-   AVA
	-   WebdriverIO
- ? Rendering mode: (Use arrow keys)
	-   Universal (SSR / SSG)
	- > Single Page App
- ? Deployment target: (Use arrow keys)
	- > Server (Node.js hosting)
	-   Static (Static/JAMStack hosting)
- ? Development tools: (Press <space> to select, <a> to toggle all, <i> to invertselection)
	- >( ) jsconfig.json (Recommended for VS Code if you're not using typescript)
	-  ( ) Semantic Pull Requests
	-  ( ) Dependabot (For auto-updating dependencies, GitHub only)
	- ※ 選択無しでEnter
- ? What is your GitHub username? 
	- GitHubのユーザー名を入力する。
- ? Version control system: (Use arrow keys)
	-   Git
	- > None

ビルド実行

>npm run build

(中略)

? Are you interested in participation? (Y/n)

n にした。

Firebase SDKのインストールとプロジェクトへの紐付け

作成したプロジェクトにFirebase SDKをインストールする。
今回はnpmで--saveでインストールする。(-gではなく)

cd (プロジェクト名のフォルダ)
npm install firebase --save

インストールしたfirebaseのバージョンを確認する。

>npm list firebase
`-- firebase@8.0.1

テスト環境で動かしてみよう

実行コマンドは次の通り。

npm run dev

http://localhost:3000/ にアクセスすると、Vuetifyの画面が出る。

プロジェクトをFirebase初期設定する

1.Firebaseコンソールでリージョンを設定

Firebaseコンソール にログインし、当該プロジェクトのSettingsを開く。
[全般] 中程の リソース ロケーション を任意のロケーションに指定する。
今回は東京リージョン asia-northeast1 を選択する。

2.Cloud Firestore の作成

Cloud Firestoreのページで、「データベースの作成」ボタンを押下する。

3. firebase init を実行

NuxtでFirebaseを使いたいので、create-nuxt-appで作成したNuxtプロジェクトディレクトリのトップでコマンド firebase init を実行する。

 to select features, then Enter to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) Database: Deploy Firebase Realtime Database Rules
 (*) Firestore: Deploy rules and create indexes for Firestore
 ( ) Functions: Configure and deploy Cloud Functions
 (*) Hosting: Configure and deploy Firebase Hosting sites
 ( ) Storage: Deploy Cloud Storage security rules
 ( ) Emulators: Set up local emulators for Firebase features
? Please select an option: (Use arrow keys)
> Use an existing project
  Create a new project
  Add Firebase to an existing Google Cloud Platform project
  Don't set up a default project

Firestore Rulesについてはデフォルトのまま Enter

? What file should be used for Firestore Rules? (firestore.rules)

Firestore indexesについてもデフォルトのまま Enter

? What file should be used for Firestore indexes? (firestore.indexes.json)
? What do you want to use as your public directory? (public)

SPAについての設定も y で。

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N)

firebase-tools のアップデート

   ╭───────────────────────────────────────────╮
   │                                           │
   │     Update available 8.4.3 → 8.15.1       │
   │   Run npm i -g firebase-tools to update   │
   │                                           │
   ╰───────────────────────────────────────────╯
>npm i -g firebase-tools

firebase.config の作成

firebase.configファイルをプロジェクトのディレクトリに作成して、 Firebase SDK snippet を書き込む。
Firebase SDK snippet は、Firebaseコンソールの「設定」-「全般」を参照する。

export default {
    apiKey: "",
    authDomain: "",
    databaseURL: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: "",
    measurementId: ""
}

firebase.configファイルは、gitignoreに設定する。

# others
firebase.config

vuex(ビューエックス)をインストール

vuexを利用するので、インストールする。

npm install vuex --save

firebaseuiをインストール

npm install firebaseui --save

FirebaseUIのcssを読み込ませる

FirebaseUIのcssは nuxt.config.js で読み込んでおく。

~/nuxt.config.js
  css: [
    "firebaseui/dist/firebaseui.css",
  ],

Firebaseの初期化処理のコーディング

Firebaseの初期化処理をpluginsに書く。firebase.configの読み込み、SNS認証の初期設定、フィルターの読み込み。
pluginsフォルダで実装したjsは、「root Vue.jsアプリケーションがマウント」される前に実行される。

フィルターは、金額をカンマ区切りで表示したい場合等に利用する。
~/filter/filters.js にファイルを作成し、pluginsで読み込ませることで、どのページでも利用できるようになる。

~/plugins/firebase.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import config from '~/firebase.config';
import Vue from 'vue';
import * as filters from '~/filter/filters';

if (!firebase.apps.length) {
  firebase.initializeApp(config);
  firebase.analytics();
}

// initialize authorization
export const authProviders = {
  // 使うものだけ定義しておきましょう
  Email: firebase.auth.EmailAuthProvider.PROVIDER_ID,
  Google: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
  Facebook: firebase.auth.FacebookAuthProvider.PROVIDER_ID,
  Twitter: firebase.auth.TwitterAuthProvider.PROVIDER_ID,
  Github: firebase.auth.GithubAuthProvider.PROVIDER_ID
};

export const auth = firebase.auth();

// initialize Firestore
const db = firebase.firestore();
export { db };

// import filters
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key]);
});
~/filter/filters.js
// 数字の3桁ごとにカンマ区切りをつけるフィルタ
export function number_format (value) {
  if (value === 0) { return 0; }
  if (value === "0") { return 0; }
  if (! value) { return 0; }
  return value.toString().replace( /([0-9]+?)(?=(?:[0-9]{3})+$)/g , '$1,' );
}

// yyyymm文字列を"yyyy年mm月"文字列にするフィルタ
export function yyyymm_format (value) {
  if (! value) { return false; }
  return value.substr( 0, 4 ) + "年" + value.substr(4) + "月";
}

プラグインをNuxt.jsで使えるように設定ファイル nuxt.config.js を編集する。

~/nuxt.config.js
  plugins: [
    '~/plugins/firebase',
  ],

SNS認証のログイン/ログアウトのステータスを保存する

~/store/auth.js
import Vue from 'vue';
import { auth } from '~/plugins/firebase';

export const state = () => ({
        user: {},
        status: ""
    });

export const mutations = {
        setUser(state, user) {
            state.status = "loggedIn";
            state.user = user;
        },
        logout(state) {
            state.status = "loggedOut";
            state.user = {};
        }
    };

export const getters = {
        isLoggedIn: (state) => {
          return state.status === "loggedIn";
        },
        getUsername: (state) => state.user.displayName,
        getUid: (state) => state.user.uid
    };

export const actions = {
        gotUser({ commit }, user) {
            commit("setUser", user);
        },
        logout({ commit }) {
            auth.signOut().then(() => {
                commit("logout");
            })
        },
    };

ログイン/ログアウトの認証情報による処理の追加

middlewareはページがレンダリングされる前に実行される。
(すべての画面遷移の前に実行される)

middlewareに、ログイン/ログアウトなどの認証情報の変化で発火するonAuthStateChangedを設定しておく。

さらに、 firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION); を追加する。
これによって、認証情報をローカルストレージに保存することができるようになる。

~/middleware/authenticated.js
import firebase from 'firebase';
import { auth } from '~/plugins/firebase';

export default function ({ route, store, redirect }) {
  auth.setPersistence(firebase.auth.Auth.Persistence.SESSION);
  auth.onAuthStateChanged((user) => {
    if (user) {
      store.dispatch("auth/gotUser", user);
    } else {
      // ログアウトせずにタブを消して、ブラウザを閉じずにまたURLから画面を開いたとき、
      // firebase.authのuserがnullなのに、ローカルストレージの情報が残っていてstoreのauthはログイン状態になっている。
      // そこで、ここで一度ログアウトを実行しておく。
      store.dispatch("auth/logout");
      // もしログインしていなかったらログインページにリダイレクト
      if(route.name !== "login") redirect("/login");
    }
  });
}
~/middleware/notAuthenticated.js
export default function ({ store, redirect }) {
  if (store.getters["auth/isLoggedIn"]) {
    return redirect('/');
  }
}

ログインボタンを表示するUI部分を作成

下記はPUGを利用したHTML記述方法になっている。
firebaseuiのimportはエラーが出たため、requireを利用することにした。

~/components/FirebaseAuth.vue
<template>
  <div id="firebaseui-auth-container"></div>
</template>

<script>
import { auth, authProviders } from '~/plugins/firebase';

export default {
  name: 'FirebaseAuth',
  mounted() {
    auth.onAuthStateChanged(user => {
      if (!user) {
        const firebaseui = require('firebaseui');

        const ui = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(auth);

        const config = {
          signInOptions: [
            // authProviders.Email,
            authProviders.Google,
            // authProviders.Facebook,
          ],
          callbacks: {
          },
          signInSuccessUrl: '/',
          signInFlow: 'popup', // ログインフロー設定。Nuxtのローカルサーバーで起こるCORSエラーがあるのでpopupがオススメです。
        };

        ui.start('#firebaseui-auth-container', config);
      }
    });
  }
}
</script>

signInFlowで設定しているログインフロー設定とは、サインアップフローをポップアップにするか、リダイレクトにするかなどを設定するためのものです。

ログインページの作成

pagesディレクトリに、login.vueを作る。とりあえず中身はない。

~/pages/login.vue

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

<script>
import { mapState, mapGetters, mapActions } from "vuex";

export default {
  middleware: 'notAuthenticated',
  name: 'Login',
}
</script>

ヘッダーの作成

ログイン/ログアウトをヘッダーに実装する。

~/components/Header.vue

<template>
  <v-app-bar
    :clipped-left="clipped"
    fixed
    app
  >
    <v-app-bar-nav-icon v-if="isLoggedIn" @click.stop="drawer = !drawer" />
    <v-btn
      icon
      v-if="isLoggedIn"
      @click.stop="miniVariant = !miniVariant"
    >
      <v-icon>mdi-{{ `chevron-${miniVariant ? 'right' : 'left'}` }}</v-icon>
    </v-btn>
    <v-toolbar-title></v-toolbar-title>
    <v-spacer />
    <v-btn text='' v-if="isLoggedIn" @click="logout"> Logout </v-btn>
    <FirebaseAuth/>
  </v-app-bar>
</template>

<script>
import FirebaseAuth from '@/components/FirebaseAuth.vue';
import { mapGetters, mapActions } from "vuex";

export default {
  components: {
    FirebaseAuth
  },
  computed: {
    ...mapGetters("auth", [
      "isLoggedIn",
      "getUsername",
      "getUid"
    ]),
  },
  methods: {
    ...mapActions("auth", ["logout"])
  }
}
</script>

フッターの作成

~/components/Footer.vue

<template>
  <v-footer>
    <div class="flex-grow-1"></div>
    <div v-if="getUid"><p class="grey--text" style="font-size: small;">
      UID: {{getUid}}
    </p></div>
  </v-footer>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters("auth", [
      "getUid"
    ]),
  },
}
</script>

FirebaseコンソールでSNS認証の利用を開始

  • Firebaseコンソール の「Authentication」で「始める」ボタンを押下する。
  • 「Sign-in method」で Google を有効にする。

Firebase Hostingの初期設定

以下のコマンドを実行する。

firebase init hosting

publicディレクトリは dist を指定する。

? What do you want to use as your public directory? dist
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
? File dist/index.html already exists. Overwrite? No

ローカル環境でテスト

これでSNS認証によるログインができるようになった。。はず

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?