The first option I considered when I decided to start up this blog was to use static site generator, and Jekyll as the most popular one was an obvious choice. Shortly after I was ready with the first version of this blog and first post - Using Jekyll, Asciidoctor and GitHub Pages for static site creation, I’ve noticed a link in @sdelamo Groovy Calamary #68 to the static site generator from Groovy world - Grain. As I consider myself as a Groovy ecosystem fan, I could not resist it and quickly migrated this blog to Grain.
Typical web resource after you request a page from it does something like following:
fetch some data from storage
process it
select one of web page templates and render it
return result
Many of them do not require dedicated data storage or data itself is changing relatively rarely. It means that web pages can be generated once and served without no additional processing for every request.
It’s important that we should not return to the boring Web 1.0 world. If client state on your site is not persisted, it can be handled by JavaScript locally. If the content is changing relatively rarely, you can just redeploy it with every change. If you need something like commenting feature, you can rely on external resources (for example disqus.com in this case).
And if you get rid of all heavy dynamic weapons like databases and server-side code and express your site as a collection of HMTL, CSS and JavaScript files you can gain some good benefits: ease of site deployment, content caching and delivering (which leads to better performance) and security management.
Typical static site generator takes your content (it can be plain text file, markdown, asciidoc, etc.) along with bunch of configuration parameters and the desired layout (usually HTML with some kind of template DSL) and transform them into a collection of HTML, CSS and JavaScript files ready for deployment and servicing as a static web resource. According to staticgen.com, there are dozens of different static sites generators, and Jekyll is the most popular from them. I’ve already posted an article about Jekyll, and today we will look closely at Grain, which is a workhorse of this blog itself.
Grain is an open source static website generator for Groovy. It provides all usual static site generator features and moreover has a particular killer feature - Groovy is a privileged citizen for all kinds of source files (configuration, layout, content and more).
Starting Grain blog is as easy as downloading one of its themes. Let’s examine it with yet another blog example, which means Grain Octopress Theme is theme of our choice. To ensure everything is working open your project directory and execute following:
If you open now http://localhost:4000, you should see following:
Before start using Grain, you need to perform some housekeeping. For example, as Grain try to rely on Groovy ecosystem tool as much as possible, it uses Gradle as build tool. But distribution that we’ve just download uses version 1.8 of Gradle wrapper (for the moment of writing this article 4.0 is actual version). You can easily update it by applying following change to build.gradle file:
And running following command:
Also, it would be great to update .gitignore file to ignore irrelevant for VCS files as following:
You should also fix JVM memory configuration in grainw files:
Modern web requires you to serve all your site content over HTTPS protocol. By default, not all Grain Octopress Theme content complies it. You should edit file theme/includes/custom/head.html as following:
The first thing you probably want to do with your blog is to create a new post. To do it, add file named yyyy-mm-dd-new-post.adoc (substitute yyyy-mm-dd with publication date and new-post with short post name) with following content:
As you can see, another great thing about Grain is that it supports Asciidoc format out-of-the-box. It’s a great benefit if your blog is going to be developer-oriented, and you probably may be satisfied with using neither markdown nor HTML for your posts. Asciidoc shares the same concept as Markdown, is partially compatible with it but has much more powerful features needed for advanced drafting of articles, technical manuals, books, presentations, and prose.
Now your blog should look like following:
And if you follow new post link:
As I said in the beginning, Groovy is a privileged citizen in the Grain world. To prove it, in the following sections I will demonstrate simple examples how you can use Groovy in all kinds of site sources - configuration, layout, content and even deployment.
As you can see, there are plenty of defaults used by your blog now. This problem is easily fixed via SiteConfig.groovy file. What is important, is that it is implemented as executable Groovy script, which constructs site build context. Inside it you can:
assign primitive values to configuration parameters
use special Groovy literals like patterns, string templates or lists
instantiate objects and execute methods on them
use Groovy builders for hierarchical parameters
You can find tons of parameters there and even introduce your own. For the beginning, let’s concentrate on the simple ones and perform following changes:
Now, your blog should look a little bit more personal:
Moreover, you can use commands
object to create custom commands for grain cli.
It means that if you execute ./grainw create-post 'HOWTO: create post from CLI'
you will got following result:
Grain has a pretty usual layout system. Let’s explore it using example of theme/layouts/blog.html which controls layout of site home page.
On the lines 1-5, you can see typical page front matter.
First of all, it configures layout inheritance.
You can open file named theme/layouts/default.html, which is parent layout for blog.html and check that blog.html content will be put inside ${content}
tag (line 14) of default.html:
Following lines of front matter are passed into special page
object and can be used to parametrize layout behavior.
After front matter, we see kind of normal HTML code with addition of Groovy.
It can be one-liner, just like in lines 19 and 36.
In these concrete example special implicit method include
is used, which takes another HTML file and optionally parameters map, renders their content and insert into original page.
The more sophisticated option is multi-line Groovy code, which is, however, very natural and clear.
You can use if
statement (like in line 8) to control which parts of page layout should be rendered and which not.
As a result, you do not need any special constructions as many other static site generators have.
For example, if you require rendering collection of elements, you can use Groovy Collection API like in line 16.
With such approach you can quickly implement some interesting features like in line 17, where you loop through list of blog posts, render content of each one, extract briefs and put them on your home page.
Just like with layout files you can simply put any Groovy code anywhere in your content file. For example, if you modify latest generated post as following:
You will get something like:
Pay attention that this code will be executed once and its result will be put into static HTML page. If you need dynamic behavior you will probable need something like:
If you need to reuse some code in multiple places, there is an excellent feature called custom tags in Grain.
If you have an experience with template frameworks like JSP, you can find something familiar in it.
As reference, open file \theme\src\com\sysgears\octopress\taglibs\OctopressTagLib.groovy which already contains several very useful tags like gist
or img
.
As you can see, custom tag is as simple as Groovy closure and HTML template so that we can implement our own in 3 minutes.
First, add following closure to \theme\src\com\sysgears\octopress\taglibs\OctopressTagLib.groovy:
Then, create new file \theme\includes\tags\dateNow.html with following content:
And last, modify your content page:
Ready! You will get something like:
Now, it’s time to finalize all our efforts and publish results of our work to the internet. It can be achieved easily with support of GitHub Pages - web platform that serves static content from GitHub repositories. If you put some static resources to your repository branch named gh-pages, GitHub Pages will automatically serve it as web resource.
So, first obvious option is to run ./grainw generate
and push content of dist folder to the gh-pages branch of your repository manually. But it is so boring!
Let’s rather set up automatic pipeline: Travis CI job which will be started automatically by each commit to develop branch, and actually do the same: run ./grainw generate
and push content of dist folder to the gh-pages branch from the same repository.
The first thing we need to do - generate key pair, so Travis job will have permissions to push to your repository. To achieve it just run ssh-keygen -t rsa
in your shell.
Then, go to GitHub settings page, and register new SSH key by providing its public part.
Next, create file .travis.yml to configure Travis job with following content:
Don’t forget to enable your repository build at Travis dashboard.
As you can see, Travis is supposed to take private part of your generated key from .travis/ directory.
But surely it’s not safe to put something private into public GitHub repository.
Luckily enough, Travis supports file encryption.
All you need is to run travis encrypt-file .travis/id_rsa --add
.
But it’s important to know two tweaks regarding this command: first, be careful enough to commit encrypted file id_rsa.enc instead of original .travis/id_rsa and second - this command does not work on Windows boxes, you need a *nix one.
As you can see, there is almost no manual scripting for interaction with git in job definition.
The reason is that grain has special grainw deploy
command which will invoke \theme\src\com\sysgears\octopress\deploy\GHPagesDeployer.groovy script.
It works fine with manual deployment process but needs some improvements to integrate with Travis.
You can take desired code here:
GHPagesDeployer script is instantiated in SiteConfig script we already seen. You need to configure it, by providing single parameter inside SiteConfig.groovy file:
The last thing you should do is to go to the setting of your Travis job and enable Build only if .travis.yml is present to prevent Travis from running build for gh-pages branch. Now you can push your latest changes to GitHub and watch how they will be processed by Travis job.
If you’ve done everything correctly, you should get the same result as I have here - https://yermilov.github.io/grain-example (sources can be examined here).
After I decided to start write things down, the first tool that I found for this task was Jekyll - a static site generator supported by GitHub Pages. It was very useful for creating the first version of this blog, but finally, I decided to use Grain (hope to present it in the following article). As a result of playing with Jekyll, in this article I will show how to build a simple blog using Jekyll as static site generator, GitHub Pages as static site server and Asciidoc as markdown language. We will create a blog from scratch, add new posts and change default configuration and web pages layout using mentioned technologies.
The web started as a bunch of static sites that provided various pieces of useful information for first explorers of the internet. But it turned into civilization phenomenon with exponential growth only when it became dynamic with all Web 2.0 stuff like social media, wikis, media platforms, etc.
Anyway, even today lots of web resources really need a very limited amount of dynamic magic. If client state on your site is not persisted, it can be handled by JavaScript locally. If content is changing relatively rarely, you can just redeploy it with every change. If you need something like commenting feature, you can rely on external resources (for example disqus.com in this case).
And if you get rid of all heavy dynamic weapons like databases and server-side code and express your site as a collection of HMTL, CSS and JavaScript files you can gain some very worthy benefits. The first and the main one is the ease of site deployment. All you need to do is copy your files into any kind of web server (Apache, Nginx). And if you go further and use cloud file storage (like S3) or dedicated web platform (like GitHub Pages), you get even more (think how it can help you in content management, content delivery, maintenance simplicity, performance, and security).
Jekyll is a static site generator written in Ruby. Actually what it does is taking your content along with the desired layout and transform them into a collection of HTML, CSS and JavaScript files ready for deployment and servicing as a static web resource. Content can be provided in any form from plain text files or markdown to pieces of HTMLs. The layout is specified as the name of one of the ready-to-go layouts Jekyll provides (with customization possibilities) or as your own HTML, CSS, and JavaScript files with template-related features.
Moreover, Jekyll is a great example of the tool with both comprehensive predefined conventions and almost endless customization possibilities. If all you need is a simple blog, you should just place you text-file posts named in a special way into the special directory, define few configuration parameters and you’re done. If you need something more specific, you can include your own pieces of HTML, CSS or JavaScript anywhere you need, even using Jekyll as just template engine for your sources ignoring all other features.
Check Jekyll quick-start guide! You need to follow these 5 steps:
Install Ruby
Execute gem install jekyll bundler
Execute jekyll new myblog
Execute cd myblog; bundle exec jekyll serve
Go to http://localhost:4000
You should get result same as this one:
However, you can do the same even without installing Ruby and Jekyll itself. First, you need to fork repository or download sources from mini-jekyll repository, or, as an alternative, you can quickly create them by yourself:
Create directory for your blog
Create file _config.yml with the following content
Create file Gemfile with the following content
Create file index.md with the following content
Create file about.md with following content
Create file _posts/2017-02-20-welcome-to-mini-jekyll.md with following content:
How can you start this site without even installing Jekyll? Easily, with support of GitHub Pages - web platform that serves static content from GitHub repositories. Besides just showing content as it is, GitHub Pages can determine that your repository contains Jekyll project, render it and serve result.
All you need to do is:
Execute git init
inside your local blog directory
Execute git add .
Execute git commit -m 'initial blog commit'
Execute git remote add origin https://github.com/yermilov/mini-jekyll.git
(substitute URL with yours)
Execute git push -u origin gh-pages
Go to https://yermilov.github.io/mini-jekyll (substitute with your github username and repository name)
If you want to create blog for simple text+images posts, you’ve already got a good starting point. But if your blog is going to be developer-oriented, you probably may not be satisfied with using neither markdown nor HTML for your posts. In this case, Asciidoc should be your default choice. It shares the same concept as Markdown, is partially compatible with it, but has much more powerful features needed for advanced drafting of articles, technical manuals, books, presentations, and prose.
Asciidoctor is a toolchain that implements Asciidoc format. We are going to integrate it with Jekyll for rendering content using jekyll-asciidoc plugin.
As a starting point, fork or download sources from jekyll-asciidoc-quickstart repository. The same as before, instead you can download it and create your own repository from scratch with same content.
Unlike previous examples, some additional setup is needed. GitHub Pages does not (yet) support rendering Asciidoc content, so you can’t just push it to GitHub repository and got rendered site back. Luckily, there is an easy way to overcome this problem. However, it will be great to show GitHub demand in Asciidoc rendering for example through GitHub support form.
Actually, we will setup Travis CI server to emulate GitHub Pages staging automation, and push blog live upon committing any change to the repository. Steps to achieve it are perfectly described in jekyll-asciidoc plugin documentation.
After cloning quickstart repository you need to make two changes in the sources:
Add GitHub personal access token (described here).
Modify original .Rakefile, to make it possible to use your e-mail for automated pushes to your repository:
After your push changes into develop branch (do not use master or gh-pages because it may cause conflicts), Travis CI automatically will pick up sources, render them using Jekyll and push them back into master or gh-pages branch (depending on GitHub conventions).
Now you can go to https://yermilov.github.io/jekyll-asciidoc-quickstart (substitute with your github username and repository name) and enjoy!
The first thing you probably want to do with your blog is to create a new post. To do it, add file named yyyy-mm-dd-new-post.adoc (substitute yyyy-mm-dd with publication date and new-post with short post name) with following content:
For quick start with Asciidoc refer to Writer’s Guide. After it, you can proceed with more advanced Syntax Quick Reference and full User Manual.
Probably, you already have some post on external resources you want to link to your new blog. With Jekyll’s flexibility, this is the matter of two easy steps. First of all, create file that will contain your external post metadata. Name it yyyy-mm-dd-external-post.md similarly to regular posts.
After it, open file _layouts/default.html and do following changes:
Now link in the posts feed is pointing to original external link.
As we have already made a minor change to default page layout in our blog, let’s try some more significant ones, like changing pages layout.
For the starting point, pages layout is pretty straightforward.
There is a file named default.html in the _layouts folder and it’s used for all site pages.
Each page (index.adoc or any from the _posts folder) during rendering is placed instead of {{ content }}
placeholder.
Let’s now split it to different layouts. First, to change home page layout, create file _layouts/home.html:
First 3 lines are YAML configuration of the layout.
Here we specify that we want to inherit default layout, which implies placing content of current page instead of {{ content }}
placeholder.
Now, create file _layouts/post.html. It will be used as layout for all post pages.
Next, modify _layouts/default.html. Do the following change:
After finishing with layout, we need to reconfigure content files. Let’s start from index.adoc. Now it can be just:
Proceed with post files. Regular post should look like:
External post metadata should look like:
The last thing we should do in scope of this post is organizing our layout a little bit. For now, our default layout is quite big, let’s split it with help of include feature. As example, we will take page footer.
First, create file _includes/footer.html with following content:
Next, do the following change with _layouts/default.html:
You can notice, that footer uses variables named starting with site.
.
They are taken from _config.yml file.
Add two lines to it (substitute with your personal data):
Now we are done! Let’s examine final result: