Recently I started to work on a new project and after a considerable amount of time spent choosing the tech stack, I decided to go with Angular, Firebase Cloud Functions, and NX Monorepo.
I want to share how I integrated Firebase Cloud Functions into an NX Monorepo and shared TS types between them because It took me a while to figure it out, so I hope it may help somebody.
Setup Project in Firebase
I won’t go into detail about how to set up a project in Firebase, it is a straightforward process that you can google, however, what I will include is that you will want to export your private key from Firebase to access your database
Add Firebase to an NX project
If you don’t have an NX project, follow its documentation on how to create one, however just by running nx g @nx/angular:application test-app
it will create a Monorepo for you.
Once an NX app is generated you want to install the following package:
npm install -g firebase-tools
Which is a tool that can be used to test, manage, and deploy your Firebase project from the command line - link to NPM.
Install Angular/Fire
To enable the interaction between our Angular application and Firebase, you want to install @angular/fire. Using NX, you have to specify which application you want to target to communicate with Firebase, so the end command will be similar to:
nx g @angular/fire:ng-add --project=test-app
Angular/Fire Problem with Standalone Project
If you are using standalone components in Angular, you most likely don’t have a app.module.ts
file. In this case, the above command will fail with the message:
My workout was to create an empty app.module.ts
file as follows:
Once this is done and you run the @angular/fire
command again, it will output a successful initialization message:
Then you can copy the generated providers from app.module.ts
into apps/test-app/src/app/app.config.ts
as follows:
Adding Firebase Cloud Functions
This is a section where things started to get a bit complicated. There is no clear guideline from NX or Firebase on how to integrate cloud functions together. However, I was able to nx-firebase repo on Github, and by following its docs the integration is not that complicated so let’s take a look.
Head over to quick-start and install the package npm install @simondotm/nx-firebase
.
Then run the following command to generate a new application only for cloud functions:
nx g @simondotm/nx-firebase:app test-app-functions
Which will generate the below folder structure:
Missing @nx/node
I the process of adding cloud function I encountered the error of missing @nx/node
, so I went to the NX docs website and manually installed npm install -D @nx/node
the library.
Cloud functions - Sharing TS types
Most likely you will want to share some typescript types/interfaces between your libraries and cloud-functions. For that, create an nx node library by nx g @nx/node:library shared-types
,
It creates a shared-types
folder under libs
directory and updates the root tsconfig.base.json
. Now you can create an interface and use this interface in your cloud function app: test-app-functions
.
Cloud functions - Serving & Deployment
When you created your cloud function directory: test-app-functions
(mine is called market-monitor-cloud-functions) it contains a package.json
with some scripts to run the app.
I personally had trouble running those script from the cloud-function app directory so instead of that I introduced 2 scripts into the root package.json
file. Those are:
"mm:cloud-function:serve": "nx build test-app-functions && firebase emulators:start --only functions --config firebase.test-app-functions.json",
"mm:cloud-function:deploy": "nx build test-app-functions && firebase deploy --only functions --config firebase.test-app-functions.json"
When serving your app by the local emulator what you also may want to do is to update the firebase.test-app.json
file at the root directory, precisely the emulators
part. I only wanted to emulate the functions, so I removed the rest of the options and ended up with the following configuration:
// firebase.test-app.json
"emulators": {
"functions": {
"port": 5001
},
"singleProjectMode": true
}
Initiaze Functions to Firebase
The first thing you have to do when it comes to deploying cloud functions is to enable your project to pay-as-you-go:
If you have ever worked with firebase functions outside of nx, most of the times you connect your functions to your firebase app, is by exporting the private key (as suggested at the beginning), importing your key into the folder and the initializing the app as follows:
import * as admin from 'firebase-admin';
import { DATABASE_URL } from './environments';
const serviceAccount = require('../firebase_key.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: DATABASE_URL,
});
The config however didn’t work for me. I was having some weird path resolving errors so I ended up just by copying the firebase_key.json
content directly into the credential
part (which is not the ideal solution), as follows:
const serviceAccount: admin.ServiceAccount = {
projectId: 'whatever-id',
privateKey: '-----BEGIN PRIVATE KEY-----',
clientEmail: 'firebase-adminsdk-knos0@something.gserviceaccount.com',
};
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: DATABASE_URL,
});
After that I run the deployment command: yarn mm:cloud-function:deploy
, it will successfully deploy my cloud functions to Firebase.
Summary
Honestly, the longer I am a developer the more technologies I have to use, however, once everything is set up I greatly appreciate the productivity it gives me.
Firebase is a great BAAS solution and NX had proven its usefulness throughout the years. Choose your frontend framework based on your preferences, however, I believe this stack is great for a side project that is intended to fail in the near future. Have fun 👋.
If you liked this article, consider following me on:
dev.to
LinkedIn
Personal Website
Github
Top comments (3)
I have an issue when I try to build the functions.
Do you know what the problem might be?
Hey Chiramet.
This may be due to multiple reasons. Check if:
1.) In your library, inside
tsconfig.lib.json
there should be only one entry for theinclude
part:"include": ["src/**/*.ts"]
. Sometimes happens that a path to a library is added there.2.) Did you export the function from
shared
in theindex.ts
?3.) Check if all the paths are correct in
tsconfig.base.json
(root directory)I checked all your 3 points and it looks right. But it still didn't work.
What I did now is instead of using
nx g @nx/node:library
I usednx g @nx/js:lib
. It has some different configurations and it works for me.Thank you anyways. And nice post! It was exactly what I needed 😊