Firebase Hosting Deployment Automation with Gitlab CI
Our current web era has decoupled the front-end (Single Page Application) and back-end (APIs) which enables you to scale independently.
Firebase Hosting is a production-grade hosting for simple static websites or single page applications like Angular, Ember, Backbone, and React. Key features of Firebase Hosting include:
- CDN-backed global content delivery
- Automatic and Free SSL certificate provisioning
- Custom (and even naked) domain support
- One-command deploy; One-click rollback
- Support for non-SNI devices, to ensure all users have a secure experience
Gitlab provides you free unlimited private repositories along with continuous integration (CI). Though you can deploy your content just in seconds with the Firebase command line interface, you can still sit back and relax with automating the deployment with CI tools like Gitlab.
Prerequisite Steps
- Install Firebase CLI tools using npm
npm i -g firebase-tools
or if you’re using yarn thenyarn global add firebase-tools
- Initialise your project with
$ firebase init
and configure your deployment directory. In case of simple websites, maintain your code in “public” directory. In case of single page applications like React, “build” directory will be your production ready target directory. Hence configure your firebase to use “build” directory instead of “public”. You can do this while initialising with$ firebase init
or manually editfirebase.json
as below:
{
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
- Make sure you can deploy using the command
$ firebase deploy
from your local machine and verify the website with the url provided in terminal
Automation Steps
Assuming you have a repository in Gitlab, you can configure your CI just with “.gitlab-ci.yml” file committed in your repository. The firebase hosting deployment can be automated as per the steps below:
- Get the Firebase Token (used to login by CI on behalf of you)
- Set the Token in Gitlab CI
- Configure CI in YML (copy pasting snippet)
Step 1: Get the Firebase Token
Firebase CLI tools helps you control your firebase account and you can generate an access token for use in non-interactive environments with the below command
$ firebase login:ci
A browser page opens and you will be prompted to login with your google account. Once you grant the access, a token will be generated. Use this token to login on a CI server
Step 2: Set the Token in Gitlab CI
Login to your Gitlab account and navigate to your repository settings and then “CI/CD” in sidebar. Expand “Secret Variables” section and add the below:
Key : FIREBASE_TOKEN
Value : 1/VXX-XXX-Your-Copied-Firebase-Token-XXX-XXE
These variables will be passed as environment variables to your pipeline in Gitlab Runner
Step 3: Configure CI in YML
Just create a file named .gitlab-ci.yml
with the below contents and commit it into your repository. Have a look at the .gitlab-ci.yml in gist.
image: rambabusaravanan/firebase
stages:
- deploy
cache:
paths:
- node_modules/
key: "$CI_BUILD_REPO"
deploy-prod:
stage: deploy
only:
- master
script:
- yarn
- yarn run build
- firebase use <project-name> --token $FIREBASE_TOKEN
- firebase deploy --only hosting -m "Pipe $CI_PIPELINE_ID Build $CI_BUILD_ID" --token $FIREBASE_TOKEN
Replace the <project-name>
with your Firebase project name and customise the deploy message if needed.
If your front-end is just a simple website (not a npm project), then below code suits best.
image: rambabusaravanan/firebase
stages:
- deploy
deploy-prod:
stage: deploy
only:
- master
script:
- firebase use <project-name> --token $FIREBASE_TOKEN
- firebase deploy --only hosting -m "Pipe $CI_PIPELINE_ID Build $CI_BUILD_ID" --token $FIREBASE_TOKEN
You’re done. Once you push this yml, you can see the magic running in “Pipelines” section of your repository in Gitlab
Explanation
Any CI job runs in container (base image) where the required software tools were installed, source code were cloned, built and then deployed. Let’s break down the .gitlab-ci.yml file for better explanation.
- Base Image: I have used an image rambabusaravanan/firebase, a light weight alphine based docker container that contains the required “firebase-tools” pre-installed in it, to save tools installation time
image: rambabusaravanan/firebase
2. Pipelines, Stages, Jobs: For a complex pipeline having multiple jobs, you can group jobs into different stages like build, test, deploy. Jobs of the same stage are executed in parallel. Our case is simpler pipeline having only one job named deploy-prod
grouped in stage named deploy
stages:
- deploy
deploy-prod:
stage: deploy
...
...
3. Job Policy: A job can be started via various triggers like every git push or based on success/failure of previous job or manually. For our case, we need to deploy on every push on ‘master’ branch.
only:
- master
4. Script: It’s the actual magic area where build and deployment happens. You can build a npm project by yarn run build
. For some projects this might vary if the build command is not configured as npm scripts in package.json.
The value for $FIREBASE_TOKEN
is passed as environment variable which is configured as CI/CD Secret Variables. Other variables like $CI_PIPELINE_ID
and $CI_BUILD_ID
are set by Gitlab CI Runners.
script:
- yarn
- yarn run build
- firebase use <project-name> --token $FIREBASE_TOKEN
- firebase deploy --only hosting -m "Pipe $CI_PIPELINE_ID Build $CI_BUILD_ID" --token $FIREBASE_TOKEN
5. Cache Policy: We’ve skipped the installation time of “firebase-tools” by using special container image. But this is not enough. Everytime we run the job, fresh installation of “node_modules” happens. To avoid this we can set the policy to cache the node_modules folder for across this repository. so that upon next run installation time of existing modules skipped, only new modules take time.
cache:
paths:
- node_modules/
key: "$CI_BUILD_REPO"
Reference:
You can find the complete .gitlab-ci.yml
file and with a readme at https://gist.github.com/rambabusaravanan/4907ea46d814bc69002c6f011ae6dd48