GitHub Pages Example

An example project and tutorial for creating and deploying GitHub Pages projects using custom build tools and Travis CI.

Published by in May 2018

TL;DR

About this project

This example project demonstrates a clean and convenient strategy to create and deploy GitHub Pages projects.

It focuses on setups, where pages are generated by a custom build tool (like webpack, gulp or whatever) and not automatically generated by GitHub using Jekyll or markdown. Although those type of projects could also benefit from shown workflows.

If you are not familiar with GitHub Pages‘ core concepts, you may want to head over to the official documentation first.

Types of GitHub Pages

There are two types of GitHub Pages: project pages and user or organization pages.

Both offer the same features, while there are some important differences:

This document focuses on project pages that are published from a gh-pages branch, as this is imho the most usual and convenient usecase.

I suppose that, after reading this tutorial, you will be able to change configuration settings according to your needs to publish your user pages or whatever you want to do.

Assumed preconditions

You have just created your new website project and your project root looks somehow like this:

./
├─ dist/          # generated pages
├─ src/           # sources and templates
├─ .gitignore     # `dist/` folder is ignored
├─ package.json   # project metadata and tasks
└─ README.md      # project information

The dist/ folder should be added to .gitignore as we do not want to commit generated files to our source branches.

Everything else should be committed to your git repository’s master branch and pushed to GitHub.

Deployment strategy

The concept is simple:

While your generated dist/ folder is ignored for the master branch, you have another branch gh-pages that only contains the generated contents of dist/, which will be automatically published at your GitHub pages URL.

This is easy to achieve using a CI/CD service like Travis CI but can also be done manually.

Deploying using Travis CI

Preparations

Enable Travis CI support

If not done already, register at Travis CI using your GitHub account and install the travis client on your machine.

Enable Travis support for your project by running travis init in your project root. When asked for main language, choose what fits your needs (i.e. node).

Afterwards, there should be a fresh generated .travis.yml in your project root.

GitHub personal access token

Go to GitHub and get a personal access token, so Travis will be authorized to push changes back to GitHub. Give it a useful description like my-project travis deploy and select public_repo as access scope.

After generating the token, encrypt it and add it to your Travis config:

travis encrypt GITHUB_TOKEN=your-personal-access-token --add
Deployment config

Travis offers the GitHub Pages deployment provider, which fullfills all our needs automagically.

With deployment options, your final .travis.yml should look like this:

language: node_js
node_js:
- '8.11.*'

env:
  global:
    secure: PDS4pIbrZhQaB…  # encrypted github token

script:
- npm run build             # build script

deploy:
  provider: pages
  github-token: $GITHUB_TOKEN
  on:
    branch: master          # trigger deploys only from master branch
  local-dir: dist           # path to generated pages
  target-branch: gh-pages   # target branch for deploy
  skip-cleanup: true        # keep generated files from build script
  keep-history: true        # keep git history in gh-pages branch

If not already existing, the gh-pages branch will be automatically created on the first deploy.

Afterwards, you can enable GitHub Pages support in your repository settings on GitHub. Make sure to set the build source to gh-pages branch.

You’re done!

Triggering deploys

Every pushed commit to master should now automatically trigger a build and push updates to gh-pages, which will be published at the respective URL.

Deploying manually

I do not recommend to use manual deployment as a common strategy. Although it seems simple, it’s prone to human error. Nevertheless, it’s good to know…

We’re assuming the same preconditions as for deploying with Travis: dist/ folder is ignored while everything else is pushed to master with no current changes in the working tree.

Preparations for manual deploy workflow

Create gh-pages branch

You can skip branch creation if you already have a branch gh-pages on your GitHub remote.

# create a new orphan branch `gh-pages` and clear its working tree
git checkout --orphan gh-pages
git rm -rf .

# create an `index.html` and commit it
echo "Hello World" > index.html
git add index.html
git commit -m "initial content"

# push `gh-pages` branch to github
git push origin gh-pages

# switch back to `master` branch and delete `gh-pages` locally
git checkout master
git branch -d gh-pages

Afterwards, you can enable GitHub Pages support in your repository settings on GitHub. Make sure to set the build source to gh-pages branch.

Clone gh-pages to dist/

Now clone the gh-pages branch to the dist/ folder inside of your repo. This way your build script will generate files directly into gh-pages.

# remove generated dist folder if existing
rm -rf dist
# clone only `gh-pages` to `dist/`
git clone git@github.com:USER/PROJECT.git --branch gh-pages --single-branch dist

Manual deployment steps

# run build script
npm run build
# go to `dist/` to commit and push generated changes
cd dist
git add -r .
git commit -m "update content"
git push origin gh-pages

When using manual deployment like this, make sure that your build script doesn’t touch the repository inside of dist/. You may want to build a little script for the deployment steps (or better use Travis CI for deployment directly).

Good to know

Feedback

Feel free to use project issues for discussion and comments.