Judicious use of toggling the comments definitely gets the job done, though once you go beyond a small handful of files it becomes error prone (releasing dev code to prod…).

To solve the issue of the comments being everywhere we can use an environment variable - though unfortunately we can’t use it to dynamically import. The following code is what we’re trying to do:

// This is not valid code!import{
getAllPokemon,
getPokemon
}from process.env.REACT_APP_PROD?'./api-store':'./memory-store';

The solution I settled on uses craco (Create React App Configuration Override) to let us modify the webpack config without ejecting, and the webpack normal module replacement plugin. Once we’re done the code will look like this:

For this implementation swap to work the method signatures and return types must be the same. One of my favourite mistakes when mocking an SDK is to forget to make my implementations async.

Add craco

In addition to craco I’m installing cross-env, which allows an environment variable to be set in a way that works over Mac and Windows.

yarnadd craco
yarnadd cross-env

Once craco has been installed, you need to update your package.json to use the craco command instead of react-scripts. This ensures that any configuration overrides we specify will get picked up.

We’re also adding a new start method which will set an environment variable. This is how we’ll decide which implementation is built, and I typically leave the default (no variable) to build the production version.

At this point your app should still work - though you need to toggle comments in order to switch implementations. We’ll fix that next.

Swap implementations based on an environment variable

To hook into webpack we’ll create a craco.config.js file in our project root. We check to see if the environment variable is set, and if so use the memory implementation, otherwise default to api. We then add a plugin and tell it that if it gets any requests to import a module with APP_TARGET in the name (e.g. from an import statement), to replace APP_TARGET with either api or memory, and import that instead.