네임스페이스화된 API에서 모듈식 API로 업그레이드

현재 compat 라이브러리부터 버전 8 이하까지 네임스페이스화된 Firebase Web API를 사용하는 앱은 이 가이드의 안내에 따라 모듈식 API로 이전하는 것이 좋습니다.

이 가이드는 사용자가 네임스페이스화된 API 사용에 익숙하며 업그레이드 및 향후 모듈식 앱 개발에 webpack 또는 Rollup과 같은 모듈 번들러를 사용한다는 가정을 바탕으로 합니다.

개발 환경에서 모듈 번들러를 사용하는 것이 좋습니다. 이 기능을 사용하지 않으면, 웹 크기 축소와 관련한 모듈식 API의 주요 이점을 활용할 수 없습니다. SDK를 설치하려면 npm 또는 yarn이 필요합니다.

이 가이드의 업그레이드 단계는 AuthenticationCloud Firestore SDK를 사용하는 가상의 웹 앱을 기반으로 합니다. 예시를 통해 지원되는 모든 Firebase 웹 SDK를 업그레이드하는 데 필요한 개념과 실용적인 단계를 익힐 수 있습니다.

네임스페이스화된(compat) 라이브러리 정보

Firebase 웹 SDK에서는 두 가지 유형의 라이브러리를 사용할 수 있습니다.

  • Modular - 웹 앱을 가능한 한 빠르고 작게 만들기 위해 Tree Shaking(사용하지 않는 코드 삭제)을 촉진하도록 설계된 새로운 API 노출 영역입니다.
  • 네임스페이스화(compat) - 이전 버전의 SDK와 완벽하게 호환되는 친숙한 API 노출 영역을 사용하면 모든 Firebase 코드를 한 번에 변경하지 않고도 업그레이드할 수 있습니다. compat 라이브러리는 네임스페이스화된 라이브러리에 비해 크기 또는 성능상의 이점이 거의 없습니다.

이 가이드는 업그레이드를 촉진하기 위해 compat 라이브러리를 활용한다는 가정을 바탕으로 합니다. 이러한 라이브러리를 사용하면 모듈식 API로 리팩터링된 코드와 함께 네임스페이스화된 코드를 계속 사용할 수 있습니다. 즉, 업그레이드 프로세스를 진행하면서 앱을 더 쉽게 컴파일 및 디버그할 수 있습니다.

Firebase 웹 SDK에 노출되는 정도가 매우 낮은 앱(예: Authentication API만 간단하게 호출하는 앱)은 compat 라이브러리를 사용하지 않고 이전 네임스페이스화된 코드를 리팩터링하는 것이 실용적일 수 있습니다. 이러한 앱을 업그레이드하는 경우 compat 라이브러리를 사용하지 않고 '모듈식 API'에 대한 이 가이드의 안내를 따를 수 있습니다.

업그레이드 프로세스 정보

업그레이드 프로세스의 각 단계에는 범위가 지정되므로 앱의 소스 수정을 완료한 후 중단 없이 컴파일하고 실행할 수 있습니다. 요약하면, 다음을 수행하여 앱을 업그레이드합니다.

  1. 앱에 모듈식 라이브러리와 compat 라이브러리를 추가합니다.
  2. 코드의 가져오기 문을 compat으로 업데이트합니다.
  3. 단일 제품(예: Authentication)의 코드를 모듈식으로 리팩터링합니다.
  4. 선택사항: 이 시점에서 계속하기 전에 Authentication을 위한 앱 크기 이점을 활용하려면 Authentication compat 라이브러리와 Authentication용 compat 코드를 삭제하세요.
  5. 각 제품(예: Cloud Firestore, FCM 등)의 함수를 모듈식으로 리팩터링하고 모든 영역이 완료될 때까지 컴파일하고 테스트합니다.
  6. 초기화 코드를 모듈식으로 업데이트합니다.
  7. 앱에서 남은 compat 문과 compat 코드를 모두 삭제합니다.

SDK의 최신 버전 다운로드

시작하려면 npm을 사용하여 모듈식 라이브러리와 compat 라이브러리를 가져오세요.

npm i firebase@11.0.2

# OR

yarn add firebase@11.0.2

가져오기를 compat으로 업데이트

종속 항목을 업데이트한 후에도 코드가 계속 작동하도록 하려면 가져오기 문을 변경하여 각 가져오기의 'compat' 버전을 사용합니다. 예를 들면 다음과 같습니다.

이전: 버전 8 이하

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

이후: compat

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

모듈식으로 리팩터링

네임스페이스화된 API는 점으로 체이닝된 네임스페이스 및 서비스 패턴을 기반으로 하지만 모듈식 접근방식은 코드가 함수를 중심으로 구성됩니다. 모듈식 API에서 firebase/app 패키지와 기타 패키지는 패키지의 모든 메서드를 포함하는 포괄적인 내보내기를 반환하지 않습니다. 대신 패키지는 개별 함수를 내보냅니다.

모듈식 API에서는 서비스가 첫 번째 인수로 전달되며, 함수는 이 서비스의 세부정보를 사용해 나머지 작업을 수행합니다. AuthenticationCloud Firestore API 호출을 리팩터링하는 두 가지 예시에서 이 기능이 어떻게 작동하는지 살펴보겠습니다.

예시 1: Authentication 함수 리팩터링

이전: compat

compat 코드는 네임스페이스화된 코드와 동일하지만 가져오기는 변경되었습니다.

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

이후: 모듈식

getAuth 함수는 firebaseApp를 첫 번째 매개변수로 사용합니다. onAuthStateChanged 함수는 네임스페이스화된 API처럼 auth 인스턴스에서 체이닝이 되지 않지만, 대신 auth를 첫 번째 매개변수로 사용하는 무료 함수입니다.

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
  // Check for user status
});

인증 메서드 getRedirectResult 처리 업데이트

모듈식 API에는 getRedirectResult에 브레이킹 체인지가 포함되어 있습니다. 리디렉션 작업이 호출되지 않으면 모듈식 API는 null 사용자와 함께 UserCredential을 반환했던 네임스페이스화된 API와는 달리 null을 반환합니다.

이전: compat

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

이후: 모듈식

const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
  return null;
}
return result;

예시 2: Cloud Firestore 함수 리팩터링

이전: compat

import "firebase/compat/firestore"

const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

이후: 모듈식

getFirestore 함수는 firebaseApp을 첫 번째 매개변수로 사용합니다. 여기서는 이전 예시의 initializeApp에서 반환됩니다. 쿼리를 구성하는 코드는 모듈식 API에서 매우 다릅니다. 체이닝이 되어 있지 않으며 query 또는 where과 같은 메서드는 이제 무료 함수로 노출됩니다.

import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";

const db = getFirestore(firebaseApp);

const q = query(collection(db, "cities"), where("capital", "==", true));

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

Firestore DocumentSnapshot.exists에 관한 참조 업데이트

모듈식 API에는 firestore.DocumentSnapshot.exists 속성이 메서드로 변경된 브레이킹 체인지가 포함되어 있습니다. 이 기능은 문서가 있는지 테스트한다는 점에서 본질적으로 동일하지만 아래에 표시된 것과 같이 최신 메서드를 사용하도록 코드를 리팩터링해야 합니다.

이전: compat

if (snapshot.exists) {
  console.log("the document exists");
}

이후: 모듈식

if (snapshot.exists()) {
  console.log("the document exists");
}

예시 3: 네임스페이스화된 코드 및 모듈식 코드 스타일 결합

업그레이드 중에 compat 라이브러리를 사용하면 모듈식 API용으로 리팩터링된 코드와 함께 네임스페이스화된 코드를 계속 사용할 수 있습니다. 즉, Authentication 또는 기타 Firebase SDK 코드를 모듈식으로 리팩터링하는 동안 Cloud Firestore의 기존 네임스페이스화된 코드를 그대로 유지하면서 두 코드 스타일을 사용하여 앱을 성공적으로 컴파일할 수 있습니다. Cloud Firestore와 같은 제품 네임스페이스화된 API 코드 및 모듈식 API 코드도 마찬가지입니다. compat 패키지를 가져오기만 하면 신규 및 이전 코드 스타일의 공존이 가능합니다.

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'

const docRef = firebase.firestore().doc();
getDoc(docRef);

앱이 컴파일되지만 앱에서 compat 문과 코드를 완전히 삭제할 때까지는 모듈식 코드의 앱 크기 이점을 얻을 수 없습니다.

초기화 코드 업데이트

모듈식 구문을 사용하려면 앱의 초기화 코드를 업데이트해야 합니다. 앱의 모든 코드 리팩터링을 완료한 이 코드를 업데이트하는 것이 중요합니다. 이는 firebase.initializeApp()가 compat API와 모듈식 API의 전역 상태를 초기화하지만 모듈식 initializeApp() 함수는 모듈식 상태만 초기화하기 때문입니다.

이전: compat

import firebase from "firebase/compat/app"

firebase.initializeApp({ /* config */ });

이후: 모듈식

import { initializeApp } from "firebase/app"

const firebaseApp = initializeApp({ /* config */ });

compat 코드 삭제

모듈식 API의 크기 이점을 활용하려면 결국 모든 호출을 위에 표시된 모듈식 스타일로 변환하고 코드에서 import "firebase/compat/* 문을 모두 삭제해야 합니다. 작업을 완료한 후에는 네임스페이스화된 API 스타일의 firebase.* 전역 네임스페이스 또는 다른 코드에 대한 참조가 더 이상 없어야 합니다.

window에서 compat 라이브러리 사용

모듈식 API는 브라우저의 window 객체가 아닌 모듈과 연동하도록 최적화되었습니다. 이전 버전의 라이브러리에서는 window.firebase 네임스페이스를 사용하여 Firebase를 로드하고 관리할 수 있었습니다. 이 방법은 미사용 코드를 제거할 수 없으므로 앞으로 권장되지 않습니다. 그러나 모듈식 업그레이드 경로를 즉시 시작하지 않으려는 개발자를 위해 자바스크립트 SDK의 compat 버전은 window와 연동됩니다.

<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-auth-compat.js"></script>
<script>
   const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
   const db = firebaseApp.firestore();
   const auth = firebaseApp.auth();
</script>

호환성 라이브러리는 내부적으로 모듈식 코드를 사용하면서 네임스페이스화된 API와 동일한 API를 제공합니다. 즉, 자세한 내용은 네임스페이스화된 API 참조 및 네임스페이스화된 코드 스니펫을 참조할 수 있습니다. 그러나 이 방법은 장기적으로 권장되지 않으며, 완전 모듈식 라이브러리로 업그레이드하는 시작점으로 사용하시기 바랍니다.

모듈식 SDK의 이점 및 제한사항

완전히 모듈화된 SDK는 이전 버전에 비해 다음과 같은 장점이 있습니다.

  • 모듈식 SDK를 사용하면 앱 크기를 상당히 줄일 수 있습니다. 최신 자바스크립트 모듈 형식을 채택하여 앱에 필요한 아티팩트만 가져오는 '트리 쉐이킹' 방식을 지원합니다. 앱에 따라 모듈식 SDK를 사용하여 트리 쉐이킹 작업을 수행하면 네임스페이스화된 API로 빌드한 앱에 비해 KB를 80% 줄일 수 있습니다.
  • 모듈식 SDK는 지속적인 기능 개발의 이점을 계속해서 누릴 수 있는 반면, 네임스페이스화된 API는 이점을 누리지 못합니다.