在ReactJS应用程序中,如何将全局环境中的环境变量替换到我的index.html文件中?

在ReactJS应用程序中,如何将全局环境中的环境变量替换到我的index.html文件中?,reactjs,npm,environment-variables,Reactjs,Npm,Environment Variables,我有一个ReactJS17应用程序,在其中我想将全局环境中的环境变量替换到我的src/index.html文件中。然而,我们没有使用.env文件,正如这个答案所暗示的--。这是src/index.html文件 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content=&qu

我有一个ReactJS17应用程序,在其中我想将全局环境中的环境变量替换到我的
src/index.html
文件中。然而,我们没有使用
.env
文件,正如这个答案所暗示的--。这是
src/index.html
文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
    
    ...
    <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="512x512">
    <script src="%REACT_APP_THIRD_PARTY_URL%"></script>
  </head>
  <body>
我正在开发模式下运行我的应用程序,使用
npmi
安装,并使用
npm run start
运行。但是,上面的替换从未进行过,页面将使用

<script src="%REACT_APP_THIRD_PARTY_URL%"></script>
编辑2:不确定这是否重要,但这在我的网页文件中

my package.json

{
  "name": "my_app",
  "version": "1.0.0",
  "description": "My desc",
  "main": "index.js",
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watchAll",
    "test:coverage": "jest --coverage",
    "build": "webpack --config webpack.production.js",
    "start": "webpack-dev-server --open --config webpack.development.js",
...
这是webpack.development.js文件

require('dotenv').config();
const { merge } = require('webpack-merge');
const common = require('./webpack.common');

const WEBPACK_WATCH_POLLING = process.env.WEBPACK_WATCH_POLLING === '1';

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
    publicPath: '/',
    historyApiFallback: true,
    disableHostCheck: true,
    hot: true,
    host: '0.0.0.0', 
    port: 8080,
  },
  output: {
    publicPath: '/',
  },
  // This is needed for docker-on-windows.
  watchOptions: !WEBPACK_WATCH_POLLING
    ? undefined
    : {
        poll: 1000,
      },
});
这是我的webpack.common文件

module.exports = {
  entry: './src/index.tsx',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json', '.css', '.scss'],
    alias: {
      '@': path.resolve('src'),
      '@sb': path.resolve('.storybook'),
      '@static': path.resolve('static'),
      common: path.resolve('src/components/common'),
    },
  },
  module: {
    rules: [
      {
        test: /\.(js|ts)x?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: true,
          },
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.(scss|css)$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.(jpe?g|gif|png)$/,
        use: {
          loader: 'url-loader',
        },
      },
      {
        test: /\.svg$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'icons/',
          },
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'fonts/',
          },
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      REACT_APP_THIRD_PARTY_URL: "http://google.com"
      //filename: './index.html',
    }),
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/manifest.json' },
        { from: 'static/**/*.{png,svg,ico}', flatten: true },
      ],
    }),
    new WorkboxWebpackPlugin.InjectManifest({
      swSrc: './src/service-worker.js',
    }),
    new EnvironmentPlugin([
      'NODE_ENV',
      'REACT_APP_THIRD_PARTY_URL',
    ]),
  ],
};
最后,我的src/index.tsx文件

import './monitor';
import * as serviceWorker from './sw-registration';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/app/App';
import './i18n.js';

ReactDOM.render(
  <React.StrictMode>
    <React.Suspense fallback={<div>Loading...</div>}>
      <App />
    </React.Suspense>
  </React.StrictMode>,
  document.getElementById('root')
);

serviceWorker.register();
import./monitor';
从“/sw注册”导入*作为serviceWorker;
从“React”导入React;
从“react dom”导入react dom;
从“./components/App/App”导入应用程序;
导入“/i18n.js”;
ReactDOM.render(
,
document.getElementById('root'))
);
register();

根据您的环境和构建工具,有几种可能的方法

我认为对您来说,最方便的方法是在构建时将它们提供给您的项目

  • 您可以动态生成
    index.html
    文件(通过使用模板引擎或为您执行作业的简单脚本),并通过从环境中读取所需变量来手动追加所需变量
  • 或者更优雅的解决方案-将此步骤集成到构建工具中。如果您正在使用
    webpack
    构建捆绑包,则可以使用
    HtmlWebpackPlugin
    为您构建
    index.html
    文件,其中包含所需的所有环境数据
  • 为此,请创建一个简单的
    .ejs
    .html
    文件,用作模板:

    <!DOCTYPE html>
    <html>
       <head>
          ...
          <script src="<%= htmlWebpackPlugin.options.thirdPartyData.url %>"></script>
       </head>
       <body></body>
    </html>
    
    Webpack
    将从环境中获取变量(通过
    节点
    ),并基于模板文件为您构建
    索引.html
    。您可以向插件提供任意数据,然后可以从
    htmlWebpackPlugin.options
    属性的模板中读取这些数据。你可以了解更多关于

    请注意,为了更改代码本身中的环境变量,您必须通过
    webpack
    进行重建,这是可以理解的

    此解决方案不需要您使用
    create react app
    .env
    文件,也不需要服务器/服务器渲染来为您执行此任务。请注意,它也完全在react应用程序的上下文之外工作(您不在react应用程序本身中,而是直接在
    .html
    标记上工作)


    另一种可能的方法是使用
    --env
    标志,通过
    npm脚本
    提供环境变量,但这将不方便您进行集成,因为它需要一些额外的工作


    评论后编辑

    这是一本书。由于codesandbox本身执行脚本的方式,提供的代码在codesandbox内部不起作用,但如果您在计算机上复制提供的示例,它将执行它应该执行的操作。为了测试它,您只需要
    index.html
    webpack.config.json
    package.json
    和一个虚拟的
    index.js
    。为了简洁起见,我已经删除了与react相关的代码

    只需下载codesandbox示例,运行
    npm安装
    ,然后
    npm启动

    然后可以将该方法迁移到特定的代码库


    编辑2

    好吧,我发现了问题。您的
    html加载程序
    会干扰
    HtmlWebpackPlugin
    ,并且不会替换模板中的变量。如果在webpack.config中注释掉
    html加载程序
    ,您会注意到转换是有效的。因此,最简单的解决方案是:

  • 创建一个新的
    index.html.ejs
    文件,并将其放在
    index.html
    旁边。这是一个实际正确的
    ejs
    模板。将
    index.html的当前内容放在那里:
  • index.html.ejs

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
        <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="512x512">
        <script src="<%= htmlWebpackPlugin.options.REACT_APP_THIRD_PARTY_URL %>"></script>
        ...
    </head>
    
    <body>
        ...
    </body>
    
    </html>
    
    此时,您甚至可以完全删除
    index.html
    ,因为它将由
    HtmlWebpackPlugin
    插件生成

    通过这种方式,您可以保留
    html加载程序
    转换(如果您真的需要它做任何事情),并获得插入的html文件。

    您可以在shell中添加程序包管理器(npm或Thread)可用于构建React应用程序的程序包


    您可以通过以下方式完成:

  • 通过添加临时变量:
  • $REACT\u APP\u第三方\u URL=http://thirdpartyurl.com npm启动
    

  • 通过添加临时变量(但来自全局shell变量)):
  • $REACT\u APP\u THIRD\u PARTY\u URL=$REACT\u APP\u THIRD\u PARTY\u URL npm start
    
    假设“REACT\u APP\u THIRD\u PARTY\u URL”定义为全局环境变量(打印
    $echo$REACT\u APP\u THIRD\u PARTY\u URL的值


    您可以类似地运行其他npm/THEAN命令,如“build”、“test”等,它将替换HTML中的值(

    使用不同的操作系统时会有细微的差别。以上示例适用于shell

    编辑: 如果您不想每次使用npm start或build命令编写这些长环境变量,可以在package.json中编写:

    “脚本”:{
    “开始”:“REACT\u APP\u THIRD\u PARTY\u URL=$REACT\u APP\u THIRD\u PARTY\u URL REACT\u APP\u other\u VAR=$REACT\u APP\u other\u VAR REACT scripts start”,
    ...
    }
    

    如果您使用的不是react脚本,而是webpack dev serverdi
    <!DOCTYPE html>
    <html>
       <head>
          ...
          <script src="<%= htmlWebpackPlugin.options.thirdPartyData.url %>"></script>
       </head>
       <body></body>
    </html>
    
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        ...
        plugins: [
            new HtmlWebpackPlugin({
                filename: 'index.html',
                template: '<PATH_TO_YOUR_TEMPLATE>',
                thirdPartyData: {
                    url: process.env.<YOUR_ENV_VARIABLE>
                }
            })
        ]
    };
    
    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
        <link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="512x512">
        <script src="<%= htmlWebpackPlugin.options.REACT_APP_THIRD_PARTY_URL %>"></script>
        ...
    </head>
    
    <body>
        ...
    </body>
    
    </html>
    
    new HtmlWebpackPlugin({
        template: './src/index.html.ejs',
        REACT_APP_THIRD_PARTY_URL: "http://google.com"
    })