diff --git a/src/htmlminifier.js b/src/htmlminifier.js index 7748f1c6..3f945576 100644 --- a/src/htmlminifier.js +++ b/src/htmlminifier.js @@ -803,7 +803,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) { } } -function minify(value, options, partialMarkup) { +function minify(value, options, partialMarkup, cb) { options = options || {}; var optionsStack = []; processOptions(options); @@ -867,14 +867,14 @@ function minify(value, options, partialMarkup) { uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)(\\s*)', 'g'); var minifyCSS = options.minifyCSS; if (minifyCSS) { - options.minifyCSS = function(text) { - return minifyCSS(escapeFragments(text)); + options.minifyCSS = function(text, cb) { + return minifyCSS(escapeFragments(text), cb); }; } var minifyJS = options.minifyJS; if (minifyJS) { - options.minifyJS = function(text, inline) { - return minifyJS(escapeFragments(text), inline); + options.minifyJS = function(text, inline, cb) { + return minifyJS(escapeFragments(text), inline, cb); }; } } @@ -941,7 +941,8 @@ function minify(value, options, partialMarkup) { trimTrailingWhitespace(charsIndex, nextTag); } - new HTMLParser(value, { + var str; + var parser = new HTMLParser(value, { partialMarkup: partialMarkup, html5: options.html5, @@ -1106,7 +1107,7 @@ function minify(value, options, partialMarkup) { } } }, - chars: function(text, prevTag, nextTag) { + chars: function(text, prevTag, nextTag, cb) { prevTag = prevTag === '' ? 'comment' : prevTag; nextTag = nextTag === '' ? 'comment' : nextTag; if (options.decodeEntities && text && !specialContentTags(currentTag)) { @@ -1160,42 +1161,83 @@ function minify(value, options, partialMarkup) { if (options.processScripts && specialContentTags(currentTag)) { text = processScript(text, options, currentAttrs); } + + var tasksWaitingFor = 0, tasksComplete = 0; + + function onTaskFinished(result) { + text = result; + if (tasksWaitingFor === ++tasksComplete) { + afterTasksFinish(); + } + } + if (isExecutableScript(currentTag, currentAttrs)) { - text = options.minifyJS(text); + try { + tasksWaitingFor++; + var minifyJSResult = options.minifyJS(text, null, onTaskFinished); + + // If the result is defined then minifyJS completed synchronously. + if (typeof minifyJSResult !== 'undefined') { + onTaskFinished(minifyJSResult); + } + } + catch (error) { + cb(error); + } } + if (isStyleSheet(currentTag, currentAttrs)) { - text = options.minifyCSS(text); - } - if (options.removeOptionalTags && text) { - // may be omitted if first thing inside is not comment - // may be omitted if first thing inside is not space, comment, , , '; + var output = ''; + var done = assert.async(); + assert.notOk(minify( + input, + { + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + '(function(){ console.log("World"); })()'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); +}); + +QUnit.test('style async minification with script sync minification', function(assert) { + var input = ''; + var output = ''; + var done = assert.async(); + assert.notOk(minify( + input, + { + minifyCSS: function(css, cb) { + setTimeout(function() { + cb(css + ' callback!'); + }, 0); + }, + minifyJS: true + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); +}); + +QUnit.test('style sync minification with script async minification', function(assert) { + var input = ''; + var output = ''; + var done = assert.async(); + assert.notOk(minify( + input, + { + minifyCSS: true, + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + ' callback!'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); +}); + +QUnit.test('style async minification with script async minification', function(assert) { + var input = ''; + var output = ''; + var done = assert.async(); + assert.notOk(minify( + input, + { + minifyCSS: function(css, cb) { + setTimeout(function() { + cb(css + ' callback!'); + }, 0); + }, + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + ' callback!'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); +}); + + +QUnit.test('async minification along side sync minification', function(assert) { + var input = ''; + var syncOutput = ''; + var asyncOutput = ''; + var done = assert.async(); + + assert.notOk(minify( + input, + { + minifyCSS: function(css, cb) { + setTimeout(function() { + cb(css + ' callback!'); + }, 0); + }, + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + ' callback!'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, asyncOutput); + done(); + } + )); + + assert.equal(minify(input, { + minifyCSS: true, + minifyJS: true + }), syncOutput); +}); + +QUnit.test('multiple async minifications', function(assert) { + var input = ''; + var output = ''; + var done = assert.async(2); + + assert.notOk(minify( + input, + { + minifyCSS: function(css, cb) { + setTimeout(function() { + cb(css + ' callback!'); + }, 0); + }, + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + ' callback!'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); + + assert.notOk(minify( + input, + { + minifyCSS: function(css, cb) { + setTimeout(function() { + cb(css + ' callback!'); + }, 0); + }, + minifyJS: function(js, inline, cb) { + setTimeout(function() { + cb(js + ' callback!'); + }, 0); + } + }, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + )); +}); + +QUnit.test('sync minify with callback', function(assert) { + var input = 'TestHello World'; + var output = input; + var done = assert.async(); + assert.equal(minify( + input, + {}, + function(error, result) { + assert.notOk(error); + assert.equal(result, output); + done(); + } + ), output); +}); + + +QUnit.test('minify error with callback', function(assert) { + var input = '