Be a lazy developer: Firebase and Vue.js using TypeScript and beautiful hot-reloading everywhere

Marco Pöhler
Firebase Developers
8 min readJul 31, 2018
Picture composed by Marco Pöhler, sources: “Life is Beautiful” by Linnaea Mallette, CC0

You will see how to set up a Firebase project which uses hosting and cloud functions written in Typescript. We add a VueJS project that will build our website and is hosted with Firebase hosting. After we set up these two parts, we are going to adjust some scripts to create a smooth development cycle with hot-reloading everywhere.

Create Firebase Project

Requirements: you need to install the Firebase CLI

First, go to the Firebase console and create a new project.

(Sorry my interface is in German.)

It is important to remember the Project-ID!

Now we have a Firebase project that can be used, let’s create the project locally. Create a folder which will be our project folder and then run firebase login. If you use the CLI for the first time you are required to log in. After logging in, run firebase init to initialize our project.

Create project folder, log in and initialize the project

Since I want to use all Firebase features I simply select all of them …

To select the project you created earlier in the Firebase console, look for the project ID. You can accept all default values except the language for Cloud Functions, as we want to use Typescript. The hosting option for single page apps should also be set — we want to get all traffic to index.html, because the app we’ll build later with Vue.js will be a Single Page App (SPA).

In our project folder we now have a fully initialized Firebase project. The important parts are:

  • the functions directory — functions/src/index.ts is the entry point for Cloud Functions.
  • the public directory — it contains the static hosting files. This is the place where we will later place our Vue.js App!
Structure of our Firebase project

Run the Firebase project locally

Let’s see if Cloud Functions and hosting are working locally. First we need to uncomment some code inside /functions/src/index.ts to have a Cloud Function to test.

Make your index.ts look like this:

Now we have a function in the TypeScript source file in our source folder. The development server cannot use it directly because the it needs JavaScript files in the lib directory. To create these JavaScript-Files, we need to compile the TypeScript sources using tsc (TypeScript compiler). The Firebase CLI already created the necessary scripts in package.json (in the functions directory). To get the Cloud Function to work we need to run the following commands:

  • npm install in the functions folder
  • npm run build in the functions folder (this uses tsc and compiles the TypeScript sources from index.ts into JavaScript in the lib directory)
  • firebase serve to start the development server

After you run these commands, you can call the Cloud Function in a browser and see the “Hello from Firebase!” text in your browser.

Hosting also works as expected, just call the hosting server on http://localhost:5000

Add hot reloading of Cloud Functions

Currently, when you update the source code in the cloud function, the change is not reflected in the development server, because you only change the TypeScript source code and the development server only listens to changes to the compiled JavaScript files. To simplify development we want to make sure any changes made to the TypeScript source files are reflected immediately.

Beside the running development server(command: firebase serve) we need a script that watches the source folder and compiles the TypeScript sources into JavaScript in the lib directory on demand.

The development itself supports hot-reloading out of the box, but registers the functions during startup. So you need to restart the development server whenever you add a new function. You don’t need a development server restart for changes in existing functions!

To have a central script we’ll add a package.json in the main directory — we already have one in the functions directory, but that one is only for our functions. To create a fresh package.json, just runnpm init in the root folder.

create a fresh empty package.json

You can add more details about your project here or just go with the defaults as I did.

Now let’s create one command that runs the development server and compiles our TypeScript sources on demand.

To be precise: We want to run the TypeScript compiler once before anything else happens to generate the JavaScript files needed by the development server at startup. Then we want the development server to be started and parallel a TypeScript compiler in watch mode.

Let’s install the necessary dependencies first. Beside TypeScript, we need the concurrently package which enables us to execute things in parallel. To install these packages run:

npm install typescript concurrently --save-dev

Add the following to the script section of the package.json in the root directory:

...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"serve": "tsc --project ./functions && concurrently --kill-others 'firebase serve' 'tsc --project ./functions --watch'"
},
...

If you now execute npm run serve in the root folder, the TypeScript compiler compiles the sources in the functions/src folder into the functions/lib folder once. If that succeeds (&&), concurrently starts the development server (firebase serve) and the TypeScript compiler again, but this time in watch mode. The kill-others option in concurrently is needed to kill all processes if one of them dies, everything else would cause unexpected behaviour.

Let’s run npm run serve in the root folder and check that everything works as expected…

As you can see, no restart is required. We can update the Cloud Function and the new function is executed immediately. That’s the way we want to work!

Let’s switch gears now and add a Vue.js Project!

Add a Vue.js project

Vue.js provides the Vue CLI, which is the preferred way to generate a new Vue.js project. It includes many best practices. In this section we will use the CLI to create a Vue.js project in a subfolder and modify our serve script to create a build of the vue project in our Firebase public folder, which is served locally by the Firebase development server. It also enabling hot reloading for the vue part!

Requirements: you need to install the Vue-CLI

npm install -g @vue/cli

Let’s first create a Vue.js project in a subfolder called frontend. The CLI already provides TypeScript based presets, but I prefer to select all features manually, because I like SASS over stylus and want my app to be a Progressive Webapp (PWA).

vue create frontend
Configure VueJS Project with Vue-CLI

After some time you should see something like this:

Let’s try to serve the vue project locally using the Vue-CLI.

cd frontend
npm run serve

That should end up like this:

When you visit http://localhost:8080 you will see this page:

VueJS Default project page

Our Vue.js project works, but is completely served by the Vue CLI and not using our Firebase development server. Let’s change that!

Change your serve script in package.json in the root folder like the following:

"serve": "tsc --project ./functions && rm -rf ./public/* && concurrently --kill-others 'firebase serve' 'tsc —-project ./functions --watch' 'cd frontend && ./node_modules/.bin/vue-cli-service build --no-clean --dest ../public --watch'"

What happens in the new bold parts here? We want to have a clean start at least when we restart our script. For that reason we clean the public folder completely during startup (rm -rf ./public/*). We add a call to the Vue CLI to the list of commands that all executed by concurrently to build the vue project. We tell the Vue CLI to place the files in the public directory and running in watch mode. That will execute a build when one of the vue projects source files is changed. The no-clean option prevents a clean up of the public folder by the Vue CLI, which would normally delete the folder before every build.

Now run our serve script and see how it works.

Hot-Reload for vueJS

That works great so far but we can still improve it a little bit more. Currently we need to wait until the build is done to hit the reload button. We can use Browersync to watch for changes in our public directory and trigger a page reload if something has changed.

First we need to add the Browsersync dependency…

npm install browser-sync --save-dev

And then add an additional entry to the list of concurrently commands in our serve script:

"serve": "tsc --project ./functions && rm -rf ./public/* && concurrently --kill-others 'firebase serve' 'tsc --project ./functions --watch' 'cd frontend && ./node_modules/.bin/vue-cli-service build --no-clean --dest ../public --watch' 'sleep 15 && browser-sync start --proxy \"localhost:5000\" --files \"public/*\"'"

What happens in the new bold parts? First we wait on startup a little bit until the Vue project build is done, then we startup Browsersync in proxy mode, which means that browsersync operates on top of our development server.

Let’s see this in action:

running devserver with Browsersync

BrowserSync opens the browser for you and reloads it whenever you make any change to the vue project sources, as well as any changes in the SASS sources. Please note that the browser opened by Browsersync points to http://localhost:3000, our development server is running on http://localhost:5000 and our Cloud Functions are available on http://localhost:5001.

Summary

In this article, I showed you how to integrate a Vue.js project into a Firebase project using TypeScript and hot reloading everywhere. I hope you like this solution! If you have any comments or run into issues, feel free to leave feedback in the comments!

--

--

Marco Pöhler
Firebase Developers

Web-Developer from Hamburg, Germany. Father, DevFest-Organizer, GDG-Lead, Running https://www.kontaktlinsen-preisvergleich.de as one-man-show