├── lib ├── html_minifier │ ├── linter.rb │ ├── task.rb │ ├── version.rb │ └── minifier.rb ├── html_minifier.rb └── js │ ├── exports.js │ ├── console.js │ ├── htmllint.js │ ├── htmlparser.js │ └── htmlminifier.js ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Gemfile ├── spec ├── html_minifier_spec.rb └── qunit_helper.js ├── html_minifier.gemspec ├── README.md └── Rakefile /lib/html_minifier/linter.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/html_minifier/task.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | /.project 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/html-minifier"] 2 | path = vendor/html-minifier 3 | url = https://github.com/kangax/html-minifier.git 4 | -------------------------------------------------------------------------------- /lib/html_minifier/version.rb: -------------------------------------------------------------------------------- 1 | module HtmlMinifier 2 | VERSION = "0.0.4" 3 | SUBMODULE = "7032d3d3d97aabf0a2c96c8155ed077b455aca31" 4 | end 5 | -------------------------------------------------------------------------------- /lib/html_minifier.rb: -------------------------------------------------------------------------------- 1 | require "html_minifier/version" 2 | require "html_minifier/minifier" 3 | 4 | module HtmlMinifier 5 | # Your code goes here... 6 | end 7 | -------------------------------------------------------------------------------- /lib/js/exports.js: -------------------------------------------------------------------------------- 1 | var exports = (function () { 2 | var logs = []; 3 | return { 4 | console: { 5 | log: function (message) { 6 | logs.push(message); 7 | }, 8 | get: function () { 9 | return logs; 10 | }, 11 | clear: function () { 12 | logs = []; 13 | } 14 | } 15 | }; 16 | })(); 17 | -------------------------------------------------------------------------------- /lib/js/console.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | var logs = []; 3 | global.console = { 4 | log: function (message) { 5 | logs.push(message); 6 | }, 7 | get: function () { 8 | return logs; 9 | }, 10 | clear: function () { 11 | var ret = logs; 12 | logs = []; 13 | return ret; 14 | } 15 | }; 16 | }(this)); 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.8.7 3 | - 1.9.2 4 | - 1.9.3 5 | - jruby 6 | before_script: "git submodule update --init --recursive" 7 | env: 8 | - EXECJS_RUNTIME=RubyRacer 9 | - EXECJS_RUNTIME=RubyRhino 10 | - EXECJS_RUNTIME=Node 11 | matrix: 12 | exclude: 13 | - rvm: 1.8.7 14 | env: EXECJS_RUNTIME=RubyRhino 15 | - rvm: 1.9.2 16 | env: EXECJS_RUNTIME=RubyRhino 17 | - rvm: 1.9.3 18 | env: EXECJS_RUNTIME=RubyRhino 19 | - rvm: jruby 20 | env: EXECJS_RUNTIME=RubyRacer 21 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in gemspec 4 | gemspec 5 | 6 | # Depend on defined ExecJS runtime 7 | execjs_runtimes = { 8 | "RubyRacer" => "therubyracer", 9 | "RubyRhino" => "therubyrhino", 10 | } 11 | 12 | if ENV["EXECJS_RUNTIME"] && execjs_runtimes[ENV["EXECJS_RUNTIME"]] 13 | gem execjs_runtimes[ENV["EXECJS_RUNTIME"]], :group => :development 14 | if execjs_runtimes[ENV["EXECJS_RUNTIME"]] == "therubyracer" 15 | gem 'libv8', '~> 3.11.8', :group => :development 16 | end 17 | end 18 | 19 | -------------------------------------------------------------------------------- /spec/html_minifier_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | require "html_minifier" 3 | 4 | class TestLogger 5 | attr_accessor :logs 6 | 7 | def initialize 8 | @logs = [] 9 | end 10 | 11 | def info message 12 | @logs << message 13 | end 14 | end 15 | 16 | describe "HtmlMinifier" do 17 | 18 | it "it works" do 19 | html = '
foo
' 20 | HtmlMinifier.minify(html).should eq html 21 | end 22 | 23 | it "it logs" do 24 | html = 'foo
' 25 | log = TestLogger.new 26 | HtmlMinifier.minify(html, :log => log).should eq html 27 | log.logs.length.should eq 1 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /html_minifier.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "html_minifier/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "html_minifier" 7 | s.version = HtmlMinifier::VERSION 8 | s.authors = ["stereobooster"] 9 | s.email = ["stereobooster@gmail.com"] 10 | s.homepage = "https://github.com/stereobooster/html_minifier" 11 | s.summary = %q{Ruby wrapper for kangax js library html-minifier. If you want pure ruby use html_press} 12 | s.description = %q{Ruby wrapper for kangax js library html-minifier. If you want pure ruby use html_press} 13 | 14 | s.files = `git ls-files`.split("\n") 15 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 16 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 17 | s.require_paths = ["lib"] 18 | 19 | s.add_development_dependency "rspec" 20 | s.add_development_dependency "submodule", ">= 0.1.0" 21 | s.add_development_dependency "rake" 22 | 23 | s.add_dependency "multi_json", ">= 1.3" 24 | s.add_dependency "execjs" 25 | end 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HtmlMinifier 2 | [](http://travis-ci.org/stereobooster/html_minifier) 3 | 4 | Ruby wrapper for js library [html-minifier](https://github.com/kangax/html-minifier/). If you want pure ruby use [html_press](https://github.com/stereobooster/html_press) 5 | 6 | ## Installation 7 | 8 | `html_minifier` is available as ruby gem. 9 | 10 | $ gem install html_minifier 11 | 12 | Ensure that your environment has a JavaScript interpreter supported by [ExecJS](https://github.com/sstephenson/execjs). Usually, installing therubyracer gem is the best alternative. 13 | 14 | ## Usage 15 | 16 | ```ruby 17 | require 'html_minifier' 18 | 19 | HtmlMinifier.minify(File.read("source.html")) 20 | ``` 21 | 22 | When initializing `HtmlMinifier`, you can pass options 23 | 24 | ```ruby 25 | HtmlMinifier::minifier.new(<' +
76 | tag + '> element<' +
81 | tag + '> element<br> sequence. Try replacing it with styling.<' + tag + '> element<', tag, '> element<', tag, '> element<', tag, '> element) sequence. Try replacing it with styling. within a )
301 | if (options.collapseWhitespace) {
302 | if (!_canTrimWhitespace(tag, attrs)) {
303 | stackNoTrimWhitespace.push(tag);
304 | }
305 | if (!_canCollapseWhitespace(tag, attrs)) {
306 | stackNoCollapseWhitespace.push(tag);
307 | }
308 | }
309 |
310 | buffer.push('<', tag);
311 |
312 | lint && lint.testElement(tag);
313 |
314 | for ( var i = 0, len = attrs.length; i < len; i++ ) {
315 | lint && lint.testAttribute(tag, attrs[i].name.toLowerCase(), attrs[i].escaped);
316 | buffer.push(normalizeAttribute(attrs[i], attrs, tag, options));
317 | }
318 |
319 | buffer.push('>');
320 | },
321 | end: function( tag ) {
322 | // check if current tag is in a whitespace stack
323 | if (options.collapseWhitespace) {
324 | if (stackNoTrimWhitespace.length &&
325 | tag == stackNoTrimWhitespace[stackNoTrimWhitespace.length - 1]) {
326 | stackNoTrimWhitespace.pop();
327 | }
328 | if (stackNoCollapseWhitespace.length &&
329 | tag == stackNoCollapseWhitespace[stackNoCollapseWhitespace.length - 1]) {
330 | stackNoCollapseWhitespace.pop();
331 | }
332 | }
333 |
334 | var isElementEmpty = currentChars === '' && tag === currentTag;
335 | if ((options.removeEmptyElements && isElementEmpty && canRemoveElement(tag))) {
336 | // remove last "element" from buffer, return
337 | buffer.splice(buffer.lastIndexOf('<'));
338 | return;
339 | }
340 | else if (options.removeOptionalTags && isOptionalTag(tag)) {
341 | // noop, leave start tag in buffer
342 | return;
343 | }
344 | else {
345 | // push end tag to buffer
346 | buffer.push('', tag.toLowerCase(), '>');
347 | results.push.apply(results, buffer);
348 | }
349 | // flush buffer
350 | buffer.length = 0;
351 | currentChars = '';
352 | },
353 | chars: function( text ) {
354 | if (currentTag === 'script' || currentTag === 'style') {
355 | if (options.removeCommentsFromCDATA) {
356 | text = removeComments(text, currentTag);
357 | }
358 | if (options.removeCDATASectionsFromCDATA) {
359 | text = removeCDATASections(text);
360 | }
361 | }
362 | if (options.collapseWhitespace) {
363 | if (!stackNoTrimWhitespace.length && _canTrimWhitespace(currentTag, currentAttrs)) {
364 | text = trimWhitespace(text);
365 | }
366 | if (!stackNoCollapseWhitespace.length && _canCollapseWhitespace(currentTag, currentAttrs)) {
367 | text = collapseWhitespace(text);
368 | }
369 | }
370 | currentChars = text;
371 | lint && lint.testChars(text);
372 | buffer.push(text);
373 | },
374 | comment: function( text ) {
375 | if (options.removeComments) {
376 | if (isConditionalComment(text)) {
377 | text = '';
378 | }
379 | else {
380 | text = '';
381 | }
382 | }
383 | else {
384 | text = '';
385 | }
386 | buffer.push(text);
387 | },
388 | doctype: function(doctype) {
389 | buffer.push(options.useShortDoctype ? '' : collapseWhitespace(doctype));
390 | }
391 | });
392 |
393 | results.push.apply(results, buffer)
394 | var str = results.join('');
395 | log('minified in: ' + (new Date() - t) + 'ms');
396 | return str;
397 | }
398 |
399 | // for CommonJS enviroments, export everything
400 | if ( typeof exports !== "undefined" ) {
401 | exports.minify = minify;
402 | } else {
403 | global.minify = minify;
404 | }
405 |
406 | }(this));
--------------------------------------------------------------------------------