Cum pot structura Nor Functii de Baza pentru a implementa mai multe functii din mai multe fișiere?

Aș dori pentru a crea Cloud multiple Funcții pentru Firebase și implementați-le pe toate în același timp la un proiect. Am dori, de asemenea, pentru a separa fiecare funcție într-un fișier separat. În prezent, pot crea mai multe funcții, dacă le-am pus amândoi în index.js cum ar fi:

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

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

Cu toate acestea, aș dori să pun foo bar și în fișiere separate. Am incercat asa:

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

în cazul în care foo.js este

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

și bar.js este

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

Există o modalitate de a realiza acest lucru fără a pune toate funcțiile în index.js?

Comentarii la întrebare (3)
Soluția

Ah, Cloud Funcții pentru Firebase sarcina nod module, în mod normal, astfel încât aceasta funcționează

structura:

/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) => {
    ...
};
Comentarii (5)

Răspunsul de @jasonsirota a fost de foarte mare ajutor. Dar poate fi util pentru a vedea mai detaliată cod, mai ales în cazul HTTP declanșat funcții.

Folosind aceeași structură ca în @jasonsirota's a răspunde, să spunem că doriți să aveți două HTTP funcții de declanșare în două fișiere diferite:

structura de directoare:

    /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'); 
}
Comentarii (1)

Update: Acest doc ar trebui ajuta, răspunsul meu este mai vechi decât acest doc.


Aici este modul în care eu personal făcut-o cu mașina de scris:

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

Permiteți-mi să încep prin a-ți dau două avertismente pentru a face acest lucru:

  1. ordinea de import / export contează în index.ts
  2. db trebuie să fie un fișier separat

Pentru punctul 2 am'm nu sunt sigur de ce. Secundo ar trebui să-mi respecte configurația index, principal și db exact (cel puțin să-l încercați).

index.ts : se ocupa cu exportul. Găsesc că este mai curat pentru a lăsa index.ts ocupă cu exporturile.

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

principal.ts: Oferte cu inițializare.

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

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

db.ts: doar reexporting db deci numele său este mai scurt decât date()`

import { database } from "firebase-admin";

export const db = database();

http-funcții.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);
}
Comentarii (5)

Cu Nodul 8 ESTE acum disponibil cu Nor/Firebase Funcții puteți face următoarele cu răspândirea operatori:

/pachet.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);
  });
Comentarii (5)

În cazul în care cu Babel/Curge ar arata astfel:

Director Layout

.
├── /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 - export Principal(s)

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


src/db.js - Cloud SQL Client pentru Postgres

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

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


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 Funcție de Un

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 Funcție de 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/**"
    ]
  }
}


# # pachet.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
Comentarii (0)

Pentru a fi păstrat simplu (dar functioneaza), eu personal am structurat un astfel de cod.

Aspect

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

Lucrări pentru directoarele de orice niveluri imbricate. Doar urmați modelul în interiorul directoare de asemenea.

credit a @zaidfazil răspunde

Comentarii (3)

Pentru a fi păstrat simplu (dar functioneaza), eu personal am structurat un astfel de cod.

Aspect

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

Lucrări pentru directoarele de orice niveluri imbricate. Doar urmați modelul în interiorul directoare de asemenea.

Comentarii (6)

Acest format permite puncte de intrare pentru a găsi funcția suplimentare de fișiere, și de export fiecare funcție în cadrul fiecărui fișier, în mod automat.

Principalul Punct De Intrare Script

Găsește toate .js fișiere în interiorul funcțiilor dosar, iar exporturile fiecare funcție exportate din fiecare fișier.

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

Exemplu de Export de Multe Funcții dintr-Un Fișier

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
}

http accesibile finale sunt numit în mod corespunzător

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

Dacă aveți doar câteva fișiere suplimentare (de exemplu, doar unul), puteți folosi:

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

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

bigcodenerd.org contur's un simplu arhitectura model în scopul de a avea metode separate în diferite fișiere și exportate în o linie în index.js fișier.

Arhitectura pentru proiect în acest eșantion este următoarea:

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

Același model ar putea fi utilizate pentru removeProfile metoda în profile fișier.

Comentarii (0)

Există o destul de bună modalitate de a organiza toate dvs. de cloud funcțiile pe termen lung. Am făcut asta recent și este de lucru impecabil.

Ceea ce am făcut a fost să organizeze fiecare nor funcție în foldere separate pe baza lor de a declanșa efectul. Fiecare nor funcția de nume se termină cu *.f.js. De exemplu, dacă ați avut onCreate " și "onUpdatedeclanseaza pe utilizator/{id}/document/{documentId} apoi, creați două fișiere onCreate.f.js" și "onUpdate.f.jsin directorulfuncții/utilizator/document/și funcția dumneavoastră va fi numituserDocumentOnCreate" și " userDocumentOnUpdate` respectiv. (1)

Aici este un eșantion directorul avem:

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

Funcție De Probă

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): puteți folosi orice nume doriți. Pentru mine, onCreate.f.js, onUpdate.f.js etc. par mai relevante pentru tipul de declanșare sunt.

Comentarii (4)

Deci am acest proiect, care are funcții de fundal și http funcții. Am, de asemenea, teste pentru unitate de testare. CI/CD va face viața mult mai ușoară atunci când implementarea cloud funcții

Structura de foldere

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

Notă: `utils/ dosarul este pentru cota de cod între funcții

functions/index.js

Aici puteți importa doar toate funcțiile de care aveți nevoie și să le declare. Nu trebuie sa ai logica aici. Ea face curat în opinia mea. `javascript necesită('modulul-alias/register'); const funcții = necesită('firebase-funcții');

const onCreate = necesită('@fundal/onCreate'); const onDelete = necesită('@fundal/onDelete'); const onUpdate = necesită('@fundal/onUpdate');

const tururi = necesită('@http/tours'); const dungă = necesită('@http/stripe');

const docPath = 'excursii/{tourId}';

module.exporturile.onCreate = funcții.firestore.document(docPath).onCreate(onCreate); module.exporturile.onDelete = funcții.firestore.document(docPath).onDelete(onDelete); module.exporturile.onUpdate = funcții.firestore.document(docPath).onUpdate(onUpdate);

module.exporturile.excursii = funcții.https.onRequest(excursii); module.exporturile.dungă = funcții.https.onRequest(bandă); ``

CI/CD

Cum despre a avea continuu de integrare și implementare de fiecare dată când apăsați modificările la repo? Puteți să-l avea, cu ajutorul google google cloud construi. L's gratuit până la un punct :) Verifica acest lucru link.

./cloudbuild.yaml ``yaml pașii de mai jos:

  • nume: "gcr.io/nor-constructori/npm" args: ["run", "instala:funcții"]
  • nume: "gcr.io/nor-constructori/npm" args: ["de testare"]
  • nume: "gcr.io/${PROJECT_ID}/firebase" args: [ "disloca", " - numai", "funcții", " P", "${PROJECT_ID}", "--semn", "${_FIREBASE_TOKEN}" ]

substituții: _FIREBASE_TOKEN: nimic ``

Comentarii (2)

Eu folosesc un vanilla JS bootloader pentru a auto-includ toate funcțiile pe care vreau să o utilizați.

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

Acest exemplu index.js fișier de auto-include directoare în rădăcină. Acesta ar putea fi extins pentru a mers pe jos directoare, onoare .gitignore, etc. Acest lucru a fost suficient pentru mine.

Cu indicele de fișier în loc, adăugarea de noi funcții este banal.

/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 rula servi randamente:

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

Acest flux de lucru este destul de mult doar "scrie și rula", fără a fi nevoie de a modifica index.js fișier de fiecare dată când o nouă funcție/fișier este adăugat/modificat/eliminat.

Comentarii (1)

Am petrecut o mulțime de timp în căutarea pentru același lucru, și nu este ceea ce cred că este cel mai bun mod de a realiza (I'm, folosind firebase@7.3.0):

https://codeburst.io/organizing-your-firebase-cloud-functions-67dc17b3b0da

Nu sudoare ;)

Comentarii (0)

Aici's un răspuns simplu daca're crearea nor funcții cu mașina de scris.

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

Aproape toate import regulat în partea de sus a exporta toate funcțiile din foo.ts.

export * din './foo';`

Comentarii (0)