How I Fixed an Issue in Firebase CLI
Tags: opensource, firebase, javascript
Published: 2021-11-20 04:00:31

I found an issue on [Firebase CLI repo](https://github.com/firebase/firebase-tools) that I could work on. The [issue](https://github.com/firebase/firebase-tools/issues/3407) 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](https://cla.developers.google.com/) (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](https://github.com/firebase/firebase-tools/issues/3407#issuecomment-958587839) on the issue to discuss my approach. Thankfully, I got some super helpful recommendations from [Daniel](https://github.com/taeold), 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:

```json
  "engines": {
    "node": "{{NODE_VERSION}}"
  },
```

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

```js
export function getNodeVersionString(): string {
  return process.versions.node.split(".")[0];
}
```

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:

```js
const nodeEngineVersion = getNodeVersionString();
if (useLint) {
    return PACKAGE_LINTING_TEMPLATE.replace(/{{NODE_VERSION}}/g, nodeEngineVersion);
  }
return PACKAGE_NO_LINTING_TEMPLATE.replace(/{{NODE_VERSION}}/g, nodeEngineVersion);
```
- _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](https://github.com/firebase/firebase-tools/pull/3894#discussion_r748674087) 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:

```js
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"
    );
}
```

## 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