如何构建 Cloud Functions for Firebase 以从多个文件部署多个函数?

IT技术 javascript firebase google-cloud-platform google-cloud-functions
2021-01-24 04:15:37

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

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

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

但是我想将 foo 和 bar 放在单独的文件中。我试过这个:

/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 中的情况下实现这一点?

6个回答

啊,用于 Firebase 加载节点module的云函数正常,所以这有效

结构体:

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

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

酒吧.js:

exports.handler = (event) => {
    ...
};
我认为我最初的问题只是关于在 1 个项目中部署多个函数而不将函数放在 index.js 文件中,传递数据库信息的位置和方式不在范围内。如果是我,我可能会创建一个单独的module来控制数据库访问并分别在 foo.js 和 bar.js 中要求它,但这是一个风格决定。
2021-03-16 04:15:37
例如,我可以在 foo module中有几个函数吗?如果是这样,如何更好地实施它?
2021-04-11 04:15:37
我想你可以,并为从 foo 导出的不同函数分配不同的处理程序:exports.bar = functions.database.ref('/foo').onWrite(fooModule.barHandler); export.baz = functions.database.ref('/bar').onWrite(fooModule.bazHandler);
2021-04-12 04:15:37
我同意@bvs,我认为 Ced 有一个很好的方法。我将通过显式导出每个module来稍微修改它以使 index.ts 超级清晰,例如从“./authenticationFunctions”导出 {newUser}
2021-04-12 04:15:37
我不喜欢这个解决方案,因为它将信息(即数据库路径)从 foo.js 和 bar.js 移动到 index.js 中,这违背了拥有这些单独文件的意义。
2021-04-14 04:15:37

@jasonsirota 的回答非常有帮助。但是查看更详细的代码可能会很有用,尤其是在 HTTP 触发函数的情况下。

使用与@jasonsirota 的回答相同的结构,假设您希望在两个不同的文件中拥有两个单独的 HTTP 触发器函数:

目录结构:

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

索引.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'); 
   }

酒吧.js:

exports.handler = function(req, res, database) {
  // Use database to declare databaseRefs:
  usersRef = database.ref('users');
      ...
  res.send('bar ran successfully'); 
}
index.js 中的当前结构对我来说效果不佳。我必须做的是首先导入 firebase module,然后初始化应用程序,然后从其他文件夹导入函数。这样我的应用程序首先初始化,验证,然后导入需要预先初始化应用程序的函数。
2021-03-20 04:15:37
我觉得应该有更好的方法将函数文件连接到 index.js?当前的手动接线方法似乎需要大量工作。
2021-04-05 04:15:37

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


这是我个人如何使用typescript做到的:

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

让我通过给出两个警告来开始这项工作:

  1. index.ts中导入/导出的顺序很重要
  2. 数据库必须是一个单独的文件

对于第 2 点,我不确定为什么。Secundo你应该尊重我的索引,主数据库的配置完全相同(至少尝试一下)。

index.ts:处理出口。我发现让 index.ts 处理导出更干净。

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

main.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);
}
我们如何在同一个文件夹中拥有 typescript 和 javascript 函数。我必须创建两个不同的文件夹(一个用于 javascript,一个用于typescript)并执行 firebase init 等。有没有更好的方法来处理这个问题?
2021-03-16 04:15:37
嘿@ced - 为什么不能db.ts里面的内容main.ts(在管理员实例化之后?)。或者你只是为了清晰/简单而以这种方式分开?
2021-04-06 04:15:37
你的 tsconfig 是什么样的?如何编译到 dist 文件夹并让 gcloud 函数知道我的 index.js 在哪里?你在github上有你的代码吗?:)
2021-04-09 04:15:37
@dsg38 这是很久以前发布的,我真的不明白为什么现在应该在一个单独的文件中查看答案..我认为这是为了清楚起见
2021-04-09 04:15:37
@choopage-JekBao 抱歉,好久不见,我没有这个项目了。如果我没记错的话,你可以给 firebase 配置一个目录(默认是公开的)。我可能是错的,因为已经一年多了
2021-04-13 04:15:37

借助 Cloud/Firebase Functions 现在提供的 Node 8 LTS,您可以使用扩展运算符执行以下操作:

/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);
  });
@atereshkov 是的,我找到了一种方法,可以使用类似于下面的答案的“process.env.FUNCTION_NAME”来仅加载请求的函数,包括它的依赖项。如果您有兴趣与我联系,我也可以分享我的回购作为参考。
2021-03-15 04:15:37
也许您没有使用 Node 8
2021-03-17 04:15:37
我想知道越来越多的导入会减慢每个功能的冷启动速度还是应该有许多完全分离的module单独开发?
2021-03-24 04:15:37
unexpected token ...在 index.js 中收到 eslint 分割错误
2021-04-03 04:15:37
@SimonFakir 好问题。你有没有发现什么?
2021-04-11 04:15:37

为了保持简单(但确实有效),我个人已经像这样构建了我的代码。

布局

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

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

数据库文件

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

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

索引.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';

适用于任何嵌套级别的目录。也只需遵循目录中的模式。

归功于@zaidfazil 的回答

我为 TS 做了类似的事情,感谢这是一个简单而好的解决方案
2021-03-17 04:15:37
这是typescript最简单的答案之一,谢谢。例如,您如何处理 firebase 数据库的单个实例化?admin.initializeApp(functions.config().firestore) const db = admin.firestore();你把它放在哪里,你如何在 foo 和 bar 中引用它?
2021-03-23 04:15:37
嘿 - 为什么不能db.ts里面的内容index.ts(在管理实例化之后?)。或者你只是为了清晰/简单而以这种方式分开?
2021-03-29 04:15:37
@dsg38 你可以混合在一起,这很清楚
2021-03-31 04:15:37