Search code examples
javascriptvue.jsvue-routergithub-pages

Vue Router, GitHub Pages, and Custom Domain Not Working With Routed Links


My domain: myname.com
My GitHub repo: myname
My GitHub name: myname

Underlying GH-Pages URL: myname.github.io/myname

My Issue: I have the following pages set up with a History Vue Router: home, contact, projects.
Whenever I go to myname.com/contact, it routes me to 404 instead. When I click on a link to redirect me to /contacts, it pushes it to the address bar but if you refresh, it routes to 404. I have read posts such as: Deploy Vue to GitHub Pages. Error with vue-router and Vue router on page refresh gets 404 but the issue persists and the custom domain is an added complexity. I have also read this: Vue Router return 404 when revisit to the url but, there is an example of a React Router page with a Browser Router working on GH-Pages: https://milosrancic.github.io/reactjs-website/activities, repo: https://github.com/milosrancic/reactjs-website.

Here is what I have done:

  • My package.json has the following line: "homepage": "https://myname.com/"
  • My vue.config.js is exactly this:
module.exports = {
    publicPath: '/'
  }
  • My Router is on my path: /src/router/index.js, passed into main.js new Vue(), and is exported like this:
export default new VueRouter({
    base: process.env.BASE_URL,
    mode: 'history',
    routes
})
  • Inside my App.vue (entry component), the template looks like this:
<template>
  <div id="app">
    <nav-bar></nav-bar>
    <router-view></router-view>
  </div>
</template>

Solution

  • I was unable to fix the problem through Vue but, as tao mentioned, this is likely an issue with GitHub and how they handle URLs. The simplest fix is to use a Hash Router instead so that the entry URL stays static. However, this will introduce that, arguably distasteful /#/ in your URL.

    Given how catch-all routes are not supported natively, someone has found a workaround for this: https://github.com/rafgraph/spa-github-pages. Note: This is likely not good for SEO because the intended URLs do not actually exist. This is doing a trick with their 404 redirects and handling it on the index page. This was for a portfolio site and as such, I am ok with this for now. If I, or someone else, finds a better solution, this will be updated.

    Workaround:

    Inside /public add a file called 404.html and paste the following contents:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>CHANGE THIS TO YOUR TITLE</title>
        <script type="text/javascript">
          // MIT License
          // https://github.com/rafgraph/spa-github-pages
          // This script takes the current url and converts the path and query
          // string into just a query string, and then redirects the browser
          // to the new url with only a query string and hash fragment,
          // e.g. https://www.foo.tld/one/two?a=b&c=d#qwe, becomes
          // https://www.foo.tld/?/one/two&a=b~and~c=d#qwe
          // Note: this 404.html file must be at least 512 bytes for it to work
          // with Internet Explorer (it is currently > 512 bytes)
    
          // If you're creating a Project Pages site and NOT using a custom domain,
          // then set pathSegmentsToKeep to 1 (enterprise users may need to set it to > 1).
          // This way the code will only replace the route part of the path, and not
          // the real directory in which the app resides, for example:
          // https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
          // https://username.github.io/repo-name/?/one/two&a=b~and~c=d#qwe
          // Otherwise, leave pathSegmentsToKeep as 0.
          var pathSegmentsToKeep = 0;
    
          var l = window.location;
          l.replace(
            l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
            l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +
            l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&/g, '~and~') +
            (l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +
            l.hash
          );
    
        </script>
      </head>
      <body>
      </body>
    </html>
    

    Inside /public/index.html, add the following inside the <head> right after <title>:

    <script type="text/javascript">
    // MIT License
    // https://github.com/rafgraph/spa-github-pages
    // This script checks to see if a redirect is present in the query string,
    // converts it back into the correct url and adds it to the
    // browser's history using window.history.replaceState(...),
    // which won't cause the browser to attempt to load the new url.
    // When the single page app is loaded further down in this file,
    // the correct url will be waiting in the browser's history for
    // the single page app to route accordingly.
    (function(l) {
        if (l.search[1] === '/' ) {
        var decoded = l.search.slice(1).split('&').map(function(s) { 
            return s.replace(/~and~/g, '&')
        }).join('?');
        window.history.replaceState(null, null,
            l.pathname.slice(0, -1) + decoded + l.hash
        );
        }
    }(window.location))
    </script>
    

    This has worked for me and I can now visit the contacts page by simply entering myname.com/contact. This should also work if you have nested SPA inside /public, using the same trick.