A fast clone of the Jekyll blogging engine, in Go

Gojekyll

Gojekyll is a partially-compatible clone of the Jekyll static site generator, written in the Go programming language. It provides build and serve commands, with directory watch and live reload.

  Gojekyll Jekyll Hugo
Stable
Fast
(~20×Jekyll)
Template language Liquid Liquid Go templates
SASS
Jekyll compatibility partial
Plugins some yes ?
Windows support
Implementation language Go Ruby Go

Usage

gojekyll build       # builds the site in the current directory into _site
gojekyll serve       # serve the app at http://localhost:4000; reload on changes
gojekyll help
gojekyll help build

Installation

Binary Downloads

  1. Ubuntu (64-bit) and macOS binaries are available from the releases page.
  2. [Optional] Highlight. To use the {% highlight %} tag, you need Pygments: pip install Pygments.
  3. [Optional] Themes. To use a theme, you need to install Ruby and bundler. Create a Gemfile that lists the theme., and run bundle install. The Jekyll theme instructions provide more detail, and should work for Gojekyll too.

From Source

Pre-requisites:

  1. Install go (1) via Homebrew: brew install go; or (2) download.
  2. See items (2-3) under Binary Downloads, above, for optional installations.

First-time install:

go get github.com/osteele/gojekyll

Update to the latest version:

go get -u github.com/osteele/liquid github.com/osteele/gojekyll

[Optional] Install command-line autocompletion

Add this to your .bashrc or .zshrc:

# Bash:
eval "$(gojekyll --completion-script-bash)"
# Zsh:
eval "$(gojekyll --completion-script-zsh)"

Status

This project is at an early stage of development.

It works on the GitHub Pages sites that I care about, and it looks credible on a spot-check of other Jekyll sites.

Current Limitations

Missing features:

Also see the detailed status below.

Other Differences

These will probably not change:

By design:

  • Plugins must be listed in the config file, not a Gemfile.
  • The wrong type in a _config.yml file – for example, a list where a string is expected, or vice versa – is generally an error.
  • Server live reload is always on.
  • serve --watch (the default) reloads the _config.yml and data files too.
  • serve generates pages on the fly; it doesn't write to the file system.
  • Files are cached in /tmp/gojekyll-${USER}, not ./.sass-cache

Upstream:

  • Markdown:
    • < and > inside markdown is interpreted as HTML. For example, This is <b>bold</b> renders as bold. This behavior matches the Markdown spec, but differs from Jekyll's default Kramdown processor.
    • The autogenerated id of a header that includes HTML is computed from the text of the title, ignoring its attributes. For example, the id of ## Title (<a href="https://example.com/path/to/details">ref</a>)) is #title-ref, not #title-https-example-path-to-details-ref.
    • Autogenerated header ids replace punctuation by the hyphens, rather than the empty string. For example, the id of ## Either/or is #either-or not #eitheror; the id of ## I'm Lucky is #i-m-lucky not #im-lucky.

Muzukashii:

  • An extensible plugin mechanism – support for plugins that aren't compiled into the executable.

Feature Checklist

  • Content
    • Front Matter
    • Posts
    • Static Files
    • Variables
    • Collections
    • Data Files
    • Assets
      • Coffeescript
      • Sass/SCSS
  • Customization
    • Templates
      • Jekyll filters
        • scssify
        • everything else
      • Jekyll tags
    • Includes
    • Permalinks
    • Pagination
    • Plugins – partial; see here
    • Themes
    • Layouts
  • Server
    • Directory watch
  • Commands
    • build
      • --source, --destination, --drafts, --future, --unpublished
      • --incremental, --watch, --force_polling, JEKYLL_ENV=production
      • --baseurl, --config, --lsi
      • --limit-posts
    • clean
    • help
    • serve
      • --open-uri, --host, --port
      • --incremental, –watch, --force_polling
      • --baseurl, --config
      • --detach, --ssl-* – not planned
    • doctor, import, new, new-theme – not planned
  • Windows

Contributing

Bug reports, test cases, and code contributions are more than welcome.

Attribution

Gojekyll uses these libraries:

Package Author(s) Usage License
github.com/jaschaephraim/lrserver Jascha Ephraim Live Reload MIT License
github.com/kyokomi/emoji kyokomi jemoji plugin emulation MIT License
github.com/osteele/liquid yours truly Liquid processor MIT License
github.com/pkg/browser pkg serve --open-url option BSD 2-clause "Simplified" License
github.com/radovskyb/watcher Benjamin Radovsky Polling file watch (--force_polling) BSD 3-clause "New" or "Revised" License
github.com/russross/blackfriday Russ Ross Markdown processing Simplified BSD License
github.com/sass/libsass Listed here C port of the Ruby SASS compiler MIT License
github.com/tdewolff/minify Taco de Wolff CSS minimization MIT License
github.com/wellington/go-libsass Drew Wells Go bindings for libsass ???
gopkg.in/alecthomas/kingpin.v2 Alec Thomas command-line arguments MIT License
gopkg.in/yaml.v2 Canonical YAML support Apache License 2.0

In addition, the following pieces of text were taken from Jekyll and its plugins. They are used under the terms of the MIT License.

Source Use Description
Jekyll template documentation test cases filter examples
jekyll help command gojekyll help text help text
jekyll-feed plugin plugin emulation feed.xml template
jekyll-redirect-from plugin plugin emulation redirect page template
jekyll-sitemap plugin plugin emulation sitemap template
jekyll-seo-tag plugin plugin emulation feed template

The theme for in-browser error reporting was adapted from facebookincubator/create-react-app.

The gopher image in the testdata directory is from Wikimedia Commons. It is used under the Creative Commons Attribution-Share Alike 3.0 Unported license.

In addition to being totally and obviously inspired by Jekyll and its plugins, Jekyll's solid documentation was indispensible --- especially since I wanted to implement Jekyll as documented, not port its source code. The Jekyll docs were always open in at least one tab during development.

Related

Hugo is the pre-eminent Go static site generator. It isn't Jekyll-compatible (-), but it's highly polished, performant, and productized (+++).

jkl is another Go clone of Jekyll. If I'd found it sooner I might have started this project by forking that one. It's got a better name.

Liquid is a pure Go implementation of Liquid templates, that I finally caved and wrote in order to use in this project.

Jekyll, of course.

License

MIT

Owner
Oliver Steele
Prof @ NYU Shanghai. Formerly @ Olin College, Nest, Apple, AOL, lotsa startups. Older projects: Apple Dylan, Quickdraw GX, Laszlo Presentation Server, PyWordNet
Oliver Steele
Comments
  • Add native chroma highlighting (~30x performance increase)

    Add native chroma highlighting (~30x performance increase)

    As this PR changes the syntax highlighting classes, I suppose it could be tagged as a major. I've seen absolutely massive performance improvements in my workload, as can be seen in the benchmarks.

    Checklist

    • [x] I have read the contribution guidelines.
    • [x] make test passes.
    • [x] make lint passes.
    • [x] Performance improvements include benchmarks.
    • [x] Changes match the documented (not just the implemented) behavior of Jekyll.
  • New pygmentize detection breaks in go < 1.16

    New pygmentize detection breaks in go < 1.16

    (As referenced here:) tags/highlight.go won't compile in go < 1.16, because it uses "io/fs":

    build github.com/osteele/gojekyll: cannot load io/fs: malformed module path "io/fs": missing dot in first path element
    

    Previous versions used this code to test for the absence of the pygmentize command, but it does not work in go 1.16 because the error is not on the specified type:

    	if e.Err == exec.ErrNotFound {
    

    831ea53 changed to use this code, but this code does not compile in go < 1.16:

    	if pathErr, ok := err.(*fs.PathError); ok {
    
  • Implement `--incremental`

    Implement `--incremental`

    The flag should be implemented for compatibility with Jekyll, but should do nothing. For now at least, emphasize making whole builds fast enough that it's not needed.

  • `serve` should build all the pages

    `serve` should build all the pages

    The server builds all the collections, but only generates non-collection pages on demand. It should build everything, so that it can report all the errors.

  • `jekyll-redirect-from`

    `jekyll-redirect-from`

    Implementation plan:

    1. site build asks config whether the plugin is active. If so, it iterates over each page's front matter's redirect_from list

    2. page load asks config whether the plugin is active. If it is and if the front matter contains a redirect_to, it changes this to a permalink and creates or appends the original page permalink to a redirect_from, so that downstream processing will do the right thing.

  • Add a plugin hook for post-HTML conversion

    Add a plugin hook for post-HTML conversion

    Some plugins (e.g. jekyll-mentions) need to operate on text inside of HTML.

    Add an HTML parsing staging after Liquid and Markdown conversion, and a plugin hook for this.

    Does parsing the HTML affect performance? If so, only do if one of the plugins has used this hook.

  • Allow `collections` to be a list instead of a map

    Allow `collections` to be a list instead of a map

    Implementation plan:

    • Add a struct collectionList {collections []string} type.
    • Reading config.yml unmarshals into this. If it's not empty, it creates a map and assigns the configuration from it.

    The configuration struct currently specifies a map. Does this cause an error if the YAML is a list?

    If so:

    • mark Config.collections with yaml:"-"
    • define collectionMap struct
    • unmarshal into collectionMap
    • assign Config.collections from collectionMap.collections
  • Themes

    Themes

    Implementation plan:

    • Site.Read adds the files in $theme/assets, before adding the files in the main site (so that the latter takes precedence)
    • layouts looks in $themes/_include, after looking in the main _include
    • include_relative from the theme directory needs to look first in the corresponding non-theme location
    • The sass copier should first copy files from $themes/_sass, then overwrite them with $site/_sass
  • jekyll-github-metadata should cache data

    jekyll-github-metadata should cache data

    The jekyll-github-metadata plugin should have an option to cache GitHub requests. This would make it easier to run benchmarks that (1) don't include network latency (which is large over slow network connections, and highly variable in general).

  • Use goreleaser to build releases

    Use goreleaser to build releases

    Expected behavior

    Add a draft release to project releases https://github.com/osteele/gojekyll/releases.

    Actual behavior

    ❯ goreleaser --rm-dist
       • running goreleaser dev   
       • loading config file       file=.goreleaser.yml
       • SETTING DEFAULTS 
       • GETTING AND VALIDATING GIT STATE
       • LOADING ENVIRONMENT VARIABLES
       • CHECKING ./DIST  
       • rm-dist is set, removing ./dist
       • BUILDING BINARIES
       • skipped ignored build     target=darwin/386
       • new folder                folder=gojekyll_0.0.1_macOS_64bit key=darwinamd64
       • building                  binary=dist/gojekyll_0.0.1_macOS_64bit/gojekyll
       • new folder                folder=gojekyll_0.0.1_Linux_64bit key=linuxamd64
       • building                  binary=dist/gojekyll_0.0.1_Linux_64bit/gojekyll
       • new folder                folder=gojekyll_0.0.1_Linux_32bit key=linux386
       • building                  binary=dist/gojekyll_0.0.1_Linux_32bit/gojekyll
       ⨯ release failed            error=build failed for linux/386:
    go build github.com/jeffjen/datefmt: no buildable Go source files in /Users/osteele/go/src/github.com/jeffjen/datefmt
    # github.com/wellington/go-libsass/libs
    ../../wellington/go-libsass/libs/sass_number.go:8: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:151: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:153: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:157: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:159: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:164: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:166: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:170: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:175: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:186: undefined: SassNumber
    ../../wellington/go-libsass/libs/sass_number.go:166: too many errors
    

    Steps to reproduce the behavior

    ❯ go get github.com/goreleaser/goreleaser
    ❯ git tag -af v0.0.1 -m "First release" && git push origin +v0.0.1
    ❯ goreleaser --rm-dist
    

    More info

    There appear to be two distinct problems: the "no buildable Go source files" warning re github.com/jeffjen/datefmt; and the "undefined: SassNumber" errors re github.com/wellington/go-libsass.

    Before I added main: ./cmd/gojekyll to .goreleaser.yml, the commands above did create a release. The gojekyll in the release zip wasn't executable, though, since the config didn't refer to a main package. The build probably was skipping all the compilation, which is why it didn't run into the errors above. This does demonstrate that the upload part is (was) working.

  • Test Windows build

    Test Windows build

    See ~https://ci.appveyor.com/project/osteele/gojekyll~ https://github.com/osteele/gojekyll/runs/5171787377?check_suite_focus=true.

    ~This issue is reported upstream at osteele/liquid#22.~

    ~Once the Liquid issue is fixed~, wellington/go-libsass#20 may be an issue.

  • Emulate the `jekyll-readme-index` plugin

    Emulate the `jekyll-readme-index` plugin

    Implementation plan:

    Site.Read asks the config whether this plugin is present. If it is, it changes the permalink of any document with README.htmlto / before putting it in the routing table.

A Discord clone using React and Go

Valkyrie A Discord clone using React and Go. Live Demo Notes: File Upload is disabled. The design does not fully match current Discord anymore. Data r

May 12, 2022
Crane - 🐦 A full-text WebAssembley search engine for static websites
Crane - 🐦 A full-text WebAssembley search engine for static websites

Crane ?? My blog post: WebAssembly Search Tools for Static Sites Crane is a technical demo is inspired by Stork and uses a near-identical configuratio

Dec 1, 2022
Remark42 is a self-hosted, lightweight, and simple comment engine
Remark42 is a self-hosted, lightweight, and simple comment engine

Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments.

Dec 28, 2022
Everything a semantic desktop search engine combined with a single-user document management system

Everything will be a semantic desktop search engine combined with a single-user document management system. It will apply ideas of the semantic web and knowledge graphs to organize your data, allowing you to maintain private knowledge graphs as well as make use of public knowledge graphs, such as Wikidata.

May 21, 2022
Misou is a personal search engine very much inspired by monocle that looks through my knowledge sources.
Misou is a personal search engine very much inspired by monocle that looks through my knowledge sources.

?? Mi 搜 - a personal search engine Misou is a personal search engine very much inspired by monocle that looks through my knowledge sources. It is writ

Nov 7, 2022
The cider is a simple tool of building GitHub pages. It's fast and easy to use.
The cider is a simple tool of building GitHub pages. It's fast and easy to use.

The cider is a simple tool of building GitHub pages. It's fast and easy to use. See example: https://www.leyafo.com Install Compiling from source code

Feb 13, 2022
Forms is a fast, powerful, flexible, sortable web form rendering library written in golang.

forms Description forms makes form creation and handling easy. It allows the creation of form without having to write HTML code or bother to make the

Oct 2, 2022
Best lightweight, powerful and really fast Api with Golang (Fiber, REL, Dbmate) PostgreSqL

Best lightweight, powerful and really fast Api with Golang (Fiber, REL, Dbmate) PostgreSqL

Dec 26, 2021
Go kickstart is a simple repository that I'm managing to a have a fast setup for Go web application

Go kickstart is a simple repository that I'm managing to a have a fast setup for Go web application with my most common use cases using practices that I found useful and easy to maintain.

Jan 30, 2022
Jump start with the golang, start building fast REST or GraphQL API's

personalized overview and instruction for everyday use golang projects and language structure.

Feb 7, 2022
Mobile Blogging System

Mobile Blogging System

Mar 3, 2022
Reddit-clone-go - Reddit clone with golang

Generate GraphQL Schema go get github.com/99designs/gqlgen/[email protected] go run gi

Dec 28, 2022
Wolfenstein3D clone in Go

WolfenGo This is a clone of Wolfenstein3D written in Go, based on Wolfenstein3DClone and licensed under GNU/GPLv2. Pull requests are welcome. Plan ini

Sep 10, 2022
Quickly clone an entire org/users repositories into one directory - Supports GitHub, GitLab, Bitbucket, and more
Quickly clone an entire org/users repositories into one directory - Supports GitHub, GitLab, Bitbucket, and more

ghorg ghorg allows you to quickly clone all of an orgs, or users repos into a single directory. This can be useful in many situations including Search

Jan 1, 2023
A Go "clone" of the great and famous Requests library

GRequests A Go "clone" of the great and famous Requests library License GRequests is licensed under the Apache License, Version 2.0. See LICENSE for t

Dec 23, 2022
a tool for code clone detection

dupl dupl is a tool written in Go for finding code clones. So far it can find clones only in the Go source files. The method uses suffix tree for seri

Dec 12, 2022
twitter clone front-end for Internet Engineering course - fall 99 built by go+echo

twitter backend build twitter-like back-end for internet engeering course - fall 99 with go+echo+gorm team mates Roozbeh Sharifnasab + Parsa Fadaee +

Nov 9, 2022
A modern UNIX ed (line editor) clone written in Go

ed (the awesome UNIX line editor) ed is a clone of the UNIX command-line tool by the same name ed a line editor that was nortorious for being and most

May 29, 2021
A better way to clone, organize and manage multiple git repositories
A better way to clone, organize and manage multiple git repositories

git-get git-get is a better way to clone, organize and manage multiple git repositories. git-get Description Installation macOS Linux Windows Usage gi

Nov 16, 2022
Dolt is a SQL database that you can fork, clone, branch, merge, push and pull just like a git repository.

Dolt is a SQL database that you can fork, clone, branch, merge, push and pull just like a git repository. Connect to Dolt just like any MySQL database to run queries or update the data using SQL commands. Use the command line interface to import CSV files, commit your changes, push them to a remote, or merge your teammate's changes.

Dec 31, 2022