如何在 create-react-app 中注入没有 REACT_APP 前缀的 dotenv 变量?
How to inject dotenv variables without REACT_APP prefix in create-react-app?
我有一个项目要从遗留 React 应用程序迁移到标准 create-react-app
应用程序(未弹出)。
在遗留项目中,它手动加载 .env
文件 dotenv
和 dotenv-expand
并通过 webpack DefinePlugin
.
注入
create-react-app
直观上支持dotenv
但只能识别前缀为REACT_APP_
的变量。
遗留代码以及其他存储库中导入的包中有很多地方使用 process.env.xxx
变量,因此现在不可能在迁移前用前缀重命名它们。
在这种情况下,如何让 create-react-app
识别没有 REACT_APP_
前缀的 dotenv 变量?
顺便说一句,我之前尝试 rewire
通过 webpack 进行一些简单的自定义来构建脚本,比如捆绑 js 和 css:
const path = require('path');
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
let webpackConfig = defaults.__get__('config');
webpackConfig.output.filename = 'static/js/[name].js';
webpackConfig.optimization.splitChunks = { cacheGroups: { default: false } };
webpackConfig.optimization.runtimeChunk = false;
webpackConfig.plugins.find(plugin => plugin.__proto__.constructor.name === 'MiniCssExtractPlugin').options.filename = 'static/css/[name].css';
webpackConfig.plugins.find(plugin => plugin.__proto__.constructor.name === 'MiniCssExtractPlugin').options.moduleFilename = () => 'static/css/[name].css';
不过好像dotenv
和DefinePlugin
比较复杂。不知道能不能用同样的方法实现。
也用rewire
// "start": "node start.js"
const rewire = require('rewire');
process.env.NODE_ENV = 'development';
let getClientEnvironment = rewire('react-scripts/config/env.js');
getClientEnvironment.__set__(
'REACT_APP',
/(^REACT_APP_|API|DEPLOY|SECRET|TOKEN|URL)/,
);
let configFactory = rewire('react-scripts/config/webpack.config.js');
configFactory.__set__('getClientEnvironment', getClientEnvironment);
let start = rewire('react-scripts/scripts/start.js');
start.__set__('configFactory', configFactory);
build
有点不同
// "build": "node build.js"
const rewire = require('rewire');
process.env.NODE_ENV = 'production';
let getClientEnvironment = rewire('react-scripts/config/env.js');
getClientEnvironment.__set__(
'REACT_APP',
/(^REACT_APP_|API|DEPLOY|SECRET|TOKEN|URL)/,
);
let configFactory = rewire('react-scripts/config/webpack.config.js');
configFactory.__set__('getClientEnvironment', getClientEnvironment);
let webpackConfig = configFactory('production');
let build = rewire('react-scripts/scripts/build.js');
build.__set__('config', webpackConfig);
Years ago Dan Abramov(CRA 的共同创建者)建议重新定义变量以适应入口点脚本中的 REACT_APP_
,然后在 package.json 中调用 react-scripts。
如果您有更简单的需求来支持这些变量,例如 CI Netlify 的 COMMIT_REF
或 Gitlab 的 CI_COMMIT_SHA
等平台变量,您可以直接设置这些变量而无需添加其他脚本。
"scripts": {
"start": "react-scripts start",
"build": "REACT_APP_COMMIT_SHA=$COMMIT_REF$CI_COMMIT_SHA react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
这会将 REACT_APP_COMMIT_SHA
设置为其内置服务的哈希值(因为其他变量将为空)。
我的解决方案是创建 config-overrides.js 并在构建时修改 process.env。
您仍然在 env 文件中定义了 REACT_APP_[VARIABLE NAME],并在构建时删除了前缀。
// config-overrides.js
const {
override,
} = require('customize-cra');
const ENV_PREFIX = /^REACT_APP_/i;
const findWebpackPlugin = (plugins, pluginName) =>
plugins.find((plugin) => plugin.constructor.name === pluginName);
const overrideProcessEnv = () => (config) => {
const plugin = findWebpackPlugin(config.plugins, 'DefinePlugin');
const processEnv = plugin.definitions['process.env'] || {};
const transformedEnv = Object.keys(processEnv)
.filter((key) => ENV_PREFIX.test(key))
.reduce((env, key) => {
const craKey = key.replace('REACT_APP_', '');
env[craKey] = processEnv[key];
return env;
}, {});
plugin.definitions['process.env'] = {
...processEnv,
...transformedEnv,
};
return config;
};
module.exports = override(
overrideProcessEnv()
)
我有一个项目要从遗留 React 应用程序迁移到标准 create-react-app
应用程序(未弹出)。
在遗留项目中,它手动加载 .env
文件 dotenv
和 dotenv-expand
并通过 webpack DefinePlugin
.
create-react-app
直观上支持dotenv
但只能识别前缀为REACT_APP_
的变量。
遗留代码以及其他存储库中导入的包中有很多地方使用 process.env.xxx
变量,因此现在不可能在迁移前用前缀重命名它们。
在这种情况下,如何让 create-react-app
识别没有 REACT_APP_
前缀的 dotenv 变量?
顺便说一句,我之前尝试 rewire
通过 webpack 进行一些简单的自定义来构建脚本,比如捆绑 js 和 css:
const path = require('path');
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
let webpackConfig = defaults.__get__('config');
webpackConfig.output.filename = 'static/js/[name].js';
webpackConfig.optimization.splitChunks = { cacheGroups: { default: false } };
webpackConfig.optimization.runtimeChunk = false;
webpackConfig.plugins.find(plugin => plugin.__proto__.constructor.name === 'MiniCssExtractPlugin').options.filename = 'static/css/[name].css';
webpackConfig.plugins.find(plugin => plugin.__proto__.constructor.name === 'MiniCssExtractPlugin').options.moduleFilename = () => 'static/css/[name].css';
不过好像dotenv
和DefinePlugin
比较复杂。不知道能不能用同样的方法实现。
也用rewire
// "start": "node start.js"
const rewire = require('rewire');
process.env.NODE_ENV = 'development';
let getClientEnvironment = rewire('react-scripts/config/env.js');
getClientEnvironment.__set__(
'REACT_APP',
/(^REACT_APP_|API|DEPLOY|SECRET|TOKEN|URL)/,
);
let configFactory = rewire('react-scripts/config/webpack.config.js');
configFactory.__set__('getClientEnvironment', getClientEnvironment);
let start = rewire('react-scripts/scripts/start.js');
start.__set__('configFactory', configFactory);
build
有点不同
// "build": "node build.js"
const rewire = require('rewire');
process.env.NODE_ENV = 'production';
let getClientEnvironment = rewire('react-scripts/config/env.js');
getClientEnvironment.__set__(
'REACT_APP',
/(^REACT_APP_|API|DEPLOY|SECRET|TOKEN|URL)/,
);
let configFactory = rewire('react-scripts/config/webpack.config.js');
configFactory.__set__('getClientEnvironment', getClientEnvironment);
let webpackConfig = configFactory('production');
let build = rewire('react-scripts/scripts/build.js');
build.__set__('config', webpackConfig);
Years ago Dan Abramov(CRA 的共同创建者)建议重新定义变量以适应入口点脚本中的 REACT_APP_
,然后在 package.json 中调用 react-scripts。
如果您有更简单的需求来支持这些变量,例如 CI Netlify 的 COMMIT_REF
或 Gitlab 的 CI_COMMIT_SHA
等平台变量,您可以直接设置这些变量而无需添加其他脚本。
"scripts": {
"start": "react-scripts start",
"build": "REACT_APP_COMMIT_SHA=$COMMIT_REF$CI_COMMIT_SHA react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
这会将 REACT_APP_COMMIT_SHA
设置为其内置服务的哈希值(因为其他变量将为空)。
我的解决方案是创建 config-overrides.js 并在构建时修改 process.env。 您仍然在 env 文件中定义了 REACT_APP_[VARIABLE NAME],并在构建时删除了前缀。
// config-overrides.js
const {
override,
} = require('customize-cra');
const ENV_PREFIX = /^REACT_APP_/i;
const findWebpackPlugin = (plugins, pluginName) =>
plugins.find((plugin) => plugin.constructor.name === pluginName);
const overrideProcessEnv = () => (config) => {
const plugin = findWebpackPlugin(config.plugins, 'DefinePlugin');
const processEnv = plugin.definitions['process.env'] || {};
const transformedEnv = Object.keys(processEnv)
.filter((key) => ENV_PREFIX.test(key))
.reduce((env, key) => {
const craKey = key.replace('REACT_APP_', '');
env[craKey] = processEnv[key];
return env;
}, {});
plugin.definitions['process.env'] = {
...processEnv,
...transformedEnv,
};
return config;
};
module.exports = override(
overrideProcessEnv()
)