reactjs - 在不同环境中运行的react.js redux生产构建中将环境变量渲染到浏览器

标签 reactjs react-redux 12factor

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

我们在 openshift kubernetes 上的容器中运行,遵循 12factor.net 原则,其中代码构建一次,然后通过环境进行推广。我们可以使用单个命令启动新环境,因此我们不想在代码中使用 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 中渲染此类脚本标签的最佳位置在哪里。

最佳答案

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

 <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_ROOT否则默认:

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 的 Express 服务器。否则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.env 上生成它和 agent.js会使用它。

更新 我在 env.js 上使用 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 步骤也很慢,因为它是一个大型应用程序。每次启动应用程序时进行构建都会使滚动部署速度减慢很多分钟。如果虚拟机崩溃并且 kubernetes 在新虚拟机上启动替换容器,则需要几分钟才能启动。预编译的应用程序将在几秒钟内启动。所以“启动时webpack”的解决方案对于数万行代码的真实业务应用来说,无论是资源消耗还是速度都不能令人满意。恕我直言,从服务器获取配置脚本的答案是优越的。

关于reactjs - 在不同环境中运行的react.js redux生产构建中将环境变量渲染到浏览器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49975735/

相关文章:

javascript - 使用 Redux/React 移动数组中的项目

docker - 如何在 docker 中动态配置应用程序属性文件

java - 12 因素应用程序配置和 Java

linux - 需要澄清十二要素应用程序声明中的第八要素和守护进程

reactjs - 用 react 钩子(Hook)构建的振荡器不会停止

javascript - 如何自定义延迟加载页面之间共享的 React 组件的样式?

reactjs - Reactjs 中的常规 400/500 错误处理

reactjs - REACT JS 类生命周期 : How to put http request in ComponentdidUpdate?

javascript - 如何在 reactjs 中验证表单

javascript - 如何在 React 中正确地将 css 文件包含在我的 index.html 文件中?