Conditionally import assets in create-react-app

You will need to use webpack (or other bundler.) The code is not being run when it's bundled, so the compiler has no way of knowing which branch of logic to follow (app_1 or app_2). Therefore you have to get into the bundler's logic in order to achieve your goal.

However, this isn't as scary as it seems since webpack has built in capability to do this (no 3rd parties required...)

I would look into using webpack.providePlugin

(https://webpack.js.org/plugins/provide-plugin)

or its sibling DefinePlugin

(https://webpack.js.org/plugins/define-plugin)

(I'm afraid these examples are off the top of my head, so it's very unlikely they'll work on first pass.)

Examples:

Both will require a provider module...

// in path/provider.js

module.exports = {
  live: '/path/to/live/image',
  dev: '/path/to/dev/image'
}

Provide Plugin Example

// in webpack

new webpack.ProvidePlugin({
    imagePath: [
      'path/provider',         // the file defined above
      process.env.ENVIRONMENT  // either 'dev' or 'live'
    ]
  }),
// in code

export default function Test() {
  return (
      <img src={imagePath} alt="" />
  );
}

Define Plugin example:

// in webpack

new webpack.DefinePlugin({
  'process.env.ENVIRONMENT': JSON.stringify(process.env.ENVIRONMENT)
});
// in code

var providers = require('path/provider'); // same path provider as above

export default function Test() {
  return (
      <img src={providers[process.env.ENVIRONMENT]} alt="" />
  );
}

In both cases the bundler is forced to collapse your variable to an actual literal value at compile time - before bundling has taken place. Since you have now collapsed the logical path down to a single option, it is now free to only bundle the relevant assets.


In the days when React didn't exist we didn't put assets into our JS files. We let the CSS to decide, what assets to load for what selectors. Then you could simply switch a corresponding class on or off for a corresponding element (or even the whole page) and viola it changes color, background, or even a form. Pure magic!

Ah. What times these were!

All above is true and I do not understand why would anyone do or recommend doing it differently. However if you still want to do it (for any reason) - you can! Latest create-react-app comes with out-of-the-box support for lazy loading of arbitrary components via dynamic importing and code splitting. All you need to do is use parenthesized version of the import() statement instead of the regular one. import() takes in a request string as usual and returns a Promise. That's it. Source code of the dynamicaly requested component won't be bundled in, but instead stored in separate chunks to be loaded on demand.

Before:

import OtherComponent from './OtherComponent';

function MyComponent() {   
  return (
    <div>
      <OtherComponent />
    </div>   
  ); 
}

After:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

Notice how function MyComponent part is identical.

For those wondering if it is tied to CRA or React, it's not. It's a generic concept that can be used in vanilla JavaScript.