构建一次,并在多个环境中部署构建文件,而更改最小的REACT和WEBPACK



在webpack.config文件中声明了一个要在应用程序中读取的变量。

let BASEURL = "http://127.0.0.1:8090";

使用这种方法,我无法在npm run build之后更新baseurl。如果baseurl更改,我想为每个环境生成新的构建。

有什么方法可以构建一次并在多个环境中部署构建文件?

tl; dr :使用ajax并在react上下文中或在全局变量中具有配置。


详细答案:

确实是您所说的,在使用npm run build构建应用程序后,环境变量变得硬连线并且无法更改。

create-react-app的官方说明是一旦部署了许多原则,就不会支持构建。来自https://create-react-app.dev/docs/adding-custom-envorirnment-variables/:

环境变量在构建时间内嵌入。由于Create React应用程序会产生静态HTML/CSS/JS捆绑包,因此可能在运行时读取它们。

但是,有一些方法可以实现该原则,只是更复杂。这个想法是,您需要从外部来源获得运行时变量的值,例如阿贾克斯。在更多详细信息中,可能的解决方案可能(但不限于(以下:

1。服务器端占位符替换

这是create-react-app提出的解决方案在向客户端渲染之前,介绍自定义占位符并用服务器上的数据替换。

<!doctype html>
<html lang="en">
  <head>
    <script>
      window.SERVER_DATA = __SERVER_DATA__;
    </script>

在工作时,它引入了一个主要的开销,因为它将整个后端实现归取决于您。根据您的技术堆栈,实施可能非常容易或非常复杂。

2。分配变量值

的动态<script>

在https://www.cotyhamilton.com/build-once-deploy-anywhere-for-react-applications/中提出了一种解决方案。在动态下载的config.js文件中,将值分配给变量。在其余的React代码中,读取和使用该变量。您可以随时更改config.js文件,而无需重新编译React应用程序。

// public/config.js
const apiUrl = 'localhost:1337';
const env = 'development';
<!-- public/index.html -->
<script src="%PUBLIC_URL%/config.js"></script>
<script>
  window.config = { apiUrl, env };
</script>

主要缺点是这不支持打字稿,并且您的IDE或LINTER可能会抱怨apiUrlenv未定义。尤其是在更大的项目中,这种方法可能很难维护。

3。带有Ajax的动态配置,并具有打字稿支持

基于第二个解决方案,本文https://profinit.eu/en/blog/blog/build-once-deploy-many-many-iny-iny-iny-inct-dynamic-configuration-properties/详细描述构建一旦用create-react-app部署了许多原则,什么是利弊。

它建议将动态配置下载为带有AJAX的JSON。主要警告是要确保在某些代码轮胎之前下载动态配置。在React Lifecycle的背景下,有两种方法可以实现这一目标。

3.1全局变量

globalConfigUrl下载动态配置JSON,将其存储在全局变量中,然后渲染React应用程序。打字稿中的示例:

// index.tsx:
import axios from "axios";
import React, {ReactElement} from "react";
import App from "./App";
import {globalConfig, globalConfigUrl} from "./configuration/config";
axios.get(globalConfigUrl)
  .then((response) => {
    globalConfig.config = response.data; // THIS IS THE IMPORTANT LINE
    return <App />;
  })
  .catch(e => {
      return <p style={{color: "red", textAlign: "center"}}>Error while fetching global config</p>;
  })
  .then((reactElement: ReactElement) => {
    ReactDOM.render(
      reactElement,
      document.getElementById("root")
    );
  });

完整的工作示例:https://codesandbox.io/s/build-once-deploy-many-global-config-object-object-dvpzr

3.2。反应上下文

将您的<App>组件与包含配置的React上下文提供商(具有undefined或某些默认值(。获取配置首次渲染App,然后将其值保存到上下文中。React将照顾其余的,并将传播价值变化!

完整的工作示例:https://codesandbox.io/s/build-once-deploy-many-reactext-context-7lk7g

基本思想是这样。检查上面的文章/工作示例以获取所有详细信息:

// App.tsx
import {useConfig} from "./configuration/useConfig";
// ... in the method: 
  const { setConfig } = useConfig(); // the `useConfig` is a custom hook, wrapping a React context. See the full working example for all details
  useEffect(() => {
    axios
      .get(dynamicConfigUrl)
      .then((response) => {
        setConfig(response.data);
      })
  }, [setConfig]);