Search code examples
reactjsdockerkubernetesreact-router-domnginx-ingress

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


Not sure if this is a Kubernetes, ingress-nginx, or ReactJS (create-react-app) issue...

Project Structure

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

Issue

  • ReactJS front-end should be running at 192.168.64.5/client when the cluster is spun up with Skaffold
  • Navigate to 192.168.64.5/client and blank screen
  • Developer Console shows:

enter image description here enter image description here

Basically, it is trying to serve static files from /static, but I need them to come from /client/static

Propsed Solutions

Assuming this is a ReactJS issue, the solutions have been the following:

None seem to work in my case. Still shows assets trying to be served from /static instead of /client/static.

ReactJS App Code

// 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 and Docker Manifests

# 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: /$1
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

So what am I doing wrong here?

EDIT:

I should note that things work fine when doing this though:

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

Repo to demo the issue:

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


Solution

  • Apparently, this is not possible currently in CRA in a dev environment:

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