There are two options as of now that I can think of: using a service worker, or manually adding all your routes as files.
Option 1: using a service worker
Service workers are really cool. They run in the background, and can be used to do stuff like cache assets and modify network requests, without a server - it all happens in your browser. Service workers are also fully async and HTTPS only. The only problem with service workers is that you need to register them before they can be used - so a user will have to naviate to the home page of your site first in order to be able to navigate correctly to other pages.
Step 1: create your service worker file
You’ll need to create a js file, usually called sw.js
, at the root of your site, with something like the following in it:
self.addEventListener("fetch", event => { // listens to requests on your project
let modifiedUrl = /^https:\/\/projectname\.glitch\.me/.test(event.request.url) // is the url on the same domain?
&& !/\.(js|css|svg|png|jpg|vue|ico)/.test(event.request.url) // is it not a static asset that we don't want to render as a page?
&& !/vite/.test(event.request.url) // only needed if you're using vite, same purpose as above
? "/" : event.request.url; // if all of the above are true, return our index.html instead of glitch's usual 404 page
event.respondWith(fetch(modifiedUrl)); // respond with the correct response
});
This will need to be adjusted for your needs - replace projectname
with ypur project name, and in the section that goes (js|css| ... |ico)
, make sure to add any file extensions that your site may need to be served normally.
Step 2: register your service worker
Once step 1 is completed, if you go to your site it will act as it usually does i.e. not work. So, you’ll need to add the following code to the top of your main script file, assuming it has the defer
tag or is loaded at the end of the <body>
- otherwise, wrap this in a window.addEventListener("load", () => { ... });
.
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
You can get rid of the console.logs if you’d like.
Now, naviagate to your home page, enter another url on your site in your browsers navigation bar, and you should see your site working correctly! And as long as all your users go to your home page first, it’ll work for them as well
Option 2: manually add all your routes
This one’s really simple. For each of your routes, e.g. this/is/a/page
, copy your index.html
to this/is/a/page/index.html
, and it should Just Work™. However, this will only work if your project is fully static and not a generated static site. If it is a generated static site, you’ll have to either write your own extra build script and/or vite/webpack/rollup/whatever plugin that imports your routes and copies build/index.html
to build/this/is/a/page/index.html
. If this is the case, I’ll leave you to your own devices to build that
Obviously neither of those options are particularly desirable, but who knows, maybe official support for this will come one day
Hopefully this very long post will help you, and happy glitching
P.S. I’d recommend checking out Redirect non-existing routes to index.html for Generated Static Sites and giving it a vote