basename 和 homepage 未按预期工作以在开发中提供 /static/ 文件

basename and homepage not working as expected to serve /static/ files in development

不确定这是 Kubernetes、ingress-nginx 还是 ReactJS (create-react-app) 问题...

项目结构

new-app/
  client/
    src/
      App.js
      index.js
      Test.js
    package.json
  k8s/
    client.yaml
    ingress.yaml
  server/
  skaffold.yaml

问题

基本上,它试图提供来自 /static 的静态文件,但我需要它们来自 /client/static

建议的解决方案

假设这是一个 ReactJS 问题,解决方案如下:

None 似乎适用于我的情况。仍然显示尝试从 /static 而不是 /client/static.

提供的资产

ReactJS 应用代码

// App.js

import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import './App.css';

import Test from './Test';

const App = () => {
  return (
    <BrowserRouter
      basename='/client'>
        <>
          <Route exact path='/' component={Test} />
        </>
    </BrowserRouter>

  );
}

export default App;
// Test.js

import React, { useState, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';

const Test = () => {

  const [data, setData] = useState('');

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios('/api/auth/test/');
      setData(result.data);
    };
    fetchData();
  }, []);

  return (
    <div className='App'>
    <header className='App-header'>
      <img src={logo} className='App-logo' alt='logo' />
      <p>
        Edit <code>src/App.js</code> and save to reload!
      </p>
      <p>
        {data}
      </p>
      <a
        className='App-link'
        href='https://reactjs.org'
        target='_blank'
        rel='noopener noreferrer'
      >
        Learn React
      </a>
    </header>
    </div>    
  )

};

export default Test;
{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "homepage": "/client",
  "dependencies": {
    "axios": "^0.19.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.2.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Kubernetes/Skaffold 和 Docker 清单

# Dockerfile.dev

FROM node:alpine
EXPOSE 3000
WORKDIR '/app'
COPY ./client/package.json ./
RUN npm install
COPY ./client .
CMD ["npm", "run", "start"]
# ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /client/?(.*)
            backend:
              serviceName: client-cluster-ip-service
              servicePort: 3000
# client.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      component: client
  template:
    metadata:
      labels:
        component: client
    spec:
      containers:
        - name: client
          image: clientappcontainers.azurecr.io/client
          ports:
            - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: client-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: client
  ports:
    - port: 3000
      targetPort: 3000
# skaffold.yaml

apiVersion: skaffold/v1beta15
kind: Config
build:
  local:
    push: false
  artifacts:
    - image: clientappcontainers.azurecr.io/client
      docker:
        dockerfile: ./client/Dockerfile.dev
      sync:
        manual:
          - src: "***/*.js"
            dest: .
          - src: "***/*.html"
            dest: .
          - src: "***/*.css"
            dest: .
deploy:
  kubectl:
    manifests:
      - manifests/ingress.yaml 
      - manifests/client.yaml

那么我做错了什么?

编辑:

我应该注意到,这样做时一切正常:

- path: /?(.*)
  backend:
    serviceName: client-cluster-ip-service
    servicePort: 3000

回购演示问题:

https://github.com/eox-dev/subdir-issue

Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in package.json (homepage). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the URL you provide (hostname included). This may be particularly useful when using a CDN to host your application.

解决这个问题的方法有以下三种:

  1. 将你的 basename 添加到 webpack 输出 -> publicPath(如果你 rejected 你的 create-react-app 项目并且你已经访问 webpack 配置文件)
  2. 将 PUBLIC_URL="/client" 添加到 .env.production 文件
  3. 主页 属性 添加到 package.json 文件中,如下所示:
{
  ...
  homepage: "/client"
  ...
}

参考:

https://create-react-app.dev/docs/advanced-configuration/

显然,目前在开发环境中的 CRA 中这是不可能的:

https://github.com/facebook/create-react-app/issues/8222#issuecomment-568308139

目前,要在生产环境中使用不同的主页,使用 CRA(或 craco),您需要设置

# .env.production
PUBLIC_URL="/client" 

在文件 .env.production 中(或者 .env.development 如果开发中的根路径不同)然后更改路由器的基本名称:

<BrowserRouter basename={process.env.PUBLIC_URL}>
  ...
</BrowserRouter>