I’m wondering if it’s possible to somehow still access the module exports of an ES6 module from within the module, like you do in CommonJS with module.exports.
For clarity, I have a js module (Config.js) that I use to export all of my config variables like so.
export const DatabaseName = "myDbName";
export const DatabasePort = 3000;
export const DatabaseHosts = ["174.292.292.32"];
export const MaxWebRequest = 50;
export const MaxImageRequests = 50;
export const WebRequestTimeout = 30;
etc...
And then I have a separate Dev.Config.js file which only holds the overrides for my dev environment.
export const DatabaseHosts = ["localhost"];
export const DatabasePort = 5500;
In my main Config.js file, I have this logic at the bottom.
try {
var environmentConfig = `./${process.env.NODE_ENV}.Config.js`;
var localConfig = require(environmentConfig)
module.exports = Object.assign(module.exports, localConfig)
} catch (error) {
console.log("Error overriding config with local values. " + error)
}
And then finally, in my consuming code, I’m able to just import my config.js file like so
import * as Config from "./Config.js";
console.log(Config.DatabaseHosts) // Gives me the correct "overridden" value on my dev environment
Currently I’ve been using babel to transpile my code all back into CommonJS which I guess is how I’m able to sort of mix and match import/export syntax, and still reference module.exports like I’ve done above.
My question is, how would I replicate this pattern in a pure ES6 module without needing to transpile this using babel where I cannot modify my module.exports from within the module itself?
2
Answers
Conditional exports isn’t a supported pattern in ESM.
In order to modify exported values using dynamic import from another module whose specifier is derived from an environment variable (in a
try...catch
statement so that a failed attempt won’t throw an uncaught exception at the top level), you can modify the structure of your exports so that they are exposed as properties on an object. Below is a reproducible example to demonstrate:./package.json
:./Dev.Config.js
:./Config.js
:./main.js
:In the terminal:
There is no way to build/overwrite the exports object dynamically in ES6 modules. Even the conditional import will already require either top-level
await
or tooling support.What you can do however is mess with
let
declarations andeval
:I would not recommend this though. Use this approach only if you cannot change how the Config.js module is used, or if there are too many exported variables for the alternatives to be feasible.
Instead, I would suggest you create a separate module that merges the configurations, though this requires spelling out the configuration names twice:
Or change the configuration modules to default-export objects, which you can manipulate arbitrarily. You loose the ability to use named imports and get static validation though.