Skip to content

Commit

Permalink
minify based on white list
Browse files Browse the repository at this point in the history
  • Loading branch information
siva-sundar authored and Turbo87 committed Feb 5, 2018
1 parent 4c7a09d commit ea4ee45
Show file tree
Hide file tree
Showing 12 changed files with 1,638 additions and 346 deletions.
1,584 changes: 1,271 additions & 313 deletions __snapshots__/hbs-minifier-plugin.test.js.snap

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
module.exports = function(defaults) {
let app = new EmberAddon(defaults, {
// Add options here
'ember-hbs-minifier': {
skip: {
elements: ['pre', 'address'],
classes: ['description'],
components: ['foo-bar']
}
}
});

/*
Expand Down
44 changes: 27 additions & 17 deletions hbs-minifier-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ const stripWhiteSpace = Util.stripWhiteSpace;
const isWhitespaceTextNode = Util.isWhitespaceTextNode;
const hasLeadingOrTrailingWhiteSpace = Util.hasLeadingOrTrailingWhiteSpace;
const stripNoMinifyBlocks = Util.stripNoMinifyBlocks;
const canTrimBlockStatementContent = Util.canTrimBlockStatementContent;
const canTrimElementNodeContent = Util.canTrimElementNodeContent;
const assignDefaultValues = Util.assignDefaultValues;

class HBSMinifierPlugin {

static createASTPlugin() {
class BasePlugin {
static createASTPlugin(config) {
config = config || {};
let preStack = [];
let visitor = {
TextNode(node) {
Expand All @@ -21,13 +24,14 @@ class HBSMinifierPlugin {

BlockStatement: {
enter(node) {
if (node.path.original === 'no-minify') {
preStack.push(true);
let canTrim = canTrimBlockStatementContent(node, config);
if (!canTrim) {
preStack.push(node);
}
},

exit(node) {
if (node.path.original === 'no-minify') {
if (preStack[preStack.length - 1] === node) {
preStack.pop();
}
},
Expand Down Expand Up @@ -57,8 +61,10 @@ class HBSMinifierPlugin {

ElementNode: {
enter(node) {
if (node.tag === 'pre') {
preStack.push(true);
let canTrim = canTrimElementNodeContent(node, config);

if (!canTrim) {
preStack.push(node);
}

if (preStack.length !== 0) {
Expand All @@ -79,7 +85,7 @@ class HBSMinifierPlugin {
exit(node) {
node.children = stripNoMinifyBlocks(node.children);

if (node.tag === 'pre') {
if (preStack[preStack.length - 1] === node) {
preStack.pop();
}
}
Expand All @@ -88,15 +94,19 @@ class HBSMinifierPlugin {

return { name: 'hbs-minifier-plugin', visitor };
}
}

transform(ast) {
let plugin = HBSMinifierPlugin.createASTPlugin();

this.syntax.traverse(ast, plugin.visitor);
module.exports = function(config) {
config = config || {};
config = assignDefaultValues(config);

return ast;
}
return class HBSMinifierPlugin extends BasePlugin {

}
transform(ast) {

module.exports = HBSMinifierPlugin;
let plugin = HBSMinifierPlugin.createASTPlugin(config);
this.syntax.traverse(ast, plugin.visitor);
return ast;
}
};
};
75 changes: 70 additions & 5 deletions hbs-minifier-plugin.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
'use strict';

/* eslint-env jest */

const defaultConfig = {
skip: {
elements: ['pre', 'address'],
classes: ['description'],
components: ['foo-bar']
}
};
const glimmer = require('@glimmer/syntax');
const HbsMinifierPlugin = require('./hbs-minifier-plugin');
const HbsMinifierPlugin = require('./hbs-minifier-plugin')(defaultConfig);

it('collapses whitespace into single space character', () => {
assert(`{{foo}} \n\n \n{{bar}}`);
Expand Down Expand Up @@ -45,17 +51,73 @@ it('does not collapse whitespace inside of {{#no-minify}} tags in other tags', f
assert(`<div>{{#no-minify}} \n\n \n{{/no-minify}}</div>`);
});

it('11. does not collapse multiple &nbsp; textNode into a single whitespace', function() {
it('does not collapse multiple &nbsp; textNode into a single whitespace', function() {
assert(`<span>1</span>&nbsp;&nbsp;<span>2</span>`);
});

it('12. does not collapse &nbsp; surrounding a text content into a single whitespace', function() {
it('does not collapse &nbsp; surrounding a text content into a single whitespace', function() {
assert(`<div>
<span> &nbsp;1&nbsp; </span>
<span> 2 </span>
</div>`);
});

it('does not minify `tagNames` specified in .hbs-minifyrc.js', function() {
assert(`<address>
Box 564,
<b>
Disneyland
</b>
<br>
<u> USA </u>
</address>`);
});

it('does not minify `classNames` specified in .hbs-minifyrc.js', function() {
assert(`<div class="description">
1
<span>
2
</span>
</div>`);
});

it('does not minify `components` specified in .hbs-minifyrc.js', function() {
assert(`{{#foo-bar}}
<span>
yield content
</span>
{{/foo-bar}}`);
});

it('minifies `tagNames` that are not specified in .hbs-minifyrc.js', function() {
assert(`<section>
Box 564,
<b>
Disneyland
</b>
<br>
<u> USA </u>
</section>`);
});

it('minifies `classNames` that are not specified in .hbs-minifyrc.js', function() {
assert(`<div class="contact-details">
John Smith
<i>
(Entrepreneur)
</i>
</div>`);
});

it('minifies `components` that are not specified in .hbs-minifyrc.js', function() {
assert(`{{#my-component}}
<span>
yield content
</span>
{{/my-component}}`);
});

function assert(template) {
let ast = process(template);
expect(ast).toMatchSnapshot();
Expand All @@ -65,9 +127,12 @@ function assert(template) {
}

function process(template) {
let plugin = () => {
return HbsMinifierPlugin.createASTPlugin(defaultConfig.skip);
};
return glimmer.preprocess(template, {
plugins: {
ast: [HbsMinifierPlugin.createASTPlugin]
ast: [plugin]
}
});
}
30 changes: 21 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
/* eslint-env node */
'use strict';
let objectHash = require('object-hash');

module.exports = {
name: 'ember-hbs-minifier',

setupPreprocessorRegistry(type, registry) {
if (type === 'parent') {
let HbsMinifierPlugin = require('./hbs-minifier-plugin');
_setupPreprocessorRegistry(app) {
let registry = app.registry;
let options = app.options || {};
let config = options['ember-hbs-minifier'] || {};

registry.add('htmlbars-ast-plugin', {
name: 'hbs-minifier-plugin',
plugin: HbsMinifierPlugin,
baseDir() { return __dirname; }
});
}
let HbsMinifierPlugin = require('./hbs-minifier-plugin')(config.skip || {});
registry.add('htmlbars-ast-plugin', {
name: 'hbs-minifier-plugin',
plugin: HbsMinifierPlugin,
baseDir() { return __dirname; },
cacheKey() { return `ember-hbs-minifier-${objectHash.MD5(config)}`; }
});
},

included(app) {
this._super.included.apply(this, arguments);
/*
Calling setupPreprocessorRegistry in included hook since app.options is not accessible
Refer PR: https://github.com/ember-cli/ember-cli/pull/7059
*/
this._setupPreprocessorRegistry(app);
}
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"ember-welcome-page": "^2.0.2",
"eslint-config-simplabs": "0.2.2",
"jest": "^21.2.0",
"loader.js": "^4.2.3"
"loader.js": "^4.2.3",
"object-hash": "1.2.0"
},
"engines": {
"node": ">= 4"
Expand Down
6 changes: 6 additions & 0 deletions tests/dummy/app/components/foo-bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Ember from 'ember';
import layout from '../templates/components/foo-bar';

export default Ember.Component.extend({
layout
});
6 changes: 6 additions & 0 deletions tests/dummy/app/components/x-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Ember from 'ember';
import layout from '../templates/components/x-button';

export default Ember.Component.extend({
layout
});
8 changes: 8 additions & 0 deletions tests/dummy/app/templates/components/foo-bar.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
1
<span>
2
</span>
<span>
3
</span>
{{yield}}
2 changes: 2 additions & 0 deletions tests/dummy/app/templates/components/x-button.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
save
{{yield}}
105 changes: 105 additions & 0 deletions tests/integration/components/dummy-component-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,109 @@ describe('HBS Minifier plugin', function() {
expect(childNode.textContent.trim()).to.equal('1');
});

it('does not minify `tagNames` specified in .hbs-minifyrc.js', function() {
this.render(hbs `
<address>
Box 564,
<b>
Disneyland
</b>
<br>
<u> USA </u>
</address>`);

let childNodes = this.$('address')[0].childNodes;
expect(childNodes[0].textContent).to.equal('\n Box 564,\n ');
// ensuring the textContent is surrounded by whitespaces
expect(childNodes[1].textContent).to.equal('\n Disneyland\n ');
expect(childNodes[2].textContent).to.equal('\n ');
expect(childNodes[4].textContent).to.equal('\n ');
expect(childNodes[5].textContent).to.equal(' USA ');
});


it('does not minify `classNames` specified in .hbs-minifyrc.js', function() {
this.render(hbs `
<div class="description">
1
<span>
2
</span>
</div>`);

let childNodes = this.$('div')[0].childNodes;
expect(childNodes[0].textContent).to.equal('\n 1\n ');
expect(childNodes[1].textContent).to.equal('\n 2\n ');
expect(childNodes[2].textContent).to.equal('\n');
});

it('does not minify `component` boundaries specified in .hbs-minifyrc.js', function() {
this.render(hbs `
{{#foo-bar}}
<span>
yield content
</span>
{{/foo-bar}}`);

let childNodes = this.$('div')[0].childNodes;
expect(childNodes[0].textContent).to.equal('1 ');
expect(childNodes[1].textContent).to.equal(' 2 ');
expect(childNodes[3].textContent).to.equal(' 3 ');
expect(childNodes[4].textContent).to.equal(' ');
expect(childNodes[5].textContent).to.equal(' ');
expect(childNodes[6].textContent).to.equal('\n yield content\n ');
expect(childNodes[7].textContent).to.equal('\n');
});

it('minify `tagNames` that are not specified in .hbs-minifyrc.js', function() {
this.render(hbs `
<ul>
<li>
1
</li>
<li>
2
</li>
</ul>`);

let childNodes = this.$('ul')[0].childNodes;
expect(childNodes.length).to.equal(3);
expect(childNodes[0].textContent).to.equal(' 1 ');
expect(childNodes[1].textContent).to.equal(' ');
expect(childNodes[2].textContent).to.equal(' 2 ');
});

it('minifies `classNames` that are not specified in .hbs-minifyrc.js', function() {
this.render(hbs `
<div class="numbers">
1
<span>
2
</span>
</div>`);

let childNodes = this.$('div')[0].childNodes;
expect(childNodes.length).to.equal(2);
expect(childNodes[0].textContent).to.equal(' 1 ');
expect(childNodes[1].textContent).to.equal(' 2 ');
});

it('minify `component` boundaries that are not specified in .hbs-minifyrc.js', function() {
this.render(hbs `
{{#x-button tagName="button"}}
<div>
yield content
</div>
{{/x-button}}`);

let childNodes = this.$('button')[0].childNodes;
expect(childNodes.length).to.equal(2);
expect(childNodes[0].textContent).to.equal('save ');
expect(childNodes[1].nodeName).to.equal('DIV');
let yieldElementChildNodes = this.$('div')[0].childNodes;
expect(yieldElementChildNodes.length).to.equal(1);
expect(yieldElementChildNodes[0].textContent).to.equal(' yield content ');
});


});
Loading

0 comments on commit ea4ee45

Please sign in to comment.