主旨
Linux/Windows WSL2 (Ubuntu 20.04LTS) でやります。各種ツールのバージョンは以下の通り。
$ npm -v
8.7.0
$ yarn -v
1.22.11
$ vue -V
@vue/cli 5.0.4
$ node -v
v16.14.0
$ firebase --version
10.7.1
準備
vue + vuetify アプリケーションの作成
vue-app
の部分は、自分の作りたいプロジェクトの名前に置き換えてください。
$ vue create vue-app
Vue CLI v5.0.4
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
Manually select features
...
$ cd vue-app
$ vue add vuetify
? Choose a preset:
Configure (advanced)
Default (recommended)
❯ Vite Preview (Vuetify 3 + Vite)
Prototype (rapid development)
Vuetify 3 Preview (Vuetify 3)
...
$ vue add router
WARN There are uncommitted changes in the current repository, it's recommended to commit or stash them first.
? Still proceed? Yes
...
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
...
vscode の拡張機能は volar を使うことが推奨されているようです。
冒頭の vue create vue-app
は下記のようにしてもいけます。
$ npm init vite@latest vue-app
typescript にしたい場合は、下記の方法でプロジェクトを作成しないと、うまくいかないようです(vue create
ではダメ)。
$ npm init vite@latest vue-app --template vue-ts
Typescript を使った場合で、vue add router
したときに Error: Cannot find module '@vue/cli-service/generator/template/src/App.vue' ... というエラーが出た場合は、先に下記コマンドを実行します。
$ npm install --save-dev @vue/cli-service
起動テスト
$ yarn dev
これで http://localhost:3000 にアクセスすると下記の画面が出るはず。
もし下記のようなエラーが出たら、jsconfig.json の target
を es6
にする。
vite.config.js:5:0:
5 │ const path = require('path')
╵ ~~~~~
The target environment was set to "es5" here:
jsconfig.json:3:14:
3 │ "target": "es5",
╵ ~~~~~
このエラーがでたら、
{
"compilerOptions": {
"target": "es6",
...
}
こうします。(vuetify3.0.0 beta 3 からは、このエラーは出なくなった気がします)
router/indes.js で process is not defined のエラーが出る
history: createWebHistory(process.env.BASE_URL),
を history: createWebHistory(import.meta.env.BASE_URL),
に書きかえます。
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
下記参照のこと。
これで動けば、vue まわりの準備は完了です。
firebase 関連の初期化
firebase コンソールでひとつプロジェクトを作って、apiKey を取得しておきます。具体的には下記を参照してください。
firebase init では必要なサービスをカーソルキーとスペースキーで選びます。最低限 hosting は必要です。下記では Hosting (github) 以外すべてを選んでいます。
$ firebase init
...
? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confir
m your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance
◉ Firestore: Configure security rules and indexes files for Firestore
◉ Functions: Configure a Cloud Functions directory and its files
❯◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
◯ Hosting: Set up GitHub Action deploys
◉ Storage: Configure a security rules file for Cloud Storage
◉ Emulators: Set up local emulators for Firebase products
(Move up and down to reveal more choices)
? 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
=== Database Setup
? What file should be used for Realtime Database Security Rules? database.rules.json
=== Storage Setup
? What file should be used for Storage Rules? storage.rules
=== Firestore Setup
? What file should be used for Firestore Rules? firestore.rules
? What file should be used for Firestore indexes? firestore.indexes.json
=== Functions Setup
? What language would you like to use to write Cloud Functions? JavaScript
? Do you want to use ESLint to catch probable bugs and enforce style? No
✔ Wrote functions/package.json
✔ Wrote functions/index.js
✔ Wrote functions/.gitignore
? Do you want to install dependencies with npm now? Yes
=== Hosting Setup
? 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
✔ Wrote dist/404.html
✔ Wrote dist/index.html
...
プロジェクトは、firebase のコンソール側で作成したものを選びます。Hostig の public directory は dist
にします。
=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm your choices. (
Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
◉ Authentication Emulator
◉ Functions Emulator
◉ Firestore Emulator
◉ Database Emulator
◉ Hosting Emulator
◉ Pub/Sub Emulator
❯◉ Storage Emulator
? Which port do you want to use for the auth emulator? 9099
? Which port do you want to use for the functions emulator? 5001
? Which port do you want to use for the firestore emulator? 8080
? Which port do you want to use for the database emulator? 9000
? Which port do you want to use for the hosting emulator? 5000
? Which port do you want to use for the pubsub emulator? 8085
? Which port do you want to use for the storage emulator? 9199
? 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
Emulator は全部チェックしておけばOKです。storage のエミュレータには問題があるようなので、以下のサンプルでは使いませんが、とりあえず有効にだけしておきます。
エミュレータのポート番号はすべてデフォルトで問題ありません。
動作テスト
$ yarn build
$ firebase emulators:start
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://127.0.0.1:4000 │
└─────────────────────────────────────────────────────────────┘
┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ 127.0.0.1:9099 │ http://127.0.0.1:4000/auth │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions │ 127.0.0.1:5001 │ http://127.0.0.1:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ 127.0.0.1:8080 │ http://127.0.0.1:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Database │ 127.0.0.1:9000 │ http://127.0.0.1:4000/database │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Hosting │ 127.0.0.1:5000 │ n/a │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Pub/Sub │ 127.0.0.1:8085 │ n/a │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Storage │ 127.0.0.1:9199 │ http://127.0.0.1:4000/storage │
└────────────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at 127.0.0.1:4400
Other reserved ports: 4500
上のような感じになったら、正常に起動しています。http://localhost:5000/ にブラウザでアクセスすると、yarn dev
のときと同じ画面が表示されるはずです。
emulator の起動の途中でエラーが出る場合は、
- firebase init での初期化が足りていない
- functions 以下のフォルダで
npm install
の操作がされていない - functions の言語を Typescript にした時に
npm run build
がされていない - 他の firebase emulator が動作している(生き残りプロセスがある)
などの理由が考えられます。最後のケースでは ps -aef | grep firebase
などとして emulator のプロセスを探して kill します。
firebase の初期化コードを追加する
下記の内容で src/firebase.js
というファイルを作ります。
import { initializeApp } from 'firebase/app';
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
};
const firebase = initializeApp(firebaseConfig);
export const firebaseApp = () => { return firebase };
export default firebase;
firebaseConfig
の部分は、firebase のコンソールで取得した apiKey を設定します。
emulator を使用する場合は、さらに下記のようにします (auth, firestore, functions, storage を使用する場合)。
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";
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
};
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;
firebase.js を .gitignore に追加しておく(オプション)
girhub などに公開状態で置くときは、.gitignore に firebase.js を追加して、firebase.js が公開されないようにしておきます。
.DS_Store
node_modules
/dist
firebase.js
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
firebase の動作テスト
firebase 関連のインストール
最初に以下のコマンドを実行します。
$ yarn add firebase
これは忘れやすい。
firebase のコンソールでメール認証を on にする
下記を参照してください。
App.vue などの編集
src/App.vue は下記の内容だけにします。
<template>
<v-app>
<router-view/>
</v-app>
</template>
<script>
import { firebaseApp } from './firebase';
</script>
src/views/HomeView.vue
を以下のように編集します。
<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>
</v-col>
</v-card-actions>
</v-card>
</div>
<div v-else>
<h2>
Success to sign in with firebase auth!
</h2>
<v-btn @click="signout">
Sign Out
</v-btn>
</div>
</v-container>
</template>
<script>
import { getAuth, signOut, onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword } from "firebase/auth";
export default {
name: 'loginpage',
data: () => ({
emailText: "",
passwordText: "",
currentUser: null,
}),
mounted()
{
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if ( user != null ){
this.currentUser = user;
}else{
this.currentUser = null;
}
});
},
methods: {
signin()
{
if ( this.emailText == "" || this.passwordText == "" ) return;
const auth = getAuth();
signInWithEmailAndPassword(auth, this.emailText, this.passwordText)
.then((userCredential) => {
// Sign In
const user = userCredential.user;
console.log( user );
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log( errorCode, errorMessage );
});
},
createAccount()
{
const auth = getAuth();
createUserWithEmailAndPassword(auth, this.emailText, this.passwordText)
.then((userCredential) => {
// Create Account
const user = userCredential.user;
console.log( user );
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log( errorCode, errorMessage );
});
},
signout()
{
const auth = getAuth();
signOut(auth).then(() => {
this.currentUser = null;
}).catch((error) => {
console.log( error );
});
}
}
}
</script>
動作テスト
$ firebase emulators:start
$ yarn dev
上のコマンドは、別々のターミナルで実行する必要があります。これで http://localhost:3000 をブラウザで開くと、下記のような画面が出ます。
email と password を入力して SIGN UP を押すと、アカウントが作成されてログインした状態になります。
たとえばこんな感じです。
ログインした状態になると、下記の画面になります。
こ画面で、SIGN OUT を押すと、ログアウトできます。
次にログインするときは、メールアドレスとパスワードを入れて E-MAIL SIGN IN を押します。
この状態で http://localhost:4000/auth をブラウザで開くと、エミュレータ上にアカウントが作成されているのが確認できます。
Deploy
$ yarn build
$ firebase deploy
いろいろ
全部のページで firebase を使うなら、src/firebase.js を書いた上で App.vue で下記のように書いておくと、個別のページで import しなくてよくなります。
<script>
import { firebaseApp } from './firebase';
</script>
一部のページだけで使うなら、都度 import したほうがよい、のかなあ?
ログインした後、別のページに飛ばしたければ、
this.$router.push('/home');
などとして飛ばします。
storage のエミュレータで、サイズが大きなファイルを扱おうとすると、エミュレータが落ちることがあるようです。storage はオンライン側を使ったほうがいいかもしれません。その場合は、firebase.js のエミュレータ関連の部分は下記のようにコメントアウトします。
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);
}
storage をオンライン側で使う場合、auth もオンライン側を使用しないと、認証時に失敗します。
おまけ
Windows で WSL を使っている場合で、レポジトリのファイルが Windows File System ↑にあると、HMR (オートリロード)が実行されません。
vite.config.js に下記を追加すると、機能が有効になります。
server: {
watch: {
usePolling: true
}
},