Build and Debug Firebase Functions in VSCode

David

Firebase is a powerful platform that helps you get a backend running fast for your web or mobile app.

Firebase Functions are individually containerized node functions that you can hit through HTTP calls, or through the Firebase SDK. There’s a lot of ways to integrate Firebase Functions into your project, but I’ll be demonstrating how to use them from a very basic webpage using the Firebase Javascript SDK. I’ll also show you how to run both Firebase Functions and Firebase Hosting locally so you can set breakpoints from VSCode both in your node functions and in your website.

Prerequisites

To get started with Firebase, you’ll want to create an account on firebase.google.com. Then, create a project from console.firebase.google.com and navigate to that project to see the project’s dashboard.

If you don’t have Node.js installed, download and run the installer from https://nodejs.org/en/download/.

Install the code editor VSCode from https://code.visualstudio.com.

Install Postman from https://www.getpostman.com/downloads/ (we’ll use this to test our functions).

Setup

Open VSCode, and then select File > Open (Open Folder on Windows) from the menu bar. Create the folder where you want your project to exist, and then open that folder.

Now, open a terminal in VSCode (Terminal > New Terminal), and type

node --version

to ensure that node was installed correctly.

We need to install the firebase-tools package in order to initialize our project. Type

npm install -g firebase-tools@latest

and the package will install (you may need to run with sudo or as an Administrator on Windows).

Now, log into Firebase using

firebase login

(this will open a browser window for you to log in), and then initialize your project using

firebase init

You will be prompted with the following in the command line. Use the spacebar and arrow keys to select Database, Functions, and Hosting.

? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your choices. 
◉ Database: Deploy Firebase Realtime Database Rules
◯ Firestore: Deploy rules and create indexes for Firestore
◉ Functions: Configure and deploy Cloud Functions
❯◉ Hosting: Configure and deploy Firebase Hosting sites
◯ Storage: Deploy Cloud Storage security rules

As you receive prompts, you can press Enter when prompted for names of things to use the default name instead.

When prompted “What language would you like to use to write Cloud Functions?”, select TypeScript.

Additionally, when prompted to install dependencies using npm, go ahead and do that (life is short, after all).

Writing a Hello World Function

With your Firebase project initialized, there are two important directories created in your project folder, functions and public.

Directories visible in the Explorer in VSCode

The functions folder holds the Firebase Functions for our project, while the public folder contains the Firebase Hosting project. We’ll start with implementing a hello world function in a Firebase function, and then move to displaying the result of that function on a webpage.

Under functions/src, open the index.ts file. You’ll see that there’s already a helloWorld function available that you can uncomment. Highlight the code from export const helloWorld… and use Edit > Toggle Line Comment to uncomment the code.

Let’s customize the function to use our name to send a customized hello world message by changing the function to the following:

export const helloWorld = functions.https.onRequest((request, response) => {
response.send({
"data": {
"message": `Hello, ${request.body.data.name}!`
}
});
});

The modification to the function will attempt to get the property “name” from the data in the body of the request we send to the function, and then send back a JSON response that includes a message property that holds our hello world message.

Debugging a Function

Being able to set breakpoints to inspect our code and pause it as it runs will be very powerful. Doing this for Firebase Functions in VSCode is a snap.

Move into your functions directory in the terminal

cd functions

and then build your function using

npm run build

Then serve the function using

firebase serve --only functions

You should get a message from the console like this:

=== Serving from '/Users/davidmccoy/Desktop/test'...i  functions: Preparing to emulate functions.
✔ functions: helloWorld: http://localhost:5000/tutorial-4dbde/us-central1/helloWorld

In Postman, set up a new request to the url you were given as in the picture below.

Postman with the request to our helloWorld function

Make sure you select POST as the request type, and select raw and JSON(application/json) for the body type.

The body of the request should be

{
"data": {
"name": "YOUR_NAME"
}
}

To set a breakpoint on this function running live, open the Debugging menu in VSCode and click the settings gear, selecting node.js when prompted, to create a launch.json configuration file for debugging. Use the following configuration in launch.json:

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach",
"port": 6000
}
]
}

To debug, we’ll need to install the Google Cloud Function emulator. Do that with

npm install -g @google-cloud/functions-emulator

Now, open another terminal window using the New Terminal button again (you can switch between terminal windows in with the dropdown for it in VSCode) and use the following command to open a debugger on our function:

functions inspect helloWorld --port 6000

(Depending on your node version, you may need to change “inspect” to “debug”)

Set a breakpoint on the line where response.send is called by clicking in the space next to the line number as seen in the image below (a red dot will appear). Then, click the green arrow in the debug sidebar on the left to attach to the debugger.

Breakpoint shown set on line 7 in the editor window

Back in Postman, click Send again, and this time, the VSCode widow should become active, and you will see that our breakpoint has been hit! You can hover over variables to see their value, and enter values into the Watch window on the left to evaluate variables and expressions, too.

Function execution shown paused on breakpoint, and the mouse is hovered over request.body.data

Using Firebase Functions from a Webpage in Javascript

Now we’re ready to try calling our function from a webpage and displaying the results.

First, head back over the the Firebase console at https://console.firebase.google.com/, navigating back to your project as needed. Then, click settings wheel next to Project Overview and select Project settings. Click the web button near the bottom of the page, and copy just the Javascript code for the config declaration.

Selecting Project settings from the Firebase console
The web button is emphasized in a red square
Copy the highlighted portion

Back in your project directory in VSCode, under the public folder, create a file called test.js and paste that code at the top. Then, copy and paste the code from below to complete this file.

//Replace this comment with your config declaration!!firebase.initializeApp(config);// var functions = firebase.functions(); // Use this to test against the deployed functionsvar functions = functionsDebug(config, 8010); //Use this to test against locally deployed functionsdocument.getElementById('helloWorldBtn').addEventListener('click', function () {
var helloWorld = functions.httpsCallable('helloWorld');
var name = document.getElementById('name').value;
helloWorld({ name: name}).then(function (result) {
// Read result of the Cloud Function.
var sanitizedMessage = result.data.message;
document.getElementById('response').innerHTML = sanitizedMessage;
}).catch(function (error) {
console.log(error);
});
});
function functionsDebug (config, port) {
var url = `http://localhost:${port}/${config.authDomain.split('.')[0]}/us-central1`
var httpsCallable = function (funcName) {
return async (data) => {
var response = await fetch(`${url}/${funcName}`, { body: JSON.stringify({ "data": data }), method: "POST", headers: { "content-type": "application/json; charset=UTF-8" } });
return await response.json();
}
}
return {
httpsCallable: httpsCallable
}
}

Then, replace the contents of the index.html file with the following:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Firebase function test</title>
<!-- Firebase scripts -->
<script defer src="/__/firebase/5.9.1/firebase-app.js"></script>
<script defer src="/__/firebase/init.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.9.1/firebase.js"></script>
</head>
<input id="name">
<button id="helloWorldBtn">Say Hello</button>
<div id="response"></div>
<!-- Test script -->
<script src="test.js"></script>
</html>

In order to hit our functions from the web in a browser, all running locally, we’ll need to enable CORS on our function (read more about cors and it’s loveliness here). In the terminal, while cd’ed into the functions directory, run the following command to install the node cors package:

npm install cors

Add the following line to import cors into index.ts:

const cors = require('cors')({origin:true});

And then modify the helloWorld function in index.ts to look like this:

export const helloWorld = functions.https.onRequest((request, response) => {
cors(request, response, () => {
response.send({
"data": {
"message": `Hello, ${request.body.data.name}!`
}
});
});
});

In our terminal window where we were running the functions, we can kill that process, and then use this command to both build the function and run both the functions and web hosting locally to see the results:

npm run build && firebase serve
Visiting localhost:5000 in the browser will display a textbox where we can send a name to our function and get a response!

Okay, whew, that was a lot to cover! Let’s finish by setting up debugging on the webpagee and talking about what’s happening in test.js.

Debugging a Webpage with Chrome debugger

With our website running locally, we can set breakpoints in VSCode in our Javascript file to see the state of the program as it runs.

Just like we set up debugging before, click the Debug button on the left in VSCode, and then click on settings wheel next to the debugging profile dropdown to open the launch.json file. Add the following configuration:

{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"url": "http://localhost:5000",
"webRoot": "${workspaceFolder}/public"
}

In the debugging profile dropdown menu, select Launch Chrome and then click the green play button.

Like before, we can set a breakpoint by clicking to the left of a line number in test.js. Now, when we click the Say Hello button on the webpage, we’ll hit a breakpoint, and we can inspect the name variable to see that we grabbed the name from the input box correctly.

Webpage Javascript execution shown paused in VSCode

Deploying Firebase Functions and Hosting to the Interwebs

Our long journey is almost complete. We’ve run and tested everything locally, but now we want our (admittedly, very basic) web app to be available to everyone on the internet.

We need to change our calls to Firebase Functions in test.js to point to the cloud functions instead of our local ones. Uncomment the line where functions is declared and comment out the debug one as seen below.

var functions = firebase.functions(); // Use this to test against the deployed functions// var functions = functionsDebug(config, 8010); //Use this to test against locally deployed functions

Now, with the wave of a magic wand, we can publish our site and functions! Recite the following incantation into your terminal window:

firebase deploy

… And that’s it!

You’ll notice that a url is provided to your site in the console window. Visit that url and you’ll see the site you were seeing locally live on the web!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade