george43g / better-firebase-functions

This repo provides functionality for a better way of organising files, imports and function triggers in Firebase Cloud Functions
Mozilla Public License 2.0
181 stars 15 forks source link

JS ESM Compatibility? #42

Open chrisspiegl opened 2 years ago

chrisspiegl commented 2 years ago

Hello, I have been trying to use this library for a few hours and can't get it to work. Here's what I am doing:

I generally use the ESM (type=module) setting in my node.js projects. However, it seems the exports setting of this library is giving me heart aches 🙈.

This is my index.js:

import bff from 'better-firebase-functions'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)

const result = bff.exportFunctions({
  enableLogger: true,
  __filename,
  exports: module.exports,
  // exportPathMode: true,
})
console.log('BFF RESULT:', result)

Note that I already found a way to replace the __filename since that appears to be missing in ESM, but no matter what I set for the exports parameter, I never get it to work. module.exports is not defined and the same is true if I just use exports.

Thank you, I am looking forward to reading from you.

Cheers, Chris

george43g commented 2 years ago

I'm really curious about this - there could be a performance benefit here. Could you please provide a non working example to a repo where I can take a closer look?

chrisspiegl commented 2 years ago

@george43g right now I do not have time to build an example repo.

But essentially it is just a project with the "type": "module" set in the package.json and then trying to use the import way of loading things as shown above instead of require().

TanguyGiton commented 8 months ago

Same issue here

drewburnett commented 1 month ago

A (little silly) solution that repeats some things BFF already does, but it works...

If you're using ES Modules in your Firebase project (i.e., you have "type": "module" in your package.json), you might encounter issues with better-firebase-functions as it's designed for CommonJS. Here's a solution to use it with ES Modules:

1. Create a wrapper

Create a file named bff-wrapper.js in your project:

import { createRequire } from 'module';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { globSync } from 'glob';

const require = createRequire(import.meta.url);
const bff = require('better-firebase-functions');

export const exportFunctions = async ({ __filename }) => {
    const __dirname = dirname(fileURLToPath(import.meta.url));
    const fakeExports = {};

    // Manually find and import functions
    const functionFiles = globSync('**/*.js', { 
        cwd: dirname(__filename), 
        ignore: ['index.js', 'wrappers/**']
    });

    for (const file of functionFiles) {
        const module = await import(`${dirname(__filename)}/${file}`);
        if (module.default && typeof module.default === 'function') {
            const funcName = bff.funcNameFromRelPathDefault(file);
            fakeExports[funcName] = module.default;
        }
    }

    // Use better-firebase-functions to process the fakeExports
    bff.exportFunctions({ 
        __filename, 
        exports: fakeExports, 
        functionDirectoryPath: dirname(__filename),
        extractTrigger: (mod) => mod // We've already extracted the default export
    });

    return fakeExports;
};

This wrapper:

2. Update your main index.js

Modify your index.js to use the wrapper:

import { exportFunctions } from './wrappers/bff-wrapper.js';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);

export const functions = await exportFunctions({ __filename });

3. Structure your function files

Ensure all your function files export their functions as the default export:

import { onDocumentCreated } from "firebase-functions/v2/firestore";

export default onDocumentCreated("colletion-name/{docId}", (event) => {
    console.log("onDocumentCreated", event);
});

Notes

I hope this helps! Let me know if you need any further clarification or assistance.