- Firebase Functions
- Nx-Firebase Functions
- Generating a new function
- Building a Firebase function
- Firebase Function Dependencies & Package Managers
- Deploying a Firebase function
- Testing & Linting your firebase function
- Managing Functions in your Workspace
- Functions & Nx-Firebase Applications
- Node Runtimes for Firebase Functions
Nx-Firebase functions are generated as individual Nx application projects, separately to the Nx-Firebase application.
-
This allows for multiple functions to be generated in a single workspace, each with their own
src/main.ts
entry point andpackage.json
file. -
The default
src/main.ts
template is the same one generated by the Firebase CLI and defaults to using 2nd gen cloud functions. This file is of course just a starting point and can be modified as needed. -
Each function project is a buildable Typescript node-based application, which is compiled and bundled using esbuild.
-
Each function project can export one or more firebase cloud functions.
-
Each function project must be linked to a single Firebase application project in the workspace, which ensures all functions can be managed by the nx-firebase plugin.
-
Functions can import code from Nx shared libraries and
esbuild
will tree-shake and bundle the code into a single output file. -
You rename or move Firebase function projects in your Nx workspace, and use the plugin sync command to keep your
firebase.json
configuration file in sync. -
Functions can be tested, linted, built and deployed using the Nx CLI
- Functions support deployment with
npm
,pnpm
oryarn
package managers.
Generate a new Firebase function using:
nx g @simondotm/nx-firebase:function
OR
nx g @simondotm/nx-firebase:func
Options | Type | Description |
---|---|---|
name |
required | the project name for your function |
--app=<app-project-name> |
required | the firebase app this function will be a dependency of |
--directory=dir |
optional | the directory this function will be located in |
--format=<'cjs' or 'esm'> |
default 'esm' | specify if esbuild should generated commonJs or ES6 output |
--runTime=<node versions> |
optional | the nodejs runtime you wish to use for this function - 14, 16, 18, 20 |
--tags |
optional | tags to set on the new project |
--setParserOptionsProject |
optional | set the parserOptions.project in the tsconfig.json file |
--projectNameAndRootFormat |
optional | derived or as-provided (see Nx docs for projectNameAndRootFormat) |
To build your firebase function use this command:
nx build your-firebase-function-project-name
This will use esbuild
to compile & bundle the input function Typescript source code to:
dist/apps/your-firebase-function-project-name/main.js
- The bundled function code, in a single ESM format output filedist/apps/your-firebase-function-project-name/package.json
- The ESM format package file for firebase CLI to process and deploy
When building a function, Nx will automatically generate a package.json
file in the output dist
directory, which contains all package dependencies used by the function.
Nx will also generate a pruned package-lock.json
, yarn.lock
or pnpm-lock.yaml
file in the function project root, depending on the package manager used in the workspace, which ensures your deployed function has exactly the same dependencies in the cloud as it does locally.
To deploy all of your firebase function projects use:
nx deploy your-firebase-app-name --only:functions
To deploy one of your firebase function projects use this command:
nx deploy your-firebase-function-name
To deploy a single function from within a firebase function project that exports multiple functions, use this command:
nx deploy <codebase> --only functions:<codebase>:function-name
Where <codebase>
is whatever name you gave your nx-firebase:function project.
IMPORTANT NOTE: Newly generated function projects do not deploy out-of-the-box. This is because the default Firebase CLI template for
main.ts
does not include code to callinitalizeApp()
so you will need to add this yourself:
import { initializeApp } from "firebase-admin/app";
initializeApp()
nx test your-firebase-function-name
nx lint your-firebase-function-name
You can use the parent Firebase app to build, test, lint, watch and deploy all of your functions at once.
nx build your-firebase-app-name
nx test your-firebase-app-name
nx lint your-firebase-app-name
nx watch your-firebase-app-name
nx deploy your-firebase-app-name
Note that there is no serve
target for individual function projects, since serving only makes sense at a firebase app level with the Firebase Emulator suite, so use the following command instead:
nx serve your-firebase-app-name
See Firebase Application Targets for more details.
The Nx-firebase plugin requires that Firebase function projects must always be a dependency of a single Firebase application project:
- This approach allows for multiple firebase projects in a single Nx workspace
- It ensures all functions can be managed by the nx-firebase plugin
- Function application projects are added as
implicitDependencies
to the parent Firebase application, which ensures we can test, lint, build & deploy all functions from the top level Firebase application - All functions share the same Firebase
--config
CLI option as the parent Firebase Application - All functions share the same Firebase
--project
CLI option as the parent Firebase Application - You can create as many Firebase function projects as you like
- Firebase function apps can export either just one or multiple firebase cloud functions
- When running the Firebase emulator using
serve
, all firebase function applications are built usingwatch
mode, so local development is much more convenient
When new Firebase function applications are generated in the workspace:
- They are automatically added to the
functions[]
declaration in the project'sfirebase.json
config file using the firebase CLI'scodebase
feature - The
codebase
name assigned to the function in the config is the function applications project name. - When using firebase
deploy
, the CLI will deploy allcodebase
's declared in the firebase config file
esbuild
is configured in the function's project.json
to only bundle 'internal' source local to the workspace:
- Import paths using TS aliases to
@nx/js
libraries will be resolved as internal imports. - All external imports from
node_modules
will be added to thepackage.json
as dependencies, since there is no good reason to bundlenode_modules
in node applications.
esbuild
is also configured by default to always output bundled code as esm
format modules:
- This ensures tree-shaking is activated in the bundling process
- Firebase functions with Node 16 or higher runtime all support ES modules
- The bundled output code in
dist
is much cleaner to review - We are only specifying that the output bundle is
esm
format. The input source code sent toesbuild
is Typescript code, which effectively uses ES6 module syntax anyway - Therefore, it is not necessary to change your workspace to use
esm
format modules to use this plugin sinceesbuild
builds from Typescript source code, not compiled JS.
If you still use Node require()
in your Typescript function code, the default esm
output setting for esbuild
may not work. Your options are:
- Refactor your code to use
import
instead ofrequire
- Modify the function
project.json
to set esbuildformat
to['cjs']
- Generate your function applications with the
--format=cjs
option
Note that using cjs
output may prevent tree-shaking optimizations.
While Webpack and Rollup are viable options for bundling node applications:
esbuild
is designed for node,- it is very fast
- it optimizes the output using tree-shaking, which is great for fast cold starts
- and it works very simply out of the box with Nx without any need for additional configuration files.
If you want to try Webpack or Rollup, just change your build
target in the function's project.json
accordingly.
The Nx Webpack bundler may be required for projects that require Typescript decorators such as NextJS.
This plugin does not set or recommend the minify option for esbuild.
- It is not really necessary for cloud function node runtime environments
- Obfuscation of the code is not necessary since it executes in a private server-side environment
- There is minimal (if any) performance benefit to be had
- If exceptions occur in the cloud run, stack traces will be readable if code is not minified
Firebase Functions are deployed by the Firebase CLI to specific Nodejs runtime environments.
The required runtime is automatically set by the nx-firebase plugin function generator, but can be manually changedt in the firebase.json
configuration as a definition (eg. nodejs16
, nodejs18
etc.):
"functions": [
{
"codebase": "firebase-project1",
"runtime": "nodejs16",
...
}
],
Runtimes are recommended to be set to the same value for all functions in a project.