ENG | Static website generator: Jekyll and Chirpy
This post is about Jekyll static site generator (SSG) and Chirpy theme. Brief info about SSGs is here.
Motivation to use Jekyll is to write sites completely in markdown, which is basically plain text file with some simple formatting. They are processed into HTML afterwards by jekyll build
command. Advantage is versioning of pages by git(hub) and no need for a database which makes backup easier.
Chirpy is quite nice theme which has a few advantages over standard minima theme.
Advantages of Chirpy
- Looks pretty good by default
- It’s a bit easier to override CSS styles
- Displays tags
- Generates Table of Content
- Supports separate images for dark and light theme
Disadvantages
- It’s so good that author deserves a donation :)
Install process
- Install ruby and some dependencies as root
1
dnf in rubygems ruby-devel openssl-devel @development-tools rubygem-jekyll nodejs-npm
- Clone git repository (optionally only one branch)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[jekyll@marten ~]$ mkdir blog
[jekyll@marten ~]$ cd blog
[jekyll@marten blog]$ git clone --branch v6.1.0 --single-branch https://github.com/cotes2020/jekyll-theme-
chirpy.git
Cloning into 'jekyll-theme-chirpy'...
remote: Enumerating objects: 9008, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 9008 (delta 0), reused 24 (delta 0), pack-reused 8984
Receiving objects: 100% (9008/9008), 3.93 MiB | 5.62 MiB/s, done.
Resolving deltas: 100% (4921/4921), done.
Note: switching to '0da2f80dd47fd30321d11a913b02eb83c7689523'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
[jekyll@marten blog]$ ls
jekyll-theme-chirpy
[jekyll@marten blog]$ cd jekyll-theme-chirpy
[jekyll@marten jekyll-theme-chirpy]$ ls
assets _data index.html _layouts _plugins rollup.config.js tools
CHANGELOG.md Gemfile _javascript LICENSE _posts _sass
_config.yml _includes jekyll-theme-chirpy.gemspec package.json README.md _tabs
[jekyll@marten jekyll-theme-chirpy]$ git status
Not currently on any branch.
nothing to commit, working tree clean
[jekyll@marten jekyll-theme-chirpy]$ git branch --list
* (no branch)
[jekyll@marten jekyll-theme-chirpy]$ git checkout -b mybranch
Switched to a new branch 'mybranch'
[jekyll@marten jekyll-theme-chirpy]$ git branch --list
* mybranch
- Install ruby gems
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[jekyll@marten jekyll-theme-chirpy]$ export GEM_HOME="$HOME/gems"
[jekyll@marten jekyll-theme-chirpy]$ bundle
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Using bundler 2.4.10
Using eventmachine 1.2.7
Fetching public_suffix 5.0.3
|
Installing jekyll-include-cache 0.2.1
Installing jekyll-archives 2.2.1
Using jekyll-theme-chirpy 6.1.0 from source at `.`
Bundle complete! 6 Gemfile dependencies, 45 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Put
export GEM_HOME="$HOME/gems"
to your.basrc
,.zshrc
or similar file(s)Try jekyll. IP address is optional (
-H ...
), if you want to check it from other computer on the network.
1
2
3
4
5
6
7
8
9
10
11
[jekyll@marten jekyll-theme-chirpy]$ jekyll serve -H 192.168.0.143
Configuration file: /home/jekyll/blog/jekyll-theme-chirpy/_config.yml
Theme Config file: /home/jekyll/blog/jekyll-theme-chirpy/_config.yml
Source: /home/jekyll/blog/jekyll-theme-chirpy
Destination: /home/jekyll/blog/jekyll-theme-chirpy/_site
Incremental build: disabled. Enable with --incremental
Generating...
done in 0.899 seconds.
Auto-regeneration: enabled for '/home/jekyll/blog/jekyll-theme-chirpy'
Server address: http://192.168.0.143:4000/
Server running... press ctrl-c to stop.
- Install npm modules (needed to make ToC work)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[jekyll@marten jekyll-theme-chirpy]$ npm install
npm WARN deprecated [email protected]: Please use @jridgewell/sourcemap-codec instead
added 398 packages, and audited 399 packages in 20s
65 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm notice
npm notice New minor version of npm available! 9.5.1 -> 9.8.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.8.1
npm notice Run npm install -g [email protected] to update!
npm notice
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[jekyll@marten jekyll-theme-chirpy]$ npm run build
> [email protected] prebuild
> npx rimraf assets/js/dist
> [email protected] build
> NODE_ENV=production npx rollup -c --bundleConfigAsCjs
_javascript/commons.js → assets/js/dist/commons.min.js...
created assets/js/dist/commons.min.js in 1.6s
_javascript/home.js → assets/js/dist/home.min.js...
created assets/js/dist/home.min.js in 885ms
_javascript/categories.js → assets/js/dist/categories.min.js...
created assets/js/dist/categories.min.js in 817ms
_javascript/page.js → assets/js/dist/page.min.js...
created assets/js/dist/page.min.js in 785ms
_javascript/post.js → assets/js/dist/post.min.js...
created assets/js/dist/post.min.js in 811ms
_javascript/misc.js → assets/js/dist/misc.min.js...
created assets/js/dist/misc.min.js in 777ms
- Check it again
1
[jekyll@marten jekyll-theme-chirpy]$ jekyll serve
Initial modifications
Deployment (podman container)
This part is missing, but it’s quite obvious from other articles, such as file collection. Also article about cloudflare tunnels might be useful to read.
Deployment script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/dash
# Updates jekyll site in container
target="nginx:/config/www"
source="/home/pavel/dev-blog"
cd $source
echo "👷 Rebuilding static web content ..."
JEKYLL_ENV=production jekyll build || exit 1
echo "🔥 Deleting old content, don't panic! ..."
podman exec nginx sh -c "cd /config/www && rm -rf *"
echo "🚚 Copying new content ..."
podman cp ~/ip.php $target
podman cp _site/. $target
My custom changes
End of file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* append your custom style below */
@import url('https://fonts.bunny.net/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans&family=IBM+Plex+Serif&display=swap');
body {
font-family: "IBM Plex Sans", sans-serif;
}
#search-results a,h5,h4,h3,h2,h1 {
font-family: "IBM Plex Serif", serif;
}
pre, code, kbd, samp {
font-family: "IBM Plex Mono", monospace;
}
/*
$main-content-max-width: 1440px !default;
*/
#main-wrapper > .container {
//max-width: $main-content-max-width;
max-width: 1440px;
padding-left: 1.75rem !important;
padding-right: 1.75rem !important;
}
After Fedora update (F38->F39, November 2023)
It helps to run some of these commands in ~/dev-blog
directory
1
2
3
4
5
6
7
8
9
# Maybe not this one, it took quite a long time
gem update
# /home/pavel/.local/share/gem/ruby/gems/bundler-2.4.22/lib/bundler/runtime.rb:304:in `check_for_activated_spec!': You have already activated public_suffix 5.0.3, but your Gemfile requires public_suffix 5.0.1. Prepending `bundle exec`
bundle update
bundle install
bundle clean --force
# /home/pavel/.local/share/gem/ruby/gems/logger-1.6.0/lib/logger.rb:384:in `level': undefined method `[]' for nil:NilClass (NoMethodError)
gem cleanup logger
Upgrade to new Chirpy version
Added 2024-04-13
Backup everything
This is basically unintended introduction to Git 😀
It’s easier to solve conflict on Windows using Fork and P4Merge, tools which I’m familiar with.
Note that these git commands are a bit unique to my setup. These could be done in Fork GUI, but I tried to educate myself.
Clone repo to Windows machine:
1
2
3
4
5
6
7
8
9
10
PS C:\dev-www> git clone https://git.pavelp.cz/pavel.perina/blog.git
Cloning into 'blog'...
remote: Enumerating objects: 9924, done.
remote: Counting objects: 100% (9924/9924), done.
remote: Compressing objects: 100% (4681/4681), done.
remote: Total 9924 (delta 5634), reused 9159 (delta 5114), pack-reused 0
Receiving objects: 100% (9924/9924), 32.35 MiB | 5.78 MiB/s, done.
Resolving deltas: 100% (5634/5634), done.
PS C:\dev-www> cd .\blog\
Add remote repositiory and fetch changes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
PS C:\dev-www\blog> git remote add github https://github.com/cotes2020/jekyll-theme-chirpy.git
PS C:\dev-www\blog> git remote -v
github https://github.com/cotes2020/jekyll-theme-chirpy.git (fetch)
github https://github.com/cotes2020/jekyll-theme-chirpy.git (push)
origin https://git.pavelp.cz/pavel.perina/blog.git (fetch)
origin https://git.pavelp.cz/pavel.perina/blog.git (push)
PS C:\dev-www\blog> git fetch github --tags
remote: Enumerating objects: 1210, done.
remote: Counting objects: 100% (140/140), done.
remote: Compressing objects: 100% (30/30), done.
remote: Total 1210 (delta 112), reused 126 (delta 110), pack-reused 1070
Receiving objects: 100% (1210/1210), 585.55 KiB | 3.11 MiB/s, done.
Resolving deltas: 100% (543/543), completed with 61 local objects.
From https://github.com/cotes2020/jekyll-theme-chirpy
* [new branch] dependabot/npm_and_yarn/npm-e7ba079bfe -> github/dependabot/npm_and_yarn/npm-e7ba079bfe
* [new branch] feature/auto-release -> github/feature/auto-release
* [new branch] master -> github/master
* [new branch] production -> github/production
* [new tag] v6.5.5 -> v6.5.5
* [new tag] v6.2.0 -> v6.2.0
* [new tag] v6.2.1 -> v6.2.1
* [new tag] v6.2.2 -> v6.2.2
* [new tag] v6.2.3 -> v6.2.3
* [new tag] v6.3.0 -> v6.3.0
* [new tag] v6.3.1 -> v6.3.1
* [new tag] v6.4.0 -> v6.4.0
* [new tag] v6.4.1 -> v6.4.1
* [new tag] v6.4.2 -> v6.4.2
* [new tag] v6.5.0 -> v6.5.0
* [new tag] v6.5.1 -> v6.5.1
* [new tag] v6.5.2 -> v6.5.2
* [new tag] v6.5.3 -> v6.5.3
* [new tag] v6.5.4 -> v6.5.4
PS C:\dev-www\blog> git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
PS C:\dev-www\blog> git checkout pavel
Switched to a new branch 'pavel'
branch 'pavel' set up to track 'origin/pavel'.
Create temporary/testing branch jekyll-update
and merge github/production
into it (alternatively git merge v7.0.0
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS C:\dev-www\blog> git checkout -b jekyll-update
Switched to a new branch 'jekyll-update'
PS C:\dev-www\blog> git merge github/production
Auto-merging .gitignore
CONFLICT (content): Merge conflict in .gitignore
Auto-merging _config.yml
CONFLICT (content): Merge conflict in _config.yml
Auto-merging _data/contact.yml
CONFLICT (content): Merge conflict in _data/contact.yml
CONFLICT (modify/delete): _posts/2019-08-08-text-and-typography.md deleted in HEAD and modified in github/production. Version github/production of _posts/2019-08-08-text-and-typography.md left in tree.
CONFLICT (modify/delete): _posts/2019-08-08-write-a-new-post.md deleted in HEAD and modified in github/production. Version github/production of _posts/2019-08-08-write-a-new-post.md left in tree.
CONFLICT (modify/delete): _posts/2019-08-09-getting-started.md deleted in HEAD and modified in github/production. Version github/production of _posts/2019-08-09-getting-started.md left in tree.
Auto-merging assets/css/jekyll-theme-chirpy.scss
CONFLICT (content): Merge conflict in assets/css/jekyll-theme-chirpy.scss
Auto-merging package.json
CONFLICT (content): Merge conflict in package.json
Automatic merge failed; fix conflicts and then commit the result.
Resolve conflicts!
Commit and push (done by Fork git client)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ git commit --file="C:/dev-www/blog/.git/COMMITMESSAGE"
[jekyll-update b050d7e] Merge remote-tracking branch 'github/production' into jekyll-update
$ git push origin refs/heads/jekyll-update --set-upstream --verbose
Enumerating objects: 1217, done.
Delta compression using up to 24 threads
Total 999 (delta 614), reused 769 (delta 391), pack-reused 0
POST git-receive-pack (343345 bytes)
remote:
remote: Create a new pull request for 'jekyll-update':
remote: https://git.pavelp.cz/pavel.perina/blog/compare/master...jekyll-update
remote:
remote: . Processing 1 references
remote: Processed 1 references in total
Pushing to https://git.pavelp.cz/pavel.perina/blog.git
To https://git.pavelp.cz/pavel.perina/blog.git
* [new branch] jekyll-update -> jekyll-update
branch 'jekyll-update' set up to track 'origin/jekyll-update'.
updating local tracking ref 'refs/remotes/origin/jekyll-update'
Switching to Linux at this point.
It’s very important to update
assetss/lib
submodule. And it’s very easy to overlook it.
1
2
3
4
5
6
7
8
9
10
11
[pavel@marten -=- /home/pavel/dev-blog]$ git fetch origin
Username for 'https://git.pavelp.cz': pavel.perina
Password for 'https://[email protected]':
[pavel@marten -=- /home/pavel/dev-blog]$ git checkout jekyll-update
M assets/lib
branch 'jekyll-update' set up to track 'origin/jekyll-update'.
Switched to a new branch 'jekyll-update'
[pavel@marten -=- /home/pavel/dev-blog]$ git submodule update
Submodule path 'assets/lib': checked out '7bc0d86b6af83d7acfc63db50f29a5975cec2513'
Now proceed with steps as when upgrading Fedora to get new packages:
1
2
3
4
5
6
# Maybe not this one, it took quite a long time
gem update
bundle update
bundle install
bundle clean --force
gem clean
Test it
It’s might be crucial to visit Cloudflare dashboard, go to Caching -> Configuration, turn on Development Mode and Purge Cache. Otherwise some old CSS styles can be mixed with new ones and if all that can be seen is white page with broken style, layout, not working JavaScript and it’s hard to debug. Also
Ctrl+F5
orCtrl+Shift+
in browser helps. Even better is to test changes in a private window.
This update changed code formatting and made page more narrow, which I previously modified in jekyll-theme-chirpy.css
Merge to my branch and remove temporary branch (local and remote):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[pavel@marten -=- /home/pavel/dev-blog]$ git checkout pavel
Switched to branch 'pavel'
Your branch is up to date with 'origin/pavel'.
[pavel@marten -=- /home/pavel/dev-blog]$ git merge jekyll-update
Updating 0fd79f6..6934c43
Fast-forward
|
120 files changed, 2832 insertions(+), 2505 deletions(-)
|
[pavel@marten -=- /home/pavel/dev-blog/_posts]$ git branch --delete jekyll-update
Deleted branch jekyll-update (was 6934c43).
[pavel@marten -=- /home/pavel/dev-blog/_posts]$ git push origin --delete jekyll-update
remote: . Processing 1 references
remote: Processed 1 references in total
To https://git.pavelp.cz/pavel.perina/blog.git
- [deleted] jekyll-update
Commit, push …
Fixes after update from v6.2 to v6.5
After some experimenting, this solved narrow window (extended from 1250px to 1440px)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
---
@import 'main';
/* append your custom style below */
@import url('https://fonts.bunny.net/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans&family=IBM+Plex+Serif&display=swap');
body {
font-family: "IBM Plex Sans", sans-serif;
}
#search-results a,h5,h4,h3,h2,h1 {
font-family: "IBM Plex Serif", serif;
}
pre, code, kbd, samp {
font-family: "IBM Plex Mono", monospace;
}
#main-wrapper > .container {
max-width: 1440px;
padding-left: 1.75rem !important;
padding-right: 1.75rem !important;
}
Fixes after update from v6.5.5 to v7.0.0
Added 2024-05-12
After update to Jekyll Chirpy v7.0.0 images are not displayed, because of breaking change.in this commit
In nearly all files in _posts
and _tabs/about.md
replace img_path
by media_subpath
in yaml pagefront header.
Sadly this sets all pages as modified today.
Additionally to previous upgrare I run
1
2
npm update
npm install build
Search and generating table of content seems broken, unless browser runs in private tab, cloudflare cache is in development mode and pruned.
Fixes after update from v7.0.1 to 7.2.0
Added 2024-12-01
Here I updated Fedora from v39 to v41 too in the early November.
- I deleted content of ~/gems/ directory due to some errors in packages or dependencies
- This solution finally fixed lot of warnings regarding to module versions
1 2 3 4 5
for i in `gem list --no-versions`; do gem uninstall -aIx $i; done cd /home/pavel rm -rf .bundle cd dev-blog bundle
I fixed some typo in deployment script, no idea why/how it worked:No, single line is correct - with two lines it has no effect, Umami stats don’t work. Why building the site did not work is a question (2024-12-22 - fixed stats)JEKYLL_ENV=production jekyll build || exit
was on a single line (maybe it’s not a typo, but it fixed some problem)- I needed to delete
~/dev-blog/_sass/dist
directory npm run build
Find broken links to images
Added 2024-04-14
Option 1 (detect when html file is returned instead of image)
First let wget to browse page recursively:
1
2
cd ~/tmp
wget --spider -o wget.log -e robots=off -r -p http://192.168.0.143:8080/
Note: adding -d
parameter makes log more verbose, it contains HTTP headers including Referer:
It gave no error, but I know arduino_ds3231_zs042_big.webp
is missing. Relevant piece of wget.log is:
1
2
3
4
--2024-04-14 09:21:23-- http://192.168.0.143:8080/assets/img/arduino_ds3231_zs042_big.webp
Reusing existing connection to 192.168.0.143:8080.
HTTP request sent, awaiting response... 200 OK
Length: 41806 (41K) [text/html]
and it points to the home page.
Second analyze the log file. ChatGPT4 prompt was like:
Ok, other way … let’s use output from wget.
there is the line
1 --2024-04-14 09:21:23-- http://192.168.0.143:8080/assets/img/ arduino_pro_mini_cp2102_rtc3231_big.webpwe can match something that looks like this, starts with “–” and contains “http://192.> 168.0.143:8080/assets/img/” because images are stored here. Two next lines can be skipped and next line contains either:
Length: 308596 (301K) [image/webp]
Length: 41806 (41K) [text/html]
I want to get content type that matches txt html and report link in the first line as error
And the response
To accomplish this task, you can write a Python script that processes the log file generated by wget. This script will read through the file line by line, identify the lines corresponding to image requests based on the URL pattern you mentioned, skip two lines, and then check the content type on the following line to see if it matches
text/html
when it should be an image.Here’s a Python script that does this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 def process_wget_log(filename): with open(filename, 'r') as file: lines = file.readlines() errors = [] i = 0 while i < len(lines): line = lines[i].strip() if line.startswith('--') and "http://192.168.0.143:8080/assets/img/" in line: # Extract URL url = line.split()[-1] if i + 3 < len(lines): content_type_line = lines[i + 3].strip() if '[text/html]' in content_type_line: errors.append(url) i += 4 # Skip the next three lines and check the next record else: i += 1 return errors log_filename = 'wget.log' errors = process_wget_log(log_filename) if errors: print("Errors found in the following image URLs:") for error in errors: print(error) else: print("No errors found.")
Surprisingly it works:
1
python3 ./wget-spider-dissector.py
1
2
3
4
5
6
7
8
9
10
11
Errors found in the following image URLs:
http://192.168.0.143:8080/assets/img/arduino_ds3231_zs042_big.webp
http://192.168.0.143:8080/assets/img/arduino_ds3231_zs042_big.webp
http://192.168.0.143:8080/assets/img/logs-aritmetic-progression-light.webp
http://192.168.0.143:8080/assets/img/logs-aritmetic-progression-light.webp
http://192.168.0.143:8080/assets/img/logs-geometric-progression-of-2-light.webp
http://192.168.0.143:8080/assets/img/logs-geometric-progression-of-2-light.webp
http://192.168.0.143:8080/assets/img/matrix-vector-multiply-figure-01.webp
http://192.168.0.143:8080/assets/img/matrix-vector-multiply-figure-01.webp
http://192.168.0.143:8080/assets/img/%7Burl%7D
http://192.168.0.143:8080/assets/img/%7Burl%7D
Option 2 (configure nginx to return 404 errors)
1
2
3
4
5
6
[pavel@marten -=- /home/pavel/tmp]$ podman exec -it nginx /bin/bash
root@20bbd34b2cd8:/# cd config/nginx/site-confs/
root@20bbd34b2cd8:/config/nginx/site-confs# vi default.conf
root@20bbd34b2cd8:/config/nginx/site-confs#
exit
[pavel@marten -=- /home/pavel/tmp]$ podman restart nginx
Here I replaced the following line so it does not read index.html by default:
1
2
#try_files $uri $uri/ /index.html /index.php$is_args$args =404;
try_files $uri $uri/ =404;
And tried it again. It found lot of files like:
1
http://192.168.0.143:8080/tags/python/%7Burl%7D
But these are all from the search results javascript template where <a href="{url}">
is just a placeholder.
Note:
This was found in nginx.conf.cloudflare, I wonder if it works:
1
2
3
4
5
6
+ # Added 2023-07-08 22:11
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for" "$http_cf_connecting_ip"';
+
+
References
- https://www.altenburger.io/posts/install_jekyll/
- https://www.altenburger.io/posts/matomo_non_cookie/
- GitHub issue Chirpy: Supports Matomo Analytics
These were found later, but as a bonus:
- RichardN This blog discusses setting Jekyll hosted on GitHub Pages guide to setup jekyll and seems like a blog with similar content to mine.
- Techno Tim’s guide to setup Jekyll
- O so techie guide to setup Jekyll in dev-container