Problem
After researching the Firebase docs, videos, StackOverflow, lots of articles, ... organizing multiple (lots of) cloud functions in an "easy" way is not obvious. Especially, since the official Firebase docs do not provide a clear vision/recommendation. Actually, the real problem is the lack of clear documentation on how to setup a Firebase project with lots of functions right from the beginning.
I am trying to find an easy approach considering the following points:
- Based on Firebase docs (that every new Firebase user is reading)
- One single index.js requirement for Firebase CLI deployments
- Using plain JavaScript over TypeScript, not too much syntactic magic sugar
- Transparent control over which files/functions are included/referenced in the index.js
- Developing lots of functions, but don't export all in the index.js directly (kind of deployment control layer)
- Not too much async/await imports like in this example https://medium.com/firebase-developers/organize-cloud-functions-for-max-cold-start-performance-and-readability-with-typescript-and-9261ee8450f0
- Not depending on naming conventions like in this nice example https://codeburst.io/organizing-your-firebase-cloud-functions-67dc17b3b0da
- Scalability in terms of # of functions
- Going from initial setup (beginner using Firebase docs) to advanced, how to migrate the structure?
- Minimize effort for adding/deploying more and more cloud functions
- Performance: Lazy loading/initialization the admin SDK + ensure it's initialized only once
- Minimizing server instance cold-start time
- Easy to explain, easy to use, easy to maintain (sure it's a bit subjective)
Solution?
Coming from manually deployed cloud functions to a simple initial CLI setup using JavaScript, I tried the following file structure with some success:
[project]/
- functions/
- index.js
- src/
- functionA.js
- functionB.js
- ...
...
index.js
Structure based on the official docs: https://firebase.google.com/docs/functions/organize-functions
const functions = require('firebase-functions');
const functionA = require('./src/FunctionA');
exports.FunctionA = functionA.FunctionA;
const functionB = require('./src/FunctionB');
exports.FunctionB = functionA.FunctionB;
FunctionA.js
Using https://gist.github.com/saintplay/3f965e0aea933a1129cc2c9a823e74d7#file-index-js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
// Prevent firebase from initializing twice
try { admin.initializeApp() } catch (e) {console.log(e);}
exports.FunctionA = ...
FunctionB.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
// Prevent firebase from initializing twice
try { admin.initializeApp() } catch (e) {console.log(e);}
exports.FunctionB = ...
Question(s)
- Is this a practicable and viable solution?
- Is there any performance concern compared to async/await imports?
- Is the try-catch block around
admin.initializeApp()
a clean implementation? - What would be the Typescript equivalent solution?
- Cold-start time: When deploying via Firebase CLI, I notice in the Google Cloud Console "Cloud Functions" section that all cloud function instances contain source code of all other functions
- When creating functions manually in the cloud console, each function only has it's own piece of code to be deployed/initialized/executed
- Any suggestions on optimization? (e.g. maintainability of index.js)