Wie strukturiere ich Cloud-Funktionen für Firebase, um mehrere Funktionen aus mehreren Dateien bereitzustellen?

163

Ich möchte mehrere Cloud-Funktionen für Firebase erstellen und alle gleichzeitig aus einem Projekt bereitstellen. Ich möchte auch jede Funktion in eine separate Datei trennen. Derzeit kann ich mehrere Funktionen erstellen, wenn ich beide in index.js einfüge, z.

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

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

Ich möchte jedoch foo und bar in getrennten Dateien ablegen. Ich habe es versucht:

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

wo foo.js ist

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

und bar.js ist

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

Gibt es eine Möglichkeit, dies zu erreichen, ohne alle Funktionen in index.js zu platzieren?

jasonsirota
quelle
1
@ JPVentura. Verstehe dich wirklich nicht gut. Bitte erkläre.
HuyLe
Wurde dies für v1.0 aktualisiert? Ich habe Probleme: stackoverflow.com/questions/50089807/…
tccpg288
2
Zu .jsrequire
Ihrer Information
Dies könnte hilfreich sein: stackoverflow.com/questions/43486278/…
Ramesh-X

Antworten:

126

Ah, Cloud-Funktionen für Firebase-Ladeknotenmodule normalerweise, also funktioniert dies

Struktur:

/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);

foo.js:

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

bar.js:

exports.handler = (event) => {
    ...
};
jasonsirota
quelle
1
Kann ich zum Beispiel mehrere Funktionen im foo-Modul haben? Wenn ja, wie ist es besser, es umzusetzen?
Alexander Khitev
1
Ich nehme an, Sie könnten verschiedenen exportierten Funktionen aus foo unterschiedliche Handler zuweisen: exports.bar = functions.database.ref ('/ foo'). OnWrite (fooModule.barHandler); exports.baz = functions.database.ref ('/ bar'). onWrite (fooModule.bazHandler);
Jasonsirota
44
Ich mag diese Lösung nicht, weil sie Informationen (nämlich die Datenbankpfade) von foo.js und bar.js in index.js verschiebt, was den Sinn dieser separaten Dateien zunichte macht.
bvs
Ich stimme @bvs zu, ich denke Ced hat einen guten Ansatz. Ich werde es leicht modifizieren, indem ich jedes Modul explizit exportiere, um die index.ts super klar zu machen, z. B. {newUser} aus "./authenticationFunctions" exportieren
Alan
2
Ich denke, meine ursprüngliche Frage war einfach, mehrere Funktionen mit einem Projekt bereitzustellen, ohne die Funktionen in die Datei index.js aufzunehmen, wo und wie Sie Datenbankinformationen übergeben, ist nicht im Geltungsbereich. Wäre ich es, würde ich wahrscheinlich ein separates Modul erstellen, das den Datenbankzugriff steuert und es in foo.js und bar.js separat benötigt, aber das ist eine stilistische Entscheidung.
Jasonsirota
75

Die Antwort von @jasonsirota war sehr hilfreich. Es kann jedoch nützlich sein, detaillierteren Code anzuzeigen, insbesondere bei durch HTTP ausgelösten Funktionen.

Angenommen, Sie möchten dieselbe Struktur wie in der Antwort von @ jasonsirota verwenden und möchten zwei separate HTTP-Triggerfunktionen in zwei verschiedenen Dateien haben:

Verzeichnisaufbau:

    /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);
});

foo.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'); 
}
Student
quelle
Die aktuelle Struktur in index.js hat für mich nicht gut funktioniert. Ich musste zuerst die Firebase-Module importieren, dann die App initialisieren und dann die Funktionen aus den anderen Ordnern importieren. Auf diese Weise initialisiert, authentifiziert meine App zuerst alles und importiert dann die Funktionen, für die die App zuvor initialisiert werden muss.
Tonkatata
46

Update: Dieses Dokument sollte helfen , meine Antwort ist älter als dieses Dokument.


So habe ich es persönlich mit Typoskript gemacht:

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

Lassen Sie mich dies vorwegnehmen, indem Sie zwei Warnungen geben, damit dies funktioniert:

  1. Die Reihenfolge des Imports / Exports ist in index.ts von Bedeutung
  2. Die Datenbank muss eine separate Datei sein

Für Punkt 2 bin ich mir nicht sicher warum. Secundo sollten Sie meine Konfiguration von Index, Main und DB genau respektieren (zumindest um es auszuprobieren).

index.ts : befasst sich mit dem Export. Ich finde es sauberer, wenn index.ts sich mit Exporten befasst.

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

main.ts : Beschäftigt sich mit der Initialisierung.

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

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

db.ts : Exportiert die Datenbank nur erneut, sodass ihr Name kürzer als istdatabase()

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
quelle
Wie sieht deine tsconfig aus? Wie kann ich in einen dist-Ordner kompilieren und gcloud-Funktionen wissen lassen, wo sich meine index.js befindet? Hast du deinen Code auf Github? :)
Bersling
@ choopage-JekBao Entschuldigung, es ist lange her, ich habe das Projekt nicht mehr. Wenn ich mich richtig erinnere, können Sie der Firebase-Konfiguration ein Verzeichnis geben (das standardmäßig öffentlich ist). Ich könnte mich jedoch irren, da es mehr als ein Jahr her ist
Ced
Hey @ced - warum kann der Inhalt von db.tsnicht nach innen gehen main.ts(nach der Instanziierung durch den Administrator?). Oder haben Sie sich aus Gründen der Klarheit / Einfachheit einfach auf diese Weise aufgeteilt?
dsg38
1
@ dsg38 dies wurde vor zu langer Zeit gepostet, ich verstehe nicht wirklich, warum es in einer separaten Datei sein sollte, die die Antwort jetzt betrachtet. Ich denke, es war aus Gründen der Klarheit
Ced
20

Mit Node 8 LTS, das jetzt mit Cloud / Firebase-Funktionen verfügbar ist, können Sie mit Spread-Operatoren Folgendes tun:

/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
quelle
Ich frage mich, ob die wachsende Anzahl von Importen den Kaltstart jeder Funktion verlangsamt oder ob es viele völlig getrennte Module geben sollte, die separat entwickelt werden.
Simon Fakir
2
Ich erhalte einen Eslint-Trennfehler unexpected token ...in index.js.
Thomas
Vielleicht verwenden Sie nicht Knoten 8
Luke Pighetti
@ SimonFakir gute Frage. Hast du etwas darüber gefunden?
Atereshkov
@atereshkov Ja, ich habe eine Möglichkeit gefunden, nur die angeforderte Funktion einschließlich ihrer Abhängigkeiten mit "process.env.FUNCTION_NAME" zu laden, ähnlich der folgenden Antwort. Ich kann mein Repo auch als Referenz teilen, wenn Sie interessiert sind, kontaktieren Sie mich.
Simon Fakir
15

Um einfach zu bleiben (aber die Arbeit erledigt), habe ich meinen Code persönlich so strukturiert.

Layout

├── /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';

Funktioniert für Verzeichnisse verschachtelter Ebenen. Folgen Sie einfach auch dem Muster in den Verzeichnissen.

Gutschrift auf @zaidfazil Antwort

Reza
quelle
1
Dies ist eine der einfachsten Antworten für Typescript, danke. Wie gehen Sie beispielsweise mit einer einzelnen Instanziierung der Firebase-Datenbank um? admin.initializeApp(functions.config().firestore) const db = admin.firestore();Wo setzen Sie das ein und wie beziehen Sie sich in foo und bar darauf?
Elprl
Hey - warum kann der Inhalt von db.tsnicht hineingehen index.ts(nach der Instanziierung durch den Administrator?). Oder haben Sie sich aus Gründen der Klarheit / Einfachheit einfach auf diese Weise aufgeteilt?
dsg38
@ dsg38 Sie können alle zusammen mischen, das macht es klar
Reza
10

Im Fall von Babel / Flow würde es so aussehen:

Verzeichnislayout

.
├── /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 - Hauptexportgüter)

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


src/db.js - Cloud SQL Client für 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 - Firebase Firestore Client

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

firebase.initializeApp(config().firebase);

export default firebase.firestore();


src/someFuncA.js - Funktion 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 - Funktion 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
quelle
9

Die Gliederung von bigcodenerd.org ist ein einfacheres Architekturmuster, damit Methoden in verschiedene Dateien getrennt und in einer Zeile innerhalb der Datei index.js exportiert werden.

Die Architektur für das Projekt in diesem Beispiel lautet wie folgt:

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 { ... }
  });

Das gleiche Muster würde für die removeProfileMethode in der Profildatei verwendet.

Adam Hurwitz
quelle
7

Um einfach zu bleiben (aber die Arbeit erledigt), habe ich meinen Code persönlich so strukturiert.

Layout

├── /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,
};

Funktioniert für Verzeichnisse verschachtelter Ebenen. Folgen Sie einfach auch dem Muster in den Verzeichnissen.

Zaidfazil
quelle
Ich kann nicht sehen, wie dies möglicherweise funktionieren könnte, da Firebase derzeit Node 6.11 unterstützt, das keine ES6-Importanweisungen unterstützt.
Aodh
Wenn Sie Typoskript verwenden, sollte das Problem niemals auftreten. Ich habe in letzter Zeit den größten Teil meines Codes in Typoskript portiert.
Zaidfazil
2
zaidfazil, sollten Sie wahrscheinlich alle Voraussetzungen in Ihrer Antwort notieren. @Aodh, es funktioniert, wenn Sie Babel so verwenden, wie Konstantin es in einer Antwort beschrieben hat. stackoverflow.com/questions/43486278/…
PostureOfLearning
1
Danke. Dies funktionierte mit Typoskript und Knoten 6 :)
Ahmad Moussa
4
Könnten Sie nicht einfach export * from './fooFunctions';und export * from './barFunctions';in index.ts haben, anstatt mit Spread-Operatoren zu importieren und erneut zu exportieren ?
Whatsthatitspat
5

Dieses Format ermöglicht es Ihrem Einstiegspunkt, zusätzliche Funktionsdateien zu finden und jede Funktion innerhalb jeder Datei automatisch zu exportieren.

Haupteinstiegspunkt-Skript

Findet alle .js-Dateien im Funktionsordner und exportiert jede aus jeder Datei exportierte Funktion.

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];
    }
  }
});

Beispiel Export mehrerer Funktionen aus einer Datei

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
}

Auf http zugängliche Endpunkte werden entsprechend benannt

✔ 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

Eine Datei

Wenn Sie nur wenige zusätzliche Dateien haben (z. B. nur eine), können Sie Folgendes verwenden:

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

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

Matthew Rideout
quelle
Wird dies nicht zu einer Überlastung beim Start für jede Funktionsinstanz führen, die sich dreht?
Ayyappa
4

Ich habe also dieses Projekt, das Hintergrundfunktionen und http-Funktionen hat. Ich habe auch Tests für Unit-Tests. CI / CD erleichtert Ihnen das Leben bei der Bereitstellung von Cloud-Funktionen erheblich

Ordnerstruktur

|-- 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

Hinweis: Der utils/ Ordner dient zum Freigeben von Code zwischen Funktionen

Funktionen / index.js

Hier können Sie einfach alle benötigten Funktionen importieren und deklarieren. Hier muss keine Logik vorhanden sein. Es macht es meiner Meinung nach sauberer.

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

Wie wäre es mit einer kontinuierlichen Integration und Bereitstellung jedes Mal, wenn Sie Ihre Änderungen in das Repo übertragen? Sie können es mit Google Google Cloud Build haben . Es ist bis zu einem bestimmten Punkt kostenlos :) Überprüfen Sie diesen Link .

./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
quelle
Ich habe exportiert, wie Sie sagten, aber die Firebase-Bereitstellung erkennt diejenige, die am Ende ist, z. B.: Gemäß Ihrem Code dauert es nur module.exports.stripe = functions.https.onRequest (Stripe);
OK200
@ OK200 Was ist der Befehl, den Sie mit der Firebase-Befehlszeile verwenden? Um Ihnen zu helfen, muss ich einen Code sehen
Ajorquera
3

Es gibt eine ziemlich gute Möglichkeit, alle Ihre Cloud-Funktionen langfristig zu organisieren. Ich habe das kürzlich gemacht und es funktioniert einwandfrei.

Ich habe jede Cloud-Funktion in separaten Ordnern basierend auf ihrem Trigger-Endpunkt organisiert. Jeder Dateiname der Cloud-Funktion endet mit *.f.js. Zum Beispiel, wenn Sie hat onCreateund onUpdateTrigger für user/{userId}/document/{documentId}erstellen Sie dann zwei Dateien onCreate.f.jsund onUpdate.f.jsim Verzeichnis functions/user/document/und Ihre Funktion wird benannt werden userDocumentOnCreateund userDocumentOnUpdatejeweils. (1)

Hier ist ein Beispiel für eine Verzeichnisstruktur:

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

Beispielfunktion

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): Sie können einen beliebigen Namen verwenden. Für mich scheinen onCreate.f.js, onUpdate.f.js usw. für die Art des Auslösers relevanter zu sein.

krhitesh
quelle
1
Dieser Ansatz ist wirklich nett. Ich habe mich gefragt, ob es möglich ist, Schrägstriche in den Funktionsnamen zuzulassen, damit Sie verschiedene API-Versionen trennen können, z. B. (API v1, API v2 usw.)
Alex Sorokoletov
Warum sollten Sie verschiedene Versionen einer Cloud-Funktion unter demselben Projekt behalten? Obwohl Sie dies tun können, indem Sie die Verzeichnisstruktur geringfügig ändern, stellt index.js standardmäßig alle Cloud-Funktionen bereit, es sei denn, Sie stellen selektiv bereit oder verwenden if-Bedingungen in Ihrer index.js, die letztendlich Ihren Code
überladen
1
Ich kann alles gut
bereitstellen
Ich erwarte, dass sich jeder http-Trigger in einer eigenen *.f.jsDatei befindet. Das Mindeste , was Sie tun können , ist die Datei für jede Version durch Voranstellung des Suffix es so etwas wie zu machen das Umbenennen *.v1.f.jsoder *.v2.f.jsusw. (Vorausgesetzt , alle Versionen aller Ihrer http Trigger sind live). Bitte lassen Sie mich wissen, wenn Sie eine bessere Lösung haben.
krhitesh
1

Ich verwende einen Vanilla JS-Bootloader, um alle Funktionen, die ich verwenden möchte, automatisch einzuschließen.

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

index.js (Bootloader)

/**
 * 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))
        }
      })
    }
  }
})

Diese Beispieldatei index.js enthält nur automatisch Verzeichnisse im Stammverzeichnis. Es könnte erweitert werden, um Verzeichnisse zu führen, .gitignore zu ehren usw. Dies war jedoch genug für mich.

Wenn die Indexdatei vorhanden ist, ist das Hinzufügen neuer Funktionen trivial.

/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 Ausbeuten:

λ ~/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

Dieser Workflow ist so ziemlich nur "Schreiben und Ausführen", ohne dass die Datei index.js jedes Mal geändert werden muss, wenn eine neue Funktion / Datei hinzugefügt / geändert / entfernt wird.

Corey
quelle
Wird das nicht beim Kaltstart sein?
Ayyappa
1

Hier ist eine einfache Antwort, wenn Sie Cloud-Funktionen mit Typoskript erstellen.

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

Nahezu alle Ihre regulären Importe oben exportieren Sie einfach alle Funktionen von foo.ts.

export * from './foo';

Markymark
quelle