If you’ve done anything in web development in the past year, you’ve undoubtedly heard of CircleCI and Firebase.

Using CircleCI to automate the deployment of an Angular Site to Firebase

If you’ve done anything in web development in the past year, you’ve undoubtedly heard of CircleCI and Firebase. Both technologies are becoming increasingly popular as alternatives to Jenkins, AWS, and other older platforms. I’ve had a great experience with both, and am going to walk through how to use them with Angular.

With regards to the walk through portion of this post, I’m going to be using an app that’s available on GitHub here. Feel free to use that and refer to the code there as I walk you through the setup.

The Angular DevOps Series

This is the third post in the Angular DevOps Series. Make sure you take a look at the other posts in the series by Tim Deschryver and Todd Palmer:

Google’s Firebase

Google’s Firebase is a web development platform that enables web hosting, as well as connections to several Google Cloud services. Firebase comes with its own set of tools that you can utilize in your apps. These tools leverage everything from file storage to machine learning. I have a post on my main blog (rhythmandbinary.com) that goes into more detail about what Firebase entails here.

To get started with Firebase, just create a Google account and then go over to Firebase’s site. Once you’ve logged in and enabled Firebase with your Google account, the next step is to create an app.

As a side note, there are several options with regards to account type for Firebase. There is a free account for developers that gives you most of what you’ll need to get started. If you’re interested in using Firebase for an enterprise application, then there is pricing available for larger accounts as well.

Once you’ve created your app, you’ll be shown a dashboard with various options.

As I mentioned, there are a lot of things that you can do just using the Firebase services provided. There are APIs associated with these services that include:

  • Authentication
  • Database Storage
  • File Storage
  • Hosting
  • Machine Learning

In order to correctly use these services in your Angular apps, you’ll need to get setup with the AngularFire library on GitHub. You can see how to get that set up here.

The APIs that come with Firebase are pretty well documented, but there are some discrepancies between Angular versions. With that in mind, make sure you are looking at the right documentation for the version of Angular you’re going to be using.

For the purposes of this post, I’m going to focus on Firebase hosting. I’d recommend checking out more of the services that are available at the links I’ve provided above.


Firebase Hosting

To start, I’d recommend downloading the sample project I mentioned before here.

After doing the initial npm install, you’ll also need to make sure your machine has the Firebase tools installed and that you’re logged in.

So after downloading the sample, open up a terminal at the project’s root directory and run the following:

npm install -g firebase-tools

This will get the tools going on your machine and make it so that you can run the commands after that.

Next, go ahead and login to Firebase from your terminal with:

firebase login

You should now see a message like this:

Now that you’re logged in, you can setup your app.

If you downloaded the sample app, you should do the following steps:

  • In the root directory, make sure to delete the .firebaserc file and the firebase.json files. These two files are what Firebase CLI uses to determine what to upload to the hosting servers, and which of your Firebase apps will be connected to this project.
  • I’m asking you to delete these two files simply so there won’t be any confusion when Firebase CLI runs. If you left them alone, the CLI will think that you have already connected your project to the Firebase App that is listed in the source repo. So when you went to deploy, Firebase CLI would attempt (and fail) to deploy to the App connected to the sample repo instead of the new one that you have created.

Now, go to the terminal at your project’s root directory and run the following:

firebase init

You should now see a screen that looks somewhat similar to this:

From here, the prompts are basically self-explanatory, but here’s a few quick notes:

  • In the first selection, make sure to select hosting
  • Select yes for the SPA app question
  • Select no for the replacing of the index.html file
  • When it asks which directory to use for the build, make sure to use the dist directory since that’s where your app will be built when you run ng build --prod

In the firebase.json file that is generated by Firebase CLI, you should see something like the following:

{
  "hosting": {
    "public": "dist/todo-list",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

This is basically the JSON that instructs Firebase CLI what to upload, and where to redirect the app.

Additionally, the .firebaserc file should look something like the following:

{
  "projects": {
    "todo-list": "todo-list-e14b0"
  }
}

This just tells Firebase CLI which project to connect to the uploaded code that you are sending to Firebase when you deploy.

When you’re all setup, you can go ahead and try the “deploy step” with the following:

firebase deploy

Congratulations! You just deployed your first app in Firebase! If you go to the link that is output from the console, you can view the public facing URL of your hosted app.

Now that you’ve been setup with Firebase, follow the next section which shows how to connect this to CircleCI.

CircleCI

CircleCI is a Continuous Integration Continuous Delivery (CICD) platform that connects directly with GitHub. As a Jenkins user myself, I was really impressed with how easy CircleCI was to understand and use. What’s more, CircleCI can do almost anything including testing, logging, alerts, and automation. In my personal blog, I’ve written several posts discussing CircleCI. Check out my in-depth walkthrough here.

I also have a good walkthrough of an open source project I deployed that uses both CircleCI and Firebase here.

Concerning accounts and pricing, CircleCI is free for developers. As with Firebase, they do have pricing for enterprise teams and larger projects on their main site.

With regards to the sample project that we used in the section above, the first step would be to go ahead and upload this code to your GitHub account. You can also do this with BitBucket as CircleCI supports both. Once you’ve done that, go to the CircleCI site here.

Once at the CircleCI site, select either Log in with GitHub or Log in with Bitbucket and it will use Single Sign on to authenticate you and connect to your repos.

You’ll next be shown a console view which you can navigate to connect your projects to CircleCI for deployment.

As you can see from the screenshot, when you start to run jobs you will see their statuses here. You can click on individual runs and view the console, metrics, etc.

Since we simply want to go ahead and connect your project to CircleCI, then just click ADD PROJECTS.

In this view, you’ll see projects you’ve already got in your GitHub or BitBucket account.

You’ll want to go ahead and select Set Up Project next to your project’s name to connect CircleCI to your specific repo.

In the view that is shown, just make sure to select Start building and then immediately CircleCI will attempt a build (don’t panic, this will fail and that’s okay).

Now you’ve got your account setup, but your build has failed. The reason your build failed was because you haven’t setup your config.yml file and the associated environment variables you’ll need for deployment.

If you’re using the sample project I provided then you’ll already have a config.yml file in the .circleci folder in the project’s root directory. This is where CircleCI looks for the configuration for your build. The yaml is pretty straightforward, and just a matter of creating a workflow with an associated “build” and “deploy” job. My post on CircleCi goes through a pretty extensive walkthrough of a deployment to AWS Cloudfront here. I would recommend reading through that post to understand how to setup this file. For the sample project I’ve provided, it’s already using Firebase so I’m just going to briefly cover how that works here.

First notice in the sample project’s “build” job definition, the last section that says:

- save_cache:
    key: v1-dist-{{ .Environment.CIRCLE_BRANCH }}-{{ .Environment.CIRCLE_SHA1 }}
    paths:
        - dist
        - package.json
        - firebase.json
        - .firebaserc

This last step in the “build” job is caching the dist folder for upload. The official documentation on deploying with Firebase did not include the additional package.json and Firebase files. When I worked through several Firebase deployments, I’ve found these are necessary for the actual deploy stage. You can potentially do a few other things to resolve these files, but just including them here is clean and works.

Next, I wanted to walk through the “deploy” workflow in the sample project. Here are the “deploy” job steps:

deploy:
    docker:
        - image: circleci/node:chakracore-8.11-browsers-legacy
    working_directory: ~/project
    steps:
        - run:
            name: Show current branch
            command: echo ${CIRCLE_BRANCH}
        - restore_cache:
            key: v1-dist-{{ .Environment.CIRCLE_BRANCH }}-{{ .Environment.CIRCLE_SHA1 }}
        - run:
            name: Install Firebase
            command: npm install --save-dev firebase-tools
        - run:
            name: Deploy Master to Firebase
            command: npm run firebase-deploy -- --token=$FIREBASE_TOKEN

This is fairly straightforward, but let’s look at it line by line.

deploy:
    docker:
        - image: circleci/node:chakracore-8.11-browsers-legacy
    working_directory: ~/project

This sets the docker image that will be used for deployment, and the directory that the CircleCI daemon is looking at to be “/project”.

steps:
        - run:
            name: Show current branch
            command: echo ${CIRCLE_BRANCH}

This starts the deployment “steps” and just runs a standard ECHO to show the current branch being deployed.

- restore_cache:
            key: v1-dist-{{ .Environment.CIRCLE_BRANCH }}-{{ .Environment.CIRCLE_SHA1 }}

In the “build” job that was setup, the last stage is to cache the dist folder. The code here “restore_cache” is un-caching the dist folder to use it for deployment. This is typical with CircleCI and allows one job to save files to be used in the next job. There are other options for doing things like this, but this method is what you normally see with CircleCI example projects cited.

- run:
            name: Install Firebase
            command: npm install --save-dev firebase-tools

This installs the Firebase toolset on the node that will be deploying your application.

- run:
            name: Deploy Master to Firebase
            command: npm run firebase-deploy -- --token=$FIREBASE_TOKEN

This uses Firebase CLI to deploy your app. Take special note of the $FIREBASE_TOKEN. That is an environment variable that you’ll need to set. It allows CircleCI to have the right authentication to connect to Firebase and upload your code to its servers. For a walkthrough of how to setup that environment variable, check out CircleCI’s page here.

So once you’ve connected your repo and created your Firebase Token (and set it as an environment variable), then you are ready to get going.

Within the workflow specified in your config.yml file you can determine the behavior of your repo’s branches. Here’ is the workflow in the sample project:

workflows:
    version: 2
    -deploy:
        jobs:
        - build
        - deploy:
            requires:
                - build
            filters:
                branches:
                    only: master

This basically translates to the “build” job will run on any branch. The “deploy” job requires “build” to run first, and only works for the “master” branch. So if you had a different branch (for example “development”) then whenever you pushed to that branch, it would create a “build” but not a “deploy”. Part of the flexibility of CircleCI is that you can cater this to the needs of your project.

Getting back to our central goal in this post, let’s actually deploy it! If you’re following with the sample project, go ahead and make a push to your master branch and then open the CircleCI console. You should first see the “build” job running. If you open it up, you’ll see output similar to the following:

If you expand any of the collectors, you’ll see the console output like the following:

Once the “build” job has completed, you should see a “success” message and an alert that it was successful. The “deploy” job should start next.

After your deploy job completes, in the last stage you should see something like this:

If you expand the last collector, you should see something similar to what you saw in your console on your machine when you ran firebase deploy before.

Congratulations! You just hosted an Angular app with Firebase and created a CICD pipeline with CircleCI.

I hope this post helped you get started. Feel free to leave comments or reach out for more information.