Automatically deploy a Gatsby site to Firebase Hosting
Software Engineer
Note from the publisher: You have managed to find some of our old content and it may be outdated and/or incorrect. Try searching in our docs or on the blog for current information.
Firebase Hosting is a web application hosting platform by Google. Through this service, you can host your web apps on Google’s infrastructure. It enables easy one-step deployment and has other cool features such as fast hosting from CDNs and rollbacks. A good overview of the service is available in the Firebase Hosting Docs.
Gatsby is a framework that enables you to create fast React-based apps and websites. It allows you to build these websites with data fetched from a wide variety of sources, including markdown files, APIs, and even CMSs. It then combines this data with a React-based frontend architecture to build extremely fast interactive websites. Gatsby compiles web apps to optimised static files, which we will deploy to Firebase Hosting. I think it’s amazing and I’m glad to share it with you!
In this post, we will setup a simple Gatsby site, host the code on a GitHub repository, and setup automatic deployment of our web application to Firebase Hosting using CircleCI.
Prerequisites
To go through this tutorial, you will need to install the following:
Note: You’ll also need to have a Google account in order to use Firebase Hosting.
Why Gatsby?
I chose Gatsby simply because it will enable us to focus on the high level details. For example, rather than building pages from scratch, figuring out routing, adding 404 pages, and so on, we will get all these built in to the starter project that we will generate shortly. Gatsby affords us these advantages out of the box, but the concepts of hosting will still apply to any other type of web application that can be compiled to static files including Vue and Angular apps or even a website generated by a static site generator.
Gatsby project setup
First, we need to install Gatsby in our local development environment. We can do this by running:
npm install --global gatsby-cli
After the installation is complete, we will have the gatsby
command available. Now, let’s use the Gatsby CLI to generate a new site:
gatsby new gatsby-site
Next, we need to change directories to the newly created gatsby-site
folder:
cd gatsby-site
And finally, we can explore our generated site by starting the development server:
gatsby develop
Your new site is now accessible on http://localhost:8000
.
If everything ran successfully, you now have a Gatsby site running locally. Go ahead and explore the site.
If you take a look around through the generated files, you’ll find that Gatsby’s folder structure is simple to follow. For example, the code for the homepage can be found in src/pages/index.js
. Also notice that links between different pages work as expected and we also have a 404 page set up. You can test the 404 page by going to a non-existent route.
Gatsby provides these low level details, such as routing, out of the box and gives us a functional web application that we can now deploy to Firebase Hosting.
Pushing to GitHub
At this point, let’s initialise a new Git repository and push the code to GitHub. Go ahead and initialise a new Git repository inside the gatsby-site
folder and create an initial commit with these lines:
git init
git add -all
git commit -m "Generate Gatsby site"
After this, proceed to create a new repository on GitHub and push the code to the repository.
This guide is an excellent resource you can refer to if you’re not familiar with GitHub.
Firebase setup
At this point, we have a functional website that we can now deploy to Firebase Hosting. Before we do this, we need to create a new project on Firebase using these three simple steps:
- Go to https://firebase.google.com and sign in with your Google account.
- Click Go To Console at the right side of the top nav bar or access the console through https://console.firebase.google.com.
- Click Add project (or New project if this is your first).
- Give your project a name in the modal that shows up and click Create project.
Once the project is created, we need to setup Firebase locally in order to link our local repository to the Firebase project. Install the Firebase command line tools by running:
npm install -g firebase-tools
We’ll also need to install the firebase-tools
package locally to our project as a devDependency
. This will come in handy later on when integrating with CircleCI, which does not allow installing packages globally by default. So let’s install it right now:
npm install -D firebase-tools
Afterwards, we need to sign in to Firebase to connect the CLI to the online Firebase account. We can do this by running:
firebase login
Once you are logged in, we can now initialise our project:
firebase init
This action will produce a prompt where we will select Hosting.
Make selections for the rest of the prompts. After the prompts are complete, the Firebase CLI generates two files:
.firebaserc
firebase.json
Note: The firebase.json
file enables configuring custom hosting behavior. To learn more about this, visit the Firebase full-config docs.
In the case that the Firebase CLI does not load your projects, you can add the project ID manually in the generated .firebaserc
file:
{
"projects": {
"default": "gatsby-site-43ac5"
}
}
This is also a good point to commit the new files to our repository and push the code to GitHub.
With this, we have connected our code to our Firebase project and we can now try out a manual deploy from our development environment.
Manual deployment to Firebase
The first step in manual deployment is generating an optimised production build. In our case, gatsby
has us covered since it includes this by default. To generate it, run the command:
gatsby build
This generates an optimised static site in the public
directory. This is the directory we will be deploying to Firebase Hosting. To manually deploy the public
directory to Firebase Hosting, it only takes one command:
firebase deploy
If everything works as expected, Firebase will deploy our site and give us a link to the deployed site’s URL.
You’ll also notice a new .firebase
folder created by Firebase to store it’s cache. Since we don’t want this folder in our repository, we can add the folder name to the .gitignore
file so it is ignored by Git.
In the next step, we are going to automate the deployment with CircleCI so that we can deploy new changes pushed to the repository immediately.
CircleCI configuration
To build our project with CircleCI, we’ll need to add a configuration file that instructs CircleCI to build our web application and automatically deploy it to Firebase each time we make changes to our code.
In our project’s root folder, create a folder named .circleci
and inside it, create a config.yml
file. CircleCI requires that the config file be located here.
Here’s the config file we’ll use for our project:
# CircleCI Firebase Deployment Config
version: 2
jobs:
build:
docker:
- image: circleci/node:10
working_directory: ~/gatsby-site
steps:
- checkout
- restore_cache:
keys:
# Find a cache corresponding to this specific package-lock.json
- v1-npm-deps-{{ checksum "package-lock.json" }}
# Fallback cache to be used
- v1-npm-deps-
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: v1-npm-deps-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Gatsby Build
command: npm run build
- run:
name: Firebase Deploy
command: ./node_modules/.bin/firebase deploy --token "$FIREBASE_TOKEN"
Let’s do a quick review of the config file.
- First, the
version
key enables us to specify that we are using CircleCI 2.0. - Next up, we specify the base Docker image where our code will be run. In this case is a container based on
Node 10
, which is the current version at the time of writing this. You can use a later version if one is available. - The
working_directory
option specifies the location where our code will be cloned. - Next is the
restore_cache
section, which instructs CircleCI to restore any previously installed dependencies. Here we’re using a checksum of thepackage-lock.json
file to detect whether to install the dependencies afresh or to use the cache to restore previously downloaded packages. - The next step is installing the dependencies through the
npm install
command. - The
save_cache
section instructs CircleCI to save the dependencies after installing them. - We then run the
Gatsby Build
command. This builds the optimized production version of the site, which is ready to be deployed. - Finally, we run the
Firebase Deploy
command that deploys our code to Firebase Hosting. In this step, you’ll notice that we need a Firebase token to allow deploying the app to our account. The command specifies that the token should be obtained from theFIREBASE_TOKEN
environment variable. We’ll get this token in a moment.
Additionally, note the change in how we are running the firebase
command from our locally installed dependencies rather than as a global command. As mentioned earlier, installing packages globally with CircleCI can be an issue, so we install all the packages we need locally in our project.
Integrating CircleCI and GitHub
We now have a config file and we can go ahead and integrate CircleCI with our GitHub repository that we created earlier.
- Create an account on CircleCI, if you haven’t already.
- Once you are logged in, ensure your account is selected on the top left corner.
- Click Add Projects on the left sidebar.
- On the next page, search for the name of your GitHub repository then click
Set Up Project
next to it. - On the next page, there’s a list of steps that are needed to build our project, the most important one being adding the CircleCI config file. Since we already have this file in our repo, let’s scroll all the way to the bottom and click
Start Building
.
Our build will finally start running, but it predictably fails in the Firebase deployment step. 😢
Fortunately, I know why the deploy fails. It’s because we’ve not yet added the Firebase deploy token to CircleCI. Let’s work on fixing this in the next section.
Getting a Firebase login token to use for deployments
In the final step, we will need to generate a Firebase token that we’ll use to allow access to our account. This token will enable CircleCI to deploy to Firebase on our behalf, since we cannot login using Firebase’s interactive prompt in a CI environment.
In our local development environment, let’s run this command to generate the token:
firebase login:ci
This will open up a browser window where you’ll be prompted to login to your Firebase account. Once you’re signed in, a token will be generated. You should get a result similar to the following after authenticating via the web browser.
Now that we have our token, all that’s left is to add the token as an environment variable in CircleCI so that we can use it in our project. Our deployment command expects to find the value in the FIREBASE_TOKEN
environment variable.
Adding the Firebase Token to CircleCI
These are the steps we’ll need to take to add the token:
- Go to your project’s settings by clicking the gear icon next to your project.
- Under the Build Settings section, click Environment Variables.
- Click Add Variable.
- In the modal that appears, enter FIREBASE_TOKEN in the
name
field, add the token we got from Firebase in thevalue
field, then finally click Add Variable to finalize adding the variable. - With this step complete, we can now rerun our build by clicking Rerun Workflow on the right of the CircleCI project page.
We now have completed a successful deployment of our web application to Firebase Hosting using CircleCI! 🎉
Conclusion
This concludes our exploration of deploying web applications to Firebase using CircleCI. From now on, when we make updates to our Gatsby site and push the changes to GitHub, they will automatically be deployed to Firebase Hosting. It really is a great combination.
This approach will work for any other frontend projects and is not specific to Gatsby. Firebase provides the hosting for the web applications and CircleCI helps in automating and simplifying the process. Go forth and deploy! 🚀
For more information on these technologies, see the following resources: