在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可能会抱怨apiUrl
和env
未定义。尤其是在更大的项目中,这种方法可能很难维护。
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]);