DEV Community

Oliver Pham
Oliver Pham

Posted on

How I Fixed an Issue in Firebase CLI

I found an issue on Firebase CLI repo that I could work on. The issue involved a hardcoded Node.js version in the generated package.json file when the command firebase init functions is executed. Moreover, there was no warning when a Node.js version in use is deprecated in Google Cloud Functions.

Getting started

To be honest, I had no idea how to approach this issue at first, so I decided to follow the contributing guide. It was very detailed and straightforward, so I had no problem setting up firebase-tools. Unlike the previous open source projects, I had to sign Google's Contributor License Agreement (CLA) before I could contribute to Firebase CLI. Thanks to the intuitive folder structure of the project, I could identify which files to be modified.

Dynamically set Node version

Based on the folder structure, firebase init functions should execute the code inside firebase-tools/src/init/features/functions/<language>.js (<language> is the programming language selected for your project). I made a comment on the issue to discuss my approach. Thankfully, I got some super helpful recommendations from Daniel, the author of the issue.

Basically, the package.json file is generated from a pre-written template. To set the right Node.js version, I needed the logic to identify it and replace the hardcoded version with it dynamically.

First, I replaced the hardcoded version with a template string inside package.json template file:

  "engines": {
    "node": "{{NODE_VERSION}}"
  },
Enter fullscreen mode Exit fullscreen mode

Then, a reliable function to detect Node.js version was implemented:

export function getNodeVersionString(): string {
  return process.versions.node.split(".")[0];
}
Enter fullscreen mode Exit fullscreen mode

Lastly, before writing package.json file to a dev's machine, I just need to replace the template string with the detected Node.js version like this:

const nodeEngineVersion = getNodeVersionString();
if (useLint) {
    return PACKAGE_LINTING_TEMPLATE.replace(/{{NODE_VERSION}}/g, nodeEngineVersion);
  }
return PACKAGE_NO_LINTING_TEMPLATE.replace(/{{NODE_VERSION}}/g, nodeEngineVersion);
Enter fullscreen mode Exit fullscreen mode
  • PACKAGE_LINTING_TEMPLATE: the content of package.json file with ESLint
  • PACKAGE_NO_LINTING_TEMPLATE: the content of package.json file without ESLint

Handle deprecated Node versions

The logic to warn developers of deprecated Node.js versions was still missing, so I discussed my approach with Daniel again. I intended to use a function that I found in their codebase, isDeprecatedRuntime(), to perform the check.

Luckily, Daniel pointed out a small bug in my approach and suggested a better one, which was to use isValidRuntime() instead. I finally got the last piece as:

if (!isValidRuntime(`nodejs${nodeEngineVersion}`)) {
    utils.logWarning(`Node ${nodeEngineVersion} is no longer supported in Google Cloud Functions.`);
    utils.logWarning(
      "See https://firebase.google.com/docs/functions/manage-functions for more details"
    );
}
Enter fullscreen mode Exit fullscreen mode

Final thoughts

I've never had to fix my code for a PR as much as this one. Thanks to their code review, I've learned a few good practices along with how I could avoid pitfalls by discussing my approach and getting feedback before actually coding it.


Issue: https://github.com/firebase/firebase-tools/issues/3407
PR: https://github.com/firebase/firebase-tools/pull/3894
Firebase: https://firebase.google.com

Discussion (0)