Publishing a Preact.js Site on GitHub Pages

I am currently working on a new map drawing library called Terra Draw. The public site makes up an important part of the project and it was getting to a point where maintaining a vanilla JavaScript app was becoming too unwieldy. Instead of reaching for my go to framework, React, I decided to be more conscious of the end users, shipping significantly less JavaScript to them.

This was all good in theory, but I found that there was a bit of work to get Preact working with GitHub pages, so let me run you through how to make this happen.

Scaffolding the project #

You can use the Preact CLI to scaffold a new project, in my case I wanted to use TypeScript so it was as simple as using the typescript template via the Preact CLI:

npx preact-cli create typescript example

This will create a folder. example with a scaffolded Preact project. Once this had been sorted I moved into the directory, initialised it as a git repository and then setup a remote with my remote github repository. Now we have things scaffolded, lets figure out how to make the two work together!

GitHub Page settings and the docs folder #

Preact creates a build folder called build where files are compiled and moved into. Unfortunately we cannot currently use a arbitrary folder on GitHub Pages, so as a compromise we use a folder called docs that is explicitly allowed as an option. This is somewhat unideal (it would be nice to use more commonly titled dist or build folders for example) but a better choice than building building your site into the root folder, which would be very messy! You can do this by going to Settings > Pages > Build and deployment > Branch and then select /docs from the second drop down.

The build script #

If you use the Preact CLI and scaffold your project, the default build script in your package.json file will come out as follows:

"build": "preact build",

Here we'll want to modify this slightly for our purposes of publishing to GitHub:

"build": "preact build --no-prerender --dest docs && echo '' > docs/CNAME",

Let's break this down a little; first we need to remove the pre-rendering, as we want to deploy this as a static site. To do this we add the --no-prerender flag.

The next thing we're going to do is change the destination folder to docs- remember currently we can only deploy the root folder on the docs folder, so docs folder it is.

The last critical step if you are using a custom domain is to add a CNAME file to the docs folder, which is required. If you are not using a custom domain this command is not necessary and you can just do preact build --no-prerender --dest docs

Routing #

Because GitHub pages are static sites, GitHub will only render subpages if they exist as index.html files in subdirectories. This clashes with Preacts client side routing strategy so instead we will have to use hash based routing. We can do using the history module from npm and use it like like so:

import { createHashHistory } from "history";

const App = () => (
<div id="app">
<Header />
<Router history={(createHashHistory() as unknown) as CustomHistory}>
<Route path="/" component={Home} />
<Route path="/docs/" component={APIDocs} />

Unfortunately there is an issue with the typings so we need to convert the result of createHashHistory o unknown and then cast it to CustomHistory for it to not complain.

Conclusion #

Combining these three methods we are able to publish a Preact site on GitHub pages without too much trouble. Just run npm run build, commit all the changes and push up to main!