i’ve done a bunch of reading but haven’t found a working solution
the closest i’ve seen is here: Export the result of async function in React
please keep in mind that I want to export an object, and that object is the result of an asynchronous function, NOT export the async function definition itself
here’s my use case and implementation so far:
we have a file called config.ts
traditionally config.ts has contained an object with relevant runtime configurations as the default export
this lets us simply
import config from '../config'
or whateverour config and secret management has gotten more complex so that it needs to make various calls to various secret repositories (aws, azure, etc)
i’ve refactored config.ts to now look something like this:
export const basicValues = { color1: 'red' } async function buildConfig(){ const valuesOut = {...basicValues} valuesOut.color2 = await getSecret('color2'); valuesOut.color3 = await getSecret('color3'); return valuesOut; } export default buildConfig()
where getSecret
is some function that makes an arbitrary async call
i’m exporting basicValues above because i have some config settings in there that are necessary to make the calls inside getSecret.
by exporting basicValues like this i can get the values out with a simple const basicConfig = require('../config').basicValues
. This way we can continue to manage all the fun config stuff in a clean, centralized, tested file but still make the values available for use very early and avoid cyclical dependencies
all together, this FEELS like it should work
i’ve tried lots of other patterns but this feels most natural and intuitive to read
here’s the bad part:
import config from '../config'
yields undefined, withexport default buildConfig()
- changing the export to be simply
export default basicValues
gives us our config object as expected (but without the async values populated, obviously)
what exactly am I doing wrong here?
happy to provide more deets as necessary
thanks in advance
Advertisement
Answer
please keep in mind that I want to export an object, and that object is the result of an asynchronous function, NOT export the async function definition itself
This is not possible. Since the value is retrieved asynchronously, all modules that consume the value must wait for the asynchronous action to complete first – this will require exporting a Promise that resolves to the value you want.
In new versions of Node, you could import the Promise and use top-level await
to wait for it to be populated:
import buildConfigProm from '../config'; const config = await buildConfigProm;
If you aren’t in Node, top-level await
isn’t supported. You could call .then
on the Promise everywhere it’s imported:
buildConfigProm.then((config) => { // put all the module's code in here });
If you don’t like that, the only real alternative is to use dependency injection. Have your modules export functions that take the config
as a parameter, eg:
// useConfig.ts export default (config: Config) => { console.log('color2', config.color2); };
This way, the only thing that has to be asynchronous is the entry point, which waits for the Promise to resolve, then calls the needed modules with it:
// index.ts import buildConfigProm from './config'; import useConfig from './useConfig'; buildConfigProm .then((config) => { useConfig(config); }) .catch(handleErrors);