DEV Community

Cover image for Angular Universal ENV Variables on Vercel
Jonathan Gamble
Jonathan Gamble

Posted on • Edited on

Angular Universal ENV Variables on Vercel

So, I moved my website Code.Build to Vercel from Cloud Run after writing all these Angular Universal articles.

Cloud Run VS AWS Lambdas

My cold start time was cut in a quarter of the time. My build time went from 15min to 3min. Granted, I didn't add any horse power to my Google Cloud Run, and I spend a total of $7 a month on hosting. I went with the default options, which Vercel uses more power. I admit my website is probably not too popular either since all my articles are cross posted here. ☹️

After reading many articles, AWS Lambdas are just faster than Docker and Cloud Run. This was extremely important to me. Google needs to spend more money developing on its Cloud Functions in order to compete. However, it is worth noting that Cloud Run does support things like Web Sockets for streaming data, while AWS Lambdas do no such thing. This is important if you're hosting a database or middleware.

So, last thing I needed to do was configure my ENV variables to work correctly in Vercel.

Firebase

For this example, I am using the Firebase env variables, and storing them in a json file. You can read about that in my Google Cloud Build article.

Basically just put the firebase information in environment.json and import it into environment.ts.

On the server, go to your project in Vercel, and add a new variable FIREBASE with your json keys.

process.env

The developers at Vercel HATE Angular. Angular is not inferior, it is just different. Notice they don't even have a tab for Angular to use ENV variables. They don't support Angular Universal, even though I wrote an aritcle about how to do it. I guess they want a plugin written. You don't need one, but I digress. Perhaps someone could write one. It may be necessary for automating advanced features like lazy loading modules to their own serverless function etc.

So, it is worth noting that process.env is available on the server, but not on the browser due to reasons listed above.

There is a probably a way to just echo the env variables to a file like I did in Cloud Build, but I went with the classic script version.

Build File

set-env.js

function setEnv() {
  fs = require("fs");
  writeFile = fs.writeFile;
  // Configure Angular `environment.prod.json` file path
  targetPath = "/vercel/path1/src/environments/environment.prod.json";
  targetPath2 = "/vercel/path2/src/environments/environment.prod.json";

  // `environment.prod.json` file structure
  envConfigFile = process.env.FIREBASE;

  console.log(
    "The file `environment.prod.json` will be written with the following content: \n"
  );
  writeFile(targetPath, envConfigFile, function (err) {
    if (err) {
      console.error(err);
      throw err;
    } else {
      console.log(
        "Angular environment.prod.json file generated correctly at" +
          targetPath +
          "\n"
      );
    }
  });
  writeFile(targetPath2, envConfigFile, function (err) {
    if (err) {
      console.error(err);
      throw err;
    } else {
      console.log(
        "Angular environment.prod.json file generated correctly at" +
          targetPath +
          "\n"
      );
    }
  });
}

setEnv();
Enter fullscreen mode Exit fullscreen mode

Create this file in your environments folder. Notice it must build two copies of the json files: one for the server, and one for the browser.

Follow my Vercel Setup instructions, add scripts.config and update scripts.vercel-build.

"config": "node src/environments/set-env.js",
"vercel-build": "npm run config && npm run build:ssr"
Enter fullscreen mode Exit fullscreen mode

Done.

Now the script runs when you build to populate the env variables on BOTH server and browser. Remember, if you just want the variables on the server, you can simple check for process.env.FIREBASE and get it that way. The problem is development environments.

Hope this helps someone,

J

Top comments (1)

Collapse
 
gpicazo profile image
Genaro Picazo

I used this script for an Angular app (non-universal) with a few minor changes and it has been working great. The most notable changes I made were:

  • single fileWrite
  • single path, targetPath = "./src/environments/environment.prod.json";
  • instead of using vercel-build, updated my build task to "build": "npm run config && ng build",

Now, I have another Angular app where the content is mostly static, so I am pre-rendering the application to be able to optimize it for SEO. I am using the same script as for the other app, however, instead of the above change to the build task, I added the following vercel-build task: npm run config && npm run prerender, which uses task: "prerender": "ng run <my-app-name>:prerender".

On local it works fine, if I create my env variables on my local machine, and run the vercel-build task, the sources are generated and the env variable values are injected correctly. However, when pushing to Vercel, it doesn't work. I do see the console log showing the success message indicating that the variables were written to disk.

If I pre-populate the environment.prod.json file with dummy entries, those dummy entries are the ones that show up in the Vercel output contents, which hints at one of the following:

  • I am writing a file but not overriding the original -- not sure how to test this
  • the write is not finishing before the build starts -- I've tested other changes that ensure that a few seconds elapse between the writefile completion and the build starting
  • the original source is "picked up" before the write and used for the build -- but then local wouldn't work either, and it does

I've tried all kinds of things and nothing seems to work, it's driving me crazy. If you can think of what I might be missing, I would really appreciate any suggestions.

P.S. Both apps are still on Angular 16.