Here is how to host a JavaScript monorepo with multiple environments on Firebase.
Let's say you have a root project with packages that needs to be built and hosted. In our example, we have 3 React apps managed by the lerna build system. We have a front app, an admin app, and a design system app.
We need, at least, a staging and a production environment. We will use different Firebase projects for each environment, and within the projects different Firebase targets (i.e. apps or sites or subprojects) for each app of our monorepo.
So for each environment, we need to create a project with these steps :
Create a Firebase project, then initialize firebase using the
firebase init
command.Deploy an empty file (such as a simple
index.html
) using thefirebase deploy
command. This step is important because it allows you to access targets (i.e. apps or sites or subprojects) in your Firebase project.Create the Firebase apps (i.e. targets or sites or subprojects) for each app of our monorepos. You can do this by clicking "Add a site" in the Hosting Product on Firebase, or via the firebase cli (not recommanded because it rewrite your
.firebaserc
file).
Now you have to modify the firebase.json
file and the .firebaserc
on your main repo, to configure for multiple targets on multiple projects.
Modify the
firebase.json
file to add the different targets for each app contained in the monorepo.Deploy the apps using the
firebase deploy -P <project_name>
commands for each environment. So if our projects areprod
andstaging
you deploy withfirebase deploy -P staging
andfirebase deploy -p prod
.
Here is my firebase.json
file. In this one, you specify the targets (subprojects) with how they are hosted (with the build
folder)
{
"hosting": [{
"target": "app1",
"public": "packages/app1/build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
{
"target": "app2",
"public": "packages/app2/build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
{
"target": "app2",
"public": "packages/app3/build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}]
}
And here is my .firebaserc
file. In this one you specify the Firebase projects for each environment and on which sites (i.e. subprojects) the targets must be hosted.
{
"projects": {
"default": "myproject-staging",
"staging": "myproject-staging",
"prod": "myproject-prod"
},
"targets": {
"myproject-staging": {
"hosting": {
"app1": [
"myproject-app1-staging"
],
"app2": [
"myproject-app2-staging"
],
"app3": [
"myproject-app3-staging"
]
}
},
"myproject-prod": {
"hosting": {
"app1": [
"myproject-app1"
],
"app2": [
"myproject-app2"
],
"app3": [
"myproject-app3"
]
}
}
}
}
To integrate this into a CI/CD strategy, you can use GitLab and add command lines to the deployment script to perform the deployments on Firebase.
To obtain the authentication token, you can use the firebase login:ci
command (although this method is deprecated, it is recommended to check for current alternatives to obtain the authentication token).
Here is my gitlab-ci.yml
file to build and deploy on firebase each environment when they have new commits on the develop
and main
branches (for staging
and production
environments)
image: node:18.12.0
stages:
- deploy
variables:
REACT_APP_API_URL: <API_URL_STAGING>
REACT_APP_SENTRY_ENVIRONMENT: staging
deploy-staging:
stage: deploy
only:
- develop
environment: staging
variables:
REACT_APP_API_URL: <API_URL_STAGING>
REACT_APP_SENTRY_ENVIRONMENT: staging
before_script:
- GENERATE_SOURCEMAP=false
script:
- npm install -g firebase-tools
- yarn --ignore-platform
- NODE_OPTIONS=--openssl-legacy-provider yarn run build
- firebase deploy -P staging --token $FIREBASE_TOKEN
deploy-production:
stage: deploy
only:
- main
environment: production
variables:
REACT_APP_API_URL: <API_URL_PRODUCTION>
REACT_APP_SENTRY_ENVIRONMENT: production
before_script:
- GENERATE_SOURCEMAP=false
script:
- npm install -g firebase-tools
- yarn --ignore-platform
- NODE_OPTIONS=--openssl-legacy-provider yarn run build
- firebase deploy -P prod --token $FIREBASE_TOKEN
I hope you find this usefull. I got stuck for a couple of hours because when I wanted to host the staging environment, the project was not initiated. I had to erase my firebase.json
file, recreate one with firebase init
to host the project with a empty index.html
file. Only then I could create the apps (subprojects = targets) in Firebase and then use my multitargets firebase.json
file.
Top comments (0)