13

I have deployed the contents of my /dist folder in the master branch of christopherkade.github.io, which has deployed my website succesfully.

But when I navigate using the navbar (christopherkade.com/posts or christopherkade.com/work) and reload the page I get an error by Github pages:

404 File not found

Note that my routing is done using Vue router like so:

export default new Router({
  mode: 'history',
  routes: [    
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/work',
      name: 'Work',
      component: Work
    },
    {
      path: '/posts',
      name: 'Posts',
      component: Posts
    },
    { path: '*', component: Home }
  ]
})

And my project is built like such:

build: {
    // Template for index.html
    index: path.resolve(__dirname, '../docs/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../docs'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }

What could be causing this issue?

Christopher
  • 1,712
  • 2
  • 21
  • 50

7 Answers7

17

But when I navigate using the navbar (christopherkade.com/posts or christopherkade.com/work) and reload the page 404 File not found

Let me explain why 404 File not found is being shown

When christopherkade.com/posts is triggered from web browser, the machine to which the domain christopherkade.com is mapped is contacted.

The path /posts is searched in its server. in your case, i believe the route for /posts doesn't exist in the server. As the result 404 is displayed

There are few ways to fix this

To prevent the browser from contacting the server when triggering the request christopherkade.com/posts, you can keep mode : 'hash' in your route configuration

How mode : 'hash' works? This is one way to fix your issue

mode : 'hash' makes use of default browser behavior which is to prevent http request from triggering the details that exists after #

As the result, when you trigger christopherkade.com/#/posts , christopherkade.com is being triggered by the browser and once response is received the /posts route from the route config is invoked.

Lets assume that you have control over the server and you are adamant that you need # to be removed from the URL

Then what you could do is to configure server in such a way that server responds with the same page everytime any paths is being sent. Once response is received in the browser, route will automatically kicked off.

Even in your current program, the routeConfig gets kicked off when you click any links (like work,posts) in your page. This is because the browser behavior is not being invoked at this point.

enter image description here

In your case, you use github for hosting this app with mode: 'history' i myself have to look for a specific solution to workaround this. i will update my answer once i get it.

i hope this was useful.

divine
  • 4,746
  • 3
  • 27
  • 38
  • have you been able to get a workaround. Just got that error and wanted to know if there is another way other than using Nuxt js – amaugo somto Nov 11 '19 at 05:25
  • 2
    @amaugosomto using `hash` seems to be the only solution – divine Nov 11 '19 at 08:59
  • this explaination is good and quite complete.But why do we not have this behaviour when working on local ? Refreshing a page on local server does not show a 404 error, even with mode history, I don't understand the difference with deployment. – Benoit Poux Nov 11 '20 at 15:35
  • 1
    @BenoitPoux this is how browsers handle web requests that are initiated by the webpage. this issue will arise while working with hosting providers like github pages,s3 ..etc and also if you host your static pages behind a reverseProxy like nginx. The way localserver works doesnot reflect the actual working of a production grade server. – divine Nov 13 '20 at 15:52
  • This is meanwhile not the best approach regarding SEO. I do recommend simply not hosting your code on Github pages but rather use Netlify/Vercel or alike. – kissu Jul 15 '22 at 16:02
  • @kissu if SPA were are hosted in netlify / vercel, those SPA apps will be SEO friendly? – divine Jul 16 '22 at 02:53
  • @divine an SPA by itself is not that good regarding SEO. But having the navigation as hash is even worse. The best would of course be a history mode for the router + some static/server side thanks to Nuxt. My point was mainly to say that Github Pages is quite cumbersome overall as a setup without much added value when compared to the other platforms. Staring your navigation with a 404 code is not the best start for sure haha. – kissu Jul 16 '22 at 07:28
11

You can fix this issue by a simple workaround. I combined all the insights from reading multiple issues about this and finally this is what helped me fix this problem.

Solution Logic - You just need a copy of index.html with the name 404.html in the dist folder

Steps to fix

Go to you package.json file, under scripts add a new script called "deploy" like below, you just need to execute this everytime after you build your page. It will automatically take care of the issue.

    "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint",
        "deploy": "cd dist && cp index.html 404.html && cd .. && gh-pages -d dist"
    },

This will copy the index.html & rename it 404.html and pushes dist folder under the branch gh-pages and after that your script will appear in the vue ui like below

deploy script appears here

or

If you are using git subtree push --prefix dist origin gh-pages method to push, then edit the deploy script in package.json to below

"deploy": "cd dist && cp index.html 404.html

and then execute the below git command. PS, don't forget to execute this script before manually using npm script method or from the vue ui

git subtree push --prefix dist origin gh-pages

Sachin Mohan
  • 883
  • 8
  • 15
  • 3
    It turned out to be the simplest method to make the routing work. For my purposes I needed only `cd dist && cp index.html 404.html`. – kwiat1990 Oct 06 '21 at 08:48
  • 1
    Thank you so much Sachin for your insights ! I had a similar approach but since I was using Github Actions to deploy my app, I added a step after the build command and it did the trick. ```- name: Build run: | npm run build cp dist/index.html dist/404.html ls dist/``` – Laila Jul 05 '23 at 11:53
4

This actually happens since your browser makes a request to christopherkade.com/posts URL which doesn't exist (this route is defined in Vue application running from index.html).

If you were running your own server, you would probably configure it to render your index.html page for any request URI, so your Vue application would be loaded from any path and handle routing by itself.

Speaking of GitHub pages, you can't just configure them to act the same way I described, but fortunately, there is a workaround which uses custom 404 page: https://github.com/rafrex/spa-github-pages

akrn
  • 748
  • 5
  • 7
1

As a workaround, I duplicated the index.html and renamed it to 404.html.

In this way, if the page is reloaded, you still get the correct page however this is served through the 404.html file.

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
Alchie
  • 51
  • 3
0

As a workaround I have created folders for each route (with a script) and placed the index.html in all of them.

404s still don't work.

Nash
  • 452
  • 1
  • 4
  • 16
0

If you use Nuxt, this fixes the problem.

layaouts/blank.vue

<template>
  <nuxt />
</template>

pages/redirect.vue

<template>
  <div></div>
</template>

<script>
export default {
  layout: 'blank',
  fetch({base, redirect, query}) {
    const param = query.p
    if (param === undefined) {
      return redirect('/')
    }
    const redirectPath = '/' + param.replace(base, '')
    return redirect(redirectPath)
  }
}
</script>

static/404.html

<html>
<head>
  <script>
    var pathName = window.location.pathname;
    var redirectPath = '/<repository-name>/redirect';
    location.href = redirectPath + '?p=' + encodeURI(pathName);
  </script>
</head>
</html>

https://gist.github.com/orimajp/2541a8cde9abf3a925dffd052ced9008

0

Very simple perfect solution just follow the below instruction

  1. Add a _redirects file inside the /public folder like /public/_redirects
  2. After that add /* /index.html 200 into the _redirects file

I think with this solution your redirect problem will be solved

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Muradtheoz
  • 530
  • 5
  • 16