diff --git a/packages/react-dev-utils/README.md b/packages/react-dev-utils/README.md index 14c69493e5..ecb8e94536 100644 --- a/packages/react-dev-utils/README.md +++ b/packages/react-dev-utils/README.md @@ -201,3 +201,33 @@ module.exports = { // ... } ``` + +#### `envDefinePlugin({regex: string, customVariables: Object.})` + +This function grabs environment variables that follows a specified regex and injects them into the application +using the webpack DefinePlugin. +In addition, the function allows defining custom environment variables to be injected. + +To use first reference it in your webpack config: + + ```js + var webpack = require('webpack'); + var envDefinePlugin = require('react-dev-utils/webpackEnvDefinePlugin'); + ``` + +and define it as a plugin in the webpack config plugin section: + + ```js + plugins: [ + ... + new webpack.DefinePlugin(envDefinePlugin({ + // Grab MY_PREFIX_* environment variables + regex: /^MY_PREFIX_/i, + customVariables: { + // Useful for injecting static values as environment variables to the application + 'APP_NAME': 'My App' + } + })), + ... + ] + ``` \ No newline at end of file diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 1fe5c556c7..347189b996 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -19,7 +19,8 @@ "openBrowser.js", "prompt.js", "WatchMissingNodeModulesPlugin.js", - "webpackHotDevClient.js" + "webpackHotDevClient.js", + "webpackEnvDefinePlugin.js" ], "dependencies": { "ansi-html": "0.0.5", diff --git a/packages/react-dev-utils/webpackEnvDefinePlugin.js b/packages/react-dev-utils/webpackEnvDefinePlugin.js new file mode 100644 index 0000000000..b85e0bfbc6 --- /dev/null +++ b/packages/react-dev-utils/webpackEnvDefinePlugin.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +/** + * Generates a webpack define plugin config injecting environment variables that pass a regex test. + * The function also support custom variables by passing them in the options argument + * + * @param {Object} options - The plugin configuration + * @param {string} options.regex - The regex to select the environment variables by + * @param {Object.} options.customVariables - A map that its keys are the + * custom injected environment + * variable names and its values are the variable values + * @returns - Returns a webpack define plugin configuration + */ +function envDefinePlugin(options) { + const regex = options.regex || /.*/; + const customVariables = options.customVariables || {}; + + return getClientEnvironment(regex, customVariables); +} + +/** + * Grabs environment variables that meets the regex test and prepare them to be injected into the + * application via DefinePlugin in Webpack configuration. + * @param {string} regex - The regex to select the environment variables by + * @param {Object.} customVariables - A map where its keys are the custom injected environment + * @returns {{[process.env]: *}} - A DefinePlugin configuration + */ +function getClientEnvironment(regex, customVariables) { + const processEnv = Object + .keys(process.env) + .filter(key => regex.test(key)) + .reduce((env, key) => { + env[key] = JSON.stringify(process.env[key]); + return env; + }, customVariables); + return { 'process.env': processEnv }; +} + +module.exports = envDefinePlugin; diff --git a/packages/react-scripts/config/env.js b/packages/react-scripts/config/env.js deleted file mode 100644 index 66ba341b35..0000000000 --- a/packages/react-scripts/config/env.js +++ /dev/null @@ -1,39 +0,0 @@ -// @remove-on-eject-begin -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// @remove-on-eject-end - -// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be -// injected into the application via DefinePlugin in Webpack configuration. - -var REACT_APP = /^REACT_APP_/i; - -function getClientEnvironment(publicUrl) { - var processEnv = Object - .keys(process.env) - .filter(key => REACT_APP.test(key)) - .reduce((env, key) => { - env[key] = JSON.stringify(process.env[key]); - return env; - }, { - // Useful for determining whether we’re running in production mode. - // Most importantly, it switches React into the correct mode. - 'NODE_ENV': JSON.stringify( - process.env.NODE_ENV || 'development' - ), - // Useful for resolving the correct path to static assets in `public`. - // For example, . - // This should only be used as an escape hatch. Normally you would put - // images into the `src` and `import` them in code to get their paths. - 'PUBLIC_URL': JSON.stringify(publicUrl) - }); - return {'process.env': processEnv}; -} - -module.exports = getClientEnvironment; diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js index c2b544cca5..8671e4388e 100644 --- a/packages/react-scripts/config/webpack.config.dev.js +++ b/packages/react-scripts/config/webpack.config.dev.js @@ -16,7 +16,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); -var getClientEnvironment = require('./env'); +var envDefinePlugin = require('react-dev-utils/webpackEnvDefinePlugin'); var paths = require('./paths'); // Webpack uses `publicPath` to determine where the app is being served from. @@ -26,8 +26,6 @@ var publicPath = '/'; // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. var publicUrl = ''; -// Get environment variables to inject into our app. -var env = getClientEnvironment(publicUrl); // This is the development configuration. // It is focused on developer experience and fast rebuilds. @@ -195,9 +193,20 @@ module.exports = { inject: true, template: paths.appHtml, }), - // Makes some environment variables available to the JS code, for example: - // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`. - new webpack.DefinePlugin(env), + // Makes some environment variables available to the JS code + new webpack.DefinePlugin(envDefinePlugin({ + // Grab REACT_APP_* environment variables + regex: /^REACT_APP_/i, + customVariables: { + // Set NODE_ENV to development + 'NODE_ENV': JSON.stringify('development'), + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + 'PUBLIC_URL': JSON.stringify(publicUrl) + } + })), // This is necessary to emit hot updates (currently CSS only): new webpack.HotModuleReplacementPlugin(), // Watcher doesn't work well if you mistype casing in a path so we use diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index e0141b851b..b113ab012a 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -18,7 +18,7 @@ var ManifestPlugin = require('webpack-manifest-plugin'); var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); var url = require('url'); var paths = require('./paths'); -var getClientEnvironment = require('./env'); +var envDefinePlugin = require('react-dev-utils/webpackEnvDefinePlugin'); function ensureSlash(path, needsSlash) { var hasSlash = path.endsWith('/'); @@ -45,14 +45,6 @@ var publicPath = ensureSlash(homepagePathname, true); // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. var publicUrl = ensureSlash(homepagePathname, false); -// Get environment variables to inject into our app. -var env = getClientEnvironment(publicUrl); - -// Assert this just to be safe. -// Development builds of React are slow and not intended for production. -if (env['process.env'].NODE_ENV !== '"production"') { - throw new Error('Production builds must have NODE_ENV=production.'); -} // This is the production configuration. // It compiles slowly and is focused on producing a fast and minimal bundle. @@ -227,11 +219,21 @@ module.exports = { minifyURLs: true } }), - // Makes some environment variables available to the JS code, for example: - // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. - // It is absolutely essential that NODE_ENV was set to production here. - // Otherwise React will be compiled in the very slow development mode. - new webpack.DefinePlugin(env), + // Makes some environment variables available to the JS code + new webpack.DefinePlugin(envDefinePlugin({ + // Grab REACT_APP_* environment variables + regex: /^REACT_APP_/i, + customVariables: { + // It is absolutely essential that NODE_ENV is set to production here. + // Otherwise React will be compiled in the very slow development mode. + 'NODE_ENV': JSON.stringify('production'), + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + 'PUBLIC_URL': JSON.stringify(publicUrl) + } + })), // This helps ensure the builds are consistent if source hasn't changed: new webpack.optimize.OccurrenceOrderPlugin(), // Try to dedupe duplicated modules, if any: