UNPKG

react-universally

Version:

A starter kit for universal react applications.

115 lines (103 loc) 4 kB
/** * Unified Configuration Reader * * This helper function allows you to use the same API in accessing configuration * values no matter where the code is being executed (i.e. browser/node). * * e.g. * import config from '../config'; * config('welcomeMessage'); // => "Hello World!" */ /* eslint-disable no-console */ /* eslint-disable import/global-require */ /* eslint-disable no-underscore-dangle */ // PRIVATES let configCache; /** * This resolves the correct configuration source based on the execution * environment. For node we use the standard config file, however, for browsers * we need to access the configuration object that would have been bound to * the "window" by our "reactApplication" middleware. * * @return {Object} The executing environment configuration object. */ function resolveConfigForBrowserOrServer() { if (configCache) { return configCache; } // NOTE: By using the "process.env.BUILD_FLAG_IS_NODE" flag here this block of code // will be removed when "process.env.BUILD_FLAG_IS_NODE === true". // If no "BUILD_FLAG_IS_NODE" env var is undefined we can assume that we are running outside // of a webpack run, and will therefore return the config file. if ( typeof process.env.BUILD_FLAG_IS_NODE === 'undefined' || process.env.BUILD_FLAG_IS_NODE === 'true' ) { // i.e. running in our server/node process. configCache = require('./values').default; return configCache; } // To get here we are likely running in the browser. if (typeof window !== 'undefined' && typeof window.__CLIENT_CONFIG__ === 'object') { configCache = window.__CLIENT_CONFIG__; } else { // To get here we must be running in the browser. console.warn('No client configuration object was bound to the window.'); configCache = {}; } return configCache; } // EXPORT /** * This function wraps up the boilerplate needed to access the correct * configuration depending on whether your code will get executed in the * browser/node. * * i.e. * - For the browser the config values are available at window.__CLIENT_CONFIG__ * - For a node process they are within the "<root>/config". * * To request a configuration value you must provide the repective path. For * example, f you had the following configuration structure: * { * foo: { * bar: [1, 2, 3] * }, * bob: 'bob' * } * * You could use this function to access "bar" like so: * import config from '../config'; * const value = config('foo.bar'); * * And you could access "bob" like so: * import config from '../config'; * const value = config('bob'); * * If any part of the path isn't available as a configuration key/value then * an error will be thrown indicating that a respective configuration value * could not be found at the given path. */ export default function configGet(path) { const parts = typeof path === 'string' ? path.split('.') : path; if (parts.length === 0) { throw new Error( 'You must provide the path to the configuration value you would like to consume.', ); } let result = resolveConfigForBrowserOrServer(); for (let i = 0; i < parts.length; i += 1) { if (result === undefined) { const errorMessage = `Failed to resolve configuration value at "${parts.join('.')}".`; // This "if" block gets stripped away by webpack for production builds. if (process.env.BUILD_FLAG_IS_DEV === 'true' && process.env.BUILD_FLAG_IS_CLIENT === 'true') { throw new Error( `${errorMessage} We have noticed that you are trying to access this configuration value from the client bundle (i.e. code that will be executed in a browser). For configuration values to be exposed to the client bundle you must ensure that the path is added to the client configuration filter in the project configuration values file.`, ); } throw new Error(errorMessage); } result = result[parts[i]]; } return result; }