Use TypeScript with Google CloudFunction and Deploy locally

2022/10/015 min read
bookmark this
Responsive image

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setup npm Repo
  4. Install Dependencies Packages
  5. Install Dev Dependencies Packages
  6. Update Main Field at package.json
  7. Start Writing Code index.ts
  8. Create tsconfig.json
  9. Ready to Deploy Code
  10. Deploy from Local
  11. TypeScript Deployment with Cloud Function and Firestore
  12. Other Choices
  13. Conclusion

Introduction

This blog tries to demonstrate how to deploy a Google Cloud Function that will interact with Firestore NoSQL database, using TypeScript for static typing at development. Instead of using a CI/CD pipeline, we will use husky locally to guard and watch the quality of the code and deploy to Google Cloud locally.

Prerequisites

Before we start writing the code, there are a few prerequisites not included in this blog but required for the application to run.

  • GCP Account/Project - make sure you have an active GCP account and GCP project set up.
  • Firebase Account/Project - Your Firebase should connect with GCP. Log on to Firebase and find the Firestore.
  • Run gcloud config list - to make sure your local environment is connected to the correct project.

Setup npm Repo

Now, let's get started. First we'll need to initialize the npm repo by running the following command on your local machine. This will create a package.json file with default settings.

npm init -y

Install Dependencies Packages

We'll install the following dependency packages since we'll interact with Firebase.

npm install --save firebase-admin firebase-functions

Install Dev Dependencies Packages

Install the following packages during build time, such as TypeScript for static typing and ESLint for syntax analysis.

npm install --save-dev typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-google eslint-plugin-import firebase-functions-test

Update main Field at package.json

Update the package.json for the start file.

"main": "dist/index.js",

Start Writing Code index.ts

Let's create a file index.ts under the root folder and add the following code. These imports bring in packages we'll use later. The firebase-functions/v2 will use Google Cloud Functions gen2, which has better performance.

import * as functions from "firebase-functions/v2";
import {initializeApp} from "firebase-admin/app";
import {getFirestore} from "firebase-admin/firestore";

Next, we'll initialize the app and start using Firestore, so add the following code.

initializeApp();

const db = getFirestore();

Finally, we'll hook into Firebase's functions to listen to the request. Now inside the onRequest we will add our main logic, which can either get data from Firestore or perform update or delete operations.

exports.main = functions
    .https.onRequest(async (request, response) => {

      console.info('on request');

    });

Create tsconfig.json

Since our first code is ready, let's create our tsconfig.json to compile the TypeScript into JavaScript. We'll also add the following command to the package.json's scripts section.

Once you run npm run build, the code will start to compile index.ts and create a JavaScript file under dist/index.js.

"scripts": {
    "build": "tsc"
}

Ready to Deploy Code

So that's all we need for now. We should be able to continue adding code to the TypeScript file index.ts and use the simple TypeScript build by running npm run build to compile the TypeScript into JavaScript, ready to deploy to production.

Deploy from Local

In this blog, we don't have many developers working on the same repo. When many people work on the same repository, it's better to use CI/CD with git pull requests so that whenever someone creates a new pull request to the main branch, continuous integration can start and deploy the latest code to the correct environment.

So instead, we'll add the following gcloud command to the scripts section. When you are ready to deploy to Google Cloud, we can just run npm run deploy, which will set the gcloud project and deploy the Cloud Function.

"scripts": {
    "deploy": "npm run deploy:project && npm run deploy:run",
    "deploy:project": "gcloud config set project set-to-the-correct-project-id",
    "deploy:run": "gcloud functions deploy your-cloud-function-name --trigger-http --region=us-central1 --runtime=nodejs16 --gen2 --allow-unauthenticated --entry-point=main --run-service-account=service-account-can-run-the-cloud-function"
}

TypeScript Deployment with Cloud Function and Firestore

That's all for creating a TypeScript Cloud Function that interacts with Firestore and deploying locally.

Other Choices

Since we use Firestore, which is part of Firebase, we could use Firebase's firebase-tools to generate a list of files to support TypeScript. When using firebase-tools to set up the Cloud Function, there are a few settings you'll have to follow with Firebase's configuration.

set node.js version

"engines": {
    "node": "16"
}

set region

functions.setGlobalOptions({
  region: 'us-west1-a'
});

set gen2

import * as functions from "firebase-functions/v2";

set function name

Now, following is how you set the function name. One thing I don't like is that exports.main limits the name that can be defined. Using gcloud to define the function name, entry point, or gen2 is much easier than Firebase's settings.

exports.main = functions

Conclusion

Using Firebase's firebase-tools can simplify setting up TypeScript for Firebase Cloud Functions. After trying both approaches, using gcloud has maximum flexibility compared with firebase-tools. It could improve, but at this point I feel just using TypeScript directly with gcloud is much easier.