How to Deploy a Vue.js Application with Dynamic Routing on GitHub Pages
Step-by-step instructions for the entire deployment process
The Problem
Dynamic routing in Vue.js is handled by vue-router
. The default mode for vue-router
is hash mode, which results in unusual-looking URLs and performs poorly in SEO. To make the Vue application more SEO friendly, we can use the router’s history mode, but a problem arises when we deploy our application to GitHub Pages — users will get a 404 error if they access a route directly in their browser.
This is because GitHub Pages does not natively support single-page applications (SPAs). When there is a fresh page load for a URL like https://<USERNAME>.github.io/test
, where /test
is a frontend route, the GitHub Pages server returns 404 because it knows nothing of /test
.
Instructions for Deployment
Deploying a Vue.js application using dynamic routing on GitHub Pages is not straightforward and I had to patch many routing issues to get my application up and running. Hope this guide saves you the trouble of having to go through several web pages/forums to get your application deployed.
The instructions provided here are meant to be concise. Detailed explanations on how the codes work can be found in the references.
1. Set the correct publicPath
in vue.config.js
.
If you are deploying to https://<USERNAME>.github.io/
or to a custom domain, you can skip this step.
If you are deploying to https://<USERNAME>.github.io/<REPO-NAME>/
, (i.e. your repository is at https://github.com/<USERNAME>/<REPO-NAME>
), set publicPath
to "/<REPO-NAME>/"
. For example, if your repo name is "my-project", your vue.config.js
should look like this:
// vue.config.js file to be placed in the root of your repositorymodule.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/my-project/'
: '/'
}
2. Update router paths to include the repository name.
The routes variable should look similar to the following:
const routes = [
{
path: '/',
redirect: { name: 'Home' }
},
{
path: '/<REPO-NAME>/',
name: 'Home',
component: Home
},
{
path: '/<REPO-NAME>/:queryParams(.*)',
name: 'Result',
component: Result,
props: true
}
]
̶3̶.̶ ̶C̶o̶p̶y̶ ̶a̶n̶d̶ ̶p̶l̶a̶c̶e̶ ̶t̶h̶i̶s̶ ̶4̶0̶4̶.̶h̶t̶m̶l̶ ̶f̶i̶l̶e̶ ̶i̶n̶ ̶t̶h̶e̶ ̶s̶a̶m̶e̶ ̶d̶i̶r̶e̶c̶t̶o̶r̶y̶ ̶a̶s̶ ̶y̶o̶u̶r̶ ̶i̶n̶d̶e̶x̶.̶h̶t̶m̶l̶ ̶f̶i̶l̶e̶ ̶(̶u̶s̶u̶a̶l̶l̶y̶ ̶i̶n̶ ̶t̶h̶e̶ ̶p̶u̶b̶l̶i̶c̶
̶d̶i̶r̶e̶c̶t̶o̶r̶y̶)̶.̶
̶I̶f̶ ̶y̶o̶u̶ ̶a̶r̶e̶ ̶s̶e̶t̶t̶i̶n̶g̶ ̶u̶p̶ ̶a̶ ̶P̶r̶o̶j̶e̶c̶t̶ ̶P̶a̶g̶e̶s̶ ̶s̶i̶t̶e̶ ̶a̶n̶d̶ ̶n̶o̶t̶ ̶u̶s̶i̶n̶g̶ ̶a̶ ̶c̶u̶s̶t̶o̶m̶ ̶d̶o̶m̶a̶i̶n̶ ̶(̶i̶.̶e̶.̶ ̶y̶o̶u̶r̶ ̶s̶i̶t̶e̶’̶s̶ ̶a̶d̶d̶r̶e̶s̶s̶ ̶i̶s̶ ̶<̶U̶S̶E̶R̶N̶A̶M̶E̶>̶.̶g̶i̶t̶h̶u̶b̶.̶i̶o̶/̶<̶R̶E̶P̶O̶-̶N̶A̶M̶E̶>̶
)̶,̶ ̶t̶h̶e̶n̶ ̶y̶o̶u̶ ̶a̶l̶s̶o̶ ̶n̶e̶e̶d̶ ̶t̶o̶ ̶s̶e̶t̶ ̶p̶a̶t̶h̶S̶e̶g̶m̶e̶n̶t̶s̶T̶o̶K̶e̶e̶p̶
̶t̶o̶ ̶1̶
̶i̶n̶ ̶t̶h̶e̶ ̶4̶0̶4̶.̶h̶t̶m̶l̶
̶f̶i̶l̶e̶ ̶i̶n̶ ̶o̶r̶d̶e̶r̶ ̶t̶o̶ ̶k̶e̶e̶p̶ ̶/̶<̶R̶E̶P̶O̶-̶N̶A̶M̶E̶>̶
̶i̶n̶ ̶t̶h̶e̶ ̶p̶a̶t̶h̶ ̶a̶f̶t̶e̶r̶ ̶t̶h̶e̶ ̶r̶e̶d̶i̶r̶e̶c̶t̶.̶
̶4̶.̶ ̶C̶o̶p̶y̶ ̶t̶h̶i̶s̶ ̶r̶e̶d̶i̶r̶e̶c̶t̶ ̶s̶c̶r̶i̶p̶t̶ ̶a̶n̶d̶ ̶a̶d̶d̶ ̶i̶t̶ ̶t̶o̶ ̶y̶o̶u̶r̶ ̶i̶n̶d̶e̶x̶.̶h̶t̶m̶l̶ ̶f̶i̶l̶e̶.̶
(Edit: Steps 3 and 4 still work, but there’s a simpler alternative. Create a file named 404.html
in the same directory as index.html
—usually in the public
directory—and copy the contents of index.html
into it. Thanks Klesun for pointing that out.)
5. Deploy the project to GitHub Pages.
Inside your project, create deploy.sh
with the following content (with bolded lines uncommented appropriately) and run it to deploy:
#!/usr/bin/env sh# abort on errors
set -e# build
npm run build# navigate into the build output directory
cd dist# if you are deploying to a custom domain
# echo 'www.example.com' > CNAMEgit init
git add -A
git commit -m 'deploy'# if you are deploying to https://<USERNAME>.github.io
# git push -f git@github.com:<USERNAME>/<USERNAME>.github.io.git main# if you are deploying to https://<USERNAME>.github.io/<REPO>
# git push -f git@github.com:<USERNAME>/<REPO>.git main:gh-pagescd -
References
Disclaimer: This article may contain extracts from these references.