Skip to content
This repository was archived by the owner on Apr 20, 2018. It is now read-only.

Commit 2a6b574

Browse files
committed
Merge pull request #337 from mcampo/custom-types
add suport for block replacement for custom block types
2 parents 6f4e4fd + 7cbdd87 commit 2a6b574

File tree

6 files changed

+110
-25
lines changed

6 files changed

+110
-25
lines changed

README.md

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Blocks are expressed as:
5151
<!-- endbuild -->
5252
```
5353

54-
* **type**: either `js` or `css`
54+
* **type**: can be `js`, `css` or a custom type with a [block replacement function](#blockreplacements) defined
5555
* If another type, the block will be ignored. Useful for "development only" blocks that won't appear in your build
5656
* **alternate search path**: (optional) By default the input files are relative to the treated file. Alternate search path allows one to change that
5757
* **path**: the file path of the optimized file, the target output
@@ -136,28 +136,28 @@ useminPrepare: {
136136

137137
### dest
138138

139-
Type: 'string' <br/>
139+
Type: 'string'
140140
Default: `nil`
141141

142142
Base directory where the transformed files should be output.
143143

144144
### staging
145145

146-
Type: 'string' <br/>
146+
Type: 'string'
147147
Default: `.tmp`
148148

149149
Base directory where the temporary files should be output (e.g. concatenated files).
150150

151151
### root
152152

153-
Type: 'string' or 'Array' <br/>
154-
Default: `nil` <br/>
153+
Type: 'string' or 'Array'
154+
Default: `nil`
155155

156156
The root directory from which your files will be resolved.
157157

158158
### flow
159159

160-
Type: 'object' <br/>
160+
Type: 'object'
161161
Default: `{ steps: { js: ['concat', 'uglifyjs'], css: ['concat', 'cssmin'] }, post: {} }`
162162

163163
This allow you to configure the workflow, either on a per-target basis, or for all the targets.
@@ -327,7 +327,7 @@ By default `usemin` will look under `dist/html` for revved versions of `styles/m
327327

328328
#### assetsDirs
329329

330-
Type: 'Array'
330+
Type: 'Array'
331331
Default: Single item array set to the value of the directory where the currently looked at file is.
332332

333333
List of directories where we should start to look for revved version of the assets referenced in the currently looked at file.
@@ -344,7 +344,7 @@ usemin: {
344344

345345
#### patterns
346346

347-
Type: 'Object'
347+
Type: 'Object'
348348
Default: Empty
349349

350350
Allows for user defined pattern to replace reference to files. For example, let's suppose that you want to replace
@@ -375,9 +375,36 @@ So in short:
375375
* FIXME
376376
* FIXME
377377

378+
#### blockReplacements
379+
380+
Type: 'Object'
381+
Default: `{ css: function (block) { ... }, js: function (block) { ... } }`
382+
383+
This lets you define how blocks get their content replaced. Useful to have block types other that `css` and `js`.
384+
385+
* Object key matches a block type
386+
* Value is the replacement function for that block type.
387+
* The replacement function gets called with a single argument: a [block](#block) object.
388+
* Must return a `String`, the "summary" line that will replace the block content.
389+
390+
For example, to create a `less` block you could define its replacement function like this:
391+
392+
```js
393+
usemin: {
394+
html: index.html,
395+
options: {
396+
blockReplacements: {
397+
less: function (block) {
398+
return '<link rel="stylesheet" href="' + block.dest + '">';
399+
}
400+
}
401+
}
402+
}
403+
```
404+
378405
#### revmap
379406

380-
Type: 'String'
407+
Type: 'String'
381408
Default: Empty
382409

383410
Indicate the location of a map file, as produced by `grunt-filerev` for example. This map file is a simple JSON file, holding an object

lib/fileprocessor.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,22 @@ var _defaultPatterns = {
6868
]
6969
};
7070

71-
var FileProcessor = module.exports = function (patterns, finder, logcb) {
71+
//
72+
// Default block replacement functions, for css and js types
73+
//
74+
var defaultBlockReplacements = {
75+
css: function (block) {
76+
var media = block.media ? ' media="' + block.media + '"' : '';
77+
return '<link rel="stylesheet" href="' + block.dest + '"' + media + '>';
78+
},
79+
js: function (block) {
80+
var defer = block.defer ? 'defer ' : '';
81+
var async = block.async ? 'async ' : '';
82+
return '<script ' + defer + async + 'src="' + block.dest + '"><\/script>';
83+
}
84+
};
85+
86+
var FileProcessor = module.exports = function (patterns, finder, logcb, blockReplacements) {
7287
if (!patterns) {
7388
throw new Error('No pattern given');
7489
}
@@ -89,6 +104,13 @@ var FileProcessor = module.exports = function (patterns, finder, logcb) {
89104
throw new Error('Missing parameter: finder');
90105
}
91106
this.finder = finder;
107+
108+
109+
this.blockReplacements = _.assign({}, defaultBlockReplacements);
110+
if (blockReplacements && _.keys(blockReplacements).length > 0) {
111+
_.assign(this.blockReplacements, blockReplacements);
112+
}
113+
92114
};
93115

94116
//
@@ -107,21 +129,13 @@ FileProcessor.prototype.replaceBlocks = function replaceBlocks(file) {
107129

108130
FileProcessor.prototype.replaceWith = function replaceWith(block) {
109131
var result;
110-
var dest = block.dest;
111132
var conditionalStart = block.conditionalStart ? block.conditionalStart + '\n' + block.indent : '';
112133
var conditionalEnd = block.conditionalEnd ? '\n' + block.indent + block.conditionalEnd : '';
113134
if (typeof block.src === 'undefined' || block.src === null || block.src.length === 0) {
114135
// there are no css or js files in the block, remove it completely
115136
result = '';
116-
} else if (block.type === 'css') {
117-
var media = block.media ? ' media="' + block.media + '"' : '';
118-
result = block.indent + conditionalStart + '<link rel="stylesheet" href="' + dest + '"' + media + '/>' + conditionalEnd;
119-
} else if (block.defer) {
120-
result = block.indent + conditionalStart + '<script defer src="' + dest + '"><\/script>' + conditionalEnd;
121-
} else if (block.async) {
122-
result = block.indent + conditionalStart + '<script async src="' + dest + '"><\/script>' + conditionalEnd;
123-
} else if (block.type === 'js') {
124-
result = block.indent + conditionalStart + '<script src="' + dest + '"><\/script>' + conditionalEnd;
137+
} else if (_.contains(_.keys(this.blockReplacements), block.type)) {
138+
result = block.indent + conditionalStart + this.blockReplacements[block.type](block) + conditionalEnd;
125139
} else {
126140
result = '';
127141
}

tasks/usemin.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ module.exports = function (grunt) {
111111
var options = this.options({
112112
type: this.target
113113
});
114+
var blockReplacements = options.blockReplacements || {};
114115

115116
debug('Looking at %s target', this.target);
116117
var patterns;
@@ -129,7 +130,7 @@ module.exports = function (grunt) {
129130
var revvedfinder = new RevvedFinder(locator);
130131
var handler = new FileProcessor(patterns, revvedfinder, function (msg) {
131132
grunt.log.writeln(msg);
132-
});
133+
}, blockReplacements);
133134

134135
this.files.forEach(function (fileObj) {
135136
var files = grunt.file.expand({
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<!-- build:less styles/main.css -->
2+
<link rel="stylesheet/less" href="styles/foo.less">
3+
<link rel="stylesheet/less" href="styles/bar.less">
4+
<!-- endbuild -->

test/test-fileprocessor.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('FileProcessor', function () {
6666
};
6767

6868
var result = fp.replaceWith(block);
69-
assert.equal(result, ' <link rel="stylesheet" href="foo.css"/>');
69+
assert.equal(result, ' <link rel="stylesheet" href="foo.css">');
7070
});
7171

7272
it('should remove css blocks which have no stylesheets linked in them', function () {
@@ -108,6 +108,24 @@ describe('FileProcessor', function () {
108108
assert.equal(result, '');
109109
});
110110

111+
it('should replace cutsom blocks using provided replacement function', function () {
112+
var blockReplacements = {
113+
less: function (block) {
114+
return 'custom replacement for ' + block.dest;
115+
}
116+
};
117+
var fp = new FileProcessor('html', {}, function () {}, blockReplacements);
118+
var block = {
119+
dest: 'foo.css',
120+
type: 'less',
121+
src: ['bar.less'],
122+
indent: ' '
123+
};
124+
125+
var result = fp.replaceWith(block);
126+
assert.equal(result, ' custom replacement for foo.css');
127+
});
128+
111129
it('should preserve defer attribute (JS)', function () {
112130
var fp = new FileProcessor('html', {});
113131
var block = {
@@ -147,7 +165,7 @@ describe('FileProcessor', function () {
147165
};
148166

149167
var result = fp.replaceWith(block);
150-
assert.equal(result, ' <link rel="stylesheet" href="foo.css" media="(min-width:980px)"/>');
168+
assert.equal(result, ' <link rel="stylesheet" href="foo.css" media="(min-width:980px)">');
151169
});
152170

153171
it('should preserve IE conditionals for js blocks', function () {
@@ -177,7 +195,7 @@ describe('FileProcessor', function () {
177195
};
178196

179197
var result = fp.replaceWith(block);
180-
assert.equal(result, ' <!--[if (lt IE 9) & (!IEmobile)]>\n <link rel="stylesheet" href="foo.css"/>\n <![endif]-->');
198+
assert.equal(result, ' <!--[if (lt IE 9) & (!IEmobile)]>\n <link rel="stylesheet" href="foo.css">\n <![endif]-->');
181199
});
182200
});
183201

test/test-usemin.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ describe('usemin', function () {
147147
var changed = grunt.file.read('build/foo/index.html');
148148

149149
assert.ok(changed.match(/<img src="\.\.\/images\/test\.23012\.png"\>/));
150-
assert.ok(changed.match(/<link rel=\"stylesheet\" href=\"styles\/main\.min\.css\"\/>/));
150+
assert.ok(changed.match(/<link rel=\"stylesheet\" href=\"styles\/main\.min\.css\">/));
151151
assert.ok(changed.match(/<img src=\"\.\.\/images\/misc\/test\.2a436\.png\">/));
152152

153153
});
@@ -331,6 +331,27 @@ describe('usemin', function () {
331331
assert.ok(changed.match('<img src="images/test.2134.png">'));
332332
});
333333

334+
it('should allow for custom block replacement functions', function () {
335+
grunt.log.muted = true;
336+
grunt.config.init();
337+
grunt.config('usemin', {
338+
html: 'index.html',
339+
options: {
340+
blockReplacements: {
341+
less: function (block) {
342+
return '<link rel="stylesheet" href="' + block.dest + '">';
343+
}
344+
}
345+
}
346+
});
347+
grunt.file.copy(path.join(__dirname, 'fixtures/block_with_custom_type.html'), 'index.html');
348+
grunt.task.run('usemin');
349+
grunt.task.start();
350+
351+
var changed = grunt.file.read('index.html');
352+
// Check replace has performed its duty
353+
assert.equal(changed, '<link rel="stylesheet" href="styles/main.css">');
354+
});
334355
});
335356

336357
describe('useminPrepare', function () {

0 commit comments

Comments
 (0)