Organize firebase functions in multiple files | Deploy error - javascript

So based on this Medium post I tried to split my firebase functions into different files.
My index.js looks like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const glob = require("glob");
const camelCase = require("camelcase");
const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**'});
admin.initializeApp(functions.config().firebase);
for(let f=0,fl=files.length; f<fl; f++){
const file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/').join('_')); // Strip off '.f.js'
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
My file test.f.js, where my function is located, is in some subfolders and looks like this:
const functions = require('firebase-functions');
exports.addNew = functions.https.onRequest((request, response) => {
...
})
My subfolders are called "dev" and "User", the file is called "Test" and my function "addNew"
When I try to deploy I get the following error:
⚠ functions[devUserTest-addNew(us-central1)]: Deployment error.
Function load error: Node.js module defined by file index.js is expected to export function named devUserTest.addNew
I hope someone can provide a solution to this problem.
Tanks!

Related

How to use a custom made library

I have a AWS dependency layer on on folder nodejs/
There is node_modules/ and package.json with npm dependencies
I created a folder called utils/ and my file is util.js
Since it's a layer on AWS, I import using const utils = require('/opt/nodejs/utils/util'); on my app.js
Problem is that my test cases started failing Cannot find module '/opt/nodejs/utils/util' from 'backend/lambdas/cars/app.js'
How can I fix my test case??
const app = require('./app');
describe('lambda', function () {
it('something', async () => {
const response = await app.lambdaHandler();
....
});
});
app.js
const httpStatusCode = require('http-status-codes');
const cors = require('/opt/nodejs/utils/util');
exports.lambdaHandler = async (event) => {
return {
statusCode: httpStatusCode.OK
};
};
PS: This nodejs folder is on the same level as the lambdas folder
You should import like this const utils = require('../nodejs/utils/util')

Fs file handler for api

So I want to make a routes folder that has subfolders that contain routes but I don't know how to use fs with it...
I only know how to get files in the routes folder and not in subfolders
here is my file handler code
const { readdirSync } = require('fs');
module.exports = function(app){
readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
const route = require('./' + name)
app.get(`/${route.name}`, async (req, res) => {
route.run(req, res)
})
});
}
it gets the files from the routes folder
-routes
|__index.js
|__route.js
|__route.js
I want to make it so it gets routes from subfolders
-routes
|__index.js
|
|__image routes
|__route1.js
I can't find any help online...
If you do not mind using external libraries i recommend using glob
What you want to do can be achieved with one function call:
const glob = require("glob");
glob("**/*.js", {cwd: __dirname}, (error, matches) => {
if (error) return;
console.log(matches);
})
This uses glob patterns to much files in a given directory, returning the whole paths like: image-routes/route1.js or index.js etc.

How do you dynamically module.export all files in a folder?

I'm trying to dynamically export modules. I'm close but can't figure out how to fix my syntax.
Hard coded:
// index.js inside folder 'models'
const { User } = require('./User');
const { Token } = require('./Token');
const { Session } = require('./Session');
module.exports = {
User,
Token,
Session,
};
Dynamically coded (doesn't work):
// index.js inside folder 'models'
const fs = require('fs');
const path = require('path');
module.exports = () => {
fs.readdirSync(__dirname).forEach((file) => {
if (file === 'index.js') return false;
const fullName = path.join(__dirname, file);
if (file.toLowerCase().indexOf('.js')) {
// I think this somehow needs to be destructured like
// `return {require(fullName)}` or
// `require(fullName)[fullName]` I think
require(fullName);
}
});
};
Elsewhere in my code, I initialize it based on the folder name:
// server.js
require('./models')();
Your dynamic export will not work because you are not returning anything to the exported function.
Try this code as your dynamic model export file
// index.js inside folder 'models'
const fs = require('fs')
const path = require('path')
const models = {}
fs.readdirSync(__dirname)
.filter(file => file !== 'index.js')
.forEach(file => {
const fullName = path.join(__dirname, file)
if (file.toLowerCase().endsWith('.js')) {
// Removes '.js' from the property name in 'models' object
const [filename] = file.split('.')
models[filename] = require(fullName)[filename]
}
})
module.exports = models
This approach no longer exports a function so your require in server.js should now look like this
// server.js
require('./models');

Iterate over folder and import index.js

I have create react app code base in which i would like to be able to iterate over a nested structure of data to import one specific file.
I have the following structure:
root.js
-modules
-- mod1
--- index.js
-- mod2
--- index.js
In root.js I would like to go over every module in modules to import index.js so that the initialization data will be run at the start of the application. Its unclear to me what is the best way to do this preferably without using any plugins if there is a solution.
In my opinion, you should include them "manually"
// root.js
require('mod1.index')
require('mod2.index')
// ...
It's more clear and direct. Unless you have 100+ modules
EDIT for dynamic import:
No dependancies proposal (variation of https://gist.github.com/kethinov/6658166#gistcomment-1603591)
'use strict'
const fs = require('fs')
const walkSync = function (dir, filelist) {
const files = fs.readdirSync(dir)
filelist = filelist || []
files.forEach(function (file) {
if (fs.statSync(dir + '/' + file).isDirectory()) {
filelist = walkSync(dir + '/' + file, filelist)
} else {
filelist.push(dir + '/' + file)
}
})
return filelist
}
allFiles = walkSync('./src')
allFiles.filter(f => f.split('/').pop() == 'index.js').forEach(f => require(f))
One dependacie proposal: Get all files recursively in directories NodejS
Turns out this was simple:
Export everything in a modules.js files.
const req = require.context('./', true, /^\.\/[a-zA-Z0-9]+\/index.js$/);
const modules = req.keys().map(req);
module.exports = modules;
Then import the modules.js file in some root.js file.

initialize firebase app in multiple files with nodejs

I want to Initialize Firebase App in multiple files to organize my methods properly, but I not sure which is the best way to do so.
Below is the file system structure:
/functions
|-keys
|-methods
| |-email.js
| |-logger.js
|-node_modules
|-index.js
|-package.json
|-package-lock.json
In my index.js, I initialize 2 projects where 1 is for production and another is for OTE.:
const functions = require('firebase-functions');
var firebaseAdmin = require('firebase-admin');
var productionServiceAccount = require('./keys/production-key.json');
var oteServiceAccount = require("./keys/ote-key.json");
var prodServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(productionServiceAccount),
databaseURL: 'https://production-panel.firebaseio.com'
}, "prod");
var oteServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(oteServiceAccount),
databaseURL: "https://ote-panel.firebaseio.com"
}, "ote");
console.log("prodServer: ", prodServer.name, "oteServer: ", oteServer.name)
var mailer = require('./methods/email.js') //import code from method folder
var logger = require('./methods/logger.js') //import code from method folder
Below is how i handle the request whether use prod or OTE project:
let admin = req.headers.env == 'prod' ? prodServer : oteServer
Now the problem is my ./methods/logger.js want to read/write log into DB as well, but I don't know how/what to do.
Below is the `logger.js` code:
var exports = {}
exports.log = function(item, ref, env) {
let admin = env == 'prod' ? prodServer : oteServer //<--problem here
return admin.database().ref(ref).push(item)
}
module.exports = exports
Should I initialize firebase project again or import it from index.js?
-If initialize firebase project again it will say the project "name" has been used.
-If import it from index.js, then I have to export it from index.js, which when I deploy it to Firebase Function, it will become an onCall Methods..?
-If I move the initialize to another file (./method/initFirebase.js) and import it to index.js when I deploy it to Firebase Function, will it automatically initialize the firebase app?
Please advise. Thank you.
You can create one additional file like you said initFirebase.js and put your initilization and export code there.
const prodServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(productionServiceAccount),
databaseURL: 'https://production-panel.firebaseio.com',
}, 'prod');
const oteServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(oteServiceAccount),
databaseURL: 'https://ote-panel.firebaseio.com',
}, 'ote');
module.exports = {
firebaseApp: env === 'prod' ? prodServer : oteServer,
};
And from all other file import firebase app
const firebaseApp = require('../YOUR_initFirebase.js')
So you dont need to worry about environment in each of the files and it is working for me on google cloud functions.
Here is how you can manage multiple apps with firebase-admin on nodejs to ensure the apps are not reinitialised.
const admin = require('firebase-admin');
const service1 = require('./app1-service.json');
const service2 = require('./app2-service.json');
const apps = {
app1: null,
app2: null,
};
void init() {
// check and init app1
const initialisedApps = admin.apps.map((item) => item.name);
if (!initialisedApps.includes('app1')) {
apps.app1 = admin.initializeApp({
credential: admin.credential.cert(service1),
}, 'app1');
} else apps.app1 = admin.app('app1');
// check and init app2
if (!initialisedApps.includes('app2')) {
apps.app2 = admin.initializeApp({
credential: admin.credential.cert(service2),
}, 'app2');
} else apps.app2 = admin.app('app2');
}
The way I solved this for ts is:
index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
exports.auth = require('./methods/email.ts');
...
email.ts
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
// Get emails
exports.getEMail = functions.https.onCall(async (data, context) => {
const uid = context?.auth?.uid ? context.auth.uid : '';
const email = await admin.firestore().collection('emails').doc(uid).get();
return email;
...

Categories

Resources