From: Jakub Pawlowicz Date: Sun, 21 Jun 2015 13:49:36 +0000 (+0100) Subject: Extracts 'remove duplicate media queries' optimization into a module. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=c97c942e7f41bc6f37b4119e5226f8a153cfb4ae;p=clean-css.git Extracts 'remove duplicate media queries' optimization into a module. --- diff --git a/lib/selectors/advanced.js b/lib/selectors/advanced.js index 4f55c398..6487106e 100644 --- a/lib/selectors/advanced.js +++ b/lib/selectors/advanced.js @@ -2,7 +2,6 @@ var optimizeProperties = require('../properties/optimizer'); var extractProperties = require('./extractor'); var canReorder = require('./reorderable').canReorder; -var stringifyAll = require('../stringifier/one-time').all; var removeDuplicates = require('./remove-duplicates'); var mergeAdjacent = require('./merge-adjacent'); @@ -10,30 +9,13 @@ var reduceNonAdjacent = require('./reduce-non-adjacent'); var mergeNonAdjacentBySelector = require('./merge-non-adjacent-by-selector'); var mergeNonAdjacentByBody = require('./merge-non-adjacent-by-body'); var restructure = require('./restructure'); +var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries'); function AdvancedOptimizer(options, context) { this.options = options; this.validator = context.validator; } -AdvancedOptimizer.prototype.removeDuplicateMediaQueries = function (tokens) { - var candidates = {}; - - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - if (token[0] != 'block') - continue; - - var key = token[1][0] + '%' + stringifyAll(token[2]); - var candidate = candidates[key]; - - if (candidate) - candidate[2] = []; - - candidates[key] = token; - } -}; - AdvancedOptimizer.prototype.mergeMediaQueries = function (tokens) { var candidates = {}; var reduced = []; @@ -141,7 +123,7 @@ AdvancedOptimizer.prototype.optimize = function (tokens) { } if (self.options.mediaMerging) { - self.removeDuplicateMediaQueries(tokens); + removeDuplicateMediaQueries(tokens); var reduced = self.mergeMediaQueries(tokens); for (var i = reduced.length - 1; i >= 0; i--) { _optimize(reduced[i][2]); diff --git a/lib/selectors/remove-duplicate-media-queries.js b/lib/selectors/remove-duplicate-media-queries.js new file mode 100644 index 00000000..44070b0f --- /dev/null +++ b/lib/selectors/remove-duplicate-media-queries.js @@ -0,0 +1,21 @@ +var stringifyAll = require('../stringifier/one-time').all; + +function removeDuplicateMediaQueries(tokens) { + var candidates = {}; + + for (var i = 0, l = tokens.length; i < l; i++) { + var token = tokens[i]; + if (token[0] != 'block') + continue; + + var key = token[1][0] + '%' + stringifyAll(token[2]); + var candidate = candidates[key]; + + if (candidate) + candidate[2] = []; + + candidates[key] = token; + } +} + +module.exports = removeDuplicateMediaQueries; diff --git a/test/media-queries-test.js b/test/media-queries-test.js deleted file mode 100644 index 35ce906e..00000000 --- a/test/media-queries-test.js +++ /dev/null @@ -1,167 +0,0 @@ -var vows = require('vows'); -var assert = require('assert'); -var CleanCSS = require('../index'); - -vows.describe('media queries') - .addBatch({ - 'different ones': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media print{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}@media print{div{display:block}}'); - } - }, - 'other than @media': { - 'topic': function () { - return new CleanCSS().minify('@font-face{font-family:A}@font-face{font-family:B}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@font-face{font-family:A}@font-face{font-family:B}'); - } - }, - 'with empty selector': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}div{}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}'); - } - } - }) - .addBatch({ - 'same two adjacent': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}div{display:block}}'); - } - }, - 'same three adjacent': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media screen{div{display:block}}@media screen{body{width:100%}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}div{display:block}body{width:100%}}'); - } - }, - 'same two with selectors in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}body{width:100%}.one{height:100px}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, 'body{width:100%}.one{height:100px}@media screen{a{color:red}div{display:block}}'); - } - }, - 'same two with other @media in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media (min-width:1024px){body{width:100%}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media (min-width:1024px){body{width:100%}}@media screen{a{color:red}div{display:block}}'); - } - }, - 'same two with breaking properties in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}.one{color:#00f}@media screen{div{display:block}}'); - } - }, - 'same two with breaking @media in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}@media (min-width:1024px){.one{color:#00f}}@media screen{div{display:block}}'); - } - }, - 'same two with breaking nested @media in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}@media (min-width:1024px){@media screen{.one{color:#00f}}}@media screen{div{display:block}}'); - } - }, - 'intermixed': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media (min-width:1024px){p{width:100%}}@media screen{div{display:block}}@media (min-width:1024px){body{height:100%}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}div{display:block}}@media (min-width:1024px){p{width:100%}body{height:100%}}'); - } - }, - 'same two with overriding shorthand in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:12px Helvetica}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font:12px Helvetica}}@media screen{div{display:block}}'); - } - }, - 'same two with different component property in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{font-size:10px}}@media (min-width:1024px){.one{font-weight:700}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media (min-width:1024px){.one{font-weight:700}}@media screen{a{font-size:10px}div{display:block}}'); - } - }, - 'same two with same values as moved in between': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media (min-width:1024px){.one{color:red}}@media screen{div{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media (min-width:1024px){.one{color:red}}@media screen{a{color:red}div{display:block}}'); - } - }, - 'duplicated but non-mergeable': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '.one{color:#000}@media screen{a{color:red}}'); - } - }, - 'many duplicated but non-mergeable': { - 'topic': function () { - return new CleanCSS().minify('@media print{a{color:#fff}}@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}@media print{a{display:block}}@media print{a{color:#fff}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '.one{color:#000}@media screen{a{color:red}}@media print{a{display:block;color:#fff}}'); - } - } - }) - .addBatch({ - 'further optimizations': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}@media screen{a{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red;display:block}}'); - } - } - }) - .addBatch({ - 'with comments': { - 'topic': function () { - return new CleanCSS().minify('@media screen{a{color:red}}/*! a comment */@media screen{a{display:block}}'); - }, - 'get merged': function (minified) { - assert.equal(minified.styles, '/*! a comment */@media screen{a{color:red;display:block}}'); - } - } - }) - .addBatch({ - 'disabled': { - 'topic': function () { - return new CleanCSS({ mediaMerging: false }).minify('@media screen{a{color:red}}@media screen{a{display:block}}'); - }, - 'keeps @media intact': function (minified) { - assert.equal(minified.styles, '@media screen{a{color:red}}@media screen{a{display:block}}'); - } - } - }).export(module); diff --git a/test/selectors/remove-duplicate-media-queries-test.js b/test/selectors/remove-duplicate-media-queries-test.js new file mode 100644 index 00000000..f07cd0d9 --- /dev/null +++ b/test/selectors/remove-duplicate-media-queries-test.js @@ -0,0 +1,41 @@ +var vows = require('vows'); +var optimizerContext = require('../test-helper').optimizerContext; + +vows.describe('remove duplicate media queries') + .addBatch( + optimizerContext('advanced on', { + 'adjacent': [ + '@media screen{a{color:red}}@media screen{a{color:red}}', + '@media screen{a{color:red}}' + ], + 'non-adjacent': [ + '@media screen{a{color:red}}@media print{a{color:#fff}}@media screen{a{color:red}}', + '@media print{a{color:#fff}}@media screen{a{color:red}}' + ], + 'single non-mergeable': [ + '@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}', + '.one{color:#000}@media screen{a{color:red}}' + ], + 'many non-mergeable': [ + '@media print{a{color:#fff}}@media screen{a{color:red}}.one{color:#000}@media screen{a{color:red}}@media print{a{display:block}}@media print{a{color:#fff}}', + '.one{color:#000}@media screen{a{color:red}}@media print{a{display:block;color:#fff}}' + ] + }) + ) + .addBatch( + optimizerContext('advanced off', { + 'keeps content same': [ + '@media screen{a{color:red}}@media screen{a{color:red}}', + '@media screen{a{color:red}}@media screen{a{color:red}}' + ] + }, { advanced: false }) + ) + .addBatch( + optimizerContext('media merging off', { + 'keeps content same': [ + '@media screen{a{color:red}}@media screen{a{color:red}}', + '@media screen{a{color:red}}@media screen{a{color:red}}' + ] + }, { mediaMerging: false }) + ) + .export(module);