小编典典

在不同环境中运行的react.js redux生产构建中将环境变量呈现给浏览器

reactjs

https://github.com/gothinkster/react-redux-realworld-example-
app上的react
redux
realworld.io应用程序的自述文件说,请编辑,src/agent.js以将更API_ROOT改为指向不同的后端api实例。我们想要进行设置,以便API_ROOT可以由运行生产版本的多个环境(例如,“
staging”和“ live”)中不同的环境变量定义。

我们正在遵循12factor.net原则在openshift
kubernetes上的容器中运行,其中先构建代码,然后通过环境进行推广。我们可以使用一个命令来启动新环境,因此我们不想在代码中使用switch语句来命名每个环境并API_ROOT为每个环境硬编码后端。相反,我希望能够使用环境变量在全新环境中运行现有的生产构建容器映像,将其更改API_ROOT为指向我们要测试的正确后端API。

我看过许多不同的博客,stackoverflow答案和官方文档。主要问题在于,典型的解决方案process.env.API_ROOT在构建时“加入”
环境变量,否则会有一个开关将所有环境的详细信息硬编码到代码中。两者都不令人满意,因为我们希望能够在现有容器中获取最新的稳定代码,并使用在此运行的API在新环境中运行它。

到目前为止,我得到的最接近的内容是编辑代码,以将渲染process.env.API_ROOT<script>标记并将其设置在window.API_ROOT变量上。然后检查是否存在,在为API_ROOT定义const时使用默认值。这感觉非常具有侵略性,而且有点脆弱,我不清楚在示例应用程序中位于https://github.com/gothinkster/react-
redux-realworld-example-app处呈现此类脚本标签的最佳位置在哪里


阅读 285

收藏
2020-07-22

共1个答案

小编典典

react-create-
app的问题#578有一个很好的答案。
tibdex 建议使用使用public/env.js正确属性生成的,然后在index.htmladd中添加:

 <script src="%PUBLIC_URL%/env.js"></script>

env.js脚本可以在窗口上设置API_ROOT:

window.env={'API_ROOT':'https://conduit.productionready.io/api'}

agent.js可以检查window.env.API_ROOTelse默认值:

function apiRoot() {
  if( window.env.API_ROOT !== 'undefined') {
    return window.env.API_ROOT
  }
  else {
    return 'https://conduit.productionready.io/api'
  }
}

const API_ROOT = apiRoot();

该文件是如何从他未描述的环境变量中创建的,但我能够使npm start命令生成该文件。

Moorman 然后建议简单地编写一个可以为/env.js其他服务器提供服务的快递服务器index.html

const express = require('express');
const path = require('path');

const app = express();

app.use(express.static(path.join(__dirname, 'build')));

const WINDOW_ENV = "window.env={'API_ROOT':'"+process.env.API_ROOT+"'}\n";

app.get('/env.js', function (req, res) {
  res.set('Content-Type', 'application/javascript');
  res.send(WINDOW_ENV);
});

app.get('/*', function (req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(process.env.PORT);

为使该脚本正常运行,启动脚本package.json很简单:

"start": "PORT=8080 node server.js",

然后一切正常。如果API_ROOT在环境变量中定义,则会在server.js其上生成它window.envagent.js使用它。

更新 我将env.js的缓存时间设置为5分钟, res.setHeader("Cache-Control", "public, max- age=300");因为该设置很少更改。

更新
我读到了很多关于此主题的困惑,人们回答“改变您的工作流程以使其与工具的默认设置保持一致”。12要素的想法是使用作为工具应遵循的最佳实践而建立的工作流,而不是相反。特别是,带标签的生产就绪容器应可由环境变量配置,并通过环境进行提升。然后,经过调试和测试的“同一件事”就可以实时运行。在单页面应用程序的情况下,它要求浏览器访问服务器以加载环境变量,而不是将其烘焙到应用程序中。恕我直言,这个答案是一种简单易行的方法,可以遵循12要素最佳实践。

更新 :@mikesparr在https://github.com/facebook/create-react-
app/issues/982#issuecomment-393601963提供了一个很好的解决方案
这是为了重组package.json以便在启动时执行生成SPA的webapp工作。我们将此方法作为战术上的解决方法。我们正在使用saas
openshift
kubernetes来收取内存费用。使用webpack构建我们的React应用需要1.2Gb(并且还在不断增加!),因此将npm构建移到容器启动命令的这种方法需要为我们启动的每个pod分配1.2Gb,这对于单个页面来说是大量的额外费用应用程序,而我们可以在预编译应用程序时获得128MB的内存分配。Webpack步骤很慢,因为它是大型应用程序。每次启动应用程序时构建,都会使滚动部署速度降低几分钟。如果VM崩溃并且kubernetes在新VM上启动替换容器,则需要几分钟的时间来启动。预编译的应用程序将在几秒钟内启动。因此,在成千上万行代码的实际业务应用程序的资源消耗和速度方面,“启动时的webpack”解决方案并不令人满意。恕我直言,从服务器获取配置脚本的答案是非常好的。

2020-07-22