Tuan Anh

container nerd. k8s || GTFO

Writing your first jekyll plugin

jekyll documentation is actually a very good source if you want to learn about writing a jekyll plugin. I highly recommend you to read that first. There are many examples at the end of the page as well.


Jekyll has a plugin system with hooks that allow you to create custom generated content specific to your site. You can run custom code for your site without having to modify the Jekyll source itself.

In general, plugins you make will fall into one of three categories:

  • Generators
  • Converters
  • Tags and liquid filters

We shall try with liquid filter first today, which is the easiest one IMO. In this tutorial, we will create a plugin that convert [x] and [] into emoji icon checkbox.

Filters are simply modules that export their methods to liquid. All methods will have to take at least one parameter which represents the input of the filter. The return value will be the output of the filter.

Create a file named Checked.rb in your _plugins folder with content as below.

module Jekyll
  module Checked
    def checked(text)
      text.sub(%r{\[x\]}i, '<span class="ballot_box_with_check"></span>').sub(%r{\[\]}i, '<span class="ballot_box"></span>')
    end
  end
end

Liquid::Template.register_filter(Jekyll::Checked)

We just created a module with a method that take a string as param and replace [x] and [] with a span tag with respective class.

We will then apply this filter on post content (or anything you want to apply this filter on).

{% content | checked %}

In your css file:

.ballot_box_with_check:before {
  content: "\2611\ ";
}

.ballot_box:before {
  content: "\2610\ ";
}

The result looks something like this

check jekyll plugin

And there you have it: your very first jekyll plugin. Be sure to check back for more jekyll tutorials :) .


How to use jekyll plugins with GitHub Pages

Very cool idea by @randymorris. Basically, actual source will now live in the source branch and generated content (_site folder) will be in master instead.

  1. Make changes in the source branch
  2. Build and test the site locally
  3. Commit changes to source branch
  4. git publish-website which consists of the following steps
git branch -D master
git checkout -b master
git filter-branch --subdirectory-filter _site/ -f
git checkout source
git push --all origin

This is actually similar to the approach: develope locally and rsync _site folder with your VPS/host public folder but works with GitHub Pages.

link bài gốc

Embedding Liquid code snippet with jekyll

If you want to share some Liquid code snippet or say some Django code, jekyll would try to process it as it looks like valid Liquid template and throw some weird errors.

The solution is to use raw tag. Again, I cannot use raw tag nested inside raw tag. Though, you would probably never have to do it, unless writing a blog post about something like this.

{% include analytics.html %}

Monthly/yearly post archive generator plugin for jekyll

Basically, this plugin will generate a archive based on your specified layout so that you can access it at url like

example.org/2014/
example.org/2014/08/

At first, I thought this is one of the default feature of jekyll but I was mistaken toto for jekyll. toto was another static site generator that I used before.

Anyway, this is what you are gonna get at the end.

jekyll archive plugin
1 - Example result of using jekyll archive plugin

I’m not the author of this plugin. I just modified it to suit my needs, adding stuff like: grouping post, generate yearly archive.

If you want to take a peak, head over to the plugin’s repo on GitHub.


Blogging with jekyll

I started using jekyll with Github Pages few years back but Github Pages didn’t allow plugins at the time and I do want to hack a bit around jekyll for my needs so I gradually move to self-hosting. As for static blog doesn’t require much resource, I opted for the lowest package on RamNode which goes for $15 a year (a bit over a buck a month for a 128MB RAM VPS). This is actually plenty for my needs.

Install jekyll

Install rvm or rbenv. If you already have one, skip this, then install jekyll

curl -L https://get.rvm.io | bash -s stable --ruby=2.0.0
gem install jekyll

Create your new blog and git init it.

jekyll new example.org
cd example.org
git init
git add .
git commit -m "Initial commit"
jekyll serve --watch

Deploy

I create a script on my repo post-receive. Upon receive my push commit, the script will rebuild the site from source, output it to nginx public folder /usr/share/nginx/html/example.org and purge varnish cache afterword. Purging varnish cache is optional but I do change my CSS/JS occationally now and then so I put it there as well.

You can do this by following this tutorial on DigitalOcean - “How To Deploy Jekyll Blogs with Git”. It’s pretty easy to follow. Use your copy-paste-fu.

Note: If you’re using Ubuntu 14.04 or later, you will have to do to apt-get install nodejs as well. jekyll itself doesn’t depend on nodejs but execjs does.

Others

I wrote a bunch of posts about jekyll as well. Check these out if they interest you.

Happy blogging. Don’t forget to share your cool jekyll hack on your new hippy blog.


BetterTube - A jekyll plugin for embedding YouTube videos

Sample syntax

{% youtube http://youtu.be/NiYCgVKioI4 %}

or even shorter

{% youtube NiYCgVKioI4 %}

Basically, this plugin will replace your youtube tag with a beautiful, responsive thumbnail of the video instead of loading the iframe and a bunch of other stuff along with that iframe, right on page load (pagespeed, remember?). On click, it will replace the image with the iframe for embedding video and play (autoplay=1). And did i mention it’s responsive too?

I will publish this plugin on Github as soon as I clean up the code.

The plugin is now available on Github.


Optimizing the hell out of your site for PageSpeed

Static assets bundling

I wrote a post about static assets combine on jekyll but the idea is similar to other framework. You can even do this on Wordpress via plugin called W3TC IIRC. As for your theme’s images, use CSS sprites to combine it to a single image. There are many tools for this purpose.

This step is critial because number of requests has a very high impact on page load. You would get a few points for PageSpeed already after this step.

Make use of Content Delivery Network (CDN)

CDN deploys your content across multiple, geographically dispersed servers, making your page loads faster from vistors’ perspective.

Also, try to load external library from a popular CDN. Chance your visitors already cache jQuery on Google CDN is pretty high. Why not take advantage of this?

CDN is cheap now. Even the free option CloudFlare is pretty good. Use it.

Minify CSS/JS/HTML

This one doesn’t take much time either. CloudFlare can also do it for you if you’re lazy.

Defer, async when possible

Defer and async all the scripts where possible. The rules are simple

  • Without defer or async, HTML parsing is paused when js code executes.

  • Defer will delay the script execution until HTML parsing is done.

  • Async won’t care when the script will be available. The script will be executed as soon as it’s ready. You may not want to use async if you have other scripts depend on that.

If you need to put external scripts (analytics, ads, etc..) on your site, try to find their async version. Most of the popular ads network provide async code snippet for your site.

Put JavaScript which are deferable in the bottom before </body in case your visitors’ browsers are not HTML5-compatible.

Optimize images

Yahoo Smush.it is a popular tool for this purpose. There’s a WordPress plugin to make it even easier to use. If you prefer an app for offline use, ImageOptim is good.

Use static site generator

jekyll is good. I have a very good experience with it. If you want a ready-to-use jekyll, take a look at Octopress. There are tons of other options as well. Take a pick.

Reverse proxy

If you’re already using a static site generator and nginx to serve it, I’m not sure if a reverse proxy would help. In my benchmark, varnish has roughly the same performance as nginx when serving static html. However, say you’re using a dynamic language like PHP with WordPress, varnish helps a lot. An old website of mine used to be able to handle 200,000 hit a day on a single $5 droplet on DigitalOcean where peak user online count was around 800, according to Google Analytics. Without varnish, the site was pretty much unresponsive.

I uses varnish to drop cookies on static assets as well as reverse proxy in front of nginx.

Google’s mod pagespeed

Pretty easy to install with apache, a bit more troublesome with nginx. I highly recommend you to install this. It makes your job a whole lot easier.

Conclusion

I did few of those tweaks and get 93/100 on Pagespeed and 99/100 on gtmetrix. Not bad for half an hour of your time huh. If i have more time, I will aim for something closer to 100 on Pagespeed.

There’s one suggestion on PageSpeed I don’t really understand . Until I figure it out, my score is probably stucked here.

None of the above-the-fold content on your page could be rendered without waiting for the following resources to load.


Static assets combine with jekyll

If you have several css files, each for different purpose, combining it into one would minimize HTTP requests and improve load times significantly. jekyll mades it very easy with include tag.

Here’s how you do it.

  • Move all the css files you want to include to _includes folder.

  • You create a new layout in _layouts folder called style.html and includes the needed css there.

---
layout: nil
---
 
/* syntax css, base css, or whatever you need to include */
{% include css/style.css %}
{% include css/syntax.css %}

This file is basically your base css file, including all the frequently used files.

  • Next, create your css file like below, include it in your head tag and you’re done. All your css files are now included in the layout style which you used as a base css for your main css.
---
layout: style
---

/* Your custom css goes here */

Alternatively, if your css file is rather small, you can embeded them right into the HTML file/layout like this. I’m not a fan of this as it would look a bit mess up, even just in the source code.

<head>
<title>Your page title</title>
  <style>
    /* include it here. It will be replaced as your css file content */
  </style>
</head>

Last step: check your PageSpeed score again and smile.


Things you may not know about JavaScript array

Let’s begin with creating an array.

arr = [1,2,3];
typeof a;
> "object"

you get object. Wow, so how would I check whether it is an array? Here’s how people usually do it.

if ('[object Array]' === Object.prototype.toString.call(arr)) {
  // your code
}

Next, what if I’m trying to access index that is greater than current length?

arr[10] = 10;

Seems ok!? No index out of range error whatsoever !? Let’s take a look at it again.

> [1, 2, 3, undefined × 7, 100]

Looks like JavaScript automatically expands the array and filled the blank with undefined.

What about if I’m trying to shrink the array

arr.length = 1;
> [1]

JavaScript reduces the size and keeps only elements from 0 to new length.

What if I try something like this

arr['hello'] = 100;
> [1]

Hmm, where is hello? Let’s try to access it again

arr['hello'];
> 100

Phew, it’s still there.

Ok, let’s stop making fun about JavaScript here for now. No matter how you see it, JS is a pretty good language. I kinda the language in general but some stuff, it’s just weird!! Though I have to admit, it’s fun to debug.


Returning query result as json array with Oracle 10G

I love Postgres SQL and one of my favorite feature is ability to return the query result as a JSON array string.

select array_to_json(array_agg(row_to_json(t)))
from (
  select * from my_table
) t

I wonder if I could do the same with Oracle.

Too bad the Oracle version at work is a bit rusty so it’s a bit more troublesome to get it work. We have to first, generate XML using DBMS_XMLGEN and then transform it to JSON using a XLTS stylesheet.

function ref_cursor_to_json (p_ref_cursor in sys_refcursor,
p_max_rows in number := null,
p_skip_rows in number := null) return clob
as
l_ctx         dbms_xmlgen.ctxhandle;
l_num_rows    pls_integer;
l_xml         xmltype;
l_json        xmltype;
l_returnvalue clob;
begin

-- generate JSON from REF Cursor

l_ctx := dbms_xmlgen.newcontext (p_ref_cursor);

dbms_xmlgen.setnullhandling (l_ctx, dbms_xmlgen.empty_tag);

-- for pagination
if p_max_rows is not null then
dbms_xmlgen.setmaxrows (l_ctx, p_max_rows);
end if;

if p_skip_rows is not null then
dbms_xmlgen.setskiprows (l_ctx, p_skip_rows);
end if;

-- get the XML content
l_xml := dbms_xmlgen.getxmltype (l_ctx, dbms_xmlgen.none);

l_num_rows := dbms_xmlgen.getnumrowsprocessed (l_ctx);

dbms_xmlgen.closecontext (l_ctx);

close p_ref_cursor;

if l_num_rows > 0 then
-- perform the XSL transformation
l_json := l_xml.transform (xmltype(get_xml_to_json_stylesheet));
l_returnvalue := l_json.getclobval();
else
l_returnvalue := g_json_null_object;
end if;

l_returnvalue := dbms_xmlgen.convert (l_returnvalue, dbms_xmlgen.entity_decode);

return l_returnvalue;

end ref_cursor_to_json;

If you want to read more about this, head over to this blog post on ORA-00001 blogspot.

This utility is available as part of plsql-utils on Google Code along with many other cool PL/SQL utilities. You should check it out if you have time.

link bài gốc