DEV Community

Preston Lamb
Preston Lamb

Posted on • Originally published at prestonlamb.com on

Angular Configuration on Netlify

tldr;

Almost every Angular application needs some configuration to run. It may be as simple as the API URL, or information needed for authentication. And many times these values change from environment to environment. So what are the options for providing this configuration in Angular apps when the app is deployed on Netlify? We’ll go over a few options in this post, and hopefully one option works for you!

Review

Before we jump fully in to the ways to provide configuration for your Angular app, let’s talk about what runtime configuration is and why we want to use it.

There are two types of configuration for your Angular app: build time and runtime configuration. Build time configuration is needed at the time the app is built. If a value is used and not provided, the application won’t build. Also, if a value changes, the app needs to be rebuilt. Runtime configuration, however, can be provided at the time the application is loaded in the user’s browser. Values can be changed, and all that’s needed is a browser refresh to get the new values. This is a much more flexible option than build time configuration.

We can load the configuration in our app at runtime using the APP_INITIALIZER token for Angular applications. That token allows code to be run at the time the app is initialized. This will make it so that the runtime configuration is available when the app starts up. You can learn more about how to do that in this previous blog post I wrote. You can also use this package to handle loading the configuration from a JSON file or a URL for you.

Angular App Configuration from Netlify

Okay, so we now have the different types of configuration refreshed in our minds, but how can we get that configuration into our app in Netlify. I have 3 different ways that I’ve thought of to do this. We’ll talk about each of those here.

Environment-based JSON Files

The first option is to have the app configuration declared in JSON files in your assets folder. This is close to how I will typically use runtime-based configuration. Generally, I put the configuration in assets/config.json. Then, in the deployed app, that file is replaced with test environment or production environment specific settings. So this first way is close to that, except that there will be a JSON file for each environment in your assets folder. Then, when you load the config, you’ll use the build time configuration files in the environment folder to store the URL for the config. Here’s an example:

// environments/environment.ts

export const environment = {
  production: false,
  runtimeConfigUrl: "./assets/config.json"
};
Enter fullscreen mode Exit fullscreen mode
// environments/environment.prod.ts

export const environment = {
  production: true,
  runtimeConfigUrl: "./assets/config.prod.json"
};
Enter fullscreen mode Exit fullscreen mode
// app.module.ts

@NgModule({
    ...
    RuntimeConfigLoaderModule.forRoot({
        configUrl: environment.runtimeConfigUrl
    })
})
Enter fullscreen mode Exit fullscreen mode

That environment file will be replaced depending on the environment for which you build the app. So for development, you can point to assets/config.json; in test you can point to assets/config.test.json; and in production you can point to assets/config.prod.json. This works, for sure, but it’s not great. And that’s because if you change a value in one of those config.json files, Netlify won’t be able to get the change until a new deploy has been done. In this case, it’s really no better than using the build time configuration provided in Angular with the environment files. So while this will work, I don’t think it’s the best idea.

Getting Configuration from a Netlify Function

The next option is similar to the one above. The difference is that in whichever environment is deployed to Netlify, we’ll call a Netlify function URL to load the configuration data. Here’s the example environment.prod.ts file:

// environments/environment.prod.ts

export const environment = {
  production: true,
  runtimeConfigUrl:
    "https://www.your-domain.com/.netlify/functions/get-runtime-config-data-function"
};
Enter fullscreen mode Exit fullscreen mode

For this environment, a Netlify function will be called, and the configuration will be returned. That configuration could be stored anywhere, like a database, or a file somewhere else. It could even be stored in the function’s process.env. Netlify allows you to add in build environment variables. In the function, you could pluck those out of the process.env and return it to the Angular app. Here’s an example Netlify function to do that:

// .netlify/functions/get-runtime-config-data

function buildConfigObject() {
  const config = {};
  for (let attr in process.env) {
    if (attr.startsWith("runtime_")) {
      const startAt = attr.indexOf("_") + 1;
      const newKey = attr.substring(startAt);
      config[newKey] = process.env[attr];
    }
  }

  return config;
}

exports.handler = function(event, context, callback) {
  try {
    const config = buildConfigObject();
    const returnObj = { body: JSON.stringify(config), statusCode: 200 };
    console.log("runtime config data: ", JSON.stringify(returnObj, null, 2));
    return callback(null, returnObj);
  } catch (error) {
    console.error(error);
    return callback({ statusCode: 500, error });
  }
};
Enter fullscreen mode Exit fullscreen mode

That function will look for process.env attributes that are prefaced with runtime_ and puts them in a new object and returns them to the Angular app. This will work great and allow you to set those environment variables with Netlify. But this method has a problem, and that is that those process.env variables are not updated until another deploy is done. Whether a new variable is added or an existing one is updated, your app won’t see it until a new build has been done. Because of that, this again isn’t much better than using the built in build time configuration. But there is a way to make this work at runtime, and that could be by calling a database from this Netlify function. FaunaDB is a great option, because it works great with Netlify. But the truth is you could call any database anywhere that you’d like. If you did that, the configuration could be different each time the function is called, thus providing real runtime configuration.

If you’d like to learn more about Netlify Functions and how to get started read this previous article of mine

Getting Configuration From a GitHub Gist

The third option that I’ve thought of again sets the config URL in the environment.ts file, but this time the production config URL will point to a GitHub gist.

// environments/environment.prod.ts

export const environment = {
  production: true,
  runtimeConfigUrl: "https://www.gist.github.com/gistId/raw/fileId"
};
Enter fullscreen mode Exit fullscreen mode

Make sure when you get the URL, you select the specific file from the gist, and then click the “raw” button so that you can get the actual JSON from the gist

This option should be fine because Angular configuration shouldn’t contain actual secrets. This is because any values that come back to a browser can be read by someone looking at the network tab. So even though the values are viewable in the gist, it should be okay. You can make a secret gist as well, which will make it so only those with the URL could see the values. That would work too.

GitHub gists aren’t the only way to do this step either. You could put the JSON anywhere that it’s publicly viewable. Google Drive or Dropbox may even be good options for this as well. As long as the file is JSON and publicly accessible, this will work.

This is the quickest of the three options that I’ve laid out here. It’s quick and easy (and free) to create a gist, and each time the gist is updated and then requested, the new values are immediately available.

Conclusion

There are many ways to get runtime configuration for your application. And as a general rule, I think all Angular configuration should be provided at runtime. But for a while I was curious as to how that could be done with Netlify. These three options, though, should provide a workable solution for you and your app.

Top comments (0)