将 CRA 创建的 React App(创建 React App)部署到具有不同 URL 路径的不同环境?

D. *_*rić 5 docker reactjs devops create-react-app

问题:

我们有一个 CRA(创建 React App)应用程序,我们需要将它部署到许多不同的环境中。我们正在使用Kubernetes来生成这些环境,因此我们将拥有许多环境,数量不是固定的。

问题是这些环境必须在相同的域名下并且必须具有相同的路径结构。(这是一项业务要求,我们无法影响它)。

环境示例:

https://www.example.com/company/app-env01/react_application/
https://www.example.com/company/app-env02/react_application/
https://www.example.com/company/app-env03/react_application/
https://www.example.com/company/app-env-foo/react_application/
https://www.example.com/company/app-env-bar/react_application/
https://www.example.com/company/app/react_application/
Run Code Online (Sandbox Code Playgroud)

所以固定结构是: https://www.example.com/company/app[-____]/react_application/

使其在单个环境中工作的方法是在脚本中指定PUBLIC_URLpackage.json build

https://www.example.com/company/app-env01/react_application/
https://www.example.com/company/app-env02/react_application/
https://www.example.com/company/app-env03/react_application/
https://www.example.com/company/app-env-foo/react_application/
https://www.example.com/company/app-env-bar/react_application/
https://www.example.com/company/app/react_application/
Run Code Online (Sandbox Code Playgroud)

这仅适用于一个环境env01在这种情况下),但我们需要将单个构建工件(静态文件包)部署到许多不同的环境,这些环境具有不同的PUBLIC_URLs。

这是否可以在不为每个环境构建应用程序的情况下实现?

我们如何构建工件:

我们的部署工件是一个Docker 镜像,它只是Nginx为之前构建的React 静态文件提供服务。

我们如何执行路由:

浏览器正在访问我们的Kubernetes Ingress,它剥离了路径并将请求转发到运行Nginx的 Docker 容器(在 K8S Pod 中)。Nginx为根目录下的 CRA 静态文件提供服务/

例子:

Browser
  ?
https://www.example.com/company/app-env01/react_application/
  ?
Ingress
  /
  ?
Nginx
  ?
Serves the CRA static files
Run Code Online (Sandbox Code Playgroud)

这很好用,问题(至少在我看来)出在React Router 中。我们正在basename动态设置,并且设置正确(https://reactrouter.com/web/api/BrowserRouter/basename-string)。问题(我假设)在这个PUBLIC_URL. 部署应用程序而不指定它是行不通的。并且需要在构建时知道。这是主要问题。

重要的:

  • 我们正在使用React Router,因此在部署应用程序时它必须正常工作
  • 我们希望在所有环境中部署单个构建工件(单个 Docker 映像)

D. *_*rić 4

解决方案

@Emile 让我考虑再次使用相对 URL,并配置 Nginx 来正确处理它。谢谢你!

将此位置块添加到 Nginx 配置中解决了问题:

  location ~ .(static)/(js|css|media)/(.+)$ {
    root   /usr/share/nginx/html;
    try_files $uri $uri/ /$1/$2/$3;
  }
Run Code Online (Sandbox Code Playgroud)

这是完整的配置(为了清楚起见进行了简化):

server {
  listen 80;
  
  # This rule internally redirects any relative requests for static files so that they start from the root
  # Example, it internally redirects `/RANDOM/SUBPATH/static/js/main.xxx.chunk.js` to `/static/js/main.xxx.chunk.js`
  # Effectively, it strips everything that comes before `/static...`
  location ~ .(static)/(js|css|media)/(.+)$ {
    root   /usr/share/nginx/html;
    try_files $uri $uri/ /$1/$2/$3;
  }

  location / {
    root   /usr/share/nginx/html;
    index  index.html;
    try_files $uri $uri/ /index.html;
  }
 
  error_page   500 502 503 504  /50x.html;
 
  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}
Run Code Online (Sandbox Code Playgroud)

进一步说明

使用相对 URL 最初不起作用的原因是:

这会工作得很好:

/company/app-env01/react_application/static/js/xxxxxxxx.chunk.js
Run Code Online (Sandbox Code Playgroud)

但这不会:

/company/app-env01/react_application/RANDOM/SUBPATH/static/js/xxxxxxxx.chunk.js
Run Code Online (Sandbox Code Playgroud)

我需要一种方法来“剥离”该/RANDOM/SUBPATH部分,无论该部分是什么,我通过添加上面列出的Nginx location块来实现它。