如何在create-react-app中注入没有REACT_APP前缀的dotenv变量?

IT技术 reactjs webpack create-react-app dotenv
2021-05-12 13:50:34

我有一个项目要从旧版 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更复杂。不确定是否可以以相同的方式实现。

3个回答

也用 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);

几年前, Dan Abramov(CRA 的共同创建者)建议重新定义变量以适应REACT_APP_入口点脚本,然后在 package.json 中调用 react-scripts。

如果您有更简单的需求来支持这些变量,例如像 NetlifyCOMMIT_REF或 Gitlab这样的 CI 平台变量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()
)