我想为Firebase创建多个云功能,并从一个项目同时部署它们。我还想将每个函数分离到一个单独的文件中。目前,我可以创建多个函数,如果我把它们都放在index.js,如:

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

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

然而,我想把foo和酒吧在单独的文件。我试了一下:

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

foo.js在哪里

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

bar.js是

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

有没有一种方法可以在不把所有函数都放在index.js中的情况下实现这一点?


当前回答

我也在为云函数寻找最佳的文件夹结构,所以我决定分享我的想法:

+  /src
|    - index.ts
|    + /events
|    |    - moduleA_events.ts
|    |    - moduleB_events.ts
|    + /service
|    |    - moduleA_services.ts
|    |    - moduleB_services.ts
|    + /model
|    |    - objectA.ts
|    |    - objectB.ts
|    |    - objectC.ts

/ src /索引。Ts此文件作为应用程序中所有可用事件(函数)的入口点,如数据库事件,HTTPS请求,计划函数。然而,函数不是直接在index.js中声明的,而是在事件文件夹indead中声明的。代码示例: 出口。user = require("./events/userEvents") 出口。order = require("./events/orderEvents") 出口。product = require("./events/productEvents")

注意:根据GCF官方文档,这种方法会自动将所有函数重命名为“模块-函数”模式。示例:如果在userEvents中有"userCreated"函数。ts, firebase将重命名此函数为"user-userCreated"

/src/events this folder should only contain cloud functions declarations and should not handle business logic directly. For the actual business, you should call custom functions from your /service folder (which maps the same modules as in the events folder). Code sample for userEvents.ts: exports.userCreated = functions.firestore.document("/users/{documentId}").onCreate(async (snapshot) => { userServices.sendWelcomeEmail() } /src/service the actual busienss logic that will connect with other firebase services such as firestore, storage, auth. You can also import your /model layer here (typescript only). /src/model the interfaces used in typescript to ensure strong typed functions and objects.

正如您所注意到的,这种方法主要基于MVC和OOP原则。有很多关于我们是否应该在无服务器环境中使用函数式编程的争论。由于我的后台背景是Java和c#,我在这里介绍的文件夹结构对我来说似乎更自然,然而,我很想知道当转向函数式编程方法时,这种文件夹结构会有什么不同。

其他回答

以上的答案为我指明了正确的方向,只是没有一个真正适合我。下面是一个工作原型,一个onCall, onRequest和数据库触发器的例子

foo.js - 随叫随到,随叫随到。

exports.handler = async function(data, context, admin) {
    // const database = admin.database();
    // const firestore = admin.firestore();
    //...
};

bar.js - onRequest

exports.handler = async function(req, res, admin) {
    // const database = admin.database();
    // const firestore = admin.firestore();
    //...
};

jar.js - trigger/document/onCreate .js

exports.handler = async function(snapshot, context, admin) {
    // const database = admin.database();
    // const firestore = admin.firestore();
    //...
};

index.js

//导入firebase管理SDK依赖项

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

// import functions
const foo = require("./foo");
const bar = require("./bar");
const jar = require("./jar");

// onCall for foo.js
exports.foo = functions.https.onCall((data, context) => {
    return foo.handler(data, context, admin);
});

// onRequest for bar.js
exports.bar = functions.https.onRequest((req, res) => {
    return bar.handler(req, res, admin);
});

// document trigger for jar.js
exports.jar = functions.firestore
  .document("parentCollection/{parentCollectionId}")
  .onCreate((snapshot, context) => {
    return jar.handler(snapshot, context, admin);
});

注意:你也可以创建一个子文件夹来存放你的各个函数

更新:Typescript现在完全支持,所以不需要下面的恶作剧。只需使用firebase cli


以下是我个人是如何使用typescript的:

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

在此之前,我先提出两点警告:

进口/出口的顺序在index.ts中很重要 db必须是一个单独的文件

第二点,我不知道为什么。其次,你应该完全尊重我的index, main和db的配置(至少要尝试一下)。

索引。Ts:与出口有关。我觉得让索引更干净。贸易部门负责出口。

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

主要。ts:处理初始化。

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

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

db。Ts:只是重新导出数据库,所以它的名字比database()短。

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

在我努力实现@zaidfazil的解决方案时,我想出了以下方法(使用JavaScript,而不是TypeScript)。

multi.js

exports.onQuestionMultiCreate = functions.database
  .ref("/questions-multi/{questionId}")
  .onCreate(async (snapshot, context) => {
   ...
    }
  });

trueFalse.js

exports.onQuestionTrueFalseCreate = functions.database
  .ref("/questions-truefalse/{questionId}")
  .onCreate(async (snapshot, context) => {
   ...
    }
  });

index.js


const multi = require("./multi");
const trueFalse = require("./trueFalse");

module.exports = {
  ...multi,
  ...trueFalse

Firebase文档现在已经更新了一个多文件代码组织的好指南:

文档>云功能>写功能>组织功能

总结:

foo.js

const functions = require('firebase-functions');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});

bar.js

const functions = require('firebase-functions');
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

index.js

const foo = require('./foo');
const bar = require('./bar');
exports.foo = foo.foo;
exports.bar = bar.bar;

Node 8 LTS现在可以与Cloud/Firebase函数一起使用,您可以使用扩展操作符执行以下操作:

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