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 \%},就指在文件中嵌入公用文件_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.
  • assets put your custorm css or javascript files here.

    • I put my custom css in /assets/css/style.scss.
  • _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.

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

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.