Skip to content

Latest commit

 

History

History
143 lines (106 loc) · 5.55 KB

0007-javascript-file-configuration.rst

File metadata and controls

143 lines (106 loc) · 5.55 KB

Promote JavaScript file configuration and deprecate environment variable configuration

Status

Accepted

Context

Our webpack build process allows us to set environment variables on the command line or via .env files. These environment variables are available in the application via process.env.

The implementation of this uses templatization and string interpolation to replace any instance of process.env.XXXX with the value of the environment variable named XXXX. As an example, in our source code we may write:

const LMS_BASE_URL = process.env.LMS_BASE_URL;

After the build process runs, the compiled source code will instead read:

const LMS_BASE_URL = 'http://localhost:18000';

Put another way, process.env is not actually an object available at runtime, it's a templatization token that helps the build replace it with a string literal.

This approach has several important limitations:

  • There's no way to add variables without hard-coding process.env.XXXX somewhere in the file, complicating our ability to add additional application-specific configuration without explicitly merging it into the configuration document after it's been created in frontend-platform.

  • The method can only handle strings.

    Other data types are converted to strings:

    # Build command:
    BOOLEAN_VAR=false NULL_VAR=null NUMBER_VAR=123 npm run build
    
    ...
    
    // Source code:
    const BOOLEAN_VAR = process.env.BOOLEAN_VAR;
    const NULL_VAR = process.env.NULL_VAR;
    const NUMBER_VAR = process.env.NUMBER_VAR;
    
    ...
    
    // Compiled source after the build runs:
    const BOOLEAN_VAR = "false";
    const NULL_VAR = "null";
    const NUMBER_VAR = "123";
    

    This is not good!

  • It makes it very difficult to supply array and object configuration variables, and unreasonable to supply class or function config since we'd have to eval() them.

Related to all this, frontend-platform has long had the ability to replace the implementations of its analytics, auth, and logging services, but no way to actually configure the app with a new implementation. Because of the above limitations, there's no reasonable way to configure a JavaScript class via environment variables.

Decision

For the above reasons, we will deprecate environment variable configuration in favor of JavaScript file configuration.

This method makes use of an env.config.js file to supply configuration variables to an application:

const config = {
  LMS_BASE_URL: 'http://localhost:18000',
  BOOLEAN_VAR: false,
  NULL_VAR: null,
  NUMBER_VAR: 123
};

export default config;

This file is imported by the frontend-build webpack build process if it exists, and expected by frontend-platform as part of its initialization process. If the file doesn't exist, frontend-build falls back to importing an empty object for backwards compatibility. This functionality already exists today in frontend-build in preparation for using it here in frontend-platform.

This interdependency creates a peerDependency for frontend-platform on frontend-build v8.1.0 or later.

Using a JavaScript file for configuration is standard practice in the JavaScript/node community. Babel, webpack, eslint, Jest, etc., all accept configuration via JavaScript files (which we take advantage of in frontend-build), so there is ample precedent for using a .js file for configuration.

In order to achieve deprecation of environment variable configuration, we will follow the deprecation process described in OEP-21: Deprecation and Removal. In addition, we will add build-time warnings to frontend-build indicating the deprecation of environment variable configuration. Practically speaking, this will mean adjusting build processes throughout the community and in common tools like Tutor.

Relationship to runtime configuration

JavaScript file configuration is compatible with runtime MFE configuration. frontend-platform loads configuration in a predictable order:

  • environment variable config
  • optional handlers (commonly used to merge MFE-specific config in via additional process.env variables)
  • JS file config
  • runtime config

In the end, runtime config wins. That said, JS file config solves some use cases that runtime config can't solve around extensibility and customization.

In the future if we deprecate environment variable config, it's likely that we keep both JS file config and runtime configuration around. JS file config primarily to handle extensibility, and runtime config for everything else.

Rejected Alternatives

Another option was to use JSON files for this purpose. This solves some of our issues (limited use of non-string primitive data types) but is otherwise not nearly as expressive or flexible as using a JavaScript file directly. Anecdotally, in the past frontend-build used JSON versions of many of its configuration files (Babel, eslint, jest) but over time they were all converted to JavaScript files so we could express more complicated configuration needs. Since one of the primary use cases and reasons we need a new configuration method is to allow developers to supply alternate implementations of frontend-platform's core services (analytics, logging), JSON was effectively a non-starter.