ラベル firebase の投稿を表示しています。 すべての投稿を表示
ラベル firebase の投稿を表示しています。 すべての投稿を表示

2019年11月11日月曜日

firebase-tools v7.5.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.5.0

  • Firestore Emulator now serves WebChannel traffic on the same port as gRPC.
  • Fix bug where emulators could not find free ports on Windows Subsystem for Linux.
  • Fixes invalid JSON output in auth.export within a scripting environment.

  • Firestore Emulatorは、gRPCと同じポートでWebChannelトラフィックを処理するようになりました。
  • エミュレーターが Windows Subsystem for Linux で空きポートを見つけられなかったバグを修正しました。
  • スクリプト環境内の auth.export での無効なJSON出力を修正しました。

Written with StackEdit.

2019年11月6日水曜日

firebase-tools v7.4.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.4.0

  • Initial release of the appdistribution:distribute command. Refer to the Firebase App Distribution Firebase CLI documentation for Android and iOS for more information about using the Firebase CLI to quickly distribute pre-release versions of your apps to testers.
  • Initial release of the Firebase Extensions ext:* commands. Refer to the CLI documentation for more information about the available commands.
  • (Removed some features from the preview list.)

  • appdistribution:distribute コマンドの初期リリース。Firebase CLIを使用してアプリのプレリリースバージョンをテスターにすばやく配布する方法の詳細については、Firebase App Distribution Firebase CLI documentation for Android および iOS を参照してください。
  • Firebase Extensions ext:*コマンドの初期リリース。 使用可能なコマンドの詳細については、CLIドキュメントを参照してください。
  • (プレビューリストから一部の機能を削除しました。)

Written with StackEdit.

2019年10月19日土曜日

firebase-tools v7.3.2 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.3.2

  • Ensures auth:export results are fully flushed to the output file.
  • Fix bug in Firestore emulator where concurrent requests for the same transaction would sometimes hang.
  • Fix bug in Firestore emulator where WriteResults for deletes had an update_time populated.
  • Set the predefined runtime environment variables in the functions emulator

  • auth:export の結果が出力ファイルに完全にフラッシュされるようにします。
  • 同じトランザクションの同時リクエストが時々ハングするFirestoreエミュレータのバグを修正しました。
  • 削除のWriteResultsに update_time が入力されていたFirestoreエミュレータのバグを修正しました。
  • Functionsエミュレータで定義済みのランタイム環境変数を設定します。

Written with StackEdit.

2019年10月18日金曜日

firebase-tools v7.3.1 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.3.1

  • Fixed bug in Firestore emulator where transactions that timed out could still modify data.
  • Fixed bug where the auth:export command could export the same page of users multiple times.

  • タイムアウトしたトランザクションがデータを変更する可能性があるFirestoreエミュレータのバグを修正しました。
  • auth:export コマンドが同じページのユーザーを複数回エクスポートできるバグを修正しました。

Written with StackEdit.

2019年10月17日木曜日

firebase-tools v7.3.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.3.0

  • Mark list command as deprecated.
  • Mark setup:web command as deprecated.
  • Mark tools:migrate command as deprecated.
  • Fix bug in Cloud Firestore emulator where committing a transaction with no writes would not release locks.

  • list コマンドを非推奨としてマークします。
  • setup:web コマンドを非推奨としてマークします。
  • tools:migrate コマンドを非推奨としてマークします。
  • 書き込みのないトランザクションをコミットしてもロックが解除されない Cloud Firestore エミュレーターのバグを修正しました。

Written with StackEdit.

2019年10月16日水曜日

firebase-tools v7.2.4 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.2.4

  • Update portfinder dependency to avoid breakage when installing firebase-tools.

  • firebase-toolsをインストールする際の破損を避けるためにportfinderの依存関係を更新しました。

Written with StackEdit.

2019年10月15日火曜日

firebase-tools v7.2.3 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.2.3

  • Introduce experimental support for browser clients to the Firestore emulator.
  • No longer require authentication to run the functions emulator.
  • Add new project management commands: projects:create, projects:list, projects:addFirebase.
  • Add new app management commands: apps:create, apps:list, apps:sdkconfig.
  • Improve init command to be able to create a new project.
  • Automatically choose a port for the Firestore emulator to serve WebChannel traffic.
  • Add support for running queries inside of transactions to the Firestore emulator.

  • ブラウザクライアントの実験的なサポートをFirestoreエミュレータに導入しました。
  • Functions エミュレーターを実行するために認証が不要になりました。
  • 新しいプロジェクト管理コマンドを追加: projects:create, projects:list, projects:addFirebase
  • 新しいアプリ管理コマンドを追加: apps:create, apps:list, apps:sdkconfig
  • init コマンドを改善して、新しいプロジェクトを作成できるようにします。
  • Firestoreエミュレーターのポートを自動的に選択して、WebChannelトラフィックを処理します。
  • トランザクション内でクエリを実行するためのサポートをFirestoreエミュレータに追加しました。

Written with StackEdit.

2019年10月14日月曜日

firebase-tools v7.2.2 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.2.2

  • Allow passing GOOGLE_APPLICATION_CREDENTIALS environment variable into the functions emulator.
  • Set FIREBASE_DATABASE_EMULATOR_HOST in emulators:exec.
  • Add upsert API for function triggers to the database emulator.
  • Fix a bug where only one RTDB function could be registered by using the RTDB emulator upsert API to register functions triggers.

  • GOOGLE_APPLICATION_CREDENTIALS 環境変数を Functions エミュレーターに渡すことを許可します。
  • emulators:execでFIREBASE_DATABASE_EMULATOR_HOSTを設定します。
  • Functions トリガーの upsert APIをデータベースエミュレーターに追加します。
  • RTDBエミュレータ upsert APIを使用して Functions トリガーを登録することにより、1つのRTDB関数のみを登録できるバグを修正しました。

Written with StackEdit.

2019年9月17日火曜日

firebase-tools v7.2.1 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.2.1

  • Fixed bug causing Realtime Database emulator to serve errors on the .inspect/coverage.json route.
  • Fixed bug causing Realtime Database emulator to reject requests with Host headers not containing "localhost".
  • Fixed regression in deployment with service account.

  • Realtime Databaseエミュレーターが .inspect/coverage.json ルートでエラーを提供する原因となるバグを修正しました。
  • Realtime Databaseエミュレーターが "localhost" を含まない Host ヘッダーのリクエストを拒否するバグを修正しました。
  • サービスアカウントを使用した展開のリグレッションが修正されました。

翻訳メモ

  • Fixed bug causing Realtime Database emulator to serve errors on the .inspect/coverage.json route.

こちらの .inspect/coverage.json` route というのがよくわからなかったので調べました。
Realtime Database エミュレータ起動時に http://localhost:9000/.inspect/coverage?ns=<database_name> にアクセスするとテストレポートが生成されるようです。
その際に起きていたエラーのバグを修正したということのようでした。

Error: Unexpected server error. At /.inspect/coverage.json?ns=foo
テストレポートを生成する


Written with StackEdit.

2019年9月6日金曜日

firebase-tools v7.2.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.2.0

  • Allow the RTDB emulator to hot-reload rules file on changes.
  • Allows emulated Cloud Functions to talk to production RTDB/Firestore if the emulators are not running.
  • Fixes an issue where internal logs would sometimes appear in stdout.
  • Improves RTDB emulator support for JWT algorithms and arbitrary Google Cloud auth tokens.
  • Fixes an issue where functions:shell logs could be double escaped.
  • Fixes an issue with false noisy logging about emulators not running.
  • Allow starting the RTDB or Firestore emulators with any project ID.

  • RTDBエミュレータが変更時に rules ファイルをホットリロードできるようにします。
  • エミュレーターが実行されていない場合、エミュレートされたCloud Functionsが実稼働しているRTDB/Firestoreと通信できるようにします。
  • 内部ログが標準出力に表示されることがある問題を修正しました。
  • JWTアルゴリズムと任意のGoogle Cloud認証トークンのRTDBエミュレーターサポートを改善します。
  • functions:shell ログが二重にエスケープされる問題を修正しました。
  • エミュレーターが実行されていないという誤ったノイズのあるログの問題を修正
  • 任意のプロジェクトIDでRTDBまたはFirestoreエミュレーターを起動できます。

Written with StackEdit.

2019年9月4日水曜日

Nuxt を 2.4.0 から 2.9.2 にバージョンアップする

2.9.0 から TypeScript の対応が変わったのでバージョンバップ時の手順を残しておきます。

こちらのリポジトリをバージョンアップしました。
https://github.com/TAC/nuxt-typescript-example/tree/Nuxt_2.4.0

バージョンアップ後はこちらになります。
https://github.com/TAC/nuxt-typescript-example

モジュールのアップグレード

まずは npm-check-updates を使って一括でアップグレードしてしまいます。

> ncu -u
Upgrading C:\work\repos\nuxt\typescript\app\package.json
[====================] 24/24 100%

 nuxt                                ^2.4.0  →     ^2.9.2
 nuxt-property-decorator             ^2.1.3  →     ^2.4.0
 ts-node                             ^8.1.0  →     ^8.3.0
 @nuxt/typescript                    ^2.7.1  →     ^2.8.1
 @nuxtjs/eslint-config               ^0.0.1  →     ^1.1.2
 @typescript-eslint/eslint-plugin    ^1.9.0  →     ^2.0.0
 babel-eslint                       ^10.0.1  →    ^10.0.3
 eslint                             ^5.15.1  →     ^6.3.0
 eslint-config-prettier              ^4.1.0  →     ^6.1.0
 eslint-config-standard            >=12.0.0  →   >=14.1.0
 eslint-loader                       ^2.1.2  →     ^3.0.0
 eslint-plugin-import              >=2.16.0  →   >=2.18.2
 eslint-plugin-jest                >=22.3.0  →  >=22.16.0
 eslint-plugin-node                 >=8.0.1  →    >=9.2.0
 eslint-plugin-nuxt                 >=0.4.2  →    >=0.4.3
 eslint-plugin-prettier              ^3.0.1  →     ^3.1.0
 eslint-plugin-promise              >=4.0.1  →    >=4.2.1
 eslint-plugin-standard             >=4.0.0  →    >=4.0.1
 eslint-plugin-vue                   ^5.2.2  →     ^5.2.3
 nodemon                            ^1.18.9  →    ^1.19.1
 prettier                           ^1.16.4  →    ^1.18.2
 rimraf                              ^2.6.3  →     ^3.0.0

Run npm install to install new versions.

package.json が更新されるので yarn でモジュールを更新します。

そして、不要になったモジュールをアンインストールします。

yarn remove ts-node @nuxt/typescript @nuxtjs/eslint-config @typescript-eslint/eslint-plugin

次に新しく必要となったモジュールを追加します。

yarn add @nuxt/typescript-runtime
yarn add -D @nuxt/typescript-build @nuxtjs/eslint-config-typescript

tsconfig.json を修正します。

app/tsconfig.json

{
  "compilerOptions": {
    "types": [
      "@types/node",
-     "@nuxt/vue-app"
+     "@nuxt/types"
    ]

nuxt.config.ts を修正します。

app/nuxt.config.ts

-import NuxtConfiguration from '@nuxt/config'
+import { Configuration } from '@nuxt/types'

-const nuxtConfig: NuxtConfiguration = {
+const nuxtConfig: Configuration = {

+  buildModules: ['@nuxt/typescript-build'],

package.json を修正して、nuxt コマンドを nuxt-ts コマンドに変更します。

app/package.json

  "scripts": {
-   "dev": "nuxt",
-   "build": "nuxt build && yarn build:copy",
+   "dev": "nuxt-ts",
+   "build": "nuxt-ts build && yarn build:copy",

.eslintrc.js を修正して ESLint の設定も変更します。

app/.eslintrc.js

  extends: [
-   '@nuxtjs',
+   '@nuxtjs/eslint-config-typescript',

これだけだと以下の警告メッセージが出ます。

=============

WARNING: You are currently running a version of TypeScript which is not officially supported by typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=3.2.1 <3.6.0

YOUR TYPESCRIPT VERSION: 3.6.2

Please only submit bug reports when using the officially supported version.

=============

これは TypeScript のバージョンが新しすぎた場合の警告で、.eslintrc.jsparserOptions で表示を抑制できるみたいですが、根本的な解決は依存しているモジュールのバージョンが新しくなることのようなので対応を待つしかないようです。

app/.eslintrc.js

module.exports = {
  parserOptions: {
+   'warnOnUnsupportedTypeScriptVersion': false
  },

functions のモジュールもアップグレード

app と同様の手順でアップグレードします。

> ncu -u                                                                                                                                      Upgrading C:\work\repos\nuxt\typescript\functions\package.json
[====================] 14/14 100%

 @nuxt/config              ^2.7.1  →   ^2.9.2
 cross-env                 ^5.2.0  →   ^5.2.1
 express                  ^4.17.0  →  ^4.17.1
 firebase                  ^6.0.2  →   ^6.5.0
 firebase-admin            ~7.0.0  →   ~8.4.0
 firebase-functions        ^2.3.0  →   ^3.2.0
 nuxt                      ^2.4.0  →   ^2.9.2
 nuxt-property-decorator   ^2.1.3  →   ^2.4.0
 ts-node                   ^8.1.0  →   ^8.3.0
 @nuxt/typescript          ^2.7.1  →   ^2.8.1
 @types/express           ^4.16.1  →  ^4.17.1
 tslint                   ^5.12.0  →  ^5.19.0
 typescript                ^3.2.2  →   ^3.6.2

Run npm install to install new versions.

次に Configuration インターフェースの取得先が @nuxt/config から @nuxt/types に変わったので、モジュールを入れ替えます。

> yarn remove @nuxt/config
> yarn add -D @nuxt/types

Nuxtの設定している箇所を修正します。

functions/src/index.ts

-import NuxtConfiguration from '@nuxt/config'
+import { Configuration } from '@nuxt/types'

-const nuxtConfig: NuxtConfiguration = {
+const nuxtConfig: Configuration = {

あとは以前と同じ手順でビルドして、firebase serve で動作確認できます。


以上の設定で 2.4.0 から 2.9.2 にバージョンアップすることができました!

参考サイト

Migration from Nuxt 2.8
Nuxt.js 2.9でのTypeScript対応
typescript環境でALEのeslint利用fixerが動かなくなっていたことの対処方法


Written with StackEdit.

2019年8月28日水曜日

NuxtでFirebaseのAuthenticationを使った認証を行う

FirebaseAuthenticationを使用しての認証機能の実装方法の紹介になります。

完成したプロジェクトは以下のリポジトリになります。
https://github.com/TAC/nuxt-firebase-auth-example

Firebaseの設定

最初にFirebaseの設定を行います。
Firebaseのアカウント作成や設定などは他のサイトなどで確認して下さい。
接続情報は.env/development.jsに記載してnuxt.config.tsで読み込むようにします。
これはリポジトリに入れていないので、上記リポジトリを clone した場合は自分で作成してください。

.env/development.js

module.exports = {
  apiKey: "<your apiKey>",
  authDomain: "<your authDomain>",
  databaseURL: "<your databaseURL>",
  projectId: "<your projectId>",
  storageBucket: "<your storageBucket>",
  messagingSenderId: "<your api messagingSenderId>"
}

app/nuxt.config.ts

import NuxtConfiguration from '@nuxt/config'
import pkg from './package.json'
import envSet from '../.env/environment.js'

const nuxtConfig: NuxtConfiguration = {
  mode: 'universal',
  srcDir: 'src',

  env: envSet,
  ...
}

設定値はprocess.env.apiKeyという形式で利用できます。

次にFirebase の初期設定を行うpluginsを作成します。

app/src/plugins/firebase.js

import firebase from 'firebase/app'

if (!firebase.apps.length) {
  firebase.initializeApp({
    apiKey: process.env.apiKey,
    authDomain: process.env.authDomain,
    databaseURL: process.env.databaseURL,
    projectId: process.env.projectId,
    storageBucket: process.env.storageBucket,
    messagingSenderId: process.env.messagingSenderId
  })
}

export default firebase

FirebaseSDKを使用する箇所でこのプラグインを読み込んで使うことになります。

認証モジュール

Vuex.Store に認証モジュールを作成します。

app/src/store/modules/auth.ts

import {
  VuexModule,
  Module,
  action,
  getRawActionContext
} from 'vuex-class-component'
import firebase from '@/plugins/firebase'
import 'firebase/auth'

@Module({ namespacedPath: 'modules/auth/', target: 'nuxt' })
class Store extends VuexModule {
  @action({ mode: 'raw' })
  public async signIn(provider) {
    const context = getRawActionContext(this)
    context.commit('models/users/UNSET_USER', null, { root: true })
    await firebase
      .auth()
      .signInWithPopup(provider)
      .then(result => {
        if (result.user) {
          context.commit('models/users/SET_USER', result.user, { root: true })
        }
      })
      .catch(error => {
        console.error(error)
        throw error
      })
  }

  @action()
  public async signInGoogle() {
    const provider = new firebase.auth.GoogleAuthProvider()
    await this.signIn(provider)
  }

  @action({ mode: 'raw' })
  public async signOut() {
    const context = getRawActionContext(this)
    await firebase
      .auth()
      .signOut()
      .then(() => {
        context.commit('models/users/UNSET_USER', null, { root: true })
      })
  }

  @action({ mode: 'raw' })
  public isSignIn() {
    const context = getRawActionContext(this)
    return new Promise(resolve => {
      const unsubscribe = firebase.auth().onAuthStateChanged(user => {
        unsubscribe()
        if (user) {
          context.commit('models/users/SET_USER', user, { root: true })
        }
        resolve(user || false)
      })
    })
  }
}

export default Store.ExtractVuexModule(Store)

渡されたプロバイダーの認証を行う signIn アクションと認証データを削除する signOut アクション、サインイン状態の確認を行う isSignIn アクションがあります。
プロバイダーに firebase.auth.GoogleAuthProvider() を渡すとGoogleアカウントの認証ができます。
これを signInGoogle アクションとして作成しておきます。
他にもTwitterやFacebookが認証プロバイダーとして用意されています。
https://firebase.google.com/docs/auth/web/start#next_steps

認証データの保存

firebase.auth().onAuthStateChanged() で取得できるユーザデータを Vuex.Store に保存しておきます。
最初、ユーザデータをそのまま Vuex.Store に保存しようとしたのですが、エラーで動かなかったので修正しました。

参考記事 : Firebase AuthenticationとVuexの合わせ技バグでハマった

app/src/store/models/users.ts

import { VuexModule, Module, getter, mutation } from 'vuex-class-component'

interface User {
  [key: string]: any
}

@Module({ namespacedPath: 'models/users/', target: 'nuxt' })
class Store extends VuexModule {
  @getter user: User | null = null

  get isAuthenticated() {
    return !!this.user
  } 

  @mutation
  public SET_USER(payload) {
    this.user = {
      uid: payload.uid,
      displayName: payload.displayName,
      email: payload.email,
      emailVerified: payload.emailVerified,
      isAnonymous: payload.isAnonymous,
      phoneNumber: payload.phoneNumber,
      photoURL: payload.photoURL,
      providerData: payload.providerData
    }
  }

  @mutation
  public UNSET_USER() {
    this.user = null
  }
}

export default Store.ExtractVuexModule(Store)

認証のテスト

FirebaseSDKをモック化してくれるモジュールをインストールします。(※ただし、このモジュールは残念なことに現在メンテされていません。)

yarn add -D firebase-mock

セットアップ手順をもとに以下のファイルを作成します。

app/tests/__mocks__/plugins/firebase.js

import firebasemock from 'firebase-mock'

const mockauth = new firebasemock.MockAuthentication()
const mockdatabase = new firebasemock.MockFirebase()
const mockfirestore = new firebasemock.MockFirestore()
const mockstorage = new firebasemock.MockStorage()
const mockmessaging = new firebasemock.MockMessaging()

const mocksdk = new firebasemock.MockFirebaseSdk(
  // use null if your code does not use RTDB
  (path) => {
    return path ? mockdatabase.child(path) : mockdatabase
  },
  // use null if your code does not use AUTHENTICATION
  () => {
    return mockauth
  },
  // use null if your code does not use FIRESTORE
  () => {
    return mockfirestore
  },
  // use null if your code does not use STORAGE
  () => {
    return mockstorage
  },
  // use null if your code does not use MESSAGING
  () => {
    return mockmessaging
  }
)

export default mocksdk

@/plugins/firebase の読み込みがモックになるように jest.config.js で設定します。

app/jest.config.js

  moduleNameMapper: {
    '^vue$': 'vue/dist/vue.common.js',
+   '^@/plugins/firebase$': '<rootDir>/tests/__mocks__/plugins/firebase.js',
    '^@/(.*)$': '<rootDir>/src/$1',
    '^~/(.*)$': '<rootDir>/src/$1'
  },

これで Jest での実行時には @/plugins/firebase の読み込みがすべてモックになります。

次に store/modules/auth.ts のテストを書いていきます。

app/tests/store/modules/auth.test.js

import 'firebase/auth'
import Vuex from 'vuex'
import { cloneDeep } from 'lodash'
import { createLocalVue } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import firebase from '@/plugins/firebase'
import auth from '@/store/modules/auth.ts'
import users from '@/store/models/users.ts'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('store/modules/auth.ts', () => {
  let store
  let user

  beforeAll(() => {
    firebase.auth().autoFlush()
  })

  beforeEach(() => {
    // create store
    store = new Vuex.Store({
      modules: {
        'modules/auth': cloneDeep(auth),
        'models/users': cloneDeep(users)
      }
    })

    // mock data
    user = {
      uid: 'alice',
      email: 'alice@mail.com'
    }

    // initialize auth
    firebase
      .auth()
      .createUser(user)
      .then(user => {
        firebase.auth().changeAuthState(user)
      })
  })

  describe('actions', () => {
    test('isSignIn', async () => {
      await store.dispatch('modules/auth/isSignIn')
      const result = store.getters['models/users/user']
      expect(result).toMatchObject(user)
    })

    test('signOut', async () => {
      await store.dispatch('modules/auth/signOut')
      const result = store.getters['models/users/user']
      expect(result).toBeNull()
    })

    test('signInGoogle', async () => {
      firebase.auth().signInWithPopup = jest.fn(provider => {
        return new Promise(resolve => {
          user.providerData = [provider]
          resolve({
            user
          })
        })
      })

      await store.dispatch('modules/auth/signInGoogle')
      await flushPromises()

      const result = store.getters['models/users/user']
      expect(result.providerData[0]).toMatchObject({
        providerId: 'google.com'
      })
    })
  })
})

ポイントとしては以下の2点になります。

  • beforeEach() で初期化時に firebase.auth().autoFlush() を呼び出し、 firebase.auth().createUser() でモック用の認証データを作成しておく
  • firebase.auth().signInWithPopup をモック化する

firebase.auth().autoFlush() を呼び出すことで firebase-mock でモック化された firebase.auth() での変更が反映されるようになります。
また、firebase.auth().signInWithPopup はすでにモックになってますが、期待通りの動きはしてくれません。
なので、正しく動作する形に再度モック関数を設定し直しています。

認証ボタンの作成

最後に作成したアクションを呼び出すボタンを pages/index.vue に配置します。

app/src/pages/index.vue

<template lang="pug">
  section.container
    template(v-if='isAuthenticated')
      ButtonsAction(@action='signOut')
        template(v-slot:buttonText) SignOut
    template(v-else)
      ButtonsAction(@action='signInGoogle')
        template(v-slot:buttonText) Sign-In Google
</template>

<script lang="ts">
import { Component, Vue, namespace } from 'nuxt-property-decorator'
import ButtonsAction from '@/components/buttons/Action.vue'

const Users = namespace('models/users')
const Auth = namespace('modules/auth')

@Component({
  components: {
    ButtonsAction
  }
})
export default class extends Vue {
  @Users.Getter('user') user
  @Users.Getter('isAuthenticated') isAuthenticated
  @Auth.Action('signInGoogle') signInGoogle
  @Auth.Action('signOut') signOut
}
</script>

これで Sign-In Google のボタンが表示され、押すとGoogleアカウント認証のウィンドウがポップアップされると思います。
そのウィンドウで任意のアカウントを選択すると認証が完了します。(GoogleChromeで認証済みの場合はパスワードの入力がスキップされると思います。)
認証が完了するとボタンが SignOut に変わりユーザIDと名前が表示されるかと思います。

SSRに対応する

これでサインイン、サインアウトの実装は終わったのですが、サインインした状態でリロードするとボタンの表示やユーザ情報の表示がちらつくのに気づくと思います。

これはSSR時に認証情報が取得できないためです。
Firebase Authentication では認証情報を IndexedDB に保存しているため、IndexedDB にアクセスできないサーバ側の処理では認証情報を取得できないのです。

そこでサーバ側の処理でも認証情報を取得できるように cookie に認証トークンを保存するように変更します。

Cookieの保存

まずは以下のモジュールを追加します。

yarn add cookie-universal-nuxt jwt-decode core-js@2.6.7

cookie-universal-nuxt はフロント側でもサーバ側でも簡単に cookie にアクセスできるようにしてくれるモジュールです。$cookies をコンテキストに追加してくれます。

jwt-decode はJWTトークンをデコードしてくれるそのまんまのモジュールです。Firebase Authentication で使う認証トークンがJWTトークンなのでこれでデコードします。

core-js は後述するシリアライズ処理で必要になります。
(Nuxt.js 2.8.1 での問題かもしれませんが追加しないとエラーが出ます。)

[追記:2019-09-28]
上記の対応は正しくなかったようです。
詳しくはこちらの記事で説明しています。

次に cookie を操作するヘルパー関数を作成します。

app/src/helpers/cookies.ts

const _OPTIONS = {
  path: '/',
  maxAge: 60 * 60 * 24 * 7,
  secure: true
}

export function getCookie(cookies, name) {
  const data = deserialize(cookies.get('__session'))
  return data[name]
}

export function setCookie(cookies, name, value, isLocalhost) {
  const data = deserialize(cookies.get('__session'))
  data[name] = value
  _OPTIONS.secure = !isLocalhost
  cookies.set('__session', serialize(data), _OPTIONS)
}

export function removeCookie(cookies, name, isLocalhost) {
  const data = deserialize(cookies.get('__session'))
  delete data[name]
  _OPTIONS.secure = !isLocalhost
  cookies.set('__session', serialize(data), _OPTIONS)
}

function serialize(obj) {
  try {
    const str = JSON.stringify(obj, function replacer(k, v) {
      if (typeof v === 'function') {
        return v.toString()
      }
      return v
    })
    return str
  } catch (e) {
    return {}
  }
}

function deserialize(str) {
  try {
    const obj = JSON.parse(str, function reciever(k, v) {
      if (typeof v === 'string' && v.startsWith('function')) {
        return Function.call(this, 'return ' + v)()
      }
      return v
    })
    return obj
  } catch (e) {
    return {}
  }
}

注意点は __session という名前で保存する必要がある点です。Firebaseでホスティングする場合、これ以外の名前の cookie は削除されてしまいます。
https://firebase.google.com/docs/hosting/manage-cache#using_cookies

__session 以外の名前が使えないので、この中に連想配列をシリアライズして登録します。

認証トークンの保存

以下に記載する箇所で認証トークンの保存と読み込みを行います。

app/src/pages/index.vue

  private signInGoogle() {
    const that = this as any
    this.authSignInGoogle().then(() => {
      const currentUser = firebase.auth().currentUser
      if (currentUser) {
        currentUser.getIdToken().then(token => {
          setCookie(that.$cookies, 'token', token, that.$isLocalhost)
        })
      }
    })
  }

  private signOut() {
    const that = this as any
    this.authSignOut().then(() => {
      removeCookie(that.$cookies, 'token', that.$isLocalhost)
    })
  }

サインインした時に認証トークンを取得して保存、サインアウトした時に保存してある認証トークンを削除します。

app/src/plugins/auth.js

import firebase from '@/plugins/firebase'
import 'firebase/auth'
import { setCookie } from '@/helpers/cookies'

export default async function({ store, app }) {
  await store.dispatch('modules/auth/isSignIn')

  const currentUser = firebase.auth().currentUser
  if (currentUser) {
    currentUser.getIdToken().then(token => {
      setCookie(app.$cookies, 'token', token, app.$isLocalhost)
    })
  }
}

認証プラグインを作成して、リロード時に認証トークンが保存されるようにします。

app/src/store/index.ts

import jwtDecode from 'jwt-decode'
import { getCookie } from '@/helpers/cookies'

export const actions = {
  nuxtServerInit: ({ commit }, { app }) => {
    const token = getCookie(app.$cookies, 'token')
    if (token) {
      commit('models/users/SET_USER', jwtDecode(token))
    }
  }
}

Vuex.storenuxtServerInit 処理時に保存してある認証トークンからユーザデータを取得します。(今回はユーザデータをFirestoreなどから取得していないのでこのような形ですが、サーバ側からデータ取得する際には認証トークンの検証が必要になります。)

認証トークンから取得できるユーザデータが onAuthStateChanged とは若干違うのでユーザデータの保存処理も修正します。(ちょっと無理やりですが・・・)

app/src/store/models/users.ts

  @mutation
  public SET_USER(payload) {
    const uid = payload.uid !== undefined ? payload.uid : payload.user_id
    const displayName =
      payload.displayName !== undefined ? payload.displayName : payload.name
    const emailVerified =
      payload.emailVerified !== undefined
        ? payload.emailVerified
        : payload.email_verified
    const photoURL =
      payload.photoURL !== undefined ? payload.photoURL : payload.picture
    this.user = {
      uid,
      displayName,
      email: payload.email,
      emailVerified,
      isAnonymous: payload.isAnonymous,
      phoneNumber: payload.phoneNumber,
      photoURL,
      providerData: payload.providerData
    }
  }

これでサインインしたあとにリロードしてもボタン等がちらつかなくなったと思います。

まとめ

ざっくりとですが Firebase Authentication を使った認証の実装の一例を紹介しました。

Firebase は他にも便利な機能があるのでもっと紹介してきたいと思います!


Written with StackEdit.

2019年8月26日月曜日

firebase-tools v7.1.1 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.1.1

  • Fixes issue deploying scheduled functions for non us-central project locations.
  • Cleans up unnecessary emulator JAR files when a new one is downloaded.

  • us-central 以外のプロジェクトの場所にスケジュールされた機能をデプロイする際の問題を修正しました。
  • 新しいファイルがダウンロードされたときに、不要なエミュレータJARファイルをクリーンアップします。

Written with StackEdit.

2019年8月23日金曜日

firebase-tools v7.1.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.1.0

  • Auto-download Firestore and RTDB emulators when using emulators:start.
  • Make functions:shell respect the --port argument.
  • Improve error message when firebase serve can’t acquire the right port.
  • Allow running the Firestore and RTDB emulators without a configuration.
  • Fixes bug where profiler table rendering crashes due to undefined path.
  • Allow the Firestore emulator to give more information about invalid rulesets.
  • Hot reload firestore rules on change.
  • Upgrade archiver dependency to 3.0.0.
  • Update functions init templates to v3.1.0
  • Fix emulation of https functions.
  • Fix bug where calling clearFirestoreData against the Firestore Emulator fails if more than 500 documents exist.
  • Fix multipart uploads in emulator.
  • Fixes long responses from emulator being truncated.
  • Fixes a bug where admin.firestore() and app.firestore() behaved differently.
  • Fix issue with npm 6.10 where an internal version check of the firebase-functions SDK caused a crash.
  • Fix bug in Firestore emulator where queries with startAfter had incorrect boundary behavior.
  • Fix bug where too many functions would hang the emulator.
  • Improves ability of Firebase CLI to be used with service accounts.

  • emulators:start を使うときは、FirestoreとRTDBエミュレータを自動ダウンロードします。
  • functions:shell--port 引数を尊重するようにします。
  • firebase serve が正しいポートを取得できない場合のエラーメッセージを改善しました。
  • 設定なしでFirestoreおよびRTDBエミュレータを実行することを許可します。
  • 未定義の path が原因でプロファイラテーブルのレンダリングがクラッシュするバグを修正しました。
  • Firestoreエミュレータが無効なルールセットについてより多くの情報を提供できるようにします。
  • Firestore rules の変更時にホットリロードします。
  • アーカイバの依存関係を3.0.0にアップグレードします。
  • Functions 初期化テンプレートを v3.1.0 に更新。
  • https Functionsのエミュレーションを修正しました。
  • Firestore Emulatorに対して500を超えるドキュメントが存在すると、clearFirestoreData の呼び出しが失敗するというバグを修正しました。
  • エミュレータでのマルチパートアップロードを修正しました。
  • エミュレータからの長い応答が切り捨てられるのを修正。
  • admin.firestore()app.firestore() の動​​作が異なるというバグを修正しました。
  • firebase-functions SDKの内部バージョンチェックがクラッシュを引き起こすnpm 6.10 の問題を修正しました。
  • startAfterを使ったクエリが誤った境界動作をしていたFirestoreエミュレータのバグを修正しました。
  • Functionsが多すぎるとエミュレータをハングさせるというバグを修正しました。
  • Firebase CLIがサービスアカウントで使用される機能が向上しました。

Written with StackEdit.

2019年8月19日月曜日

firebase-tools v7.0.2 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.0.2

  • Fixes a bug where the functions emulator did not work with firebase-functions versions 3.x.x.
  • Make the Functions emulator automatically point to the RTDB emulator when running.
  • Fixes issue where the functions runtime would not always exit on success (#1346).

  • Functions エミュレータが firebase-functions のバージョン 3.x.x で動作しなかったバグを修正しました。
  • 実行時にFunctions エミュレータが自動的にRTDBエミュレータを指すようにします。
  • Functions ランタイムが成功時に常に終了しない問題を修正しました。 (#1346)

Written with StackEdit.

2019年7月30日火曜日

firebase-tools v7.0.1 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.0.1

  • Fixes bug where firebase serve --only functions dropped the host argument.
  • Fixes bug where grpc-js connections used the wrong credentials.
  • Fixes bug where firebase open would return an error.
  • Sets version of inquirer package to prevent issues in firebase init.

  • firebase serve --only functions がホスト引数を削除していたバグを修正しました。
  • grpc-js 接続が間違った認証情報を使っていたバグを修正しました。
  • firebase open がエラーを返すというバグを修正しました。
  • firebase init の問題を防ぐために inquirer パッケージのバージョンを設定します。

Written with StackEdit.

2019年7月6日土曜日

firebase-tools v7.0.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v7.0.0

  • BREAKING The CLI no longer supports being run in Node 6 environments.
  • BREAKING RTDB Emulator comes up with open rules by default.
  • Modify RTDB emulator to publish triggers to the functions emulator.
  • Modify functions emulator to invoke RTDB emulator triggers.
  • Engines field is now required in package.json for functions deploys.
  • Fix bug where raw body was missing on HTTPS function request.
  • Fix bug with Functions Emulator and firebase-admin@8.0.0.
  • Fix req.baseUrl in Functions Emulator.
  • Add FUNCTIONS_EMULATOR environmental variable when running in Functions Emulator.
  • Set FIRESTORE_EMULATOR_HOST env var in “emulators:exec”.
  • Fix bug in printing Function logs when the text payload was undefined.
  • Update functions init templates to use firebase-functions v3 and firebase-admin v8.

  • 重要な変更 CLI は Node6 環境での実行をサポートしなくなりました。
  • 重要な変更 RTDB エミュレータはデフォルトでオープンルールを思い付きます。
  • Functions エミュレータにトリガを発行するようにRTDBエミュレータを変更します。
  • RTDBエミュレータトリガを呼び出すように Functions エミュレータを修正します。
  • Functions のデプロイには、package.json で Engines フィールドが必須になりました。
  • raw body がHTTPS関数リクエストで欠けていたバグを修正しました。
  • Functions エミュレータと firebase-admin@8.0.0 のバグを修正。
  • Functions エミュレータの req.baseUrl を修正。
  • Functions エミュレータで実行するときは、 FUNCTIONS_EMULATOR 環境変数を追加してください。
  • "emulators:exec" に FIRESTORE_EMULATOR_HOST 環境変数を設定してください。
  • テキストペイロードが未定義のときにFunctionログを印刷する際のバグを修正しました。
  • firebase-functions v3firebase-admin v8 を使うように functions init テンプレートを更新。

翻訳メモ

BREAKING重要な変更

BREAKING だけだと 壊れる とかになるが、他の Release Note 等を見てみると breaking changes という表現が使われていた。
これだと 重要な変更 といった意味になるようなのでこれを採用した。


Written with StackEdit.

2019年7月3日水曜日

firebase-tools v6.12.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v6.12.0

  • Set FIRESTORE_EMULATOR_HOST env var in “emulators:exec”.
  • Fixes bug in printing Function logs when the text payload was undefined.
  • Fixes bug in Firestore emulator where property paths with special characters would cause errors due to ClassNotFound exceptions.
  • Fixes bug in Firestore emulator where auto-id allocation only worked once per collection.
  • Adds REST API to Firestore emulator for setting security rules.
  • Functions emulator now limits request sizes to 10MB.
  • Fixes bug where firebase emulators:exec would succeed even if the script failed.
  • Initializing Firestore or Storage now requires a cloud resource location to be set.

  • FIRESTORE_EMULATOR_HOST 環境変数を “emulators:exec” に設定してください。
  • テキストペイロードが未定義のときにFunctionログを印刷する際のバグを修正しました。
  • 特殊文字を含むプロパティパスで ClassNotFound 例外が原因でエラーが発生するFirestoreエミュレータのバグを修正しました。
  • 自動ID割り当てがコレクションごとに1回しか機能しなかったFirestoreエミュレータのバグを修正しました。
  • セキュリティルールを設定するためのREST APIをFirestoreエミュレータに追加します。
  • Functionsエミュレータは要求サイズを10MBに制限しました。
  • スクリプトが失敗しても firebase emulators:exec が成功するというバグを修正しました。
  • FirestoreまたはStorageを初期化するには、クラウドリソースの場所を設定する必要があります。

Written with StackEdit.

2019年6月29日土曜日

firebase-tools v6.11.0 release note 和訳

※翻訳勉強中のため、間違っている可能性があります。


https://github.com/firebase/firebase-tools/releases/tag/v6.11.0

  • Fixed bug in Firestore emulator where some FieldTransforms were sending back incorrect results.
  • Fixed bug where read-only transactions would cause errors in the Firestore emulator.
  • Fixed bug where collection group query listeners would cause errors in the Firestore emulator.
  • Fixed bug where query parameters were not sent to HTTP functions.
  • Fixed bug where some HTTP methods (like DELETE) were not allowed.
  • Fixed bug where CORS headers were too restrictive.
  • Fixed bug where CSV exporting users with commas in displayName causes columns to no longer align.
  • Fixed bug where environment variables are unset for script in emulators:exec.
  • emulators:exec script now inherits stdout and stderr.
  • Improved reliability and performance of project listing for firebase use command.
  • Fixed bug where firestore:delete skips legacy documents with numeric IDs.
  • Fixed bug in Firestore emulator where it ignored x-forwarded-host header.
  • Improved Scheduled Functions deployment to keep and not recreate schedules that are already correct.

  • いくつかの FieldTransforms が誤った結果を送り返していたFirestoreエミュレータのバグを修正しました。
  • 読み取り専用トランザクションがFirestoreエミュレータでエラーを引き起こすというバグを修正しました。
  • Collection Group Query リスナーがFirestoreエミュレータでエラーを引き起こすというバグを修正しました。
  • クエリパラメータがHTTP関数に送信されなかったバグを修正しました。
  • いくつかのHTTPメソッド(DELETEなど)が許可されていなかったバグを修正しました。
  • CORSヘッダの制限が厳しすぎるというバグを修正。
  • displayName にカンマを使用してCSVをエクスポートすると、列が整列されなくなるというバグが修正されました。
  • 環境変数が emulators:exec のスクリプトに設定されていないバグを修正しました。
  • emulators:exec スクリプトは現在 stdoutstderr を継承しています。
  • firebase use コマンドのプロジェクト一覧の信頼性とパフォーマンスが向上しました。
  • firestore:delete が数値IDを持つレガシードキュメントをスキップするバグを修正しました。
  • Firestoreエミュレータが x-forwarded-host ヘッダを無視していたバグを修正しました。
  • Scheduled Functions のデプロイを改善し、すでに正しいスケジュールを保持し、再作成しないようにしました。

Written with StackEdit.

2019年6月4日火曜日

NuxtでTypeScriptを使うときのVeux.storeの設定方法

NuxtTypeScript で構築した時に Vuex.store の構成をどうしたらいいかを考えてみました。

結論としては vuex-class-component を使用してモジュールモードで構成する、という感じになりました。

完成したプロジェクトは以下のリポジトリになります。
https://github.com/TAC/nuxt-vuex-typescript-example

簡単なカウンターを作成しました。

環境

- version
OS Windows10
Node.js v8.15.0
Nuxt.js v2.7.1

どのモジュールがいいのか?

Vuex.store を簡潔にかけるようにするモジュールはいくつかあって、以下の2つが主に使われてるようでした。

vuex-class-component
https://github.com/michaelolof/vuex-class-component

vuex-module-decorators
https://github.com/championswimmer/vuex-module-decorators

Nuxt では store ディレクトリ以下にファイルを配置すれば自動で Vuex のモジュールモードで構築してくれます。

ただし、 store/index.ts が関数を返すとクラシックモードになり、その恩恵を受けることができません。
また、各モジュールのファイルも関数ではなくオブジェクトを返す必要があり、それができるのが vuex-class-component でした。
また、Nuxt.jsv3.0.0 ではクラシックモードが非対応になるようなので、それを考慮に入れての選択になります。

ディレクトリ構成

以下のような構成を考えてみました。

src/store/index.ts
  +- modules/
      +- counter.ts

modules に機能毎に分けたモジュールを作成していく感じです。
models とか作ってDBのテーブル毎などに分けたモジュールを作成してもいいかもしれない。

counter.ts

デコレータを使って以下のように記述します。

import {
  VuexModule,
  Module,
  action,
  getter,
  mutation
} from 'vuex-class-component'

interface Counter {
  value: number
}

@Module({ namespacedPath: 'modules/counter/', target: 'nuxt' })
export class CounterStore extends VuexModule implements Counter {
  @getter value = 0

  @mutation
  public SET_VALUE(value: number) {
    this.value = value
  }

  @action()
  public increment(value: number) {
    this.SET_VALUE(this.value + value)
  }

  @action()
  public decrement(value: number) {
    this.SET_VALUE(this.value - value)
  }
}

export default CounterStore.ExtractVuexModule(CounterStore)

ポイントは2つあって、1つは @Module のオプションに namespacedPathtarget:'nuxt' を指定するところです。
もう1つは、最後の行で ExtractVuexModule を使ってオブジェクト形式で export してあげるところです。
これで Vuex.store のモジュールモードに対応できました。

index.ts

index.ts もデコレータを使って記述しようとしたのですが、 nuxtServerInit の定義がどうしてもできなかったので、デコレータを使わずに記述します。

export const actions = {
  nuxtServerInit: ({ commit }) => {
    commit('modules/counter/SET_VALUE', 20)
  }
}

ここでは modules/counter の初期化を行ってみました。

呼び出すComponent

components/Counter.vue を作成します。

<template lang="pug">
  div [counter]
    div {{ counter }}
    div
      button(@click="increment") +
      button(@click="decrement") -
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'

@Component
export default class Counter extends Vue {
  get counter() {
    return this.$store.getters['modules/counter/value']
  }

  public increment() {
    this.$store.dispatch('modules/counter/increment', 1)
  }
  public decrement() {
    this.$store.dispatch('modules/counter/decrement', 1)
  }
}
</script>

呼び出す箇所は通常の使い方と同じです。

これでごちゃごちゃしがちな store 周りをスッキリとかけるようになったかと思います。

Written with StackEdit.