Running Jekyll/Github Pages in a Devcontainer
Overview
I’ve written a few times in the past about setting up Github Pages.
Behind the scenes Github Pages uses Jekyll as its templating mechanism, allowing people to write content in Markdown and then to render the markdown in to valid HTML themed with CSS.
On occasion, it’s useful to be able to validate Jekyll-templated content locally, prior to publication/pushing to Github. For example the Markdown rendering in Jekyll is slightly different to the Markdown Preview in VSCode (VSCode keyboard shortcut: CTRL
-SHIFT
-v
).
In order to serve Jekyll locally we can set up a Devcontainer using the existing Devcontainer template definition and, with a few additional steps, serve content locally.
Set up the Devcontainer
First, set up the Devcontainer. I’m running Podman which requires a few additional elements out-of-the-box.
-
Create the Devcontainer folder:
wmcdonald@fedora:~/workspace/github-pages$ mkdir -p ~/workspace/github-pages/.devcontainer/podman
-
Add the Devcontainer config in
devcontainer.json
:wmcdonald@fedora:~/workspace/github-pages$ cat ~/workspace/github-pages/.devcontainer/podman/devcontainer.json { "name": "Jekyll", "image": "mcr.microsoft.com/devcontainers/jekyll:2-bookworm", "runArgs": [ "--security-opt", "label=disable", "--userns=host", "--hostname=jekyll-dev-container" ], "remoteUser": "root" // "onCreateCommand": ".devcontainer/bin/onCreateCommand.sh", // "updateContentCommand": ".devcontainer/bin/updateContentCommand.sh", }
Note #1: The
runArgs
used here are the minimum required to run the Devcontainer on Podman. Docker may run with fewer explicit options.Note #2: We’re using Podman so we can drop a Podman-specific devcontainer configuration into
.devcontainer/podman/devcontainer.json
, we can also have a Docker-specific devcontainer configuration in.devcontainer/docker/devcontainer.json
. The plugin should in theory chose the correct config for the runtime in use. -
Open the Devcontainer:
In VSCode,
CTRL
-SHIFT
-p
, then selectDev Containers: Rebuild and Reopen in Container
Set up Jekyll
-
In the Devcontainer, start Jekyll by running
jekyll serve
:root ➜ /workspaces/github-pages (main) $ jekyll serve Configuration file: /workspaces/github-pages/_config.yml Source: /workspaces/github-pages Destination: /workspaces/github-pages/_site Incremental build: disabled. Enable with --incremental Generating... Jekyll Feed: Generating feed for posts ... <<snip>> ... done in 0.295 seconds. Auto-regeneration: enabled for '/workspaces/github-pages' Server address: http://127.0.0.1:4000 Server running... press ctrl-c to stop.
-
Test Local Content Serving
Open a browser and navigate to http://127.0.0.1:4000. Depending on the state of your Jekyll site content, you may only see a bare HTML index, if this is the case see the following step.
-
Fix the Wrinkle in Rendering
If you only see a bare HTML index, we will need to add a
layout
to theindex.md
.root ➜ /workspaces/github-pages (main) $ cat index.md --- # Feel free to add content and custom Front Matter to this file. # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults layout: home ---
-
Optionally: Restart the Jekyll server and retest your content.
Jekyll will hot-reload changes by default, although this behaviour can be controlled through config.
-
As good practice, also append these additional items to
.gitignore
:root ➜ /workspaces/github-pages (main) $ cat /tmp/jk/.gitignore _site .sass-cache .jekyll-cache .jekyll-metadata vendor root ➜ /workspaces/github-pages (main) $ cat /tmp/jk/.gitignore >> /workspaces/github-pages/.gitignore
-
If you still have CSS rendering issues with individual posts, you can include the following in
_config.yml
:defaults: - scope: type: posts path: _posts values: isPost: true layout: post
Notes
devcontainer-info
You can see more about the devcontainer you’re using by running devcontainer-info
:
07:50:29 root@jekyll-dev-container wmcdpages ±|main|→ devcontainer-info
Development container image information
- Image version: 2.1.9
- Definition ID: jekyll
- Variant: 3.3-bookworm
- Source code repository: https://github.com/devcontainers/images
- Source code release/branch: v0.4.8
- Timestamp: Wed, 16 Oct 2024 18:48:12 GMT
More info: https://github.com/devcontainers/images/tree/main/src/jekyll/history/2.1.9.md
Devcontainer Build Details
You can see more about how the devcontainer was built reviewing:
We can see the Dockerfile COPY in /usr/local/post-create.sh
and that the devcontainer.json
sets "postCreateCommand": "sh /usr/local/post-create.sh"
.
As a result, post-create.sh
runs on devcontainer startup to bundle install
if a Gemfile
is present.
Scratch Jekyll site
If you need a quick Jekyll dummy site to expirment, test theming or generally fuck around and find out, you can create an entirely new throwaway site and serve it as follows:
root ➜ /workspaces/github-pages (main) $ mkdir /tmp/jk
root ➜ /workspaces/github-pages (main) $ jekyll new /tmp/jk/
Running bundle install in /tmp/jk...
Bundler: Fetching gem metadata from https://rubygems.org/............
Bundler: Resolving dependencies...
Bundler: Fetching rake 13.2.1
Bundler: Installing rake 13.2.1
Bundler: Fetching bigdecimal 3.1.8
Bundler: Installing bigdecimal 3.1.8 with native extensions
Bundler: Fetching google-protobuf 4.28.2 (x86_64-linux)
Bundler: Installing google-protobuf 4.28.2 (x86_64-linux)
Bundler: Fetching sass-embedded 1.80.1 (x86_64-linux-gnu)
Bundler: Installing sass-embedded 1.80.1 (x86_64-linux-gnu)
Bundler: Fetching minima 2.5.2
Bundler: Installing minima 2.5.2
Bundler: Bundle complete! 7 Gemfile dependencies, 35 gems now installed.
Bundler: Use `bundle info [gemname]` to see where a bundled gem is installed.
New jekyll site installed in /tmp/jk.
root ➜ /workspaces/github-pages (main) $ cd /tmp/jk/
root ➜ /workspaces/github-pages (main) $ jekyll serve