Q: A better way of sharing env-specific variables on both client and server?

Author: glennrCreated Feb 4, 2016Updated Jun 6, 2019

I came up with a solution to have the URL prefix of my API configurable, on a per environment basis.

In my case, I'm not using server proxying as in the boilerplate - my app connects directly to my API. This means I need a fully qualified domain name on my requests, whether they happen during SSR, or in the browser.

If we look at the current version of ApiClient.js, we have;

function formatUrl(path) {
  const adjustedPath = path[0] !== '/' ? '/' + path : path;
  if (__SERVER__) {
    // Prepend host and port of the API server to the path.
    return 'http://' + config.apiHost + ':' + config.apiPort + adjustedPath;
  }
  // Prepend `/api` to relative URL, to proxy to API server.
  return '/api' + adjustedPath;
}

and in config.js

  apiHost: process.env.APIHOST || 'localhost',
  apiPort: process.env.APIPORT,

So I want ApiClient to look something like this, which (I think) is the least amount of code I need to change;

function formatUrl(path) {
  const adjustedPath = path[0] !== '/' ? '/' + path : path;
  // Prepend host and port of the API server to the path.
    return 'http://' + config.apiHost + ':' + config.apiPort + adjustedPath;
}

Which won't work client-side since process.env vars are from node.

The solution I came up with was this;

(Note in my code below I combine apiHost and apiPort into 'apiUrl')

in Html.js

          <script
            charSet="UTF-8"
            dangerouslySetInnerHTML={{__html: `window.__apiUrl='${config.apiUrl}'`}}
          />

and in config.js

  apiUrl: __SERVER__ ? process.env.APIURL || 'localhost' : window.__apiUrl,

This feels a bit of a hack. The config module writes a variable, which is read by the server code to render the html with a variable, which is read by the config module in the client. Phew.

Is there a better way to share env variables between client & server code?

Source: erikras/react-redux-universal-hot-example