你如何让子路径在 minikube 中为 create-react-app 工作?
How do you get subpaths to work for create-react-app in minikube?
认为这很简单,但显然并非如此。
我有两个 CRA 微服务 运行 位于:
/
/admin
minikube ip
是 192.168.64.5
,所以完整的路由在浏览器中应该是 192.168.64.5/
和 192.168.64.5/admin
。 Dockerfile.dev
只是每个都以 npm start
开头。
根路由工作正常,但是 /admin
我无法让静态文件在我的一生中正常服务...花了几个小时。我得到的只是 Uncaught SyntaxError: Unexpected token '<'
,这是由于静态文件未正确提供。
话虽如此,当我执行 npm build
或只是转到 localhost:3000/admin
时,Web 应用程序会得到正确的服务。 npm build
显然不适合开发。使用 localhost
只是绕过集群路由,因此可能在开发中发现的问题现在会出现在暂存中。如果我不能让它工作,我将不得不走那条路。
我已经尝试了 "homepage:"
和 basename={process.env.PUBLIC_URL}
,但没有解决问题:
# package.json
{
"name": "admin",
"version": "0.1.0",
"private": true,
"homepage": "/admin",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"history": "^5.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3"
},
"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"
]
}
}
# index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
export const history = createBrowserHistory({
basename: process.env.PUBLIC_URL
});
ReactDOM.render(
<Router basename={process.env.PUBLIC_URL}>
<Switch>
<Route path="/">
<App />
</Route>
</Switch>
</Router>,
document.getElementById("root")
);
serviceWorker.unregister();
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<base href="%PUBLIC_URL%/">
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<!-- <link rel="manifest" href="./manifest.json" /> -->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
另外,用.env
PUBLIC_URL
试过,效果和"homepage":
一样。
Normally, Create React App ignores the hostname.
但显然 minikube ip
和集群有一些不喜欢的地方。似乎这是一个很常见的要求,所以我可能忽略了一个直接的解决方案。
有什么建议可以让它正常工作吗?
# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
name: ingress-service-dev
namespace: default
spec:
rules:
- http:
paths:
- path: /admin/?(.*)
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4001
- path: /?(.*)
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
- path: /api/?(.*)
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
好的,显然问题出在 ingress.yaml
中的 nginx.ingress.kubernetes.io/rewrite-target: /
。我把它注释掉了,它开始工作了。
上面的index.html
、index.js
、package.json
没有变化,可以参考
我最后的ingress.yaml
是:
# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: ingress-service-dev
namespace: default
spec:
rules:
- http:
paths:
- path: /admin/
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4001
- path: /api/
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
- path: /
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
到目前为止没有任何问题,一切都按预期工作。
认为这很简单,但显然并非如此。
我有两个 CRA 微服务 运行 位于:
/
/admin
minikube ip
是 192.168.64.5
,所以完整的路由在浏览器中应该是 192.168.64.5/
和 192.168.64.5/admin
。 Dockerfile.dev
只是每个都以 npm start
开头。
根路由工作正常,但是 /admin
我无法让静态文件在我的一生中正常服务...花了几个小时。我得到的只是 Uncaught SyntaxError: Unexpected token '<'
,这是由于静态文件未正确提供。
话虽如此,当我执行 npm build
或只是转到 localhost:3000/admin
时,Web 应用程序会得到正确的服务。 npm build
显然不适合开发。使用 localhost
只是绕过集群路由,因此可能在开发中发现的问题现在会出现在暂存中。如果我不能让它工作,我将不得不走那条路。
我已经尝试了 "homepage:"
和 basename={process.env.PUBLIC_URL}
,但没有解决问题:
# package.json
{
"name": "admin",
"version": "0.1.0",
"private": true,
"homepage": "/admin",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"history": "^5.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3"
},
"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"
]
}
}
# index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
export const history = createBrowserHistory({
basename: process.env.PUBLIC_URL
});
ReactDOM.render(
<Router basename={process.env.PUBLIC_URL}>
<Switch>
<Route path="/">
<App />
</Route>
</Switch>
</Router>,
document.getElementById("root")
);
serviceWorker.unregister();
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<base href="%PUBLIC_URL%/">
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<!-- <link rel="manifest" href="./manifest.json" /> -->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
另外,用.env
PUBLIC_URL
试过,效果和"homepage":
一样。
Normally, Create React App ignores the hostname.
但显然 minikube ip
和集群有一些不喜欢的地方。似乎这是一个很常见的要求,所以我可能忽略了一个直接的解决方案。
有什么建议可以让它正常工作吗?
# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
name: ingress-service-dev
namespace: default
spec:
rules:
- http:
paths:
- path: /admin/?(.*)
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4001
- path: /?(.*)
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
- path: /api/?(.*)
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
好的,显然问题出在 ingress.yaml
中的 nginx.ingress.kubernetes.io/rewrite-target: /
。我把它注释掉了,它开始工作了。
上面的index.html
、index.js
、package.json
没有变化,可以参考
我最后的ingress.yaml
是:
# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: ingress-service-dev
namespace: default
spec:
rules:
- http:
paths:
- path: /admin/
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4001
- path: /api/
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
- path: /
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
到目前为止没有任何问题,一切都按预期工作。