Jekyll converts markdown files to html; helps to generate blogs in a minimalistic style. This blog provides a quick start for installation, configuration, and simple usage.

Installation

Before you can use Jekyll to create a GitHub Pages site, you must install Jekyll and Git. Follow the instruction in the websites below:

https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/creating-a-github-pages-site-with-jekyll

https://jekyllrb.com/docs/ruby-101/

Which shell am I using?

Starting with macOS Catalina (10.15), Apple set the default shell to the Z shell (zsh). In previous macOS versions, the default was Bash.

  • In zsh, the configuration file is ~/.zshrc.

  • In bash, it’s ~/.bash_profile.

Every time you make changes with the configuration file

  • run source ~/.bash_profile if you have bash. [✘]

  • run source ~/.zshrc if the shell is zsh. [✔]

After having installed ruby, run ruby -v to check ruby version.

A Gemfile is a list of gems used by your site. Every Jekyll site has a Gemfile in the main folder.

  • Create a Gemfile in the root. The file should be called ‘Gemfile’ and should not have any extension. You can create a Gemfile with Bundler and then add the jekyll gem:

    bundle init
    bundle add jekyll
    
  • Manage plugins

    1. add plugins to your Gemfile

      source 'https://rubygems.org'
           
      gem 'jekyll'
           
      group :jekyll_plugins do
        gem 'jekyll-sitemap'
        gem 'jekyll-feed'
        gem 'jekyll-seo-tag'
      end
      
    2. add plugins to _config.yml

      plugins:
        - jekyll-feed
        - jekyll-sitemap
        - jekyll-seo-tag
      
    3. install them by running bundle update

Gemfile syntax

  • ~> Pessimistically greater than or equal to
gem "devise", "~> 3.1" # same as >= 3.1.0 and < 4.0.0

Q: What is a Gemfile.lock?

A: Gemfile.lock file contains all the information about the gems that are currently installed. This file is created automatically after we run the bundle install command. A Gemfile.lock has a list of the exact versions of the gems required for the application.

Bundler is a gem that installs all gems in your Gemfile. Gem manager. Commands start with bundle <>.

  • Install Bundler using gem install bundler. You only need to install it once, not every time you create a new Jekyll project.

  • To install gems in your Gemfile using Bundler and serve the website, run the following in the directory that has the Gemfile:

    bundle install # install gem dependencies for the project
    bundle exec jekyll serve # serve the website, run the site locally
    

    Now you can navigate to http://localhost:4000 to preview your site.

    Jekyll rebuilds automatically after each change.

  • All of the normal Jekyll commands are available to you, but you should prefix them with bundle exec so that Bundler runs the version of Jekyll that is installed in your project folder.

  • bundle add webrick Add gem to the Gemfile and run bundle install.

  • help page bundle add --help


Jekyll file structure

Workflow of software develoment:

coding $\rightarrow$ build $\rightarrow$ deploy $\rightarrow$ test $\rightarrow$ release

Deploying

Deploying is taking website content and publishing it to the Internet. Technically speaking, it is the process of compiling, or building, your code and hosting the JavaScript, CSS, and HTML on a web server. After deployment, you will always have your live website, which is called the live environment or production environment.

Development

If you want the ability to make changes without these affecting your live website, then you can add additional environments. These environments are called development environments or deployment environments.

https://jekyllrb.com/docs/structure/

https://nicolas-van.github.io/easy-markdown-to-github-pages/

.
|-- _config.yml
|-- _includes
|-- _layouts
|   |-- default.html
|   |-- post.html
|-- _posts
|   |-- 2007-10-29-why-every-programmer-should-play-nethack.textile
|   |-- 2009-04-26-barcamp-boston-4-roundup.textile
├── _sass
│   ├── _base.scss
│   └── _layout.scss
|-- _site
|-- index.html # => http://example.com/
|-- about.md # => http://example.com/about.html
|-- contact.html # => http://example.com/contact.html
  • _config.yml
    Configuration file, put in the root directory of your site.

    • set global variables; configure plugins;
  • index.md
    The index page of your website can be a index.md file or a README.md file. If both exists the index.md file has priority.

  • _includes
    Contains snippets of code that can be inserted in multiple layouts within the same theme-gem.

    页面的共有部分,可以存储成一个单独的文件。这样设计可以方便以后的维护。而这个单独的公用文件就存放在_includes里面。这里面的公用文件,可以被_layouts_post目录下面的文件嵌入。其嵌入方法,采用的是Liquid标签实现。比如:{\% include file.ext \%} (without backslashes),就指在文件中嵌入公用文件_includes/file.ext中的内容。

    _includes包括的内容比如:

    • head.html — Code-block that defines the <head></head> in default layout.
    • custom-head.html — Placeholder to allow users to add more metadata to <head />.
    • header.html — Defines the site’s main header section. By default, pages with a defined title attribute will have links displayed here.
    • footer.html — Defines the site’s footer section.
    • google-analytics.html — Inserts Google Analytics module (active only in production environment).
    • disqus_comments.html — Code to markup disqus comment box.
    • social.html — Renders social-media icons based on the minima:social_links data in the config file.
    • social-item.html — Template to render individual list-item containing graphic link to configured social-profile.
    • social-links/*.svg — SVG markup components of supported social-icons.
  • _layouts
    Files in the _layouts/ directory can be used as page templates. 网页模板

    All the repeating code on our site like the header, footer and navigation are typically in a layout.

    • base.html
      equivalent to default.html. content is a special variable, the value is the rendered content of the post or page being wrapped.

      每一篇博客的模板。如果想要在每一个帖子下 load js script, css,在base.html 中改动。

      Layout inheritance is useful when you want to add something to an existing layout for a portion of documents on your site. The following templates are all based on base.html. You specify your original layout in front matter:

      ---
      layout: default
      ---
      <-- make changes to suit your need for the new template type -- >
      
      • home.html homepage typesetting, 网站主页模板。基于 base.html 可以做更多修改。

      • post.html 基于 base.html 可以做更多修改。比如这个 layout 用于文字较多的贴。

      • page.html 基于 base.html 可以做更多修改。比如这个 layout 用于代码或者公式较多的贴。可以加载不一样的 js script 和 css,不需要的就不用加载,以让网页内容加载速度更快。

  • assets
    put your custorm css or javascript files here.

    • I put my custom css in /assets/css/style.scss for general setting and /assets/css/syntax.css for rouge syntax highlighting.
  • _sass
    These are sass partials that can be imported into your main.scss which will then be processed into a single stylesheet main.css that defines the styles to be used by your site.

    • Jekyll provides built-in support for Sass and can work with CoffeeScript via a Ruby gem. In order to use them, you must first create a file with the proper extension name (one of .sass, .scss, or .coffee) and start the file with two lines of triple dashes, not need to write front matter, like this:

      ---
      ---
          
      // start content
      .my-definition
        font-size: 1.2em
      

      Jekyll treats these files the same as a regular page, in that the output file will be placed in the same directory that it came from. For instance, if you have a file named css/styles.scss in your site’s source folder, Jekyll will process it and put it in your site’s destination folder under css/styles.css.

  • _site 这个目录,是 Jekyll 运行之后生成的。存放着整个网站的最终静态页面。其中的内容,不用去关心。

  • Pages are the most basic building block for content.

    • The simplest way of adding a page is to add an HTML file in the root directory with a suitable filename. You can also write a page in Markdown using a .md extension and front matter which converts to HTML on build. For a site with a homepage, an about page, and a contact page, here’s what the root directory and associated URLs might look like:

      .
      ├── about.md    # => http://example.com/about.html
      ├── contact.html  # => http://example.com/contact.html
      └── index.html    # => http://example.com/
      
    • index.html contents in this file will show on the home page.


Categories or Tags

The hallmark difference between categories and tags is that categories of a post may be incorporated into the generated URLfor the post, while tags cannot be.

  1. add category variable in the front matter of each post.

    category: study
    categories: [life, drive]
    tag: study
    tags: [life, drive]
    
  2. creating a category page. Using the category frontmatter variable, we can make a categories page called categories.md in the _pages directory where you can categorize and list each post by its category like so.

Useful references:


Build Jekyll locally

This allows you to use plugins not supported by Github Pages.

References:

Github Pages only supports certain plugins.

Two ways to build Jekyll websites:

  1. Build with GitHub Pages

    In one sentence: write a GitHub Actions workflow to publish your site.

    GitHub Actions: https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-ruby

    pros: simpler to get a site set up; don’t need to manage branches;

    cons: restricted whitelisted plugins and themes can be used.

    GitHub now provides you with the option to use their in-house CI/CD product named GitHub Actions to build and deploy (host) your Jekyll site with complete control over the build environment and gemset.

    • Advantages of using GitHub Actions:
      • can specify any Jekyll version instead of using the classic GitHub Pages-provided version at 3.9.3;

        .github/workflows/jekyll.yml:

        steps:
        - name: Setup Ruby
          uses: ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1
          with:
            ruby-version: '3.1' # Not needed with a .ruby-version file
        - run: bundle install   # Install dependencies with Bundler
        - run: bundle exec rake
        

        The setup-ruby action takes a Ruby version as an input and configures that version on the runner.

        • Alternatively, you can check a .ruby-version file into the root of your repository and setup-ruby will use the version defined in that file.

        The setup-ruby action will automatically install bundler for you.

        • The version is determined by your gemfile.lock file.
        • If no version is present in your lockfile, then the latest compatible version will be installed.
      • can use any Jekyll plugins irrespective of them being whitelisted by GitHub, including any *.rb files placed in the _plugins directory of your site;

      • while using a custom theme is possible without Actions, it is now possible to use themes depending on features introduced in newer versions of Jekyll.

  2. Build locally and push the build directory contents to the gh-pages branch on your repository.

    Publishing from a branch.

    pros: flexible, full control of your website contents

    cons: have to mange branches; one master branch containing build html files and one source branch to manage all source files.

If we want to use a custom plugin or a newer version of Jekyll, for example, the Jekyll scholar plugin page to manage .bib files used in this research page,

group :jekyll_plugins do
  gem 'jekyll-scholar'

We need to build the _site locally in a branch other than master or gh-pages, and then sync and merge ONLY the built html files to either of these two branches.

  1. We need to have a master branch, and a source branch (any name would do draft, working, etc).

    • master is where GitHub pages are deployed; It only include the _site directory.
    • source is where we work on writing the posts, css, js, etc. source has the entire jekyll project.
    • Note: It is recommended to change your default branch to source. Optionally, you can make the source branch protected to prevent it from being accidently deleted or overriden.
  2. Make changes and build locally in source branch. This will create _site folder. _site folder (where the site is built into) should be in the .gitignore.

  3. Navigate to master branch,

    1. copy files in _site folder to the root folder.
    2. create .nojekyll in the master branch. .nojekyll tells the gh-pages that there is no need to build.
    3. Meanwhile, in the _config.yml of the source branch, under the include key, we need to add - .nojekyll.

Code Highlighting

References:

Add syntax highlighting to your Jekyll site with Rouge

Rouge (胭脂) is a pure-ruby syntax highlighter and has been the default highlighter for Jekyll since Jekyll 3 (replacing pygments).

  1. Make sure that the kramdown and rouge gems are installed.

    # check whether they are installed
    gem list
    # if not, install with
    gem install kramdown rouge
    
  2. Edit your _config.yml settings.

    Add the following lines to your _config.yml file if they’re not there already.

    markdown: kramdown
       
    kramdown:
      input: GFM
      syntax_highlighter: rouge
    

    If that doesn’t work, you can try:

    markdown: kramdown
    highlighter: rouge
    

    By experience, my build times when using the first option are usually faster.

    Until now, rouge should have been working on your site, but you won’t see the syntax highlighting as there is no css styling. The highlighting effect will appear once you add a css file following Step 3.

  3. Create a css file for the highlighting style you want.

    Rouge comes built-in with rougify, a command-line tool that converts a style theme to a css file.

    You can check what languages are supported by entering:

    rougify list
    

    You can see the available rouge themes by entering:

    rougify help style
    

    base16, base16.dark, base16.monokai, base16.monokai.light, base16.solarized, base16.solarized.dark, colorful, github, gruvbox, gruvbox.light, molokai, monokai, monokai.sublime, thankful_eyes

    Rouge theme preview page: https://spsarolkar.github.io/rouge-theme-preview/

    For example, if you want to use the github theme, you first create a css file in your css folder using rougify:

    rougify style github > assets/css/syntax.css
    

    The usual directory for the css files is assets/css while the usual name for the syntax highlighting css file is syntax.css.

    Then don’t forget to include the stylesheet in your HTML template (usually within <head></head>):

 <link href="{{site.baseurl}}/assets/css/syntax.css" rel="stylesheet">

will be rendered as:

    <link href="/Econ-Study/assets/css/syntax.css" rel="stylesheet">

Note that {{site.baseurl}} is added before assets/css/syntax.css as we need to specify the relative path to the stylesheet. Otherwise, the file cannot be found by Jekyll.


Using highlight.js

Add highlight.js and css of the color scheme you want in the header page. Either you can add cdn url or copy it in your project and give local path. This will find and all highlight the code inside of <pre><code> tags.

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.8/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.8/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

Table of Supported Syntax. See the full list Jekyll - Syntax Highlighting, supported languages.

Note that the names are case-sensitive, sql is recognizable, but not SQL.

Name Aliase Description
console terminal A generic lexer for shell sessions
csharp c#,cs a multi-paradigm language targeting .NET
docker dockerfile Dockerfile syntax
html - HTML, the markup language of the web
javascript js JavaScript, the browser scripting language
markdown md, mkd Markdown, a light-weight markup language for authors
php php3, php4, php5 The PHP scripting language (php.net)
plaintext text A boring lexer that doesn’t highlight anything
powershell posh, msshell PowerShell
python py The Python programming language
r R,s,S The R statistics language
shell bash, zsh, ksh, sh Linux / Unix shell
typescript ts TypeScript, a superset of JavaScript
xml - XML
yaml yml Yaml Ain’t Markup Language (yaml.org)

Example for console (Windows terminal) Syntax Highlighting:

 {% highlight console %}
echo "Hello World in Jekyll: console"
  {% endhighlight %} 
echo "Hello World in Jekyll: console"

Example for shell (Linux terminal) Syntax Highlighting:

 {% highlight shell %}
echo "Hello World in Jekyll: shell"
{% endhighlight %} 
echo "Hello World in Jekyll: shell"

Example for powershell Syntax Highlighting:

 {% highlight powershell %}
Write-Host "Hello World in Jekyll: powershell"
  {% endhighlight %} 
Write-Host "Hello World in Jekyll: powershell"

Example for R Syntax Highlighting:

 {% highlight r %}
for (x in 1:10) {
  print(x)
}
{% endhighlight %} 
for (x in 1:10) {
  print(x)
}

Fenced code blocks with three backticks (```) or three tildes (~~~):

R

for (x in 1:10) {
  print(x)
}

Javascript

function sayHello(name) {
  if (!name) {
    console.log('Hello World');
  } else {
    console.log(`Hello ${name}`);
  }
}

Python

def function():
  print('Yes')

Troubleshooting

Issue: Faild in Ubuntu-24.04-x64 runner when trying to deploy to GitHub Pages.

Error: The current runner (ubuntu-24.04-x64) was detected as self-hosted because the platform does not match a GitHub-hosted runner image (or that image is deprecated and no longer supported).

In such a case, you should install Ruby in the $RUNNER_TOOL_CACHE yourself, for example using https://github.com/rbenv/ruby-build

You can take inspiration from this workflow for more details: https://github.com/ruby/ruby-builder/blob/master/.github/workflows/build.yml

$ ruby-build 3.1.4 /opt/hostedtoolcache/Ruby/3.1.4/x64

Once that completes successfully, mark it as complete with:

$ touch /opt/hostedtoolcache/Ruby/3.1.4/x64.complete

It is your responsibility to ensure installing Ruby like that is not done in parallel.

Fix: Your workflow is using an older version. Need to update workflow.

I found my solutions here.

Old workflow:

uses: ruby/setup-ruby@8575951200e472d5f2d95c625da0c7bec8217c42 # v1.161.0

New workflow:

uses: ruby/setup-ruby@086ffb1a2090c870a3f881cc91ea83aa4243d408 # v1.195.0

  1. I compared my .github/workflows/jekyll.yml with this script, making sure my actions versions are consistent.
  2. I also commented out line 40 (# ruby-version: '3.1' # Not needed with a .ruby-version file).

Bundler default gem URI dependency error

bundler: failed to load command: jekyll (/home/runner/work/Econ-Study/Econ-Study/vendor/bundle/ruby/2.7.0/bin/jekyll)

/opt/hostedtoolcache/Ruby/2.7.2/x64/lib/ruby/gems/2.7.0/gems/bundler-2.4.22/lib/bundler/runtime.rb:304:in `check_for_activated_spec!': 

You have already activated uri 0.10.0, but your Gemfile requires uri 0.12.0. Since uri is a default gem, you can either remove your dependency on it or try updating to a newer version of bundler that supports uri as a default gem. (Gem::LoadError)

Cause: The issue lies with Rubygems being outdated. If you update RubyGems, it will fix the issue.

Fix: Add the following line to jekyll.yml (in my case, I added to line 47 after Setup Pages). It installs the required version of the uri gem.

- run: gem install uri

Reference:

https://travis-ci.community/t/deployments-are-failing-due-to-uri-dependency/14375/3

https://github.com/orgs/community/discussions/101754

https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-ruby


Themes

Minimal Mistakes

homepage: https://mmistakes.github.io/minimal-mistakes/docs/stylesheets/

stylesheets css: https://github.com/mmistakes/minimal-mistakes/tree/master/_sass/minimal-mistakes

Minima

jtx-minima: user customized theme based on Minima

How to use custom css with Jekyll minima theme

  1. First need to find the right css file path to overrule.

    grep "stylesheet.*css" _site/index.html
    

    In my case I got

    <link rel="stylesheet" href="/Econ-Study/assets/css/style.css"><link type="application/atom+xml" rel="alternate" href="http://localhost:4000/Econ-Study/feed.xml" title="Personal Notes" />
    

    Therefore, I need to make changes to /assets/css/style.css.

  2. Need to do proper style inheritance. Source the active theme using @import "minima". Below this header, you can add additional CSS rules as you like.

    ---
    # Only the main Sass file needs front matter (the dashes are enough)
    ---
       
    @import
      "minima/skins/classic",
      "minima/initialize";
    

How to use js in Jekyll

js script allows you to define some computer-customer interactions. For instance, when a user clicks a button, it will invoke some reactions.

  • Load external js file in the page where you want to use the function. E.g.,

    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
    
  • Load project js file using relative url

    <script src="/Econ-Study/assets/js/script.js"></script>
    
  • If you want the script available on every page, put the call in your base.html or post.htmllayout file, whichever your post template is. Every page that uses that default.html layout will then call the script. That layout file can be found at _layouts/base.html.

  • If you just want it on your current page, just call it in your some-page.md markdown in the same way.

  • If you only want to call it when it is live and DON’T want to call it while you are developing - like, for example, a google analytics script - then wrap the call in an if statement like this:

  {% if site.environment == "production" %}
  <script src="//localhost:port/liveload.js"></script>
  {% endif %}  
  • Note: Use Chrome $\rightarrow$ View $\rightarrow$ Developer $\rightarrow$ Inspect Element

    • use Application to check if the website load the js script at all.
    • use Console to check if there is any bug in your js code. If there is bug, js cannot run.
    • http://127.0.0.1:4000/Econ-Study/assets/ check this url to see if you find your js files here.

Same problem here: can’t load js file to jekyll.

https://stackoverflow.com/questions/46263180/how-to-add-javascripts-to-jekyll

https://github.com/orgs/community/discussions/68439

How to add a script tag in Jekyll: https://stackoverflow.com/a/47109176

Example: The following codes let you click the Change text button to change the text of the header from “Hello World” to “Have a nice day”.

<h1 id="myHeader">Hello World</h1>
<button onclick="displayResult()">Change text</button>

Hello World


Things could be improved:

   {% assign posts = site.posts | sort: 'update' | reverse %}   

But then you have to specify the update property for every post. reverse makes it sorted descending, i.e., from newest to oldest.