npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nx-cloud-functions-deployer

v3.0.0

Published

Nx plugin to manage firebase functions v2

Downloads

1,081

Readme

nx-cloud-functions-deployer

npm (nx-cloud-functions-deployer)

This is a plugin for Nx that adds support for deploying Cloud Functions for Firebase.

From version 2.0.0 this plugin only supports cloud functions v2, if you want v1 support use version 1.2.2.

Features

  • Auto alias support
  • Support for multiple environments
  • Esbuild for faster builds
  • Detect changes and only deploy changed functions
  • No longer export all functions in a index.ts file, but deploy each function individually for smaller bundles
  • Configurable deploy options
  • Deploy with Node 14/16/18/20 and esm
  • Cloud functions v2 support
  • Deploy rules and indexes
  • Execute scripts locally
  • Read env file and copy to clipboard
  • Cloud cache support
  • Run emulators locally
  • AWS SAM: build, deploy and watch logs for lambda functions

Install

pnpm i -D nx-cloud-functions-deployer

Description

This plugin adds a deploy executor that will build and deploy your cloud functions.

It uses esbuild to bundle your functions and then uses the firebase-tools to deploy them.

Prerequisites

  • You will need to have the firebase-tools installed. Either globally or locally in your project. If you install it globally you have to set packageManager option to global.
pnpm i -D firebase-tools

If you want to use Cloud cache or run scripts you will also need tsx installed.

pnpm i -D tsx

Helper Functions

You need to import the helper functions from nx-cloud-functions-deployer. This will allow you to configure your functions and make the functions stronger typed.

Schedule Example

For schedule functions options.schedule is required.

import { onSchedule } from 'nx-cloud-functions-deployer';

export default onSchedule(
	(context) => {
		console.log('daily', context);
	},
	{
		schedule: 'every day 00:00',
	},
);

Auth Example

Auth triggers have the following functions: onAuthCreate, onAuthDeleted,beforeAuthCreate and beforeAuthDeleted.

import { onAuthCreate } from 'nx-cloud-functions-deployer';

export default onAuthCreate(({ uid }) => {
	console.log('New user created: uid', uid);
});

Database Example

Database triggers have the following functions: onValueCreated, onValueDeleted, onValueUpdated and onValueWritten. You must always add the ref for each database function.

import { onValueCreated } from 'nx-cloud-functions-deployer';

export default onValueCreated(
	({ data }) => {
		console.log('New gmail user created:', data.val());
	},
	{
		ref: '/user/{data.key=*@gmail.com}',
	},
);

Firestore Example

When you use the onWritten, onCreated, onUpdated or onDeleted helper functions for firestore. The data will automatically convert the snapshot to

{
 ...documentSnapshot.data(),
 id: documentSnapshot.id,
}
// shared lib
import type { CoreData } from 'nx-cloud-functions-deployer';
export interface UserData extends CoreData {
	email: string;
}
import { onCall } from 'nx-cloud-functions-deployer';
import type { UserData } from '@my-project/shared';

export default onCreated<UserData>(({ data }) => {
	console.log(`User ${data.email} created`);
});

Https Example

onCall and onRequest can give even better typing with frontend. By importing a interface from a shared file.

// shared lib
export type MyFunctions = {
	my_function_name: [
		{
			message: string; // request data
		},
		{
			response: boolean; // response data
		},
	];
};
import { onCall } from 'nx-cloud-functions-deployer';
import type { MyFunctions } from '@my-project/shared';

export default onCall<MyFunctions, 'my_function_name'>(({ data }) => {
	console.log(data); // { message: string }
	return { response: true };
});

Assets and external dependencies

To include assets and external dependencies you can use the assets and external options.

External will install the dependencies in the function folder and add them to the package.json. This is useful for dependencies that do not work with bundle.

Assets will copy the files from src/assets to the dist folder (right next to index.js)

import { onCall } from 'nx-cloud-functions-deployer';

export default onCall(
	({ data }) => {
		return { response: true };
	},
	{
		assets: ['test.png'],
		external: ['sharp'],
		keepNames: true,
	},
);

Also note that if you use sharp, you need keepNames: true. See documentation

Limitations

You cannot have comments, variables or numeric separators in the options section. If the options section is invalid it will skip the options and deploy as default.

All these lines in the options are not allowed:

import { onCall } from 'nx-cloud-functions-deployer';

const region = 'europe-west1';
const memory = '2GB';

export default onCall(
	(data, context) => {
		return { response: true };
	},
	{
		region,
		timeoutSeconds: 1_800,
		memory: memory,
		// a random comment
	},
);

Folder Structure

See the example for a better understanding of the folder structure.

It is recommend to have the following folder structure, but it is not required.


├── your-nx-project
│   ├──src
│   │  ├── controllers
│   │  │  ├── https
│   │  │  │  ├── callable
│   │  │  │  ├── request
│   │  │  ├── database
│   │  │  ├── firestore
│   │  │  ├── storage
|   |  |  ├── auth
│   │  │  ├── pubsub
│   │  │  │  ├── schedule
│   │  │  │  ├── topic

The folders in controllers will different deployment types:

The default function names will be the path from the api/callable/database/scheduler folder to the file. For example, the function controllers/api/stripe/webhook_endpoint.ts will be deployed as stripe_webhook_endpoint.

Firestore Structure

The firestore structure is a little different. It is recommend the folder structure to match to structure in the firestore. For example, if you have a firestore structure like this:

├── users # collection
│   ├── uid # a user document
│   │  ├── notifications # a sub collection
│   │  │  ├── notificationId # a notification document in the sub collection

Then you would have the following folder structure:

├── firestore
│  ├── users
│  │  ├── [uid]
│  │  │  ├── created.ts # will be called every time a user document is created.
│  │  │  ├── updated.ts # will be called every time a user document is updated.
│  │  │  ├── deleted.ts # will be called every time a user document is deleted.
│  │  │  ├── notifications
│  │  │  │  ├── [notificationId]
│  │  │  │  │  ├── created.ts # will be called every time a notification document is created.

The default function name for database/firestore functions will omit [id]. Example: controllers/database/users/[id]/created.ts will be deployed as users_created.

Custom Structure

To customize the folder structure, change the functionsDirectory in options. If you change the structure you have to specify the document for firestore functions and ref for database functions.

Example:

// controllers/firestore/my-custom-user-created-file.ts
import { onCreated } from 'nx-cloud-functions-deployer';
import type { UserData } from '@my-project/shared';

export default onCreated<UserData>(
	({ data }) => {
		console.log(`User ${data.email} created`);
	},
	{
		functionName: 'custom_function_name',
		document: 'users/{id}',
	},
);

Cloud cache

The plugin will detect changes on the deployed functions locally. But it is also possible to cache the changes for the deployed functions on your own server. To do this create a file in the project directory called functions-cache.ts. The file needs to export two function fetch and update which will be called by the plugin. Note you will also get the environments, so you can use process.env, if you want to hide production secrets for fetching/updating the cache.

import type {
	FunctionsCacheFetch,
	FunctionsCacheUpdate,
} from 'nx-cloud-functions-deployer';

export const fetch: FunctionsCacheFetch = async ({ flavor }) => {
	// fetch the cache from the cloud
};

export const update: FunctionsCacheUpdate = async ({
	flavor,
	newFunctionsCache,
}) => {
	// update the cache in the cloud
};

See the example for how to setup cloud cache with jsonbin

Logger

If you want to see metric for each function (like opentelemetry or sentry) , add a logger.ts file in the src folder (see example). The logger will be build and added for each function.

Executors

deploy

...
 "targets": {
  "deploy": {
   "executor": "nx-cloud-functions-deployer:deploy",
   "options": {
    "flavors": {
     "development": "firebase-project-development-id",
     "production": "firebase-project-production-id"
    }
   }
  },

deploy options

| Option | Description | Default | Alias | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ---------------- | | flavors | A object of the flavors to use, the key is the flavor name and value is the firebase project id. | required | | | flavor | The flavor to use, default will be the first key in the flavors object | | | | production | If true, the flavor will be 'production' if flavor is not defined | false | prod | | development | If true, the flavor will be 'development' if flavor is not defined | false | dev | | outputDirectory | The output directory. | dist/<relative-path-to-project> | outDir | | envFiles | the key is the flavor name and value is path to the env file, default is .env.${flavor} | | | | tsconfig | The tsconfig file to use for the build in the project directory. | tsconfig.json | tsconfig | | region | The default region to deploy the functions, if it is not set in the deploy file. See Cloud Functions Locations. | us-central1 | location | | silent | Whether to suppress all logs. | false | s | | verbose | Whether to run the command with verbose logging. | false | v | | concurrency | The number of functions to deploy in parallel | 5 | c | | envString | Stringify version of the environment. This is useful when you want to deploy using CI/CD. | undefined | ciEnv | | only | Only deploy the given function names separated by comma | undefined | o | | force | Force deploy all functions, even if no files changed | false | f | | packageManager | The package manager to use for deploying with firebase-tools. Either: pnpm, npm, yarn or global. | pnpm | pm | | dryRun | If true, then it will only build the function and not deploy them. | false | d, dry | | functionsDirectory | Relative path from the project root to the functions directory. | src/controllers | inputDirectory | | nodeVersion | The node version to use for the functions. | 20 | node | | minify | Whether to minify the functions | true | |

deploy examples

pnpm nx deploy functions --flavor production
pnpm nx deploy functions --development
pnpm nx deploy functions --development --only my_function,my_other_function --f
# will deploy only the functions my_function and my_other_function
# and deploy them even if no files have changed

script

The plugin also provide support to run scripts locally. The plugin will run any files in the scripts directory. The files needs to export default a function.

import { firestore } from '$configs/firestore';
import type { ScriptFunction } from 'nx-cloud-functions-deployer';

export default (async ({ prompt }) => {
	console.log('prompt', prompt);
	const { uid } = await prompt<{ uid: string }>({
		type: 'input',
		name: 'uid',
		message: 'Enter the uid',
		validate: (value) => {
			if (value.length === 20) {
				return true;
			}

			return 'The uid must be 20 characters long';
		},
	});

	const documentSnap = await firestore.collection('users').doc(uid).get();

	if (!documentSnap.exists) {
		throw new Error('User not found');
	}
	return { id: documentSnap.id, ...documentSnap.data() };
}) satisfies ScriptFunction;

You can also add a script-config.{flavor}.ts file in the project root. In these files you can execute code before before running a script.

To make firebase work locally see example.

...
 "targets": {
  "script": {
   "executor": "nx-cloud-functions-deployer:script",
   "options": {
    "flavors": {
     "development": "firebase-project-development-id",
     "production": "firebase-project-production-id"
    }
   }
  },

script options

| Option | Description | Default | Alias | | ------------- | ------------------------------------------------------------------------------------------------ | --------------- | ---------- | | flavors | A object of the flavors to use, the key is the flavor name and value is the firebase project id. | required | | | flavor | The flavor to use, default will be the first key in the flavors object | | | | production | If true, the flavor will be 'production' if not defined | false | prod | | development | If true, the flavor will be 'development' if not defined | false | dev | | envFiles | the key is the flavor name and value is path to the env file, default is .env.${flavor} | | | | tsconfig | The tsconfig file to use for the script in the project directory. | tsconfig.json | tsconfig | | silent | Whether to suppress all logs. | false | s | | verbose | Whether to run the command with verbose logging. | false | v | | scriptsRoot | Relative path from the project root to the scripts directory. | scripts | | | runPrevious | Rerun the last executed script. | false | p | | script | The name of the script to run. If not set, it will prompt you to select from a list. | undefined | file |

script examples

pnpm nx script functions --production
pnpm nx script functions --flavor development
pnpm nx script functions --development -p
# will run the last executed script in development

delete

The plugin provide support to delete unused function that are not in the project anymore. The plugin will delete any functions that are not in the functions directory.

...
 "targets": {
  "delete-unused": {
   "executor": "nx-cloud-functions-deployer:delete",
   "options": {
    "flavors": {
     "development": "firebase-project-development-id",
     "production": "firebase-project-production-id"
    }
   }
  },

delete options

| Option | Description | Default | Alias | | ------------- | ------------------------------------------------------------------------------------------------ | --------------- | ---------- | | flavors | A object of the flavors to use, the key is the flavor name and value is the firebase project id. | required | | | flavor | The flavor to use, default will be the first key in the flavors object | | | | production | If true, the flavor will be 'production' if not defined | false | prod | | development | If true, the flavor will be 'development' if not defined | false | dev | | envFiles | the key is the flavor name and value is path to the env file, default is .env.${flavor} | | | | tsconfig | The tsconfig file to use for the script in the project directory. | tsconfig.json | tsconfig | | silent | Whether to suppress all logs. | false | s | | verbose | Whether to run the command with verbose logging. | false | v | | deleteAll | Whether to delete all functions even if they are in your project. | false | |

emulate

The plugin provide support to emulate functions locally. The plugin will emulate any functions that are in the functions directory.

...
 "targets": {
  "emulate": {
   "executor": "nx-cloud-functions-deployer:emulate",
   "options": {
    "flavors": {
      "development": "firebase-project-development-id",
      "production": "firebase-project-production-id"
    },
 "only": ["functions"],
 "packageManager": "global",
 "minify": false
   }
  },

emulate options

| Option | Description | Default | Alias | | ---------- | --------------------------------------------------------------------------------------------------------------- | --------------- | ---------- | | flavors | A object of the flavors to use, the key is the flavor name and value is the firebase project id. | required | | | flavor | The flavor to use, default will be the first key in the flavors object | | | | envFiles | the key is the flavor name and value is path to the env file, default is .env.${flavor} | | | | tsconfig | The tsconfig file to use for the script in the project directory. | tsconfig.json | tsconfig | | silent | Whether to suppress all logs. | false | s | | verbose | Whether to run the command with verbose logging. | false | v | | only | Only emulate the given services separated by comma "auth", "functions","firestore","hosting","pubsub","storage" | undefined | o | | minify | Whether to minify the functions | true | |

read-env

This will read your .env file in your selected flavor, copy it to the clipboard and print it in console. This is so you can use envString when you deploy your functions in CI.

...
 "targets": {
  "delete-unused": {
   "executor": "nx-cloud-functions-deployer:read-env",
   "options": {
    "flavors": {
     "development": "firebase-project-development-id",
     "production": "firebase-project-production-id"
    }
   }
  },

read-env options

| Option | Description | Default | Alias | | ---------- | ------------------------------------------------------------------------------------------------ | -------- | ----- | | flavors | A object of the flavors to use, the key is the flavor name and value is the firebase project id. | required | | | flavor | The flavor to use, default will be the first key in the flavors object | | | | envFiles | the key is the flavor name and value is path to the env file, default is .env.${flavor} | | | | silent | Whether to suppress all logs. | false | s | | verbose | Whether to run the command with verbose logging. | false | v |

rules

See the example here.

sam

There is now also support for aws sam to deploy and watch logs. You need the SAM CLI installed to use this feature. See the example here.

...
  "deploy": {
   "executor": "nx-cloud-functions-deployer:sam-deploy",
   "options": {
    "flavors": {
     "development": "example-dev-test"
    },
    "bucket": "test"
   }
  },
  "logs": {
   "executor": "nx-cloud-functions-deployer:sam-logs",
   "options": {
    "flavors": {
     "development": "example-dev-test"
    },
    "name": "ExampleFunction",
    "tail": true
   }
  }