Extension vers Codebase Functions & Migration du Package npm
Aperçu
Cette skill guide l'agent dans la migration d'un repository Firebase Extension ou d'une instance vers l'un des deux éléments suivants :
- Une codebase Cloud Functions for Firebase autonome (
firebase-functions, pour l'intégration dans l'app de l'utilisateur final), ou - Un package npm publiable / package open source partageable (pour les éditeurs d'extensions distribuant des fonctions V2 réutilisables).
Elle s'appuie sur les capacités GA natives de Cloud Functions for Firebase pour gérer les permissions, les dépendances et les hooks du cycle de vie nativement dans le code, et fournit des instructions pour moderniser les triggers V1 hérités vers V2 en utilisant le Destructuring Compatibility Shim.
Triggers
Activez cette skill quand un utilisateur demande à :
- Migrer ou convertir une Firebase Extension installée en codebase functions autonome.
- Convertir un repository d'extension en package npm publiable (package open source partageable).
- Mettre à niveau les triggers d'extension de V1 à V2.
Workflows de Migration Cibles
Avant de commencer, déterminez la destination cible avec le développeur :
-
Cible A : Codebase Functions Local (Intégration App Utilisateur Final)
- Résultat : Code source placé dans le dossier
functions/src/du projet. - Configuration : Paramètres définis via
defineString,defineSecret, etc. dans.env. - Déploiement : Déployé directement via
firebase deploy --only functions.
- Résultat : Code source placé dans le dossier
-
Cible B : Package npm Publiable / Package Open Source Partageable
- Résultat : Package npm réutilisable contenant des fonctions V2 exportées.
- Configuration :
package.jsonavec mapexportsetfirebase-functionsdéclaré dansdependencies(oupeerDependencies). - Utilisation : Les utilisateurs finaux installent le package (
npm i <package-name>) et réexportent les fonctions dans leurindex.ts.
Démarrage & Sécurité Git
- Statut Git : Vérifiez que l'espace de travail a un statut git propre avant de commencer.
- Copie Sur Place : Si vous copiez du code vers un nouveau sous-répertoire dans le même repository :
- Utilisez
git cp(ou copiez les fichiers et commitez) pour copier le répertoire source de l'extension vers le répertoire cible. - Commitez immédiatement :
"Copying [extension-name] extension to [directory] in preparation for rewrite"
- Utilisez
Règles et Contraintes
1. Zéro Surcharge Locale (Intégration Cloud Functions)
Supposez que Cloud Functions for Firebase Workload Identities, Declarative Security et SDK Lifecycle Hooks sont entièrement GA.
- Ne produisez PAS d'instructions ou de scripts demandant aux utilisateurs d'exécuter des commandes IAM
gcloudmanuelles ou de créer des comptes de service. - Ne rédigez PAS de commentaires de code instruisant les utilisateurs d'activer manuellement les API Google dans la console cloud.
- Utilisez à la place des imports déclaratifs
requiresAPIetrequiresRoledu SDK.
2. Restriction d'Accès aux Paramètres Globaux
-
N'appelez jamais
.value()sur un paramètre à la portée globale. -
Si une variable globale ou une instance de classe est initialisée en utilisant une valeur de paramètre, déclarez la variable globalement et initialisez-la à l'intérieur du callback
onInit():import { defineString } from "firebase-functions/params"; import { onInit } from "firebase-functions/v2"; const bqDataset = defineString("DATASET_ID"); let bqClient: BigQuery; onInit(() => { bqClient = new BigQuery({ datasetId: bqDataset.value() }); });
3. Parité de Concurrence & Coût pour V2
Lors de la mise à niveau des triggers vers V2 :
- Par défaut, les fonctions V2 activent la concurrence (jusqu'à 80 requêtes par instance).
- Si vous voulez maintenir le tarif CPU fractionnaire V1 (et désactiver la concurrence), définissez
cpu: "gcf_gen1"dans l'objet options de la fonction.
Exécution de la Migration Étape par Étape
Étape 1 : Inventorier l'Extension
Effectuez un inventaire complet de tout ce que l'extension déclare, livre et documente afin que rien ne soit perdu lors de la migration :
- Inventorier
extension.yaml:params: Convertir en params Functions (defineString,defineSecret, etc.).apis: Convertir en déclarationsrequiresAPI(...).roles: Convertir en déclarationsrequiresRole(...).lifecycleEvents(onInstall,onUpdate,onConfigure) : Convertir en hooksafterFirstDeployetafterRedeploy.resources: Notez tous les triggers de fonction à convertir de 1ère génération (firebase-functions/v1) à 2ème génération (firebase-functions/v2), incluant les triggers d'événements standard, les gestionnaires HTTP et les queues de tâches (onTaskDispatched).
- Inventorier Fichiers & Outillage :
functions/: Code source, triggers, helpers et gestionnaires de queue de tâches.- Documentation :
README.md,PREINSTALL.mdetPOSTINSTALL.md. scripts/: Notez les scripts de remplissage, d'importation ou d'aide livrés avec l'extension.
Étape 2 : Créer / Mettre à Jour package.json
Créez un package npm pour le code d'extension migré (soit à la racine du projet, soit dans un répertoire d'espace de travail dédié) :
- Définissez un nom de package publiable (
name: "<package-name>"). - Préservez les Dépendances Dev & Test : Préservez toutes les
devDependenciesexistantes, les test runners (jest,ts-jest,@types/jest,mocha,@types/mocha) et les scripts de test ("test": "...") de l'extension héritage (functions/package.jsonoupackage.jsonracine). Ne supprimez pas les frameworks de test ou les définitions de type. - Déclarez
firebase-functions(p. ex.^7.0.0) dansdependencies(oupeerDependenciessi vous créez un package middleware léger où le consommateur racine gère la version d'exécution) :{ "name": "<package-name>", "version": "1.0.0", "main": "lib/index.js", "types": "lib/index.d.ts", "exports": { ".": { "types": "./lib/index.d.ts", "default": "./lib/index.js" } }, "engines": { "node": ">=22" }, "dependencies": { "firebase-admin": "^12.0.0", "firebase-functions": "^7.0.0" } }
Étape 3 : Déplacer le Code de Fonction & Exposer les Fonctions Déployables
Déplacez la source de la fonction de l'extension dans le dossier src/ du package :
- Gardez les exports de trigger Firebase normaux. Le package doit exposer des fonctions déployables que les utilisateurs finaux peuvent réexporter depuis leur point d'entrée (
index.ts). - Documentez que les consommateurs doivent déployer les fonctions empaquetées en les réexportant :
export * from "<package-name>"; // Ou exports nommés : // export { syncV2, initBigQuerySync } from "<package-name>";Remarque : Un import nu (
import "<package-name>") n'est pas suffisant. La Firebase CLI ne déploie que les fonctions exportées depuis le fichier d'entrée racine de l'utilisateur.
Étape 4 : Mettre à Niveau les Fonctions de 1ère à 2ème Génération
Convertissez chaque trigger de fonction exportée 1ère génération (onWrite, onRequest, tasks.taskQueue().onDispatch) en son équivalent 2ème génération (onDocumentWritten, onRequest, onTaskDispatched de firebase-functions/v2/...) :
- Signatures & Destructuring Shim : Utilisez le Destructuring Compatibility Shim (
{ shimmedKey, context }) pour préserver la logique métier V1 sans réécrire les corps de fonction. Voir signature-mapping.md et destructuring-shim.md. - Exception des Triggers d'Authentification : Si votre extension utilise les triggers d'authentification v1 (
auth.user().onCreate(),auth.user().onDelete()), instruisez l'agent de vérifier en direct si une alternative 2ème génération existe dans le packagefirebase-functionsinstallé ou la documentation en direct. Si les triggers Auth 2ème génération ne sont pas encore supportés pour ces événements, avertissez clairement l'utilisateur et arrêtez ou refusez la migration pour ces triggers spécifiques jusqu'à ce qu'une alternative V2 devienne disponible.
Étape 5 : Remplacer les Params d'Extension par les Params Functions
Chaque paramètre dans extension.yaml devient un appel Parameterized Configuration :
- Mappez les primitives et attributs de paramètre :
- Type
string->defineString("PARAM_NAME", { label: "...", description: "...", default: "..." }) - Type
secret->defineSecret("PARAM_NAME") - Type
int->defineInt("PARAM_NAME", { label: "...", default: 123 }) - Type
boolean->defineBoolean("PARAM_NAME", { default: true }) - Type
select/multiSelect-> mappezoptionseninput:defineString("PARAM_NAME", { input: { select: { options: [{ value: "val", label: "Val" }] } } }) validationRegex-> mappez en options d'entrée de texte :defineString("PARAM_NAME", { input: { text: { validationRegex: "^[a-z]+$" } } })required: true/ Validation non-vide -> mappeznonEmpty: trueen options d'entrée :defineString("PARAM_NAME", { input: { text: { nonEmpty: true } } })
- Type
- Lisez les valeurs de paramètre à l'intérieur des gestionnaires en utilisant
paramName.value(). - Gardez les Noms de Paramètre Exacts : Ne changez jamais les noms de paramètres (
COLLECTION_PATH,DATASET_ID, etc.) afin que les valeurs existantes se reportent sans problème dans.env.
Étape 6 : Migrer les Appels Internes de Queue de Tâches (queue.enqueue(...))
Si votre code d'extension met en queue des tâches sur sa propre queue en utilisant l'Admin SDK (getFunctions().taskQueue(...)):
-
Sous le runtime Extensions, l'Admin SDK a résolu les queues par nom de fonction plus
process.env.EXT_INSTANCE_ID. -
Dans un package npm / codebase régulière : Supprimez complètement le deuxième argument (
EXT_INSTANCE_ID). L'Admin SDK cible automatiquement la codebase actuelle :// Avant (runtime extension) : // const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`, process.env.EXT_INSTANCE_ID); // Après (package npm) : const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`); await queue.enqueue(taskData);
Étape 7 : Migrer les Secrets
Pour les paramètres déclarés avec type: secret :
- Déclarez le secret explicitement :
import { defineSecret } from "firebase-functions/params"; const apiKey = defineSecret("API_KEY"); - Liez le secret aux options du trigger :
export const fn = onRequest({ secrets: [apiKey] }, handler); - Gardez les noms de secret exacts inchangés afin que les liaisons Secret Manager existantes fonctionnent.
Étape 8 : Déclarer les APIs et les Rôles IAM Requis
Remplacez apis et roles de extension.yaml par du code déclaratif dans votre fichier d'entrée :
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
Au moment du déploiement, la Firebase CLI accorde automatiquement ces rôles au compte de service d'exécution géré et active les APIs requises.
Étape 9 : Convertir les Hooks de Cycle de Vie (afterFirstDeploy & afterRedeploy)
Remplacez lifecycleEvents (onInstall, onUpdate, onConfigure) par des hooks de cycle de vie SDK :
-
Convertissez les gestionnaires de queue de tâches (
initBigQuerySync,setupBigQuerySync) en V2onTaskDispatcheddefirebase-functions/v2/tasks(supprimant les appels héritésgetExtensions().runtime().setProcessingState(...)). -
Enregistrez les hooks de cycle de vie dans le code :
import { afterFirstDeploy, afterRedeploy } from "firebase-functions/v2"; // Remplace onInstall : afterFirstDeploy({ task: { function: "runInitialSetup", body: {} } }); // Remplace onUpdate & onConfigure : afterRedeploy({ task: { function: "runInitialSetup", body: { reconcile: true } } }); -
Assurez-vous que les gestionnaires sont idempotents et documentez les commandes de réexécution manuelles :
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
Étape 10 : Documenter la Configuration pour Vos Utilisateurs (README.md)
Préservez toute la documentation, les secrets et les instructions de configuration que l'extension d'origine a déjà documentés dans README.md (et PREINSTALL.md / POSTINSTALL.md), en les mettant à jour si nécessaire :
- Mettre à Jour les Références de Configuration : Remplacez les instructions référençant les invites d'installation
extension.yamlhéritées ou les fichiersext-*.envpar la configuration Parameterized Configuration standard.envcorrespondant aux paramètresdefineString. - Inclure l'Extrait de Réexportation : Assurez-vous que l'extrait de réexportation racine basique est affiché (
export * from "<package-name>";) afin que les utilisateurs sachent comment exposer les fonctions dans leurindex.tsracine. - Éviter les Boilerplate Inutiles : Ne générez pas de tableaux de comparaison redondants ou d'étapes d'installation génériques si la configuration est évidente dans le code ou déjà couverte par les sections README existantes.
Étape 11 : Vérification de la Compilation & des Tests
- Vérifier la Compilation Source : Exécutez
npm run build(tsc) pour assurer l'absence d'erreurs de compilation TypeScript danssrc/. - Vérifier la Suite de Tests Unitaires & les Définitions de Type :
- Si des tests unitaires existants (
__tests__/,test/) sont présents dans l'extension :- Assurez-vous que
@types/jest(ou les types du framework de test d'origine) sont présents dansdevDependenciesafin que les fichiers de test se type-checkent proprement. - Mettez à jour les invocations de test pour les triggers V2 mis à niveau afin de passer un objet d'événement destructuré unique (
({ change: mockChange, context: mockContext })au lieu d'arguments positionnels(mockChange, mockContext)). - Exécutez
npm testou type-check les fichiers de test (npx tsc --noEmit) pour vérifier l'absence de régressions.
- Assurez-vous que
- Si des tests unitaires existants (
Références & Ressources Officielles
- Guide Officiel de Migration Google : Prepare Firebase Extensions for migration to Cloud Functions
- Contacts de Support Éditeur :
- Email de support :
firebase-extensions-migrator-support-external@google.com - Abonnement au groupe de support :
firebase-extensions-migrator-support-external+subscribe@google.com
- Email de support :
- Destructuring Shim : Voir destructuring-shim.md pour les détails sur la traduction des propriétés d'événement.
- Mappage des Triggers : Voir signature-mapping.md pour les définitions de triggers V1 vs V2 et les clés shim.
- Configuration & Paramètres : Voir configuration-migration.md pour les options
runWith, les params et les liaisons de secrets.