[Nuxt3] Firebase 데스크에서 실행합니까 서버에서 실행합니까

66779 단어 FirebaseNuxt 3tech
불꽃놀이를 영어로는 Fireflower라고 부른다.

프론트 데스크에서부터 집행을 시작하다

  • 써 보시면 다음과 같은 글을 참고하실 수 있습니다.(하나의compoosable에는 초기화와 방법이 포함되어 있어users와products 등 여러 개로 저장하면 다 쓸 수 없음)
  • https://zenn.dev/ramo798/articles/5707ce0c2bff9e
  • 더 실용적이라면 아래 글을 참고하세요.
  • https://github.com/nuxt/framework/discussions/2404
  • 위 방법에서 Nuxt의 폴더는 다음과 같은 작용으로 나뉜다.
  • plugens에 Firebase init를 기술하고useState에 Firebase 정보를 저장합니다.
  • compoosable에서 데이터 취득과 로그인 관계를 기술하는 방법
  • 페이지와 각component를 통해 사용하는 방법.
  • 페이지를 읽을 때users를 표시하는 중 오류가 발생했다는 단점이 있습니다.
    왜냐하면db를 정의하기 전에 FirebaseApp 기반의 비동기 처리를 초기화하지 않았기 때문에db는undefined
  • 로 바뀌었다.
    <script setup lang="ts">
    // これはうまくいく
    const users = ref<User[]>([])
    async getUsersTest(){
    	users.value = await useFirestore().getUsers()
    }
    
    // ページ読み込みの時にユーザー一覧を表示させようとして以下のように書くとエラーが出る
    const users = await useFirestore().getUsers()
    console.log(users)
     
    </script>
    
    <template>
    <button @click="getUsersTest()">ユーザー取得</button>
    </template>
    
    expected first argument to collectin() to be a CollectionReference・・・
    

    프런트에서 하는 방법.


    클릭하여 보기

    plugins/firebase.client.ts

  • plugens 파일에 client를 추가하여 클라이언트에서만 실행합니다.
  • firestore 또는auth를 사용할 때 Firebase app를 통해 초기 인증을 해야 하는 대상.초기화 처리는 모두plugens로 간단합니다.
  • 초기화 처리가 끝난 auth와db는useState에 저장되며compoosable에서 사용할 수 있습니다.useState에 저장하면 각 구성 요소에서 공동으로 사용할 수 있습니다.
  • import { defineNuxtPlugin, useState } from '#app'
    import { FirebaseApp, initializeApp } from 'firebase/app'
    import { Firestore, getFirestore } from 'firebase/firestore'
    import { Auth, initializeAuth } from 'firebase/auth'
    
    // Initialize Firebase
    const firebaseConfig = {
        apiKey: "",
        authDomain: "",
        databaseURL: "",
        projectId: "",
        storageBucket: "",
        messagingSenderId: "",
        appId: "",
        measurementId: ""
    };
    
    const firebaseApp:FirebaseApp = initializeApp(firebaseConfig)
    
    export const db:Firestore = getFirestore(firebaseApp)
    export const auth:Auth = initializeAuth(firebaseApp)
    
    export default defineNuxtPlugin((nuxtApp) => {
        useState('firebaseApp', () => firebaseApp)
        useState('auth', () => auth)
        useState('db', () => db)
    })
    

    composables


    1. useFirestore.ts

  • 각 구성 요소에서compoosable의 함수와 상태 변수에 접근합니다.
    compoosable의 함수는 모두Promise를 되돌려줍니다. 예를 들어 쓰기에 성공한 경우'success'의res를 되돌려주고 실패한 경우'failure'의res를 되돌려줍니다.
  • 각res가 무엇을 하려는지(정보 표시와 페이지 이동 등)에 따라 동작은 구성 요소에 적힌 함수에 기술됩니다.
  • import {
        Firestore,
        collection,
        query,
        where,
        getDocs,
        doc,
        getDoc
    } from 'firebase/firestore';
    
    type User = {
        id:String,
        name:String
    }
    type Users = Array<User>
    
    export const useFirestore = () => {
        const db:Firestore = useState('db').value;
    		// 全ユーザーを取得
        async function getUsers(){
            return new Promise(async(resolve, reject)=>{
                const q = query(
                    collection(db, 'users'),
                );
                const querySnapshot = await getDocs(q);
    
                const users:Users = querySnapshot.docs.map((doc) => {
                    const data = doc.data()
                    const user:User = {
                        id:doc.id,
                        name:data.name
                    }
                    return user
                });
                resolve(users)
            })
        };
    
        async function getUserById(id:string){
            return new Promise(async(resolve, reject)=>{
                const docRef = doc(db, 'users', id);
                const docSnap = await getDoc(docRef);
    
                if (docSnap.exists()) {
                    const data = docSnap.data()
                    const user:User={
                        id:docSnap.id,
                        name:data.name
                    }
                    resolve(user)
                  } else {
                    reject(null)
                  }
            })
        }
        async function getHashiraUsers(){
            return new Promise(async(resolve, reject)=>{
                const q = query(
                    collection(db, 'users'),
                    where('hashira','==',true)
                );
                const querySnapshot = await getDocs(q);
    
                const users:Users = querySnapshot.docs.map((doc) => {
                    const data = doc.data()
                    const user:User = {
                        id:doc.id,
                        name:data.name
                    }
                    return user
                });
                resolve(users)
            })
        }
        return {
            getUsers,getUserById,getHashiraUsers
        };
    };
    

    2. useAuth.ts


    import {
        Auth,
        createUserWithEmailAndPassword,
        signInWithEmailAndPassword,
        onAuthStateChanged,
        signOut
    } from 'firebase/auth'
    
    export const useAuth = () => {
        const currentUser = ref<T>(null)    
        const auth:Auth = useState('auth').value
    
        async function signUp(email:string, password:string){
            return new Promise((resolve)=>{
                createUserWithEmailAndPassword(auth, email, password)
                .then((userCredential) => {
                    // サインアップできたらログインする
                    const currentUser = userCredential.user;
                    resolve("success")
                })
                .catch((error) => {
                    const errorCode = error.code;
                    const errorMessage = error.message;
                    resolve(errorCode)
                });            
            })
    
        }
    
        async function passwordSignIn(email:string,password:string){
            return new Promise((resolve)=>{
                signInWithEmailAndPassword(auth, email, password)
                    .then((userCredential) => {
                        // ログインできた時
                        currentUser.value = userCredential.user
                        resolve('success')
                    })
                    .catch((error) => {
                        // ログインできていない時
                        resolve(error)
                    })
            })
        };
    
        function getUserData(){
            console.log(`getUserDataが呼び出された`)
            onMounted(() => {
                onAuthStateChanged(auth, (currentUser) => {
                    if (currentUser) {
                        console.log(`currentUserあり`)
                        currentUser.value = currentUser
                    }else{
                        console.log(`currentUserなし`)
                        user.value = null
                    }
                })
            })
        }
    
        async function signout() { 
            return new Promise((resolve)=>{
                signOut(auth)
                    .then(()=>{
                        currentUser.value = null
                        resolve("success")
                    })
                    .catch((error)=>{
                        resolve(error)
                    })
            })
        }
    
        return {
          signUp, passwordSignIn, signout, currentUser, getUserData
        };
    };
    

    app


    app.vue

  • nuxt2는layouts에 판식을 기술했다.nuxt3도 layouts를 사용할 수 있지만,layouts/default는 사용할 수 있습니다.vue만 넣으면 일부러 안 해도 돼요.ve로 대체할 수 있습니다.
  • v-if를 통해 주요 내용 부분의 로그인 여부를 변경합니다.
  • <script setup lang="ts">
    const {signUp, passwordSignIn, signout, currentUser, getUserData} = useAuth();
    
    const router = useRouter()
    
    const email = ref<String>('[email protected]')
    const password = ref<String>('password')
    
    const message = ref<String>('ログインしていません')
    
    const items = [
        {
            title:'ダッシュボード',
            to:'/',
            icon:''
        },{
            title:'authのテスト',
            to:'/authtest',
            icon:''        
        },{
            title:'storeのテスト',
            to:'/dbtest',
            icon:''
        }
    ]
    async function createAccount(){
        const res:String = await signUp(email.value,password.value)
        if(res=="success"){
            // ダッシュボードに遷移するなど
        }else if(res=="email-already-in-use"){
            message.value = '既にアカウントを作成されているメールアドレスです'
        }
    }
    
    async function login(){
        const res:string = await passwordSignIn(email.value,password.value)
        console.log(`ログイン結果, ${res}`)
        if(res==="success"){
            // ダッシュボードに遷移するなど
            console.log(`ログインしました`)
        }else if(/^.+wrong-password.+$/.test(res)){
            message.value = `パスワードが間違っています`
        }else if(/^.+user-not-found.+$/.test(res)){
            message.value = `メールアドレスが間違っています`
        }else{
            message.value = `エラーが発生しました`
        }
    }
    
    async function logout(){
        const res:string = await signout()
        console.log(`ログアウト結果, ${res}`)
        if(res=="success"){
            router.push('/')
            message.value = 'ログアウトしました'
        }else{
            message.value = 'ログアウトに失敗しました。もう一度やり直してください'
        }
    }
    
    </script>
    
    <template>
        <div style="outline:1px solid;height:50px;display:flex;justify-content: space-between;">
            <h1 style="margin:0 10px;">Nuxt3</h1>
            <div v-if="currentUser">{{currentUser.uid}}</div>
            <button v-if="currentUser" @click="logout">ログアウト</button>
        </div>
    
        <div v-if="currentUser" style="display:flex">
            <div style="outline:1px solid;width:150px;height:90vh">
                <ul style="list-style-type: none;padding:10px">
                    <li v-for="item of items" :key="item.title">
                        <NuxtLink :to="item.to">{{item.title}}</NuxtLink>
                    </li>                
                </ul>
            </div>
            <div style="padding:10px">
                <NuxtPage/>            
            </div>
        </div>
    
        <div v-else style="margin:0 auto;width:30vw">
            {{message}}
            <div>
                <input type="text" id="email" v-model="email" placeholder="メールアドレス">            
            </div>
            <div>
                <input type="text" id="password" v-model="password" placeholder="パスワード">            
            </div>
            <button @click="createAccount">サインアップ</button>
            <button @click="login">ログイン</button>
        </div>
    </template>
    

    pages


    authtest.vue


    <script setup lang="ts">
    const {signUp, passwordSignIn, signout, user} = useAuth();
    
    const email = ref<String>('[email protected]')
    const password = ref<String>('password')
    
    const message = ref<String>('')
    
    async function createAccount(){
        const res:String = await signUp(email.value,password.value)
        if(res=="success"){
            // ダッシュボードに遷移するなど
        }else if(res=="email-already-in-use"){
            message.value = '既にアカウントを作成されているメールアドレスです'
        }
    }
    
    async function login(){
        const res:string = await passwordSignIn(email.value,password.value)
        console.log(`ログイン結果, ${res}`)
        if(res==="success"){
            // ダッシュボードに遷移するなど
            console.log(`ログインしました`)
        }else if(/^.+wrong-password.+$/.test(res)){
            message.value = `パスワードが間違っています`
        }else if(/^.+user-not-found.+$/.test(res)){
            message.value = `メールアドレスが間違っています`
        }else{
            message.value = `エラーが発生しました`
        }
    }
    
    async function logout(){
        const res:string = await signout()
        console.log(`ログアウト結果, `)
        if(res=="success"){
            // ログインページに遷移するなど
        }else{
            message.value = 'ログアウトに失敗しました。もう一度やり直してください'
        }
    }
    
    </script>
    
    <template>
        <input
            type="text"
            id="email"
            v-model="email"
            placeholder="メールアドレス"
        >
        <input
            type="text"
            id="password"
            v-model="password"
            placeholder="パスワード"
        >
        <button @click="createAccount">サインアップ</button>
        <button @click="login">ログイン</button>
        <button @click="logout">ログアウト</button>
    
        <div>メッセージ</div>
        <div>{{message}}</div>
    
        <div>ログインユーザー情報</div>
        <div>{{user}}</div>
    
    </template>
    

    dbtest.vue


    <script setup lang="ts">
    type User = {
        id:String,
        name:String
    }
    type Users = Array<User>
    const users = ref<Users>()
    const user = ref<User>()
    
    const { getUsers, getUserById, getHashiraUsers } = useFirestore();
    
    async function test1(){
        users.value = await getUsers()
    }
    
    async function test2() {
        user.value = await getUserById('tanjiro')
    }
    
    async function test3(){
        users.value = await getHashiraUsers()
    }
    async function test4(){
        users.value = []
        user.value=null
    }
    </script>
    
    <template>
        <div>
            <button @click="test1">全ユーザーを取得</button>
            <button @click="test2">炭治郎を取得</button>
            <button @click="test3">柱を取得</button>
            <button @click="test4">クリア</button>
            <div style="height:200px;outline:solid 1px">
                ここにusersを表示
                <ul>
                    <li v-for="user of users" :key="user.id">{{user.name}}</li>
                </ul>
            </div>
    
            <div style="height:300px;outline:solid 1px">
                ここにuserを表示
                <div>{{user}}</div>
            </div>
        </div>
    </template>
    

    참고 자료


    nuxt3+firebasev9를 시도해 보세요.
    How to integrate Firebase v9 with Nuxt3? · Discussion #2404 · nuxt/framework

    서버에서 실행

  • 해결 방법으로 데이터 취득과 로그인에 관한 방법을 서버/api에 저장하는 것이지compoosable가 아니다.
  • 이렇게 하면useFetch를 통해 각 구성 요소에서 데이터를 얻을 수 있습니다.
  • 이것을 사용하는 방법에 관해서는 다른 기사로 쓰시오.

    좋은 웹페이지 즐겨찾기