Comment structurer Cloud Functions for Firebase pour déployer plusieurs fonctions à partir de plusieurs fichiers?

164

Je souhaite créer plusieurs fonctions cloud pour Firebase et les déployer toutes en même temps à partir d'un projet. Je voudrais également séparer chaque fonction dans un fichier séparé. Actuellement, je peux créer plusieurs fonctions si je les mets toutes les deux dans index.js telles que:

exports.foo = functions.database.ref('/foo').onWrite(event => {
    ...
});

exports.bar = functions.database.ref('/bar').onWrite(event => {
    ...
});

Cependant, je voudrais mettre foo et bar dans des fichiers séparés. J'ai essayé ceci:

/functions
|--index.js (blank)
|--foo.js
|--bar.js
|--package.json

où foo.js est

exports.foo = functions.database.ref('/foo').onWrite(event => {
    ...
});

et bar.js est

exports.bar = functions.database.ref('/bar').onWrite(event => {
    ...
});

Existe-t-il un moyen d'accomplir cela sans mettre toutes les fonctions dans index.js?

Jasonsirota
la source
1
@JPVentura. Je ne te comprends vraiment pas bien. S'il vous plaît, expliquez.
HuyLe
Cela a-t-il été mis à jour pour la v1.0? J'ai des problèmes: stackoverflow.com/questions/50089807/…
tccpg288
2
Pour info, cet exemple officiel de fonctions Firebase contient plusieurs .jsfichiers importés via require: github.com/firebase/functions-samples/tree/master
...
Cela pourrait être utile: stackoverflow.com/questions/43486278/…
Ramesh-X

Réponses:

126

Ah, Cloud Functions pour Firebase charge normalement les modules de nœuds, donc cela fonctionne

structure:

/functions
|--index.js
|--foo.js
|--bar.js
|--package.json

index.js:

const functions = require('firebase-functions');
const fooModule = require('./foo');
const barModule = require('./bar');

exports.foo = functions.database.ref('/foo').onWrite(fooModule.handler);
exports.bar = functions.database.ref('/bar').onWrite(barModule.handler);

toto.js:

exports.handler = (event) => {
    ...
};

bar.js:

exports.handler = (event) => {
    ...
};
Jasonsirota
la source
1
Puis-je par exemple avoir plusieurs fonctions dans le module foo? Si oui, comment est-il préférable de le mettre en œuvre?
Alexander Khitev
1
Je suppose que vous pouvez, et attribuer différents gestionnaires à différentes fonctions exportées à partir de foo: exports.bar = functions.database.ref ('/ foo'). OnWrite (fooModule.barHandler); exports.baz = functions.database.ref ('/ bar'). onWrite (fooModule.bazHandler);
jasonsirota
44
Je n'aime pas cette solution car elle déplace les informations (à savoir les chemins de la base de données) de foo.js et bar.js vers index.js, ce qui va à l'encontre de l'intérêt d'avoir ces fichiers séparés.
bvs le
Je suis d'accord avec @bvs, je pense que Ced a une bonne approche. Je vais le modifier légèrement en exportant explicitement chaque module pour rendre l'index.ts super clair, par exemple exporter {newUser} depuis "./authenticationFunctions"
Alan
2
Je pense que ma question initiale portait simplement sur le déploiement de plusieurs fonctions avec 1 projet sans placer les fonctions dans le fichier index.js, où et comment vous transmettez les informations de la base de données ne sont pas dans la portée. Si c'était moi, je créerais probablement un module séparé qui contrôlait l'accès à la base de données et l'exigerait séparément dans foo.js et bar.js, mais c'est une décision stylistique.
jasonsirota
75

La réponse de @jasonsirota a été très utile. Mais il peut être utile de voir du code plus détaillé, en particulier dans le cas des fonctions déclenchées par HTTP.

En utilisant la même structure que dans la réponse de @ jasonsirota, disons que vous souhaitez avoir deux fonctions de déclenchement HTTP distinctes dans deux fichiers différents:

structure de répertoires:

    /functions
       |--index.js
       |--foo.js
       |--bar.js
       |--package.json`

index.js:

'use strict';
const fooFunction = require('./foo');
const barFunction = require('./bar');

// Note do below initialization tasks in index.js and
// NOT in child functions:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase); 
const database = admin.database();

// Pass database to child functions so they have access to it
exports.fooFunction = functions.https.onRequest((req, res) => {
    fooFunction.handler(req, res, database);
});
exports.barFunction = functions.https.onRequest((req, res) => {
    barFunction.handler(req, res, database);
});

toto.js:

 exports.handler = function(req, res, database) {
      // Use database to declare databaseRefs:
      usersRef = database.ref('users');
          ...
      res.send('foo ran successfully'); 
   }

bar.js:

exports.handler = function(req, res, database) {
  // Use database to declare databaseRefs:
  usersRef = database.ref('users');
      ...
  res.send('bar ran successfully'); 
}
Étudiant universitaire
la source
La structure actuelle dans index.js ne fonctionnait pas bien pour moi. Ce que je devais faire était d'abord d'importer les modules Firebase, puis d'initialiser l'application, puis d'importer les fonctions des autres dossiers. De cette façon, mon application initialise, authentifie tout d'abord, puis importe les fonctions qui nécessitent l'initialisation préalable de l'application.
tonkatata
47

Mise à jour: ce document devrait vous aider , ma réponse est plus ancienne que ce document.


Voici comment je l'ai fait personnellement avec dactylographié:

/functions
   |--src
      |--index.ts
      |--http-functions.ts
      |--main.js
      |--db.ts
   |--package.json
   |--tsconfig.json

Permettez-moi de commencer en donnant deux avertissements pour que cela fonctionne:

  1. l'ordre d'importation / exportation compte index.ts
  2. la base de données doit être un fichier séparé

Pour le point numéro 2, je ne sais pas pourquoi. Secundo, vous devez respecter ma configuration d'index, main et db exactement (au moins pour l'essayer).

index.ts : traite de l'exportation. Je trouve plus propre de laisser index.ts s'occuper des exportations.

// main must be before functions
export * from './main';
export * from "./http-functions";

main.ts : traite de l'initialisation.

import { config } from 'firebase-functions';
import { initializeApp } from 'firebase-admin';

initializeApp(config().firebase);
export * from "firebase-functions";

db.ts : il suffit de réexporter la base de données pour que son nom soit plus court quedatabase()

import { database } from "firebase-admin";

export const db = database();

http-functions.ts

// db must be imported like this
import { db } from './db';
// you can now import everything from index. 
import { https } from './index';  
// or (both work)
// import { https } from 'firebase-functions';

export let newComment = https.onRequest(createComment);

export async function createComment(req: any, res: any){
    db.ref('comments').push(req.body.comment);
    res.send(req.body.comment);
}
Ced
la source
à quoi ressemble votre tsconfig? comment puis-je compiler dans un dossier dist et faire savoir aux fonctions gcloud où se trouve mon index.js? Avez-vous votre code sur github? :)
bersling
@ choopage-JekBao désolé ça fait longtemps, je n'ai plus le projet. Si je me souviens bien, vous pouvez donner à la configuration de firebase un répertoire (qui est public par défaut). Je peux me tromper car cela fait plus d'un an
Ced
Hey @ced - pourquoi le contenu de ne peut-il pas db.tsentrer main.ts(après l'instanciation de l'administrateur?). Ou vous êtes-vous simplement séparé de cette manière pour plus de clarté / simplicité?
dsg38
1
@ dsg38 cela a été posté il y a trop longtemps, je ne vois pas vraiment pourquoi cela devrait être dans un fichier séparé en regardant la réponse maintenant .. Je pense que c'était pour plus de clarté
Ced
21

Avec Node 8 LTS désormais disponible avec les fonctions Cloud / Firebase, vous pouvez effectuer les opérations suivantes avec les opérateurs de diffusion:

/package.json

"engines": {
  "node": "8"
},

/index.js

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

module.exports = {
  ...require("./lib/foo.js"),
  // ...require("./lib/bar.js") // add as many as you like
};

/lib/foo.js

const functions = require("firebase-functions");
const admin = require("firebase-admin");

exports.fooHandler = functions.database
  .ref("/food/{id}")
  .onCreate((snap, context) => {
    let id = context.params["id"];

    return admin
      .database()
      .ref(`/bar/${id}`)
      .set(true);
  });
Luke Pighetti
la source
Je me demande si le nombre croissant d'importations ralentit le démarrage à froid de chaque fonction ou s'il devrait y avoir de nombreux modules totalement séparés développés séparément?
Simon Fakir
2
J'obtiens une erreur de séparation eslint unexpected token ...dans index.js.
thomas
Peut-être que vous n'utilisez pas Node 8
Luke Pighetti
@SimonFakir bonne question. Avez-vous trouvé quelque chose à ce sujet?
atereshkov le
@atereshkov oui j'ai trouvé un moyen de charger uniquement la fonction demandée, y compris ses dépendances, en utilisant "process.env.FUNCTION_NAME" similaire à la réponse ci-dessous. Je peux également partager mon repo comme référence si vous êtes intéressé à me contacter.
Simon Fakir du
16

Pour être simple (mais fait le travail), j'ai personnellement structuré mon code comme ça.

Disposition

├── /src/                      
   ├── index.ts               
   ├── foo.ts           
   ├── bar.ts
|   ├── db.ts           
└── package.json  

foo.ts

import * as functions from 'firebase-functions';
export const fooFunction = functions.database()......... {
    //do your function.
}

export const someOtherFunction = functions.database().......... {
    // do the thing.
}

bar.ts

import * as functions from 'firebase-functions';
export const barFunction = functions.database()......... {
    //do your function.
}

export const anotherFunction = functions.database().......... {
    // do the thing.
}

db.ts

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';

export const firestore = admin.firestore();
export const realtimeDb = admin.database();

index.ts

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';

admin.initializeApp(functions.config().firebase);
// above codes only needed if you use firebase admin

export * from './foo';
export * from './bar';

Fonctionne pour les répertoires de tous les niveaux imbriqués. Suivez simplement le modèle à l'intérieur des répertoires.

crédit à @zaidfazil réponse

Reza
la source
1
C'est l'une des réponses les plus simples pour Typescript, merci. Comment gérer une seule instanciation de la base de données Firebase par exemple? admin.initializeApp(functions.config().firestore) const db = admin.firestore();Où mettez-vous cela et comment vous y référez-vous dans foo et bar?
elprl
Hé - pourquoi le contenu de ne peut-il pas db.tsentrer index.ts(après l'instanciation de l'administrateur?). Ou vous êtes-vous simplement séparé de cette manière pour plus de clarté / simplicité?
dsg38
1
@ dsg38, vous pouvez mélanger tous ensemble, cela rend les choses claires
Reza
J'ai fait quelque chose de similaire pour TS merci c'est une solution simple et bonne
Ruben il y a
10

Dans le cas de Babel / Flow, cela ressemblerait à ceci:

Disposition du répertoire

.
├── /build/                     # Compiled output for Node.js 6.x
├── /src/                       # Application source files
   ├── db.js                   # Cloud SQL client for Postgres
   ├── index.js                # Main export(s)
   ├── someFuncA.js            # Function A
   ├── someFuncA.test.js       # Function A unit tests
   ├── someFuncB.js            # Function B
   ├── someFuncB.test.js       # Function B unit tests
   └── store.js                # Firebase Firestore client
├── .babelrc                    # Babel configuration
├── firebase.json               # Firebase configuration
└── package.json                # List of project dependencies and NPM scripts


src/index.js - Principales exportations

export * from './someFuncA.js';
export * from './someFuncB.js';


src/db.js - Client Cloud SQL pour Postgres

import { Pool } from 'pg';
import { config } from 'firebase-functions';

export default new Pool({
  max: 1,
  user: '<username>',
  database: '<database>',
  password: config().db.password,
  host: `/cloudsql/${process.env.GCP_PROJECT}:<region>:<instance>`,
});


src/store.js - Client Firebase Firestore

import firebase from 'firebase-admin';
import { config } from 'firebase-functions';

firebase.initializeApp(config().firebase);

export default firebase.firestore();


src/someFuncA.js - Fonction A

import { https } from 'firebase-functions';
import db from './db';

export const someFuncA = https.onRequest(async (req, res) => {
  const { rows: regions } = await db.query(`
    SELECT * FROM regions WHERE country_code = $1
  `, ['US']);
  res.send(regions);
});


src/someFuncB.js - Fonction B

import { https } from 'firebase-functions';
import store from './store';

export const someFuncB = https.onRequest(async (req, res) => {
  const { docs: regions } = await store
    .collection('regions')
    .where('countryCode', '==', 'US')
    .get();
  res.send(regions);
});


.babelrc

{
  "presets": [["env", { "targets": { "node": "6.11" } }]],
}


firebase.json

{
  "functions": {
    "source": ".",
    "ignore": [
      "**/node_modules/**"
    ]
  }
}


package.json

{
  "name": "functions",
  "verson": "0.0.0",
  "private": true,
  "main": "build/index.js",
  "dependencies": {
    "firebase-admin": "^5.9.0",
    "firebase-functions": "^0.8.1",
    "pg": "^7.4.1"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-jest": "^22.2.2",
    "babel-preset-env": "^1.6.1",
    "jest": "^22.2.2"
  },
  "scripts": {
    "test": "jest --env=node",
    "predeploy": "rm -rf ./build && babel --out-dir ./build src",
    "deploy": "firebase deploy --only functions"
  }
}


$ yarn install                  # Install project dependencies
$ yarn test                     # Run unit tests
$ yarn deploy                   # Deploy to Firebase
Konstantin Tarkus
la source
9

bigcodenerd.org esquisse un modèle d'architecture plus simple afin d'avoir des méthodes séparées en différents fichiers et exportées en une seule ligne dans le fichier index.js .

L'architecture du projet dans cet exemple est la suivante:

projectDirectory

  • index.js
  • podcast.js
  • profile.js

index.js

const admin = require('firebase-admin');
const podcast = require('./podcast');
const profile = require('./profile');
admin.initializeApp();

exports.getPodcast = podcast.getPodcast();
exports.removeProfile = profile.removeProfile();

podcast.js

const functions = require('firebase-functions');

exports.getPodcast = () => functions.https.onCall(async (data, context) => {
      ...
      return { ... }
  });

Le même modèle serait utilisé pour la removeProfileméthode dans le fichier de profil .

Adam Hurwitz
la source
7

Pour être simple (mais fait le travail), j'ai personnellement structuré mon code comme ça.

Disposition

├── /src/                      
   ├── index.ts               
   ├── foo.ts           
   ├── bar.ts           
└── package.json  

foo.ts

export const fooFunction = functions.database()......... {
    //do your function.
}

export const someOtherFunction = functions.database().......... {
    // do the thing.
}

bar.ts

export const barFunction = functions.database()......... {
    //do your function.
}

export const anotherFunction = functions.database().......... {
    // do the thing.
}

index.ts

import * as fooFunctions from './foo';
import * as barFunctions from './bar';

module.exports = {
    ...fooFunctions,
    ...barFunctions,
};

Fonctionne pour les répertoires de tous les niveaux imbriqués. Suivez simplement le modèle à l'intérieur des répertoires.

zaidfazil
la source
Je ne vois pas comment cela pourrait fonctionner puisque Firebase prend actuellement en charge Node 6.11 qui ne prend pas en charge les directives d'importation ES6?
Aodh
Si vous utilisez dactylographié, le problème ne devrait jamais se poser. J'ai récemment porté la plupart de mon code en manuscrit.
zaidfazil
2
zaidfazil, vous devriez probablement noter les pré-requis dans votre réponse. @Aodh, cela fonctionne si vous utilisez Babel de la même manière que Konstantin a décrit dans une réponse. stackoverflow.com/questions/43486278/…
PostureOfLearning
1
Merci. cela a fonctionné avec dactylographié et le nœud 6 :)
Ahmad Moussa
4
Plutôt que d'importer et de réexporter avec des opérateurs de diffusion, ne pourriez-vous pas simplement avoir export * from './fooFunctions';et export * from './barFunctions';dans index.ts?
whatsthatitspat
5

Ce format permet à votre point d'entrée de trouver des fichiers de fonctions supplémentaires et d'exporter automatiquement chaque fonction dans chaque fichier.

Script du point d'entrée principal

Recherche tous les fichiers .js dans le dossier des fonctions et exporte chaque fonction exportée à partir de chaque fichier.

const fs = require('fs');
const path = require('path');

// Folder where all your individual Cloud Functions files are located.
const FUNCTIONS_FOLDER = './scFunctions';

fs.readdirSync(path.resolve(__dirname, FUNCTIONS_FOLDER)).forEach(file => { // list files in the folder.
  if(file.endsWith('.js')) {
    const fileBaseName = file.slice(0, -3); // Remove the '.js' extension
    const thisFunction = require(`${FUNCTIONS_FOLDER}/${fileBaseName}`);
    for(var i in thisFunction) {
        exports[i] = thisFunction[i];
    }
  }
});

Exemple d'exportation de plusieurs fonctions à partir d'un fichier

const functions = require('firebase-functions');

const query = functions.https.onRequest((req, res) => {
    let query = req.query.q;

    res.send({
        "You Searched For": query
    });
});

const searchTest = functions.https.onRequest((req, res) => {
    res.send({
        "searchTest": "Hi There!"
    });
});

module.exports = {
    query,
    searchTest
}

Les points de terminaison accessibles http sont correctement nommés

✔ functions: query: http://localhost:5001/PROJECT-NAME/us-central1/query
✔ functions: helloWorlds: http://localhost:5001/PROJECT-NAME/us-central1/helloWorlds
✔ functions: searchTest: http://localhost:5001/PROJECT-NAME/us-central1/searchTest

Un fichier

Si vous ne disposez que de quelques fichiers supplémentaires (par exemple un seul), vous pouvez utiliser:

const your_functions = require('./path_to_your_functions');

for (var i in your_functions) {
  exports[i] = your_functions[i];
}

Matthew Rideout
la source
N'y aura-t-il pas une surcharge au démarrage pour chaque instance de fonction qui tourne?
Ayyappa
4

J'ai donc ce projet qui a des fonctions d'arrière-plan et des fonctions http. J'ai aussi des tests pour les tests unitaires. CI / CD vous simplifiera la vie lors du déploiement des fonctions cloud

Structure des dossiers

|-- package.json
|-- cloudbuild.yaml
|-- functions
    |-- index.js
    |-- background
    |   |-- onCreate
    |       |-- index.js
            |-- create.js
    |
    |-- http
    |   |-- stripe
    |       |-- index.js
    |       |-- payment.js
    |-- utils
        |-- firebaseHelpers.js
    |-- test
        |-- ...
    |-- package.json

Remarque: utils/ dossier est pour partager le code entre les fonctions

fonctions / index.js

Ici, vous pouvez simplement importer toutes les fonctions dont vous avez besoin et les déclarer. Pas besoin de logique ici. Cela le rend plus propre à mon avis.

require('module-alias/register');
const functions = require('firebase-functions');

const onCreate = require('@background/onCreate');
const onDelete = require('@background/onDelete');
const onUpdate = require('@background/onUpdate');

const tours  = require('@http/tours');
const stripe = require('@http/stripe');

const docPath = 'tours/{tourId}';

module.exports.onCreate = functions.firestore.document(docPath).onCreate(onCreate);
module.exports.onDelete = functions.firestore.document(docPath).onDelete(onDelete);
module.exports.onUpdate = functions.firestore.document(docPath).onUpdate(onUpdate);

module.exports.tours  = functions.https.onRequest(tours);
module.exports.stripe = functions.https.onRequest(stripe);

CI / CD

Que diriez-vous d'avoir une intégration et un déploiement continus chaque fois que vous apportez vos modifications au dépôt? Vous pouvez l'avoir en utilisant google google cloud build . C'est gratuit jusqu'à un certain point :) Vérifiez ce lien .

./cloudbuild.yaml

steps:
  - name: "gcr.io/cloud-builders/npm"
    args: ["run", "install:functions"]
  - name: "gcr.io/cloud-builders/npm"
    args: ["test"]
  - name: "gcr.io/${PROJECT_ID}/firebase"
    args:
      [
        "deploy",
        "--only",
        "functions",
        "-P",
        "${PROJECT_ID}",
        "--token",
        "${_FIREBASE_TOKEN}"
      ]

substitutions:
    _FIREBASE_TOKEN: nothing
Ajorquera
la source
j'ai exporté comme vous l'avez dit mais le déploiement de la base de feu détecte celui qui est à la fin, ex: selon votre code, il ne prend que module.exports.stripe = functions.https.onRequest (stripe);
OK200
@ OK200 quelle est la commande que vous utilisez avec la ligne de commande Firebase? Pour vous aider, j'aurai besoin de voir du code
ajorquera
3

Il existe un très bon moyen d'organiser toutes vos fonctions cloud sur le long terme. Je l'ai fait récemment et cela fonctionne parfaitement.

Ce que j'ai fait, c'est d'organiser chaque fonction cloud dans des dossiers séparés en fonction de leur point de terminaison de déclenchement. Chaque nom de fichier de fonction cloud se termine par *.f.js. Par exemple, si vous aviezonCreate et onUpdatedéclenche sur user/{userId}/document/{documentId}alors créez deux fichiers onCreate.f.jset onUpdate.f.jsdans le répertoire functions/user/document/et votre fonction sera nommée userDocumentOnCreateet userDocumentOnUpdaterespectivement. (1)

Voici un exemple de structure de répertoire:

functions/
|----package.json
|----index.js
/----user/
|-------onCreate.f.js
|-------onWrite.f.js
/-------document/
|------------onCreate.f.js
|------------onUpdate.f.js
/----books/
|-------onCreate.f.js
|-------onUpdate.f.js
|-------onDelete.f.js

Exemple de fonction

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const db = admin.database();
const documentsOnCreate = functions.database
    .ref('user/{userId}/document/{documentId}')
    .onCreate((snap, context) => {
        // your code goes here
    });
exports = module.exports = documentsOnCreate;

Index.js

const glob = require("glob");
const camelCase = require('camelcase');
const admin = require('firebase-admin');
const serviceAccount = require('./path/to/ServiceAccountKey.json');
try {
    admin.initializeApp({ credential: admin.credential.cert(serviceAccount),
    databaseURL: "Your database URL" });
} catch (e) {
    console.log(e);
}

const files = glob.sync('./**/*.f.js', { cwd: __dirname });
for (let f = 0, fl = files.length; f < fl; f++) {
    const file = files[f];
    const functionName = camelCase(file.slice(0, -5).split('/')); 
    if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
        exports[functionName] = require(file);
      }
}

(1): Vous pouvez utiliser le nom de votre choix. Pour moi, onCreate.f.js, onUpdate.f.js etc. semblent plus pertinents pour le type de déclencheur qu'ils sont.

krhitesh
la source
1
Cette approche est vraiment sympa. Je me demandais s'il était possible de régler pour autoriser les barres obliques dans les noms de fonction afin que vous puissiez séparer différentes versions d'API, par exemple (api v1, api v2, etc.)
Alex Sorokoletov
Pourquoi voudriez-vous conserver différentes versions d'une fonction cloud dans le même projet? Bien que vous puissiez le faire en modifiant légèrement la structure des répertoires, par défaut, index.js déploiera toutes les fonctions du cloud, sauf si vous déployez de manière sélective ou utilisez des conditions if dans votre index.js qui finiront par encombrer votre code
krhitesh
1
Je suis d'accord pour tout déployer, je veux juste versionner les fonctions que j'ai mises (déclenchées par http)
Alex Sorokoletov
Je m'attends à ce que chaque déclencheur http soit dans son propre *.f.jsfichier. Le moins que vous puissiez faire est de renommer le fichier pour chaque version en ajoutant le suffixe pour en faire quelque chose comme*.v1.f.js ou *.v2.f.jsetc. (en supposant que toutes vos versions de tous vos déclencheurs http sont actives). Veuillez me faire savoir si vous avez une meilleure solution.
krhitesh
1

J'utilise un bootloader JS vanilla pour inclure automatiquement toutes les fonctions que je souhaite utiliser.

├── /functions
   ├── /test/
      ├── testA.js
      └── testB.js
   ├── index.js
   └── package.json

index.js (chargeur de démarrage)

/**
 * The bootloader reads all directories (single level, NOT recursively)
 * to include all known functions.
 */
const functions = require('firebase-functions');
const fs = require('fs')
const path = require('path')

fs.readdirSync(process.cwd()).forEach(location => {
  if (!location.startsWith('.')) {
    location = path.resolve(location)

    if (fs.statSync(location).isDirectory() && path.dirname(location).toLowerCase() !== 'node_modules') {
      fs.readdirSync(location).forEach(filepath => {
        filepath = path.join(location, filepath)

        if (fs.statSync(filepath).isFile() && path.extname(filepath).toLowerCase() === '.js') {
          Object.assign(exports, require(filepath))
        }
      })
    }
  }
})

Cet exemple de fichier index.js inclut automatiquement les répertoires de la racine. Il pourrait être étendu pour parcourir les répertoires, honorer .gitignore, etc. Cela me suffisait cependant.

Avec le fichier d'index en place, l'ajout de nouvelles fonctions est simple.

/test/testA.js

const functions = require('firebase-functions');

exports.helloWorld = functions.https.onRequest((request, response) => {
 response.send("Hello from Firebase!");
});

/test/testB.js

const functions = require('firebase-functions');

exports.helloWorld2 = functions.https.onRequest((request, response) => {
 response.send("Hello again, from Firebase!");
});

npm run serve donne:

λ ~/Workspace/Ventures/Author.io/Firebase/functions/ npm run serve

> functions@ serve /Users/cbutler/Workspace/Ventures/Author.io/Firebase/functions
> firebase serve --only functions


=== Serving from '/Users/cbutler/Workspace/Ventures/Author.io/Firebase'...

i  functions: Preparing to emulate functions.
Warning: You're using Node.js v9.3.0 but Google Cloud Functions only supports v6.11.5.
✔  functions: helloWorld: http://localhost:5000/authorio-ecorventures/us-central1/helloWorld
✔  functions: helloWorld2: http://localhost:5000/authorio-ecorventures/us-central1/helloWorld2

Ce flux de travail est à peu près juste "écrire et exécuter", sans avoir à modifier le fichier index.js chaque fois qu'une nouvelle fonction / fichier est ajoutée / modifiée / supprimée.

Corey
la source
ce ne sera pas avoir sur démarrage à froid?
Ayyappa
1

Voici une réponse simple si vous créez des fonctions cloud avec dactylographié.

/functions
|--index.ts
|--foo.ts

Près de toutes vos importations régulières en haut, exportez simplement toutes les fonctions à partir de foo.ts.

export * from './foo';

Markymark
la source