環境
ツール | version | 前提 |
---|---|---|
macOS Ventura | 13.4.1 | |
VSCode | 1.86.2 | Plugin は Volar + TypeScript Vue Plugin (Volar) Vue - Official v2.0.4 1Vetur は使わない。Yarn Pnp対応 |
node | v20.11.1 | nodebrew で管理 |
yarn | v4.1.0 | corepack のを使う。 PnPモードで使う |
Firebase CLI (firebase-tools) |
13.4.0 | プロジェクト毎のインストール推奨 |
firebase | v10.8.0 | モジュラー API 版 |
【2024-04-05 追記】
パワーアップ版の記事を書きました。
0. 前提(すっ飛ばしても良い)
nodebrew
インストール
アップグレード(するなら)
% nodebrew selfupdate
node
nodebrew で入れます。
% nodebrew ls-remote
% nodebrew install v20.11.1
% nodebrew use v20.11.1
最新のnodeを使うなら nodebrew install latest
。
yarn
node同梱のcorepackをOnにすればそのまま使える(のでインストールが不要になった)。
% corepack enable
何らかのために止めるなら corepack disable
。
% corepack prepare yarn@stable --activate
デフォルトでの yarn のバージョンは 1.22.21。依存関係的に問題なければ v4を使う。
yarn はプロジェクト毎に package.json
でどのバージョンを使うかを指定して使う。
viteを使いたい時など、プロジェクトに依存しない yarn は上記コマンドで指定しておく。
(設定は macOS では ~/.cache/node/corepack/lastKnownGood.json に残る)
ちなみプロジェクト毎の yarn を最新にする場合は以下のコマンド。このコマンドはカレントディレクトリ直下に以下のような package.json を作るので注意。コマンドを叩いた場所がプロジェクトのディレクトリでないならば そのままにしてはいけない。
% yarn set version stable
{
"packageManager": "yarn@4.1.0"
}
例えば package.json
が作られたカレントディレクトリがプロジェクトを置く用のディレクトリ(例: /Users/yusuke/Workspaces)だったとして、その配下に vite なりで新たにプロジェクトのリポジトリ(/Users/yusuke/Workspaces/MyProject)を作ったとする。
MyProject に cd で移動し yarn
すると、以下のようなエラーが出る。
Usage Error: The nearest package directory (/Users/yusuke/Workspaces/MyProject) doesn't seem to be part of the project declared in /Users/yusuke/Workspaces.
- If /Users/yusuke/Workspaces isn't intended to be a project, remove any yarn.lock and/or package.json file there.
- If /Users/yusuke/Workspaces is intended to be a project, it might be that you forgot to list MyProject in its workspace configuration.
- Finally, if /Users/yusuke/Workspaces is fine and you intend MyProject to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.
MyProject が何らかの親プロジェクトのサブモジュールなら、(親プロジェクトの) package.json
に workspace設定を追加しなさい、カレントディレクトリが単なるプロジェクト置き場ならば package.json は削除しなさいとのこと。
関連するエラー
npm や homebrew で入れていたグローバルな yarn v1 がいると下記のようなエラーも出るので消しておくこと。
error This project's package.json defines "packageManager": "yarn@4.1.0". However the current global version of Yarn is 1.22.21.
Presence of the "packageManager" field indicates that the project is meant to be used with Corepack, a tool included by default with all official Node.js distributions starting from 16.9 and 14.19.
Corepack must currently be enabled by running corepack enable in your terminal. For more information, check out https://yarnpkg.com/corepack.
% npm uninstall -g yarn
% brew uninstall yarn
1. Viteによるプロジェクトの作成
方法1
viteを使って。ここでの プロジェクト名は MyPdoject
としていますがお好きに。
% yarn create vite
➤ YN0000: · Yarn 4.1.0
➤ YN0000: ┌ Resolution step
➤ YN0085: │ + create-vite@npm:5.2.1
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0013: │ A package was added to the project (+ 250.6 KiB).
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental
➤ YN0000: └ Completed
➤ YN0000: · Done with warnings in 0s 144ms
✔ Project name: … MyPdoject
? Select a framework: › - Use arrow-keys. Return to submit.
Vanilla
❯ Vue
React
Preact
Lit
Svelte
Solid
Qwik
Others
? Select a variant: › - Use arrow-keys. Return to submit.
❯ TypeScript
JavaScript
Customize with create-vue ↗
Nuxt ↗
Scaffolding project in /Users/yusuke/Workspaces/MyPdoject...
Done. Now run:
cd MyPdoject
yarn
yarn dev
yarnを最新化して依存ライブラリをインストール
% cd MyPdoject
% yarn set version stable
% yarn
方法2
テンプレートを使う場合。
% yarn create vite MyProject --template vue-ts
➤ YN0000: · Yarn 4.1.0
➤ YN0000: ┌ Resolution step
➤ YN0085: │ + create-vite@npm:5.2.1
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0013: │ A package was added to the project (+ 250.6 KiB).
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental
➤ YN0000: └ Completed
➤ YN0000: · Done with warnings in 0s 66ms
Scaffolding project in /Users/yusuke/Workspace/MyProject...
Done. Now run:
cd MyProject
yarn
yarn dev
方式 1 or 2 でプロジェクトを生成したら、vite.config.ts
を開いてみる。
エラーが出ている場合には「Yarn の PnPモード に対応する」へ。
Yarn の PnPモード に対応する
Yarn は v2 以降、node_modules
以下にライブラリをダウンロードしなくなった。
これを Plyg and Play の略で、pnpモードという。
VSCode は node_modules
以下にライブラリを探しに行くので、ないよ、となっている。
VSCode を pnpモードに対応させる
- VSCodeの拡張機能として
ZipFS
をインストール(詳細は割愛) - SDKパッケージをダウンロードして実行
- VSCodeが使うTypeScriptバージョンをSDKのものに指定
% yarn dlx @yarnpkg/sdks vscode
これを行うと、.vscode
以下に settings.json
ができる。
{
"search.exclude": {
"**/.yarn": true,
"**/.pnp.*": true
},
"typescript.tsdk": ".yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
最後にVSCodeが使うTypeScriptバージョンをSDKのものに指定するには tsファイル上で、Shift
+ Commnd
+ p
を押し、「Select TypeScript Version」を選択。
ワークスペースのバージョン(5.x.x-sdk となっているもの)を選択。
これでOK。あとは以下を .gitignore
するべきとのこと。
+ # yarn
+ .pnp.*
+ .yarn/*
+ !.yarn/patches
+ !.yarn/plugins
+ !.yarn/releases
+ !.yarn/sdks
+ !.yarn/versions
ちなみに v1 互換である node-modulesモードにすることもできて、プロジェクトのルートに
.yarnrc.yml` を作って以下のようにすればよい。
nodeLinker: node-modules
dev serverを起動して動作確認
% yarn dev
2. Firebaseの導入
ローカルのエミュレータでテストができるを目指します。
ローカルマシンに Firebase CLI をインストール
Cloud Functionsをローカルでエミュレートしたい人は注意
インストール方法がいくつかありますが、自動インストールスクリプトでスタンドアロンバイナリをインストールするのでなく、yarnでプロジェクト毎にインストールするのがオススメです。
Cloud Functionsをエミュレータで使う場合、スタンドアロンのFirebase CLIを使っていると、バイナリに同梱されているnodeのバージョン(現状は 18)を指定しなければいけません。
例えば 20 を使いたいならば、yarnでローカルインストールが良いです。
yarnでプロジェクト毎にインストール(推奨)
% yarn add --dev firebase-tools
% yarn firebase login
自動インストールスクリプトでインストール(するなら)
ちなみに シェルの中 に使い方が書いてあります。
% curl -sL https://firebase.tools | bash
% curl -sL https://firebase.tools | upgrade=true bash
% curl -sL https://firebase.tools | uninstall=true bash
プロジェクトにFirebase設定を追加(ここではAuthのエミュレータ設定だけ)
エミュレータが動けば Firebaseコンソールでのプロジェクトはいらないやと思ったのだけど、それだとエミュレータが起動しなかったのでこれの後でプロジェクトも作っています。
% yarn firebase init
######## #### ######## ######## ######## ### ###### ########
## ## ## ## ## ## ## ## ## ## ##
###### ## ######## ###### ######## ######### ###### ######
## ## ## ## ## ## ## ## ## ## ##
## #### ## ## ######## ######## ## ## ###### ########
You're about to initialize a Firebase project in this directory:
/Users/yusuke/Workspaces/robustive-ts-boilerplate
? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm 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
◯ Remote Config: Configure a template file for Remote Config
◯ Extensions: Set up an empty Extensions manifest
(Move up and down to reveal more choices)
=== Project Setup
First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.
? Please select an option:
Use an existing project
Create a new project
Add Firebase to an existing Google Cloud Platform project
❯ Don't set up a default project
=== 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
◯ Eventarc Emulator
(Move up and down to reveal more choices)
? Which port do you want to use for the auth emulator? (9099)
? Would you like to enable the Emulator UI? (Y/n)
? 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? (Y/n)
i ui: downloading ui-v1.11.7.zip...
i Writing configuration info to firebase.json...
i Writing project information to .firebaserc...
✔ Firebase initialization complete!
Progress: =======>------------------------------------------------------------------------------------------------------------------------------------------------------- (5% of 4MB
プロジェクトルートに以下のファイルができる。
{
"emulators": {
"auth": {
"port": 9099
},
"ui": {
"enabled": true
},
"singleProjectMode": true
}
}
本当にエミュレータのセットアップだけを後から追加で行うなら、以下のコマンド。
% yarn firebase init emulators
Firebaseプロジェクトを作る
Project ID はグローバルでユニークである必要があるので誰かと被るとErrorになる。。
% yarn firebase init emulators
######## #### ######## ######## ######## ### ###### ########
## ## ## ## ## ## ## ## ## ## ##
###### ## ######## ###### ######## ######### ###### ######
## ## ## ## ## ## ## ## ## ## ##
## #### ## ## ######## ######## ## ## ###### ########
You're about to initialize a Firebase project in this directory:
/Users/yusuke/Workspaces/MyProject
Before we get started, keep in mind:
* You are initializing within an existing Firebase project directory
=== Project Setup
First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.
? Please select an option:
Use an existing project
❯ Create a new project
Add Firebase to an existing Google Cloud Platform project
Don't set up a default project
i If you want to create a project in a Google Cloud organization or folder, please use "firebase projects:create" instead, and return to this command when you've created the project.
? Please specify a unique project id (warning: cannot be modified afterward) [6-30 characters]:
myproject-4649
? What would you like to call your project? (defaults to your project ID) MyProject
✔ Creating Google Cloud Platform project
✔ Adding Firebase resources to Google Cloud Platform project
🎉🎉🎉 Your Firebase project is ready! 🎉🎉🎉
Project information:
- Project ID: myproject-4649
- Project Name: MyProject
Firebase console is available at
https://console.firebase.google.com/project/myproject-4649/overview
i Using project myproject-4649 (MyProject)
fireabseプロジェクトの情報は、プロジェクトルートの以下のファイルに書かれる(のでオープンソースなどで公開する場合は .firebaserc
を .gitignore
に追加すること)。
{
"projects": {
"default": "myproject-4649"
}
}
Firebaseコンソールにて、ウェブアプリ </>
を追加し、configファイルの内容などを取得する(詳細は割愛)。
取得した内容は firebase.json などのファイルにして import して使うか、以下のように vite.config.ts
にて define で定義し、グルーバル変数とするでも良い。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
+ define: {
+ __FIREBASE_CONFIG__: {
+ apiKey: "AIzaSyAv9VnvR6YK4ljBjPe7UZjnBV9N4h0c7qE",
+ authDomain: "myproject-4649.firebaseapp.com",
+ projectId: "myproject-4649",
+ storageBucket: "myproject-4649.appspot.com",
+ messagingSenderId: "539906050176",
+ appId: "1:539906050176:web:24e2561daf2e7c4b785973"
+ }
}
})
その場合、type を declare してあげないとErrorになるので vite-env.d.ts
にて型を宣言する。
/// <reference types="vite/client" />
+ declare var __FIREBASE_CONFIG__: { [x:string]: string }
エミュレータを起動するようにpackage.jsonのscriptsを修正
ちなみにエミュレータはデータを保存(永続化)してくれない。なので終了時にデータをエクスポートし、起動時にインポートする設定も入れる。
"scripts": {
- "dev": "vite",
+ "dev": "firebase emulators:start --import .emulator-data --export-on-exit .emulator-data & vite",
起動すると firebase-debug.log
および ui-debug.log
ができるので .gitignore
に追加する。エミュレータのデータも追加。
+ # firebase emulator
+ *-debug.log
+ .emulator-data
Firebaseの依存関係を追加
% yarn add firebase
ソースコードにFirebaseの接続設定
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
+ import { initializeApp } from 'firebase/app'
+ // Initialize Firebase
+ const firebaseApp = initializeApp(__FIREBASE_CONFIG__)
createApp(App).mount('#app')
ローカルではエミュレータに接続するようにする
viteには 環境変数 import.meta.env
が用意されていて、dotenv も使える。
yarn dev
で起動した場合、import.meta.env.MODE
が development
になるので、これで場合分けを行う。
ちなみに import.meta.env
が 'ImportMeta' に存在しないと怒られるので、vite-env.d.ts
に以下を追記する。
/// <reference types="vite/client" />
declare var __FIREBASE_CONFIG__: { [x:string]: string }
+ interface ImportMetaEnv {
+ readonly MODE: string
+ }
+ interface ImportMeta {
+ readonly env: ImportMetaEnv
+ }
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { initializeApp } from 'firebase/app'
+ import { connectAuthEmulator, getAuth } from "firebase/auth"
// initialize firebase
const firebaseApp = initializeApp(__FIREBASE_CONFIG__)
+ // Initialize Firebase Authentication and get a reference to the service
+ if (import.meta.env.MODE === 'development') {
+ const auth = getAuth()
+ connectAuthEmulator(auth, "http://127.0.0.1:9099")
+ } else {
+ getAuth(firebaseApp)
+ }
createApp(App).mount('#app')
GoogleOAuthでのサインイン/サインアウトを実装
ここではアーキテクチャは考えず、初めからある HelloWorld.vue
を 魔改造してサインイン/アウトの確認だけを行う。
<script setup lang="ts">
- import { ref } from 'vue'
+ import { reactive } from 'vue'
+ import { AuthError, getAuth, GoogleAuthProvider, onAuthStateChanged, signInWithPopup, signOut, User, UserCredential } from 'firebase/auth'
defineProps<{ msg: string }>()
- const count = ref(0)
+ const state = reactive<{
+ user: User | null
+ }>({
+ user: null
+ })
+ // サインインステータスを観測
+ onAuthStateChanged(getAuth(), (user: User | null) => {
+ if (user) {
+ console.log("onAuthStateChanged: signIn", user)
+ state.user = user
+ } else {
+ console.log("onAuthStateChanged: signOut")
+ state.user = null
+ }
+ })
+ const requiredScope: string[] = ["https://www.googleapis.com/auth/contacts.readonly"]
+ const signin = () => {
+ const provider = new GoogleAuthProvider()
+ requiredScope.forEach(scope => provider.addScope(scope))
+ return signInWithPopup(getAuth(), provider)
+ .then((result: UserCredential) => {
+ // This gives you a Google Access Token. You can use it to access the Google API.
+ const credential = GoogleAuthProvider.credentialFromResult(result)
+ console.log('credential', credential)
+ })
+ .catch((error: AuthError) => console.error('Google Sign-In Error:', error))
+ }
+ const signout = () => {
+ return signOut(getAuth())
+ .then(() => console.log('signOut'))
+ .catch((error: AuthError) => console.error('Google Sign-Out Error:', error))
+ }
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
- <button type="button" @click="count++">count is {{ count }}</button>
+ <button v-if="state.user === null" type="button" @click="signin()">Sign In</button>
+ <button v-else type="button" @click="signout()">Sign Out [{{ state.user.email }}] </button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
初め、signInWithRedirect
で確認していたのだけど、現時点では動かなかった(特にエラーもなくリダイレクトするけど、エミュレータにアカウントが作成されていない)2 3。