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

2024-05-17

React redux realworld.io 应用程序的自述文件位于https://github.com/gothinkster/react-redux-realworld-example-app 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 into a <script>标签将其设置为window.API_ROOT多变的。然后检查是否存在,否则在定义 API_ROOT 的 const 时使用默认值。这感觉非常具有侵入性并且有点脆弱,我不清楚在示例应用程序中渲染此类脚本标签的最佳位置在哪里https://github.com/gothinkster/react-redux-realworld-example-app https://github.com/gothinkster/react-redux-realworld-example-app


问题 #578 https://github.com/facebook/create-react-app/issues/578React-create-app 有一个很好的答案。tibdex建议使用public/env.js是用正确的属性生成的,然后在index.html add:

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

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

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

And 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 else 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会使用它。

update我在 env.js 上设置了五分钟的缓存时间res.setHeader("Cache-Control", "public, max-age=300");因为设置很少会改变。

update我读到了很多围绕这个主题的困惑,人们的回答都是“改变你的工作流程以与工具的默认设置保持一致”。 12 因素的想法是使用作为工具应遵循的最佳实践而建立的工作流程,而不是反之亦然。具体来说,标记的生产就绪容器应该可以通过环境变量进行配置并通过环境进行升级。然后是经过调试和测试并实时运行的“同一件事”。在这种单页应用程序的情况下,它要求浏览器访问服务器来加载环境变量,而不是将它们烘焙到应用程序中。恕我直言,这个答案是一种简单明了的方法,能够遵循 12 因素最佳实践。

update:@mikesparr 对此问题给出了一个很好的答案https://github.com/facebook/create-react-app/issues/982#issuecomment-393601963 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”的解决方案对于数万行代码的真实业务应用来说,无论是资源消耗还是速度都不能令人满意。恕我直言,这个从服务器获取配置脚本的答案是更好的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 如何使用 vanilla JS 实现可维护的反应式 UI

    今天我遇到了一个问题 可以通过使用像 Vue 这样的反应式和状态管理框架来轻松解决 遗憾的是 无法使用它 以下 简化 情况 链接到代码笔 https codepen io theiaz pen BazErKV 我们有一个服务器渲染的页面 其
  • XAML 中的 CSS 等效项

    在 Web 开发中 样式表非常常用 Swing 中有用于处理 GUI 的布局管理器 我关于 XAML 应用这些范例之一的假设是否正确 两个都 在这种情况下 哪一个是首选 我已经检查过 Intellisense 但除了Style领域 我没有发
  • 如何在 Angular 项目中使用 Bootstrap?

    我开始我的第一次Angular应用程序和我的基本设置已完成 我怎样才能添加引导程序我的申请 如果您可以提供一个示例 那么这将是一个很大的帮助 如果您使用Angular CLI要生成新项目 还有另一种方法可以使 bootstrap 可访问角度
  • 是否有与 C++11 emplace/emplace_back 函数类似的 C# 函数?

    从 C 11 开始 可以写类似的东西 include
  • IntelliJ IDEA 覆盖 $user

    这是一个非常简单的问题 但我无法使用 SO Search 和 Google 找到答案 是否可以覆盖默认值 userVTL变量在文件模板中全局使用 而不是在每个模板中设置它 set user 就像 IntelliJ 本身的某种设置脚本一样 我
  • 有没有办法在 MS Windows(Powershell 或 CMD)的 ripgrep 中转义引号?

    我想找一个字符串 Hello Hello 以双引号开头 在文本文件中使用ripgrep 通常 在 Bash 或 ZSH 中 这可以通过用反斜杠转义或用单引号括起来来实现 rg Hello rg Hello 然而 在 MS Windows P
  • NSCFData fastCharacterContents 崩溃? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我目前在控制台中收到此崩溃日志 20
  • Oracle即时客户端和Oracle客户端之间的区别

    Oracle即时客户端和Oracle客户端有什么区别 你能给我解释一下吗 谢谢 Oracle 客户端附带一个安装程序和许多可执行文件 例如 sqlplus tnsping 很完整而且很大 Oracle Instant 客户端是一个基本的轻量
  • 获取点击的的DOM路径

    HTML div class lol a class rightArrow href a div 伪代码 rightArrow click function rightArrowParents this dom dom is the pse
  • 在 Android 中上传文件出现内存不足错误

    我的上传代码如下 String end r n String twoHyphens String boundary try URL url new URL ActionUrl HttpURLConnection con HttpURLCon
  • 自托管 WCF REST 服务和基本身份验证

    我创建了一个自托管的 WCF REST 服务 带有 WCF REST Starter Kit Preview 2 中的一些额外内容 这一切工作正常 我现在正在尝试向服务添加基本身份验证 但我在 WCF 堆栈中遇到了一些相当大的障碍 这阻止了
  • 以编程方式在 App Store 上运行搜索?

    是否可以从我的应用程序中打开 App Store 应用程序并运行搜索 我想看看是否有一个 appstore 类型的 URL 可以使用 就像 mailto 和 sms 分别打开邮件和短信一样 有谁知道这是否可能 编辑 更多信息 我一直在尝试使
  • 使用 EmberData 在本地存储中缓存远程数据

    我有一个关于使用 Ember 加载和缓存远程对象的问题 我正在开发一个 Ember 应用程序 它通过 REST API 使用服务器端存储 一些获取的数据很少发生变化 因此每次应用程序加载时都从服务器获取数据是不必要的 但这对于需要离线工作并
  • 为什么 std::allocator 在 C++17 中丢失成员类型/函数?

    一边看着std 分配器 http en cppreference com w cpp memory allocator 我看到成员 value type pointer const pointer reference const refer
  • Xamarin Android:获取内存中的所有进程

    有没有办法读取所有进程 而不仅仅是正在运行的进程 如果我对 Android 的理解正确的话 一次只有一个进程在运行 其他所有进程都被冻结 后台进程被忽略 您可以使用以下代码片段获取当前正在运行的所有 Android 应用程序进程 Activ
  • 如何在php中使用preg添加html属性

    我正在寻找在 php 中编写一个脚本来扫描 html 文档并根据它找到的内容向元素添加新标记 更具体地说 我是扫描文档并为每个元素搜索CSS标记 float right left 如果找到它 它会添加align right left 基于它
  • hive sql查找最新记录

    该表是 create table test id string name string age string modified string 像这样的数据 id name age modifed 1 a 10 2011 11 11 11 1
  • Django - 提交具有同一字段多个输入的表单

    预警 我对 Django 以及一般的 Web 开发 非常陌生 我使用 Django 托管一个基于 Web 的 UI 该 UI 将从简短的调查中获取用户输入 通过我用 Python 开发的一些分析来提供输入 然后在 UI 中呈现这些分析的可视
  • 合并数据框而不重复行

    我想合并两个数据框 但如果有多个匹配项 则不想重复行 相反 我想总结一下那天的观察结果 来自 合并 提取两个数据框中与指定列匹配的行并将其连接在一起 如果有多个匹配项 则所有可能的匹配项各贡献一行 这是一些示例代码 days lt as d
  • 在不同环境中运行的react.js redux生产构建中将环境变量渲染到浏览器

    React redux realworld io 应用程序的自述文件位于https github com gothinkster react redux realworld example app https github com goth