Search Lessons, Code Snippets, and Videos
search by algolia
X
#native_cta# #native_desc# Sponsored by #native_company#

Use TypeScript and WebPack With Firebase Cloud Functions

Episode 38 written by Jeff Delaney
full courses for pro members

Firebase Cloud Functions provide an incredible way to build and deploy microservices and background tasks. But there’s one major annoyance for Angular develpoers… They are written in plain JavaScript. Fortunately, we can fix this problem by modifying our functions environment to run on TypeScript and WebPack - just like most Angular 2/4 apps.

If you have a complex set of cloud functions managing your backend, I highly recommend using TypeScript for debugging and Webpack for modularity. Cloud Functions are already difficult to debug, so this will just make your life easier. Hopefully this will help you avoid deploying broken functions, then sifting through the logs to find the problem. The main benefits of this lesson include:

  • Improved Firebase Cloud Function debugging
  • Reliable strong-typed server-side JS code
  • Modular file structure with Webpack

Starting Cloud Functions from Scratch

I am going to assume you have never used cloud functions before and that you have an existing Angular project (although it doesn’t have to be Angular).

Initialize Functions

firebase init functions
cd functions

This creates a functions directory with a default NodeJS environment.

Updating the Node Environment for TypeScript

We need to reorganize the functions directory to make it modular. In this example, we have a root index.ts file that serves as a manifest of all functions we want deployed. Below that, we have subdirectories for each function type, such as email or image functions.

Replace index.js with src/index.js

Create a new directory /src inside the functions environment. Then create a new index.ts file there.

mkdir src
touch src/index.ts
rm index.js

The index.js that was removed will now be generated automatically with Webpack. This is the file that ultimately gets deployed to Firebase, but you should never need to alter it.

Update package.json

Now we need to install the ts-loader and webpack. We can do this with the following command (you may need to prefix with sudo).

npm install --save-dev ts-loader webpack-node-externals

Our final package.json should look something like this:

{
"name": "functions",
"description": "Cloud Functions for Firebase",
"dependencies": {
"firebase-admin": "~4.2.1",
"firebase-functions": "^0.5.7"
},
"private": true,
"devDependencies": {
"ts-loader": "^2.3.2",
"webpack-node-externals": "^1.6.0"
}
}

Configure TypeScript

First, we need to create a tsconfig.json file to configure TypeScript settings.

tsconfig.json

{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./",
"noImplicitAny": true,
"strictNullChecks": false
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

Configure Webpack

Now we need to tell Webpack how to piece together this code into in a single index.js file that can be deployed to Firebase. This code was taken from this helpful medium article discussing the process.

webpack.config.js

'use strict';

var nodeExternals = require('webpack-node-externals');

module.exports = {
entry: './src/index.ts',
output: {
filename: 'index.js', // <-- Important
libraryTarget: 'this' // <-- Important
},
target: 'node', // <-- Important
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
},
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
externals: [nodeExternals()] // <-- Important
};

Adding functions

The goal is to keep our functions in a logical format. You can create a new directory for each function, or organize them by a common role. In this example we are doing the latter.

Organize Functions by Role

mkdir src/images
touch src/images/index.ts

mkdir src/email
touch src/email/index.ts

At this point our functions directory should look like this:

functions/
node_modules

src/
email/
index.ts
images/
index.ts
index.ts

package.json
tsconfig.json
webpack.config.js

Creating a Couple Functions

Here we are creating three different empty functions. First, we add one to the email index.

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'


export const sendEmail = functions.https
.onRequest( (req, res) => {

console.log(req)
})

Then add a couple more to the images index.

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'


export const updateImage = functions.database
.ref('/images/{imageId}')
.onCreate( event => {

console.log(event)
})


export const resizeImage = functions.database
.ref('/images/{imageId}')
.onCreate( event => {

console.log(event)
})

Import Functions in src/index.ts

Now we need to add our functions to the main index.ts manifest.

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
admin.initializeApp()

/// Organize cloud functions based on logical roles
import * as email from './email'
import * as images from './images'

/// Export functions you want deployed
export const sendEmail = email.sendEmail

export const updateImage = images.updateImage
export const resizeImage = images.resizeImage

Deploying Functions

You can compile the TS code into a single index.js file by running

webpack

Then deploy the functions to Firebase

firebase deploy --only functions

That’s it for TypeScript/Webpack powered Firebase Cloud Functions. Let me know what you think in the comments.