1

After deploying my GitHub portfolio project (source repo) using:

react-scripts build --entry ./src/index.jsx
npx gh-pages -d build

The final deployed page has nothing inside <div id="root"></div>.

I've had a successful deployment with a fresh test react app.

npx create-react-app test

And when I slowly migrate code to the test react app here are the results:

  1. [successful] package.json and index.jsx
  2. [fail] App.jsx and remaining components

Here is a portion of my code, full code can be found in the source repo linked above:

package.json

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "homepage": "https://ltbd78.github.io/test",
  "dependencies": {
    "@emailjs/browser": "^3.10.0",
    "@fortawesome/free-brands-svg-icons": "^6.2.1",
    "@fortawesome/free-solid-svg-icons": "^6.2.1",
    "@fortawesome/react-fontawesome": "^0.2.0",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "animate.css": "^4.1.1",
    "loaders.css": "^0.1.2",
    "prettier": "^2.8.4",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-leaflet": "^4.2.0",
    "react-loaders": "^3.0.1",
    "react-router-dom": "^6.8.1",
    "react-scripts": "5.0.1",
    "sass": "^1.58.0",
    "serve": "^14.2.0",
    "web-vitals": "^2.1.4"
  },
  "devDependencies": {
    "gh-pages": "^5.0.0"
  },
  "scripts": {
    "start": "react-scripts start --entry ./src/index.jsx",
    "build": "react-scripts build --entry ./src/index.jsx",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "prettier": "npx prettier --write .",
    "predeploy": "npm run build",
    "deploy": "npx gh-pages -d build",
    "serve": "npx serve -s build"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

index.jsx

import "./index.scss";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import React from "react";
import ReactDOM from "react-dom/client";
import reportWebVitals from "./reportWebVitals";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: 
reportWebVitals();

App.jsx

import "./App.scss";
import { Routes, Route } from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import Layout from "./components/Layout";

export default function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
      </Route>
    </Routes>
  );
}
Linsu Han
  • 135
  • 1
  • 8

1 Answers1

1

You are using react-router, so you will need to specifiy a basename atrribute to the Router.

import React from 'react';
import {
    BrowserRouter as Router,
    Routes,
    Route,
    Link
} from "react-router-dom";

import './App.scss';
import {Home} from "./views/home/Home";
import {Counter, CounterClassic} from "./views/counter";
import {ListItems} from "./views/list-rendering/ListItems";
import {TodoContainer} from "./views/todos/TodoContainer";

function App() {
    return (
        <Router basename={process.env.REACT_APP_URI}>
            <nav>
                <Link to="">Home</Link>
                <Link to="counter">Counter</Link>
                <Link to="counter-classic">Counter (classic)</Link>
                <Link to="list-rendering">List rendering</Link>
                <Link to="todo-list">TODO List</Link>
                <a target="_blank"
                   href="https://github.com/sombriks/react-studies" 
                   rel="noreferrer">See on github</a>
            </nav>
            <Routes>
                <Route path="" element={<Home/>}/>
                <Route path="counter" element={<Counter/>}/>
                <Route path="counter-classic"
                       element={<CounterClassic/>}/>
                <Route path="list-rendering"
                       element={<ListItems items={[
                           {id: 1, label: "One"},
                           {id: 2, label: "two"}]}/>}/>
                <Route path="todo-list" element={<TodoContainer/>}/>
            </Routes>
        </Router>
    );
}

export default App;

More detailed explanation here.

Sombriks
  • 3,370
  • 4
  • 34
  • 54
  • Still new to React, forgive me for my dumb follow-up question: Do I place it in my `App.jsx` `` OR `index.jsx` `` – Linsu Han Mar 23 '23 at 22:21
  • you are using react-router 6, therefore your BrowserRouter can be aliased as just Router https://github.com/sombriks/react-studies/blob/main/src/App.tsx no need to keep two Routers. see the article and the github repo with working source code to get the general idea. The source code has a quite handy github action to publish on gh-pages and the article explains a little how things ended up using that `process.env.REACT_APP_URI`. – Sombriks Mar 23 '23 at 22:29
  • So I tried editing `index.jsx` replacing `` with both `` and then ``. Neither worked on gh-pages. The latter errors when running locally. Am I implementing your solution incorrectly? – Linsu Han Mar 23 '23 at 22:43
  • Thanks to your blog, I got closer to the solution! Apparently keeping everything else unchanged and editing my `App.jsx` from `}>` to `}>` allowed my home page to render on GitHub! There was no need to add the `basename` parameter. The drawback is that now my localhost starts at: `http://localhost:3000/portfolio/` instead of `http://localhost:3000/`. I think your solution allows it work for both `/` and `/portfolio` right? If so, that's the next step I'm trying to figure out. – Linsu Han Mar 23 '23 at 23:02
  • 1
    i just opened a pull request, easier to test using the local script rather than pushing to gh-pages every time https://github.com/ltbd78/portfolio/pull/1 – Sombriks Mar 23 '23 at 23:13
  • 1
    I merged it with a test branch and deployed, and both local (/) and gh-pages (/portfolio) appears to be working! I'll take some time to digest your code and then update my master to reflect the changes. Thank you so much! – Linsu Han Mar 24 '23 at 00:03
  • One follow-up question I have, how does react know to read `.env.development` and `.env.production`? I don't see the `packages.json` reference it in any of the scripts. – Linsu Han Mar 24 '23 at 00:11
  • 1
    @LinsuHan the dotenv files are read by CRA itself, doing the poper transformations to the final output: https://create-react-app.dev/docs/adding-custom-environment-variables/ – Sombriks Mar 24 '23 at 01:20
  • According to the doc, it looks like variables without the prefix `REACT_APP_` is ignored? If so, what is the purpose of including the `PUBLIC_URL` env variable? – Linsu Han Mar 24 '23 at 19:21
  • 1
    That one is special: "Apart from a few built-in variables (NODE_ENV and PUBLIC_URL), variable names must start with REACT_APP_ to work." – Sombriks Mar 24 '23 at 19:33
  • So one drawback with BrowserRouter I noticed is when I refresh the github page, I get a 404 (explained [here](https://stackoverflow.com/a/36623117/6535624)). It looks like HashRouter is a good solution to this but I can't seem to get the right basename so that it works on github; do you have any ideas? (For now I'm using MemoryRouter as a placeholder). – Linsu Han Mar 24 '23 at 20:38
  • 1
    sadly not, the 404 happens because this is the way real links work. using github pages we are unable to do the url rewrite to index.html where react routes could then kick in. more details at https://create-react-app.dev/docs/deployment/#notes-on-client-side-routing – Sombriks Mar 24 '23 at 21:28