※翻訳勉強中のため、間違っている可能性があります。
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.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.2.4
Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.2.3
projects:create, projects:list, projects:addFirebase.apps:create, apps:list, apps:sdkconfig.init command to be able to create a new project.Functions エミュレーターを実行するために認証が不要になりました。projects:create, projects:list, projects:addFirebaseapps:create, apps:list, apps:sdkconfiginit コマンドを改善して、新しいプロジェクトを作成できるようにします。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.2.2
GOOGLE_APPLICATION_CREDENTIALS environment variable into the functions emulator.GOOGLE_APPLICATION_CREDENTIALS 環境変数を Functions エミュレーターに渡すことを許可します。Functions トリガーの upsert APIをデータベースエミュレーターに追加します。upsert APIを使用して Functions トリガーを登録することにより、1つのRTDB関数のみを登録できるバグを修正しました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/nuxt/nuxt.js/releases/tag/v2.8.1
バグ修正
vue-renderer vue-appconsole.logcli vue-renderer vue-app console.log をオーバーライドしないようにしたcli リファクタ
typescript typescript Typescript サポートを準備するWritten with StackEdit.
以前、こちらの記事で
以下のエラーに対応するために core-js@2.6.7 を別途追加する
旨の記載をしましたが、対応が間違っていたようです。
こちらのリポジトリを修正してあります。
https://github.com/TAC/nuxt-firebase-auth-example
These dependencies were not found: friendly-errors 16:19:36
friendly-errors 16:19:36
* core-js/modules/es6.array.find in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es6.array.iterator in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es6.date.to-string in ./.nuxt/utils.js, ./src/helpers/cookies.ts friendly-errors 16:19:36
* core-js/modules/es6.function.name in ./.nuxt/client.js, ./src/store/models/users.ts friendly-errors 16:19:36
* core-js/modules/es6.object.assign in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es6.object.keys in ./.nuxt/index.js friendly-errors 16:19:36
* core-js/modules/es6.object.to-string in ./.nuxt/router.scrollBehavior.js, ./.nuxt/components/nuxt-link.client.js and 2 others friendly-errors 16:19:36
* core-js/modules/es6.promise in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es6.regexp.constructor in ./.nuxt/utils.js friendly-errors 16:19:36
* core-js/modules/es6.regexp.match in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es6.regexp.replace in ./.nuxt/store.js, ./.nuxt/components/nuxt.js friendly-errors 16:19:36
* core-js/modules/es6.regexp.search in ./.nuxt/utils.js friendly-errors 16:19:36
* core-js/modules/es6.regexp.split in ./.nuxt/store.js, ./node_modules/babel-loader/lib??ref--2-0!./node_modules/vue-loader/lib??vue-loader-options!./.nuxt/components/nuxt-build-indicator.vue?vue&type=script&lang=js&
* core-js/modules/es6.regexp.to-string in ./.nuxt/utils.js, ./src/helpers/cookies.ts friendly-errors 16:19:36
* core-js/modules/es6.string.includes in ./.nuxt/client.js, ./.nuxt/components/nuxt-link.client.js and 1 other friendly-errors 16:19:36
* core-js/modules/es6.string.iterator in ./.nuxt/App.js friendly-errors 16:19:36
* core-js/modules/es6.string.repeat in ./.nuxt/utils.js friendly-errors 16:19:36
* core-js/modules/es6.string.starts-with in ./.nuxt/utils.js, ./src/helpers/cookies.ts friendly-errors 16:19:36
* core-js/modules/es6.symbol in ./.nuxt/store.js, ./.nuxt/components/nuxt-link.client.js friendly-errors 16:19:36
* core-js/modules/es7.array.includes in ./.nuxt/store.js, ./.nuxt/components/nuxt-link.client.js and 1 other friendly-errors 16:19:36
* core-js/modules/es7.object.get-own-property-descriptors in ./.nuxt/utils.js friendly-errors 16:19:36
* core-js/modules/es7.promise.finally in ./.nuxt/client.js friendly-errors 16:19:36
* core-js/modules/es7.symbol.async-iterator in ./.nuxt/client.js, ./.nuxt/components/nuxt-link.client.js friendly-errors 16:19:36
* core-js/modules/web.dom.iterable in ./.nuxt/App.js, ./.nuxt/components/nuxt-link.client.js
確かに core-js@2.6.7 を追加することでエラーは解消し、正常に動作するようになりますが、どうやら yarn.lock を削除して node_modules を構築し直すとエラーは解消するようでした。
バージョンアップによって依存関係が正しく変更されなかった影響のようです。
Nuxt 2.5.0 にバージョンアップしたら core-js のエラーが出るようになった
core-js problems with 2.5.0
Written with StackEdit.
「NuxtでFirebaseのAuthenticationを使った認証を行う」でつかったプロジェクトのモジュールをアップグレードした際に vuex-class-component がバージョンアップしていたことではまったので、その内容と解決方法を記録しておきます。
修正内容は以下のリポジトリに反映してあります。
https://github.com/TAC/nuxt-firebase-auth-example
「Nuxt を 2.4.0 から 2.9.2 にバージョンアップする」でやった手順をもとにバージョンアップしたところ、以下のエラーが発生するようになりました。
ERROR [Vue warn]: Error in render: "TypeError: Cannot redefine property: user"
当初はどこに問題があるのかわからなかったのですが、調べていくうちに vuex-class-component が1.6.0 から 2.0.4 へ大きくバージョンアップして、使用方法が変わっていることにたどりつきました。
さらに調べた結果、バージョンアップの影響で state に getter を付与する方法だと、上記のエラーが出るようになってしまっていたので、該当箇所は以下のように変更しました。
app/src/store/models/users.ts
- @getter user: User | null = null
+ private user: User | null = null
+ get get() {
+ return this.user
+ }
app/src/pages/index.vue
export default class extends Vue {
- @Users.Getter('user') user
+ @Users.Getter('get') user
nullやundefineを設定していた場合に出るエラーのようでした。- @getter user: User | null = null
+ @getter user: User = {}
get isAuthenticated() {
- return !!this.user
+ return !!this.user.uid
}
@mutation
public UNSET_USER() {
- this.user = null
+ this.user = {}
}
これでビルドは通ったのですが、Sign-In Google のボタンを押下したときに以下のエラーが出るようになりました。
[vuex] unknown local action type: modules/signIn, global type: modules/auth/modules/signIn
どうやらモジュールモードでのパスの設定がうまく行っていないようでした。
該当箇所を以下のように修正することで対応できました。
app/src/store/modules/auth.ts
- @action()
+ @action({ mode: 'raw' })
public async signInGoogle() {
+ const context = getRawActionContext(this)
const provider = new firebase.auth.GoogleAuthProvider()
- await this.signIn(provider)
+ await context.dispatch('signIn', provider)
}
Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/nuxt/nuxt.js/releases/tag/v2.8.0
開発者の体験
pages/ creation when default page displayedpages/ の作成に注意してください。バグ修正
vue-renderer server builder generator types babel.presetsvue-app utils serializeFunction edge casevue-renderer server builder generator types babel.presets のタイプ定義を追加vue-app utils serializeFunction エッジケースの処理機能
vue-renderer リファクタ
core require.resolve instead of Module internalsbuilder nuxtOptionsvue-app general core Module 内部の代わりに require.resolve を使用builder nuxtOptions としてテンプレートに渡しますvue-app general 事例
auth-jwt typescript (※) Vuexモジュールモードのことと思われる
雑用
ci general ci general cross-env を削除しますFUNDING.md を追加しますreadme のリンクを改善するテスト
general Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.2.1
.inspect/coverage.json route.Host headers not containing "localhost"..inspect/coverage.json ルートでエラーを提供する原因となるバグを修正しました。"localhost" を含まない Host ヘッダーのリクエストを拒否するバグを修正しました。
- Fixed bug causing Realtime Database emulator to serve errors on the
.inspect/coverage.jsonroute.
こちらの .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.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.2.0
functions:shell ログが二重にエスケープされる問題を修正しました。Written with StackEdit.
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.js の parserOptions で表示を抑制できるみたいですが、根本的な解決は依存しているモジュールのバージョンが新しくなることのようなので対応を待つしかないようです。
app/.eslintrc.js
module.exports = {
parserOptions: {
+ 'warnOnUnsupportedTypeScriptVersion': false
},
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.
FirebaseのAuthenticationを使用しての認証機能の実装方法の紹介になります。
完成したプロジェクトは以下のリポジトリになります。
https://github.com/TAC/nuxt-firebase-auth-example
最初に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時に認証情報が取得できないためです。
Firebase Authentication では認証情報を IndexedDB に保存しているため、IndexedDB にアクセスできないサーバ側の処理では認証情報を取得できないのです。
そこでサーバ側の処理でも認証情報を取得できるように 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.store の nuxtServerInit 処理時に保存してある認証トークンからユーザデータを取得します。(今回はユーザデータを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.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.1.1
us-central project locations.us-central 以外のプロジェクトの場所にスケジュールされた機能をデプロイする際の問題を修正しました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.1.0
emulators:start.functions:shell respect the --port argument.firebase serve can’t acquire the right port.path.v3.1.0clearFirestoreData against the Firestore Emulator fails if more than 500 documents exist.admin.firestore() and app.firestore() behaved differently.6.10 where an internal version check of the firebase-functions SDK caused a crash.startAfter had incorrect boundary behavior.emulators:start を使うときは、FirestoreとRTDBエミュレータを自動ダウンロードします。functions:shell が --port 引数を尊重するようにします。firebase serve が正しいポートを取得できない場合のエラーメッセージを改善しました。path が原因でプロファイラテーブルのレンダリングがクラッシュするバグを修正しました。v3.1.0 に更新。clearFirestoreData の呼び出しが失敗するというバグを修正しました。admin.firestore() と app.firestore() の動作が異なるというバグを修正しました。firebase-functions SDKの内部バージョンチェックがクラッシュを引き起こすnpm 6.10 の問題を修正しました。startAfterを使ったクエリが誤った境界動作をしていたFirestoreエミュレータのバグを修正しました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.0.2
firebase-functions versions 3.x.x.firebase-functions のバージョン 3.x.x で動作しなかったバグを修正しました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.0.1
firebase serve --only functions dropped the host argument.grpc-js connections used the wrong credentials.firebase open would return an error.inquirer package to prevent issues in firebase init.firebase serve --only functions がホスト引数を削除していたバグを修正しました。grpc-js 接続が間違った認証情報を使っていたバグを修正しました。firebase open がエラーを返すというバグを修正しました。firebase init の問題を防ぐために inquirer パッケージのバージョンを設定します。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v7.0.0
firebase-admin@8.0.0.FUNCTIONS_EMULATOR environmental variable when running in Functions Emulator.raw body がHTTPS関数リクエストで欠けていたバグを修正しました。firebase-admin@8.0.0 のバグを修正。req.baseUrl を修正。FUNCTIONS_EMULATOR 環境変数を追加してください。"emulators:exec" に FIRESTORE_EMULATOR_HOST 環境変数を設定してください。firebase-functions v3 と firebase-admin v8 を使うように functions init テンプレートを更新。BREAKING だけだと 壊れる とかになるが、他の Release Note 等を見てみると breaking changes という表現が使われていた。
これだと 重要な変更 といった意味になるようなのでこれを採用した。
Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v6.12.0
firebase emulators:exec would succeed even if the script failed.FIRESTORE_EMULATOR_HOST 環境変数を “emulators:exec” に設定してください。ClassNotFound 例外が原因でエラーが発生するFirestoreエミュレータのバグを修正しました。firebase emulators:exec が成功するというバグを修正しました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/firebase/firebase-tools/releases/tag/v6.11.0
emulators:exec.emulators:exec script now inherits stdout and stderr.firebase use command.firestore:delete skips legacy documents with numeric IDs.x-forwarded-host header.FieldTransforms が誤った結果を送り返していたFirestoreエミュレータのバグを修正しました。Collection Group Query リスナーがFirestoreエミュレータでエラーを引き起こすというバグを修正しました。displayName にカンマを使用してCSVをエクスポートすると、列が整列されなくなるというバグが修正されました。emulators:exec のスクリプトに設定されていないバグを修正しました。emulators:exec スクリプトは現在 stdout と stderr を継承しています。firebase use コマンドのプロジェクト一覧の信頼性とパフォーマンスが向上しました。firestore:delete が数値IDを持つレガシードキュメントをスキップするバグを修正しました。x-forwarded-host ヘッダを無視していたバグを修正しました。Scheduled Functions のデプロイを改善し、すでに正しいスケジュールを保持し、再作成しないようにしました。Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/nuxt/nuxt.js/releases/tag/v2.7.1
修正
依存関係のアップグレード
style property when resolving (jsless/postcss-import-resolver#2)styleプロパティが優先される必要がある (jsless/postcss-import-resolver#2)Written with StackEdit.
※翻訳勉強中のため、間違っている可能性があります。
https://github.com/nuxt/nuxt.js/releases/tag/v2.7.0
SSRのログをブラウザへ出力
We all know the console.log debugging method, but when working with universal applications, you have to remember that sometimes, your logs are in your terminal and not in your browser console.
console.logというデバッグ方法がありますが、ユニバーサルアプリケーションを作成している場合、ログはブラウザコンソールではなくターミナルに出力されることがあるのを覚えておかなければなりません。
This can be really annoying when developing a Nuxt.js application, starting with this version and running nuxt dev, the ssr logs are now reported to your browser console:
このバージョンから始めて nuxt devを実行して、Nuxt.jsアプリケーションを開発するとき、これは本当に厄介なことになるかもしれません、SSRのログはブラウザのコンソールに表示されるようになりました。
store/ creation 👀store/ ディレクトリの作成を検出
Nuxt.js now detects when you created a store/ directory and will reload himself auto-magically so you don’t have to restart it anymore.
Nuxt.jsは、あなたが store/ディレクトリを作成したことを検出し、自動的に自分自身を再ロードするので、もう再起動する必要はありません。
PS: We also improved the serverMiddleware watch to restart Nuxt.js and clean their cache
PS:Nuxt.jsを再起動してキャッシュを消去するために serverMiddlewareの監視を改良しました。
修正
watch:restart after watch:fileChanged hook (#5620)watchQuery option in routerViewKey (#5516)spa:templateParams hook (#5619)HardSourcePlugin (#5653)serverMiddleware paths (#5681)watch:fileChangedフックの後にwatch:restartを呼び出す (#5620)routerViewKeyのwatchQueryオプションを検討してください(#5516)spa:templateParamsフックを待ってください (#5619)HardSourcePluginに警告するように設定します (#5653)serverMiddlewareパスを監視する (#5681)特徴
transition to pageTransition and deprecate it (#5558)babel.presets and babel envName (#5637)transitionをpageTransitionに改名して非推奨になりました (#5558)babel.presetsとバベルenvName(#5637)リファクタリング
chalkの警告を削除 (#5609)core-js@3 example in the readme (#5633)core-js@3の例を追加 (#5633)Only for typescript users, Nuxt.js v2.7 dropped support for node < 8.6 relate to ts-loader v6
TypeScriptユーザのみ、Nuxt.js v2.7ではts-loader v6に関連してNode v8.6未満のサポートを終了しました
context.app type (#5701)extendRoutes method type (#5700)ts-node to register twice (#5699)config typesにbabelを追加 (#5666)context.appタイプを修正 (#5701)extendRoutesメソッドの型を修正 (#5700)ts-nodeが2回登録されるのを防ぎます (#5699)Written with StackEdit.