在不同环境中运行的react.js redux生产构建中将环境变量呈现给浏览器 [英] Rendering an environment variable to the browser in a react.js redux production build running in different environments

查看:154
本文介绍了在不同环境中运行的react.js redux生产构建中将环境变量呈现给浏览器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The readme of the react redux realworld.io application at https://github.com/gothinkster/react-redux-realworld-example-app says to edit the src/agent.js to change the API_ROOT to point to a different backend api instance. We want to set things up so that API_ROOT can be defined by an environment variable that is different within the multiple environments (e.g., "staging" and "live") where we run the production build.

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

We are running in containers on openshift kubernetes following 12factor.net principles where the code is built once then promoted through environments. We can spin up new environments with a single command so we don’t want to have a switch statement within the code that names each environment and hardcodes the backend API_ROOT for each environment. Instead, I want to be able to run an existing production build container image in a fresh environment using an environment variable change the API_ROOT to point to the correct backend API we want to test against.

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

I have looked at a number of different blogs, stackoverflow answers and the official documentation. The main problem is that typical solutions "bake in" the process.env.API_ROOT environment variable at build time else have a switch that hardcodes the details of all environments into the code. Neither of which are satisfactory as we want to able to take the latest stable code in an existing container and run it in a new environment using the API running there.

到目前为止,我最接近的是编辑代码以将process.env.API_ROOT呈现为<script>标记,并将其设置在window.API_ROOT变量上.然后检查是否存在,在为API_ROOT定义const时使用默认值.这感觉非常具有侵略性,而且有点脆弱,我不清楚在

The closest I have got so far is to edit the code to render the process.env.API_ROOT into a <script> tag that sets it on a window.API_ROOT variable. Then check whether that exists else use a default when defining the const for API_ROOT. This feels very invasive and a bit fragile and it is not clear to me where is the best place to render such a script tag in the sample app at https://github.com/gothinkster/react-redux-realworld-example-app

推荐答案

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

Issue #578 of react-create-app has a good answer. tibdex suggested using a public/env.js that is generated with the correct properties then in the index.html add:

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

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

That env.js script can set the API_ROOT on the window:

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

并且agent.js可以检查window.env.API_ROOT否则为默认值:

And agent.js can check for the window.env.API_ROOT else default:

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命令生成该文件.

Exactly how that file is created from an environment variable he doesn't describe but I was able to have the npm start command generate it.

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

Moorman then suggested simply writing an express server that serves that /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中的启动脚本很简单:

To get that to work the start script in the package.json is simply:

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

然后一切正常.如果在环境变量中定义了API_ROOT,则server.js将在window.env上生成它,而agent.js将使用它.

Then everything works. If API_ROOT is defined in environment variables then the server.js will generate it on window.env and the agent.js will use it.

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

update I set a cache time of five minutes on env.js with res.setHeader("Cache-Control", "public, max-age=300"); as the setting is rarely going to change.

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

update I read a lot of confusion around this topic and people answering it along the lines of "change your workflow to align to the defaults of the tools". The idea of 12-factor is to use a workflow that is established as best practice that the tools should follow, not vice-versa. Specifically a tagged production ready container should be configurable by environment variables and promoted through environments. Then it's "the same thing" that is debugged and tested that runs in live. In this case of a single page app it requires that the browser makes a trip to the server to load the environment variables rather than baking them into the app. IMHO this answer is a straightforward and simple way of doing that to be able to follow 12-factor best practices.

更新:@mikesparr在

update: @mikesparr gives a good answer to this problem at https://github.com/facebook/create-react-app/issues/982#issuecomment-393601963 which is to restructure the package.json to do the webapp work of generating the SPA upon start up. We took this approach as a tactical workaround. We are using a saas openshift kubernetes that charges for memory. Building our react app with webpack needs 1.2Gb (and rising!) So this approach of moving the npm build to the container startup command we need to allocate 1.2Gb to every pod we start which is a significant amount of additional costs for a single page app whereas we can get away with 128MB as the memory allocation when the app is precompiled. The webpack step is also slow as it is a large app. Building every time we start up the app slows down rolling deployments by many minutes. If a VM crashes and kubernetes starts replacement containers on a new VM it takes minutes to start up. A precompiled app starts in a few seconds. So the solution of "webpack at startup" is not satisfactory in terms of resource consumption and speed for real business application that are tens of thousands of lines of code. IMHO this answer of fetching a configuration script from the server is superior.

这篇关于在不同环境中运行的react.js redux生产构建中将环境变量呈现给浏览器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆