public
Last active

A jekyll plugin for compressing HTML, JavaScript files when rendering.

  • Download Gist
compressor.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#
# File compressor plugin for jekyll
# =================================
#
# By [mytharcher](https://github.com/mytharcher)
# 2012-05-20
#
# Updated by [nicoespeon](https://github.com/nicoespeon)
# 2013-04-12
#
# This plugin for compressing text files, including
# HTML and JavaScript of jekyll site. NOT support CSS
# file yet.
#
# The JavaScript compressing requires 'packr', a
# third-party lib. I'm not sure if GitHub has this
# extension. But the compressor for HTML files works OK.
#
# For HTML files it uses Alan Moore's regexp :
# http://stackoverflow.com/questions/5312349/minifying-final-html-output-using-regular-expressions-with-codeigniter
# It removes spaces between HTML, excepted within
# <textarea> and <pre> code, so you don't get into trouble!
#
 
require 'packr'
 
module Jekyll
 
module Compressor
 
def compress_html(content)
content.gsub(/(?>[^\S ]\s*|\s{2,})(?=(?:(?:[^<]++|<(?!\/?(?:textarea|pre)\b))*+)(?:<(?>textarea|pre)\b|\z))/ix, '')
end
 
# Really writing process
def output_file(dest, content)
FileUtils.mkdir_p(File.dirname(dest))
File.open(dest, 'w') do |f|
f.write(content)
end
end
 
def output_html(dest, content)
path = self.destination(dest)
self.output_file(path, compress_html(content))
end
 
def output_js(dest, content)
self.output_file(dest, Packr.pack(content,
:shrink_vars => true
))
end
 
end
 
 
 
# Overwrite old methods to insert a hook
 
class Post
 
include Compressor
 
def write(dest)
self.output_html(dest, self.output)
end
 
end
 
 
 
class Page
 
include Compressor
 
def write(dest)
self.output_html(dest, self.output)
end
 
end
 
 
 
class StaticFile
 
include Compressor
def write(dest)
dest_path = self.destination(dest)
 
return false if File.exist?(dest_path) and !self.modified?
@@mtimes[path] = mtime
 
case File.extname(dest_path)
when '.html'
self.output_html(dest_path, File.read(path))
when '.js'
self.output_js(dest_path, File.read(path))
else
FileUtils.mkdir_p(File.dirname(dest_path))
FileUtils.cp(path, dest_path)
end
 
true
end
 
end
 
end

Nice plugin :)
I've improved it by adding a regexp matching html comments. Here is the modified function:

def compress_html(content)
  content.gsub(/>\s+</, '><').
    gsub(/<!--([^-]*(-[^-][^>])?(--[^>])?)*-*-->/m, '')
end

Maybe the regexp can be made cleaner. Here is a test case: http://rubular.com/r/GJFgiTGaUI

You can try html_press to compress html, css_press to compress css and uglifier to compress js

Very nice, it also solves the difficulties I've been having with conditional IE comments. I'll use that :)

Good to see your nice work! I may have a try @stereobooster's new plugin in my next Jekyll site.

PS: I am just wondering why GitHub didn't notify me when you commented on Gist?

Jekyll Asset Pipeline adds a powerful asset pipeline to Jekyll. It supports conversion of CoffeeScript, Sass, Less or any other language via custom preprocessors. It can also automatically compress assets with Yahoo's YUI Compressor or Google's Closure Compiler.

Hey @mytharcher, thanks a lot for sharing this, it helps me so much.

I may found a solution to improve the regexp thanks to Alan Moore's one :

def compress_html(content)
  content.gsub(/(?>[^\S ]\s*|\s{2,})(?=(?:(?:[^<]++|<(?!\/?(?:textarea|pre)\b))*+)(?:<(?>textarea|pre)\b|\z))/ix, '')
end

Doing so, you keep spaces in your HTML within <textarea> or other <pre> code and so you don't get into trouble with that kind of things... What do you think?

Here is the source for the regexp.
You can also check my fork if you wish.

Cheers \o/

Thanks @nicoespeon! And sorry for delay.

It's very nice of your improvement. I will merge it.

@mytharcher This is great but it strips whitespace between liquid elements when the HTML is generated, for example the following code wouldn't output any space between the post title and excerpt:

{{ post.title }} {{ post.excerpt }}

I use a folder structure with Jekyll and this plugin seems to generate new subfolders. foo/index.html turns into foo/foo/index.html. I'd debug it myself, but I'm not keen on picking up Ruby right this instant :) Thanks for your work!

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.