If you deploy your Angular Application to a Google Cloud Run Container, you should do it through Github Actions and Google Cloud Build. This is what creates the CI/CD (Continuous Integration and Continuous Delivery) deployments easily.
Obviously this makes more sense for Angular Universal than Angular, since you need a node server or container to run the former.
Local Version
Angular Universal is not made to use the dotenv
package, despite what articles tell you:
- https://javascript.plainenglish.io/setup-dotenv-to-access-environment-variables-in-angular-9-f06c6ffb86c0
- https://ferie.medium.com/how-to-pass-environment-variables-at-building-time-in-an-angular-application-using-env-files-4ae1a80383c
Bonus Tip - Right Click - Open in New Private Window on all these medium articles that won't display... that is the reason I love dev.to!
Getting it to work is a pain in the butt. So, why not just use simple JSON!?
- Create
environment.prod.json
andenvironment.json
in yoursrc/environments
folder - Ignore the json files:
.gitignore
# Config Files
/src/environments/*.json
3. Update your environment.ts
files
import * as firebase_env from './environment.prod.json';
export const environment = {
production: true,
firebase: firebase_env
};
4. Add the appropriate JSON data to the environment.prod.json
file(s).
{
"key": "value",
...
}
Notice you need to have quotes in the key.
5. Enable JSON imports
Edit tsconfig.json
and add
{
"compilerOptions": {
...
"resolveJsonModule": true,
...
}
Deployment
This post is not about Deployment itself. You need to know the basics of Cloud Run, Cloud Container Registry, Github Actions, and Cloud Build.
That being said, you don't have to understand much but how to enable them.
Here are a few links for that:
- https://fireship.io/courses/angular/ssr-deploy-cloud-run/
- https://towardsdatascience.com/deploy-to-google-cloud-run-using-github-actions-590ecf957af0
- https://javascript.plainenglish.io/your-guide-for-deploying-an-angular-app-on-google-cloud-aint-complete-f6d5998332fb
Cloud Build
Cloud Build pretty much does everything for you. You can get Github Actions working through Github, but it is much easier to go through Cloud Build.
Basically go to Cloud Build, make sure it is enabled, click Setup Build Trigger, name it, and chose your repository. You will be prompted to login to Github, allow access etc.
You may need to change the main
branch to master
depending on your setup.
YAML File
You can create your own cloudbuild.yaml
, but you don't have to. It is done automatically for you once you connect your repository.
Once you have all this configured, click the Open Editor
button.
There, you can modify your inline YAML file. Now add the build-arg
to the build step like so:
steps:
- name: gcr.io/cloud-builders/docker
args:
- build
- '--build-arg'
- _FIREBASE=$_FIREBASE
- '--no-cache'
- '-t'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- .
- '-f'
- Dockerfile
id: Build
In this case, I am adding the _FIREBASE
variable which will be passed to the docker file.
You may also need to add timeout: 1600s
to the bottom of the file if you believe the build will take more than 10 minutes. Angular Builds can take a while due to all the optimizations etc.
Now, click DONE
Add your Secret Variable as you want. Since we are using JSON, make sure the key is wrapped in quotes.
Dockerfile
Finally, use this Dockerfile if you use Angular Universal
FROM node:14-slim
ARG _FIREBASE
WORKDIR /usr/src/app
COPY . .
RUN npm i
RUN npm audit fix
RUN echo "$_FIREBASE" >> src/environments/environment.prod.json
RUN npm run build:ssr
CMD ["npm", "run", "serve:ssr"]
Basically, it creates the environment file from the substitution variable. You need to add the ARG
for this to work. You can do any variables you like.
I have not seen any other tutorial do it quite like this, so this is a unique approach, and much simpler IMHO than using .env files.
Client API Keys? Why do we need to do all this?
If you read the correct answer on stackoverflow, officially it explains that you don't need to do any of this. Your client API key is going to be viewable, or gettable, as your frontend source is not secure. You can run firebase commands in console.log, and do way more see Fireship Video. If you use Supabase, Firebase, or any API with a client key, it is hackable. Firebase should be secured with App Check and Security Rules, Supabase with Row Level Policies, etc, etc.
That being said, I still don't want someone easily copying and pasting my configuration code into their project on every fork or clone. Another layer of security is always good.
If your project is a backend project, this is especially good.
More Sveltekit and Vercel Sharing Varaibles
More Angular Universal setup
If you have a professional APP, you may want to look into Cloud Run CDN, which is Vercel's Edge equivalent. See here.
Hope this helps someone,
J
Top comments (1)
This was really insightful,
I have done a lot of search about this env variable stuff, and your article stood out.
Thanks for this.
Just like you said,
there's a tiny chance for someone to start inspecting your scripts to find your keys, but there's a higher chance for them to copy it from a repo.