Separate development/production deployment by using Firebase Multisite hosting
20 Sep 2020Developing an production-level service requires whole new bunch of things to ensure production-level quality.
Consumers, or users are hot-tempered. They don’t tolerate errors, bugs, and waitings.
Quality assurance(QA) becomes is much more important compared to personal toy projects.
Separating development/production deployment offers benefits a lot.
You can fearlessly deploy to development environment and test your development, without contaminating production environment. Plus, there are some features that could only be tested after deployment, such as CI/CD configurations and OAuth implementations.
Today, let’s find out how to separate dev/prod deployment by using Firebase hosting.
TL;DR
Use multisite hosting. If you already have a project deployed to Firebase hosting, just make sure to login again right after implementing multisite configurations.
- Add another site in Firebase console.
- Apply sites by using Firebase CLI:
firebase target:apply hosting TARGET_NAME RESOURCE_NAME
- Log out and log in again to acquire new token.
- Deploy to desired environment:
firebase deploy --only hosting:dev
orfirebase deploy --only hosting:prod
Add another site.
Pretend we have a site called blablamusic already on firebase hosting.
Just create another site called blablamusic-dev
or whatever you want, just be sure to include prefix/sufix that indecates develepment environment.
Setting site targets
Assuming that you have an existing firebase project, let’s add tarets.
I guess your local project already been initiated with firebase and has .firebaserc
and firebase.json
.
Run command below:
$ firebase target:apply hosting prod blablamusic
$ firebase target:apply hosting dev blablamusic-dev
The rule is simple:
firebase target:apply hosting TARGET_NAME RESOURCE_NAME
TARGET_NAME is like an alias that distinguishes site.
RESOURCE_NAME is a name of your site (blablamusic
or blablamusic-dev
).
This will add dev/prod targets.
Your firebaserc will look like:
{
"projects": {
"default": "blablamusic"
},
"targets": {
"blablamusic": {
"hosting": {
"prod": [
"blablamusic"
],
"dev": [
"blablamusic-dev"
]
}
}
}
}
Make sure to log out and log in again to acquire brand new token, unless you’ll encounter an error when publishing your site.
$ firebase logout
$ firebase login:ci
The command in the second line will print out firebase token. Be sure to copy it, for you need to store that token in GitHub to use automated deployment by using GitHub Actions.
Deployment From local CLI
Let’s test our first deployment from terminal.
Build your app and deploy.
$ firebase deploy --only hosting:dev
This will deploy your site only to blablamusic-dev
.
GitHub Integration
Using GitHub actions, the whole deployment process could easily be automated.
Token Setup
In order to automate the deployment, Firebase token should be registered as GitHub secrets.
- Go to your GitHub project, settings > secrets.
- Add new secret called
FIREBASE_TOKEN
and paste your firebase token.
Deployment Strategy
- Deploy to development whenever commits has been pushed to origin.
- Deploy to production when pull request has been merged into master branch.
We will use GitHub actions to automate deployment and w9jds/firebase-action
library will be in use.
Before begin, create .github/workflows
directory in the root of your project.
Development Deployment
Create deploy.yml
in .github/workflows
directory.
---
name: Deploy
on:
- push
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run build
- name: Archive Production Artifact
uses: actions/upload-artifact@master
with:
name: build
path: build
deploy:
name: Deploy Development
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Download Artifact
uses: actions/download-artifact@master
with:
name: build
path: build
- name: Deploy to Firebase
uses: w9jds/firebase-action@v1.5.0
with:
args: deploy --only hosting:dev
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
Production Deployment
Create release.yml
in .github/workflows
directory.
---
name: Release
on:
pull_request:
types: [closed]
branches:
- master
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run build
- name: Archive Production Artifact
uses: actions/upload-artifact@master
with:
name: build
path: build
deploy:
if: github.event.pull_request.merged == true
name: Deploy
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Download Artifact
uses: actions/download-artifact@master
with:
name: build
path: build
- name: Deploy to Firebase
uses: w9jds/firebase-action@v1.5.0
with:
args: deploy --only hosting:prod
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
The code below triggers production release(deployment) only when the PR has been merged to branch master:
name: Release
on:
pull_request:
types: [closed]
branches:
- master
# ...
deploy:
if: github.event.pull_request.merged == true