With the recent addition of Actions to GitHub's product lineup, we now have the ability to create a 100% Pure, Unfiltered™ JavaScript alternative to Jekyll (and Ruby) in GitHub Pages. This is a big deal. Really.
Back story
GitHub Pages, for the uninitiated, allows you to create websites from the source code stored in a GitHub repo. There are no databases to set up, no servers to provision, and no file transfers (at least not in the traditional sense). Better yet, it allows you to transform plain text into static websites and blogs with the help of Jekyll.
Jekyll is a pretty sweet static site generator. It's been around quite awhile, is battle tested, and is backed by a huge community. It's also simple enough for beginners and yet powerful enough for advanced users. Unfortunately, customizing it requires running it locally and this is where things get sticky. Jekyll is based on Ruby. For casual users, Ruby is a challenge to set up and maintain—especially on Windows. Scaling is also an issue for Jekyll/Ruby as bigger builds are notorious for taking a long time to compile.
While there are plenty of competitive static site generators out there, the one piece that was missing was the integrated of build and deploy to GitHub's web server. Pages+Jekyll took care of that build and deploy mumbo-jumbo for you, automagically. Just commit to the gh-pages
branch and poof, your site is updated.
More recently, workarounds from Netlify and others have popped up. They handle build/deploy and offer additional features worth considering, but at the end of the day they are yet another dependency to maintain.
If only we could run a static site generator on Pages with all the hooks and privileges of Jekyll but with the ease-of-setup and performance provided by more modern alternatives.
Well, now you can. All the pieces have finally fallen into place.
The build
This brief tutorial will cover the essentials of migrating from Jekyll to JavaScript. The following are required to get started:
- GitHub account
- NodeJS set up locally
Of course, it would also make sense to already have an existing Jekyll repo. If not, then create a new GitHub repo (public or private) with a README initialized. Follow the follow-up instructions to clone and set it up locally.
Set up the static site generator
It took awhile for someone to distill the essence of Jekyll into JavaScript. With Eleventy, Zach Leatherman (@zachleat) has really distilled, bottled, and shipped it. Oh, and did I mention that it's fast? I'll skip the rest of the sales pitch here and let the experts do the talking.
- Dave Rupert: What I Like About Eleventy
- iandroid: Why I'm Digging Eleventy
- Paul Lloyd: Turn Jekyll Up to Eleventy
If you haven't already guessed, I'm smitten with Eleventy. It's that multi-purpose knife that fits just perfectly in your pocket and makes you smile every time you use it.
It also makes the transition from Jekyll to JavaScript almost completely seamless. So let's roll with it.
Install and configure
Open a terminal and navigate to your repo.
-
If you don't already have a
package.json
file in the root directory, then take this moment to initialize npm.
npm init
-
Install Eleventy as a
devDependency
.
npm install --save-dev @11ty/eleventy
-
To the site root, add an empty
.nojekyll
file to disable the default Jekyll build.
touch .nojekyll
-
Keeping things simple, we'll assume a default Jekyll file structure.
.. ├── _layouts │ ├── default.html ├── assets │ ├── css │ ├── images │ └── js ├── index.html ..
To the site root, add a
.eleventy.js
config file with the following contents. For more details, see the Eleventy configuration docs.
module.exports = (eleventyConfig) => { // Copy the "assets" directory to the compiled "_site" folder. eleventyConfig.addPassthroughCopy('assets'); return { dir: { input: './', output: './_site', layouts: './_layouts', }, templateFormats: [ 'html', 'liquid', 'md', 'njk', ], }; };
Looking at the
dir.output
above, notice that we are maintaining parity with Jekyll's deployment, using the./_site
directory for our compiled code. To the
scripts
section ofpackage.json
, add the following. We'll need thebuild
script for our deployment later.
"scripts": {
"clean": "rm -rf ./_site",
"build": "npm run clean && eleventy",
"start": "eleventy --serve --watch"
},
- clean: empties out the deployment directory
- build: cleans the deploy directory and builds the site with Eleventy
- start: runs Eleventy in developer mode with live browser refreshes
The deployment
Now for the real magic sauce, GitHub Actions-style.
Set up workflow
- Open a browser to your GitHub repo and then select the Actions tab.
- Tap on the New workflow button.
- Tap on the Set up a workflow yourself button.
- In the {repo_name}/.github/workflows/
main.yml
field, enter "eleventy_build.yml
". -
Into the Edit new file textarea, cut and paste the following:
name: Eleventy Build # Controls when the action will run. Triggers the workflow on push or pull request # events but only for the master branch on: push: branches: [ master ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - name: Setup Node.js environment uses: actions/setup-node@v1.4.1 - name: Install packages run: npm ci - name: Run npm build run: npm run build - name: Deploy to gh-pages uses: peaceiris/actions-gh-pages@v3 with: deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} publish_dir: ./_site
Tap the Start commit button.
Complete the Commit new file form and select Commit directly to the
master
branch.
The workflow script should be fairly self-descriptive. See that ${{ secrets.ACTIONS_DEPLOY_KEY }}
line near the end of the workflow? We need to add deploy keys to GitHub before attempting a deployment.
Set up deployment keys
The following instructions were cribbed from a third-party GitHub Actions for GitHub Pages page. Please check that site for updates before proceeding as these instructions may have changed.
-
Generate a SSH key locally to use as your deploy key.
ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N "" # You will get 2 files: # gh-pages.pub (public key) # gh-pages (private key)
Open a browser to your repo and select the Settings tab.
-
Select Deploy keys from the left menu.
- Tap the Add deploy key button.
- In the Title field, enter "
Public key of ACTIONS_DEPLOY_KEY
". - In the Key field, cut and paste the contents of your
gh-pages.pub
SSH key file made in step 1 above. - Check the Allow write access box.
- Tap the Add key button.
-
Select Secrets from the left menu.
- Tap the Add a new secret link.
- In the Name field, enter "
ACTIONS_DEPLOY_KEY
". - In the Value field, cut and paste the contents of your
gh-pages
SSH key file from step 1 above. - Tap the Add secret button.
IMPORTANT: Delete the local
gh-pages
keys at this point. You certainly do not want to add them to your version control (for all to see). To initiate a deployment, commit/merge to the
master
branch. The first deploy will fail (because thegh-pages
branch has not been created yet).-
Go back to the Settings tab.
- Scroll down to the GitHub Pages section.
- From the Source options, select
gh-pages branch
.
Merge some more code into
master
to initiate another deploy.
Congrats. You're done! From here on out, you should be able to trigger a fresh build and deploy by:
- working/saving locally, committing, and pushing to
origin master
. - editing your code at github.com and saving to
master
.
Your updates will deploy to live in mere seconds. All of this takes place within the ecosystem that you version your code in. There are no additional dependencies, no additional accounts, nada. How cool is that?
The custom domain
GitHub provides default user sites that may suit you just fine. If, however, you want to use a custom domain, there's a bit more work involved.
Set up a custom domain
If you haven't already set up an apex domain (e.g.,
example.com
) for this repo, then you will need to add it. Follow the GitHub instructions for managing a custom domain.-
The
CNAME
file created when you entered your domain in the Custom domain field (above) needs to be included in our distribution directory.- Open the
gh-pages
branch and copy theCNAME
file. - Go back to the
master
branch and add thatCNAME
file to the source directory (in this case, the root directory). -
Open the
.eleventy.js
config file and add the CNAME file to the list of pass-through copies.
.. eleventyConfig.addPassthroughCopy('CNAME'); ..
Save, commit, and push to origin.
- Open the
Conclusion
For 12 years, GitHub teased us with a web hosting product that almost did everything we needed. We were grateful and we made due. Along the way, we came up with hacks and workarounds, employing one or more outside services to complete the task. But nothing quite combined source code versioning, flexible site generation, and web hosting in one elegant package.
With Eleventy and GitHub Actions, we now have it all.
Top comments (0)