20

I'm trying to post my SPA app that works fine locally but when I push it to Github Pages, the interior pages don't register if you navigate to them directly.

For example http://USER.github.io/PROJECT_NAME/ works but http://USER.github.io/PROJECT_NAME/about doesn't because theres no redirect or rewrite. The index.html is located at the root of the project.

tkiethanom
  • 537
  • 2
  • 6
  • 21
  • 3
    Build the app using hashbangs if you don't have the server resources to generate *the actual page being requested* for pushState URIs. – Quentin Mar 29 '16 at 22:10
  • when you say locally, do you mean using Jekyll? – bitoiu Mar 29 '16 at 22:11
  • No I haven't tried installing Jekyll. I wouldn't know how to configure it to do what I'm talking about. – tkiethanom Mar 29 '16 at 22:12
  • I could use hashes but I was wondering if there was something built in to handle this. It seems like there should be. – tkiethanom Mar 29 '16 at 22:14
  • 1
    As far as I know, hashbangs is the only way for now. Buth there is an issue https://github.com/isaacs/github/issues/408 – Alexey Sidash Mar 29 '16 at 22:45
  • @tkiethanom — You miss the point. If you are using real URLs then every URL shouldn't give you the homepage (and then depend on JavaScript to transform it into the page that the URL is supposed to reflect). – Quentin Mar 30 '16 at 06:49
  • @Quentin - I'm using React.js and my index.html page is pretty much empty. React-router reads the path and figures out what to display. Not sure why that is wrong. I think everyone else does it this way too. – tkiethanom Mar 30 '16 at 09:33
  • @tkiethanom — No, only people writing fragile apps that completely depend on JavaScript do it that way. Robust, search engine friendly apps have a server side backup. – Quentin Mar 30 '16 at 09:40
  • @Quentin - You're talking about isomorphism right? I'm not doing that for this small project. Would you be able to run that on Github Pages? – tkiethanom Mar 30 '16 at 17:13
  • @tkiethanom — No, because it needs server side support. Isomorphic JS is just one approach to implementing that though (it reuses the same JS server side and client side). – Quentin Mar 30 '16 at 17:53

9 Answers9

13

If you are creating react app and you want to use Browser router in your gh pages the solution is to create 404.html file in your root directory and copy all the content in index.html to 404.html after you have build your react-app.

When a user try accessing your page e.g https://successtar.github.io/teamwork/ GitHub will serve your index.html page while if a user try accessing https://successtar.github.io/teamwork/foo, since it does not exist, GitHub will serve the 404.html page which has same content as the index.html and with this you get your react app working as expected.

Here is the source code for the example https://github.com/successtar/teamwork/tree/gh-pages

UPDATE

You can automate the process for every time you run npm run build to auto generate the 404.html file.

First Step: install shx for cross platform commands as follow npm install shx --save-dev

Second Step: Go to your package.json in the scripts block replace "build": "react-scripts build" with "build": "react-scripts build && shx cp build/index.html build/404.html"

That is all.

Whenever you run npm run build the 404.html file will be auto generated.

successtar
  • 319
  • 3
  • 4
  • 1
    Hell even `mv index.html 404.html`. Works great thanks. – Joseph Garrone Oct 22 '20 at 20:10
  • it is good to keep both files. The 404.html file is just to act as fall back when GitHub can't serve your index.html file. – successtar Nov 05 '20 at 13:01
  • 3
    Just `cp index.html 404.html` – Nick Roz Sep 07 '21 at 15:14
  • Copying the `index.html` into `404.html` is the only solution that matches the real behavior of an NGINX or Apache redirect for single page applications. The other solutions do not allow reloading the page and triggering the `BrowserRouter` for React applications properly as they only redirect to the home page. – Amin NAIRI Dec 29 '21 at 09:11
8

Github pages allows you to create a 404.html page that will be shown each time ... there is a 404 error. If http://USER.github.io/PROJECT_NAME/about doesn't exists, it will show your 404.html content with the "not found" url as window.location.

So, this page can contain a script that redirect to a hashbang style route. eg : react router, even using clean urls (browserHistory) can understand a route like PROJECT_NAME/#/about and will automatically push to PROJECT_NAME/about.

That's ugly !

David Jacquel
  • 51,670
  • 6
  • 121
  • 147
  • This is closer to what I was looking for but I agree it doesn't look pretty. I can settle for hashes for now I guess. – tkiethanom Mar 30 '16 at 09:34
6

I just built this tiny package (for bower / npm) to solves that exact problem so I thought I'd share it here as an answer to your question,

https://github.com/websemantics/gh-pages-spa

If you include the package in your 404.html and index.html pages, it will redirect all the traffic to Index.html,

It supports Project and User/Org Pages type repositories, handles QueryStrings and comes with a working example,

Adnan
  • 191
  • 3
  • 5
2

Well, there is an easy way out. Create a file in the root directory of your github pages repository named 404.html. Contents of that file should be:

<!DOCTYPE html>
<html lang="en" id="htmlbody">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Loading...</title>
</head>
<body>
    <script>
        var doc = document.getElementById('htmlbody');
        xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4) {
                if (this.status == 200) {
                    doc.innerHTML = this.responseText;
                    doc.removeAttribute("id");
                }
                if (this.status == 404) doc.innerHTML = "Page not found.";
            }
        }
        xhttp.open("GET", "index.html", true);
        xhttp.send();
    </script>
</body>
</html>

Basically, that script just uses Javascript to perform an XHR on index.html and make the content the document.
I was reluctant to use document.body because I'm thinking of updating the whole document, but if it doesn't work, change doc variable to document.body.
Not sure if this works, so I'll really appreciate feedback.
Remember to use the same domain for the index.html else CORS will kick in.

scoochy
  • 693
  • 1
  • 6
  • 14
2

When a page is not found, 404 page is served to inform the user. Also, when a 404.html file exists, then that is served instead of the default one.

We can use this to our advantage by creating a 404.html file in the root of your project (where the index.html resides) with a meta tag that redirects to the index.html. Just replace "https://example.com" with your domain.

This worked for me, hope it does for you too!

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="refresh" content="0; URL='https://example.com'" />
    <title>404 - redirect</title>
</head>

<body></body>

</html>
asd0999
  • 51
  • 2
2

For me, I have always appreciated the simplest solution.

Just add one file, 404.html

Entire Contents:

<script>
    window.location.href = "/";
</script>

That's it! Hope it helps!

PaliKai
  • 45
  • 6
0

Add this code to your index.html and 404.html files:

  // if it's on index.html
  if (window.sessionStorage.path) {
  let path = window.sessionStorage.path; // gets the path saved on sessionStorage
  window.history.pushState(null, null, path); // push it on url
  window.sessionStorage.removeItem('path'); // removes from session

} else { // if it's on 404.html (path doens't exist)
  let path = window.location.pathname; // get the path url
  window.sessionStorage.path = path; // saves on sessionStorage
  window.location.href = '/'; // go to index
}
Maycow Moura
  • 6,471
  • 2
  • 22
  • 19
0

Created two files 404.md and 404.html

  1. 404.md should have below content:
---
permalink: /404.html
---
  1. 404.html should have the same content as index.html

this solved my issue for an Angular app.

Amith B
  • 327
  • 2
  • 11
0

Sorry for the late reply. GitHub will look for the 404.html file; if it is not found, GitHub will display its default page.

So you can create a 404.html file that redirects users to the index.html file.

For that, you need to use vanilla Javascript; see the example below.

404.html

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Page not found</title>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <script>
    const urlToRedirect = 'https://rajgohil07.github.io/todo-app-redux/'
    window.location = urlToRedirect;
  </script>
</body>

</html>

You can pass your project link to the urlToRedirect variable.

Raj Gohil
  • 209
  • 3
  • 6