loading...
Cover image for Angular + Firebase Hosting + Gitlab CI/CD (Staging + Production)

Angular + Firebase Hosting + Gitlab CI/CD (Staging + Production)

seankerwin profile image Sean Kerwin ・5 min read

So in the short guide, I'm going to show you how I deploy an angular site to Google's firebase hosting using Gitlabs CI/CD Pipelines to do all the build and deploy for me.

I'm also going to be doing a staging / production builds, this way I can see things in staging and test/play and when i'm happy, push my changes to the repo's main/master branch and Gitlab will deploy it all to production.

Ok, so first thing, we need the Firebase CLI installed, using the following command in your terminal:

npm install -g firebase-tools
Enter fullscreen mode Exit fullscreen mode

Once that is all done, head over to the Firebase Console and create 2 new projects:

For this demo, I created 2

fir-hosting-demo-staging
and
fir-hosting-demo-prod

You need to have 2 seperate projects if you want to deploy to staging and then production, if you don't, just create the one project.

Once they're created, head back over to your Angular application, we've got a bit of preparation to do.

Navigate to your angular application using a terminal and run the following command:

firebase init

Highlight the hosting option and then the Use an existing project option.

Select your Staging project from the list that you get by using the arrow keys.

You'll then be asked the question

What do you want to use as your public directory?
Enter fullscreen mode Exit fullscreen mode

This is the path that is set in the angular.json for outputPath, it's the path that everything goes to when you run ng build.

For me, it is dist/firebase-hosting-demo as that is the name of my Angular application. So set it to that.

You'll then be asked about redirects and as its an angular application, you'll want to select yes to redirect everything to index.html.

Once you have ran this command, open up the newly created file called .firebaserc and it should look something like this:

{
  "projects": {
    "default": "fir-hosting-demo-staging"
  }
}
Enter fullscreen mode Exit fullscreen mode

I like to rename my project alias, so go ahead and change default to staging

{
  "projects": {
    "staging": "fir-hosting-demo-staging"
  }
}
Enter fullscreen mode Exit fullscreen mode

We're now going to add our production hosting, run the following command in the terminal.

firebase use --add

You'll then be given a list of your current firebase projects, select the production one you created.

You then have to give it an alias, I like to call mine production.

If you head over to the .firebaserc file, it should now look like this:

{
  "projects": {
    "staging": "fir-hosting-demo-staging",
    "production": "fir-hosting-demo-prod"
  }
}
Enter fullscreen mode Exit fullscreen mode

You can now in the terminal of that project, just run

firebase use staging and it will switch to use the staging project, same for firebase use production.

Now, if everything has been setup right, you can go ahead and do a test build/deploy.

In your terminal, make sure you're using staging by running
firebase use staging

Build your Angular application using the command
ng build

Once that has built, you should have a dist folder with your application inside, for me it's dist/firebase-hosting-demo.

Go ahead and run the command firebase deploy --only hosting and watch as Firebase will now take all the built files from the output folder and upload them to firebase staging branch.

Once that has completed, the firebase cli will return a Hosting URL where you can see you staging application.

You can do the same for the production branch buy running the command to switch to production firebase use production and then the same firebase deploy --only hosting and the same files will be pushed to the production project in firebase.

This is good for testing, but it will become a bit tedious to remember which branch you're on, which project you're using and remembering that you need to build/push your code.

This is where we're going to leverage Gitlab and let it do all of the work for you.

Other CI/CD tools can do the same, I just mainly use Gitlab.

So now this is all setup, let's move onto the next step!

Gitlab

If you have your code all stored in Gitlab, the way I like to work is have 3 branches, master, staging, and develop.

Both master and staging are protected branches and cannot be pushed to locally, only via a merge request using Gitlab.

So, for me, I'm going to switch to the develop branch of my code.

git checkout -b develop

We're going to need a CI Token, this is a firebase token that Gitlab can use to act on our behalf. To get one of these, in your terminal, run the command

firebase login:ci
Enter fullscreen mode Exit fullscreen mode

A popup will appear in your browser to login and ask for permissions, once you have done that, back in your terminal, you'll be given a CI Token that looks a bit like this.

1//03s000000000000000000000F-L9I00000000000000W-_000000Tg
Enter fullscreen mode Exit fullscreen mode

I have purposely changed mine for this demo, yours won't have lots of zeros inside it.

Head over to gitlab as we now need to store this token in the project.

In your repo in gitlab, click the Settings > CI/CD and expand the section for Variables.

Click the Add Variable button and a window like this will appear.

Gitlab Variables

Call the variable FIREBASE_TOKEN, and paste in the value you got from the ci:login before. I don't have the variable protected or masked, I have found that sometimes Gitlab has issues when I check these options.

Save the variable and we're done with this part of the setup.

Back into our code, create a new file at the ROOT level of your project called .gitlab-ci.yml. This is a file that gives Gitlab the instructions needed to build your project.

Paste in the following into that file:

stages:
    - build
    - deploy

image: node:12.13.0-alpine

cache:
    paths:
        - node_modules/

build-staging:
    stage: build
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    script:
        # Install dependencies
        - npm install
        # Build App
        - npm run build
    artifacts:
        paths:
            # Build folder
            - dist/firebase-hosting-demo
        expire_in: 1 hour

deploy-staging:
    stage: deploy
    script:
        - npm install -g firebase-tools
        - firebase use --token $FIREBASE_TOKEN staging
        - firebase deploy --only hosting -m "Pipeline $CI_PIPELINE_ID, build $CI_BUILD_ID" --non-interactive --token $FIREBASE_TOKEN
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"

build-production:
    stage: build
    rules:
        - if: $CI_COMMIT_BRANCH == "master"
    script:
        # Install dependencies
        - npm install
        # Build App
        - npm run build
    artifacts:
        paths:
            # Build folder
            - dist/firebase-hosting-demo
        expire_in: 1 hour

deploy-production:
    stage: deploy
    script:
        - npm install -g firebase-tools
        - firebase use --token $FIREBASE_TOKEN production
        - firebase deploy --only hosting -m "Pipeline $CI_PIPELINE_ID, build $CI_BUILD_ID" --non-interactive --token $FIREBASE_TOKEN
    rules:
        - if: $CI_COMMIT_BRANCH == "master"

Enter fullscreen mode Exit fullscreen mode

I'm not going to go over in depth what this file does, but essentially, it will build and deploy your Angular application for you, but use different Firebase projects depending on what Git branch you use.

So the idea is, make some code changes on your develop branch. Once you're happy, commit and push your code to the remote develop branch.

Do a merge request when you're ready from develop to staging and watch as Gitlab will start a pipeline to build your Angular app and deploy it to Firebase.

When you're happy to go live, do another merge request from staging to master in Gitlab and it will build again and deploy to production.

The first time this runs it might take some time, this is because in my gitlab-ci.yml file, I have specified to cache the node_modules, but once this has done, pipelines that run after this should be faster!

Hope you enjoyed my guide, and any questions, don't hesitate to contact me!.

Discussion

pic
Editor guide