• Stars
    star
    3,818
  • Rank 11,524 (Top 0.3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Host single page apps with GitHub Pages

Single Page Apps for GitHub Pages

Demo app

This is a lightweight solution for deploying single page apps with GitHub Pages. You can easily deploy a React single page app with React Router <BrowserRouter />, like the one in the demo app, or a single page app built with any frontend library or framework.

Why it's necessary

GitHub Pages doesn't natively support single page apps. When there is a fresh page load for a url like example.tld/foo, where /foo is a frontend route, the GitHub Pages server returns 404 because it knows nothing of /foo.

How it works

When the GitHub Pages server gets a request for a path defined with frontend routes, e.g. example.tld/foo, it returns a custom 404.html page. The custom 404.html page contains a script that 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. For example, example.tld/one/two?a=b&c=d#qwe, becomes example.tld/?/one/two&a=b~and~c=d#qwe.

The GitHub Pages server receives the new request, e.g. example.tld/?/..., ignores the query string and returns the index.html file, which has a script that checks for a redirect in the query string before the single page app is loaded. If a redirect is present it is converted back into the correct url and added to the browser's history with window.history.replaceState(...), but the browser won't attempt to load the new url. When the single page app is loaded further down in the index.html file, the correct url will be waiting in the browser's history for the single page app to route accordingly. (Note that these redirects are only needed with fresh page loads, and not when navigating within the single page app once it's loaded).

Usage instructions

For general information on using GitHub Pages please see Getting Started with GitHub Pages, note that pages can be User, Organization or Project Pages
 

Basic instructions - there are two things you need from this repo for your single page app to run on GitHub Pages.

  1. Copy over the 404.html file to your repo as is
    • Note that if you are setting up a Project Pages site and not using a custom domain (i.e. your site's address is username.github.io/repo-name), then you need to set pathSegmentsToKeep to 1 in the 404.html file in order to keep /repo-name in the path after the redirect. If you are using React Router you'll need to tell it to use the repo-name as the basename, for example <BrowserRouter basename="/repo-name" />.
  2. Copy the redirect script in the index.html file and add it to your index.html file - Note that the redirect script must be placed before your single page app script in your index.html file.  

Detailed instructions - using this repo as a boilerplate for a React single page app hosted with GitHub Pages. Note that this boilerplate is written in TypeScript but is setup to accept JavaScript files as well. It was previously written in JS and if you prefer a JS only boilerplate you can use version 6.

  1. Clone this repo ($ git clone https://github.com/rafgraph/spa-github-pages.git)
  2. Delete the .git directory (cd into the spa-github-pages directory and run $ rm -rf .git)
  3. Instantiate the repository
    • If you're using this boilerplate as a new repository
      • $ git init in the spa-github-pages directory, and then $ git add . and $ git commit -m "Add SPA for GitHub Pages boilerplate" to initialize a fresh repository
      • If this will be a Project Pages site, then change the branch name from main to gh-pages ($ git branch -m gh-pages), if this will be a User or Organization Pages site, then leave the branch name as main
      • Create an empty repo on GitHub.com (don't add a readme, gitignore or license), and add it as a remote to the local repo ($ git remote add origin <your-new-github-repo-url>)
      • Feel free to rename the local spa-github-pages directory to anything you want (e.g. your-project-name)
    • If you're adding this boilerplate as the gh-pages branch of an existing repository
      • Create and checkout a new orphaned branch named gh-pages for your existing repo ($ git checkout --orphan gh-pages), note that the gh-pages branch won't appear in the list of branches until you make your first commit
      • Delete all of the files and directories (except the .git directory) from the directory of your existing repo ($ git rm -rf .)
      • Copy all of the files and directories (including hidden dot files) from the cloned spa-github-pages directory into your project's now empty directory ($ mv path/to/spa-github-pages/{.[!.],}* path/to/your-projects-directory)
      • $ git add . and $ git commit -m "Add SPA for GitHub Pages boilerplate" to instantiate the gh-pages branch
  4. Set up a custom domain (optional) - see GitHub Pages instructions for setting up a custom domain
    • Update the CNAME file with your custom domain, don't include https://, but do include a subdomain if desired, e.g. www or your-subdomain
    • Update your CNAME and/or A record with your DNS provider
    • Run $ dig your-subdomain.your-domain.tld to make sure it's set up properly with your DNS (don't include https://)
  5. Set up without using a custom domain (optional)
    • Delete the CNAME file
    • If you are creating a User or Organization Pages site, then that's all you need to do
    • If you are creating a Project Pages site, (i.e. your site's address is username.github.io/repo-name):
      • Set pathSegmentsToKeep to 1 in the 404.html file in order to keep /repo-name in the path after the redirect
      • Add your repo-name to the absolute path of assets in index.html, change the bundle.js src to "/repo-name/build/bundle.js"
      • In React Router set the basename to /repo-name here like <BrowserRouter basename="/repo-name" />
      • In the start script in package.json replace --open with --open-page repo-name
      • In webpack.config.js:
  6. Run $ npm install to install React and other dependencies, and then run $ npm run build to update the build
  7. $ git add . and $ git commit -m "Update boilerplate for use with my domain" and then push to GitHub ($ git push origin gh-pages for Project Pages or $ git push origin main for User or Organization Pages) - the example site should now be live on your domain
  8. Create your own site
    • Write your own React components, create your own routes, and add your own style
      • Note that the example site is styled with Stitches and uses React Interactive for the links and other interactive components.
    • Change the title in index.html and the title in 404.html to your site's title
    • Remove the favicon links from the header of index.html and the favicon directory.
    • Update or delete robots.txt and sitemap.txt as you see fit (see SEO section below for more info)
    • Change the readme, license and package.json as you see fit
    • For testing changes locally see development environment info below
    • To publish your changes to GitHub Pages run $ npm run build (this runs webpack -p for production) to update the build, then $ git commit and $ git push to make your changes live

Serving from the /docs folder on the main branch - alternatively you can serve your site from the /docs folder instead of the root folder while your source code remains in the root folder.

  1. After following the previous set of instructions for using this repo as a boilerplate, create a /docs folder in the root and move index.html, 404.html and the /build folder into /docs
  2. Add --content-base docs/ to the start script in package.json
  3. In webpack.config.js change the output path to path: `${__dirname}/docs/build`,
  4. On GitHub in your repo settings select the /docs folder as the source for GitHub Pages

Development environment

I have included webpack-dev-server for testing changes locally. It can be accessed by running $ npm start (details below). Note that webpack-dev-server automatically creates a new bundle whenever the source files change and serves the bundle from memory, so you'll never see the bundle as a file saved to disk.

  • $ npm start runs the start script in package.json, which runs the command $ webpack-dev-server --host 0.0.0.0 --disable-host-check --open
    • --host 0.0.0.0 --disable-host-check is so you can access the site on your local network from other devices at http://[YOUR COMPUTER'S IP ADDRESS]:8080
    • --open will open automatically open the site in your browser
  • webpack-dev-server will serve index.html at http://localhost:8080 (port 8080 is the default). Note that you must load the index.html from the server and not just open it directly in the browser or the scripts won't load.

SEO

When I first created this solution in 2016 Google treated the redirect in 404.html the same as a 301 redirect and indexed pages without issue. Around 2019 Google changed their algorithm and no longer follows redirects in 404.html. In order to have all the pages on your site indexed by Google you need to create a robots.txt and sitemap.txt file to let Google know what pages exist. The robots.txt file needs to contain the location of the sitemap, and the sitemap.txt file needs to contain the redirect links for each page of your site so the crawler doesn't get a 404 response when it requests the page. To make this easier I created a sitemap link generator that transforms normal links into redirect links to use in the sitemap. I have done this for the demo site (this repo) and you can see the pages indexed here. Note that since Google is no longer associating the redirect links with the real paths, incoming links from other sites won't help your site's page rank. If you are creating a site where page rank on generic search terms is important, then I'd suggest looking for another solution. Some options are using GitHub Pages with a static site generator like Gatsby which generates an html file for each page as part of its build process, or hosting your single page app on a service that has native support for spas, like Netlify.

Miscellaneous

  • The .nojekyll file in this repo turns off Jekyll for GitHub Pages
  • One of the great things about the GitHub Pages CDN is that all files are automatically compressed with gzip, so no need to worry about compressing your JavaScript, HTML or CSS files for production

More Repositories

1

react-router-hash-link

Hash link scroll functionality for React Router
JavaScript
732
star
2

fscreen

Vendor agnostic access to the Fullscreen API
JavaScript
436
star
3

detect-it

Detect if a device is mouseOnly, touchOnly, or hybrid, and if the primary input is mouse or touch.
TypeScript
415
star
4

rollpkg

Zero-config build tool to create packages with Rollup and TypeScript
TypeScript
174
star
5

react-interactive

Better hover, active and focus states than CSS pseudo-classes, and a callback when the interactive state changes.
TypeScript
167
star
6

fractal

Mandelbrot fractal generator - js web app, uses zero libraries
JavaScript
130
star
7

react-github-pages

React with React Router boilerplate for GitHub Pages
JavaScript
49
star
8

detect-passive-events

Detect if the browser supports passive event listeners
TypeScript
39
star
9

event-from

Determine if a browser event was caused by mouse, touch or key input.
TypeScript
21
star
10

react-markdown-tree

Renders markdown as React components and never uses dangerouslySetInnerHTML
JavaScript
15
star
11

the-listener

Easily set complex listeners for mouse, touch and pointer events without conflicts
JavaScript
13
star
12

browserslist-config-css-grid

Browserslist config of all browsers that support css grid
JavaScript
11
star
13

current-input

Detect the current input (mouse or touch) and fix the sticky :hover bug on touch devices.
TypeScript
9
star
14

simplemark

A smaller version of Markdown
JavaScript
9
star
15

detect-touch-events

Detect if the browser has a touch screen and supports the Touch Events API
JavaScript
8
star
16

detect-touch

Detect if a device has a touch interface
JavaScript
5
star
17

detect-pointer-events

Detect if the browser supports the Pointer Events API
JavaScript
5
star
18

react-fast-mount

Fast mount slow loading React components
JavaScript
5
star
19

react-simplemark

React component and renderer for Simplemark
JavaScript
4
star
20

four-corner-layout

Design concept for four presentation pages on a single web page
JavaScript
4
star
21

device-responsive-apps

Device responsive apps presentation
JavaScript
3
star
22

sticky-hover

Fixing the sticky hover problem on mobile
JavaScript
3
star
23

rollpkg-example-package

Example package for Rollpkg
TypeScript
3
star
24

polymorphic-as-prop-api

Polymorphic as prop api standard proof of concept. Brings composability to the polymorphic as prop.
TypeScript
3
star
25

react-markdown-tree-config-default

Default Config for React Markdown Tree
JavaScript
3
star
26

detect-hover

JavaScript wrapper for hover and any-hover media queries
JavaScript
2
star
27

flux-async-dispatcher

Asynchronous app dispatcher for Flux design pattern with React
JavaScript
2
star
28

detect-it-v1-demo

JavaScript
1
star
29

detect-it-v3-demo

JavaScript
1
star
30

detect-pointer

JavaScript wrapper for pointer and any-pointer media queries
JavaScript
1
star
31

interactive-style-options

Created with CodeSandbox
TypeScript
1
star
32

test-exports

JavaScript
1
star
33

react-interactive-v0-demo

Demo app fro React Interactive v0
JavaScript
1
star
34

randompage

HTML
1
star
35

react-component-dev

Minimal boilerplate for developing and demonstrating a React component
JavaScript
1
star