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

Commit

Permalink
Merge pull request #535 from stephanebachelier/eli-colins-works-rebased
Browse files Browse the repository at this point in the history
Rebase on #306 and additions
  • Loading branch information
stephanebachelier committed Apr 12, 2015
2 parents 1797026 + a7befbd commit dff7e20
Show file tree
Hide file tree
Showing 13 changed files with 558 additions and 92 deletions.
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ It uses only one target: `html`, with a list of the concerned files. For example
By default, it will consider the directory where the looked-at file is located as the 'root' filesystem. Each relative path (for example to a javascript file) will be resolved from this path. Same goes for the absolute ones.
If you need to change the 'root' dir, use the `root` option (see below).

Note that `useminPrepare` and `usemin` tasks will both throw an error if a resource is not found.

```js
useminPrepare: {
html: 'index.html'
Expand Down Expand Up @@ -255,6 +257,84 @@ useminPrepare: {

The given steps or post-processors may be specified as strings (for the default steps and post-processors), or as an object (for the user-defined ones).

### resolveSource

Type: 'function'
Default: `undefined`

This is an optional hook allowing applications to override how source urls
are resolved to filesystem paths. This function is called with the signature
`resolveSource(sourceUrl, fileDir, fileName, blockTarget, searchPath)`, where:

* `sourceUrl` is the source reference being resolved,
* `fileDir` and `fileName` are respectively, the directory and name of the file, the reference was found in,
* `blockTarget` is the target path for the block the reference occurred within,
* `searchPath` is an array of the directories that would be searched by default.

The return value of this function should be :
* the path to the source file,
* `null` to indicate the default resolution rules should be used to resolve `sourceUrl`,
* `false` to indicate the file cannot be resolved, thus default resolution rules are not used.

The default resolution is to search the `sourceUrl` in all provided entries in `searchPath` array.

For example:

* To override a specific URL prefix, and use the default behavior for all others:

```js
'useminPrepare', {
options: {
resolveSource: function (sourceUrl, fileDir, fileName, blockTarget, searchPath) {
var fs = require('fs');
var path = require('path');

var match = sourceUrl.match(/^\/alt-static-url\/(.*)/);
if (match) {
var source = path.join("alt-static-location", match[1]);
// return the override source path if found on filesystem
// else will default to null which means that resource will be search using
// default behavior
if (fs.existsSync(source)) {
return source;
}
/*
// You might be interested in return false if source cannot be resolved using the
// following code instead:
// it will return the overriden source path if resource found on filesystem
// or false if not found, meaning default behavior will not be used
return fs.existsSync(source) ? source : false;
*/
}
// returning null will match the default behavior for any url not matching
// the prefix `^/alt-static-url/`
return null;
}
}
}
```

* To replicate the default behavior, use the following version. It should be noted that this is only for illustration purpose, as the default behavior will be used if no `resolveSource` hook is provided, or if `resolveSource` fails to resolve the sourceUrl, hence returning null.

```js
'useminPrepare', {
options: {
resolveSource: function (sourceUrl, fileDir, fileName, blockTarget, searchPath) {
var fs = require('fs');
var path = require('path');
for (var i = 0; i < searchPath.length; ++i) {
var source = path.join(searchPath[i], fname);
if (fs.existsSync(source)) {
return source;
}
}
// source not found, so returning false as it cannot be resolved
return false;
}
}
}
```

#### User-defined steps and post-processors

User-defined steps and post-processors must have 2 attributes:
Expand Down
20 changes: 1 addition & 19 deletions lib/config/concat.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';
var path = require('path');
var fs = require('fs');
var _ = require('lodash');

exports.name = 'concat';

Expand All @@ -21,23 +19,7 @@ exports.createConfig = function (context, block) {
// Depending whether or not we're the last of the step we're not going to output the same thing
var files = {};
files.dest = outfile;
files.src = [];

context.inFiles.forEach(function (f) {
if (_.isArray(context.inDir)) {
context.inDir.every(function (d) {
var joinedPath = path.join(d, f);
var joinedPathExists = fs.existsSync(joinedPath);
if (joinedPathExists) {
files.src.push(joinedPath);
}
return !joinedPathExists;
});
} else {
files.src.push(path.join(context.inDir, f));
}
});

files.src = context.inFiles.map(context.resolveInFile, context);
cfg.files.push(files);
context.outFiles = [block.dest];
return cfg;
Expand Down
5 changes: 1 addition & 4 deletions lib/config/cssmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ exports.createConfig = function (context, block) {
// Depending whether or not we're the last of the step we're not going to output the same thing
var files = {};
files.dest = outfile;
files.src = [];
context.inFiles.forEach(function (f) {
files.src.push(path.join(context.inDir, f));
});
files.src = context.inFiles.map(context.resolveInFile, context);
cfg.files.push(files);
context.outFiles = [block.dest];
return cfg;
Expand Down
8 changes: 3 additions & 5 deletions lib/config/uglify.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ exports.createConfig = function (context, block) {
var files = {};
var ofile = path.join(context.outDir, block.dest);
files.dest = ofile;
files.src = context.inFiles.map(function (fname) {
return path.join(context.inDir, fname);
});
// cfg[ofile] = context.inFiles.map(function (fname) { return path.join(context.inDir, fname);});
files.src = context.inFiles.map(context.resolveInFile, context);
// cfg[ofile] = context.inFiles.map(context.resolveInFile, context);
cfg.files.push(files);
context.outFiles.push(block.dest);
} else {
context.inFiles.forEach(function (fname) {
var file = path.join(context.inDir, fname);
var file = context.resolveInFile(fname);
var outfile = path.join(context.outDir, fname);
cfg.files.push({
src: [file],
Expand Down
77 changes: 64 additions & 13 deletions lib/configwriter.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
'use strict';
var path = require('path');
var fs = require('fs');
var grunt = require('grunt');
var File = require('./file');
var _ = require('lodash');

var deepMerge = function (origCfg, cfg) {
var outCfg = origCfg;

// If the newly generated part is already in the config file
// with the same destination update only the source part, instead of add the whole block again.
// This way the same targets wont be regenerated multiple times if usemin is called
// multiple times which can happen with grunt-watcher spawn:false mode (#307)
// If the newly generated part is already in the config file
// with the same destination update only the source part, instead of add the whole block again.
// This way the same targets wont be regenerated multiple times if usemin is called
// multiple times which can happen with grunt-watcher spawn:false mode (#307)

if (origCfg.files && cfg.files) {
var done = false;
Expand Down Expand Up @@ -54,13 +56,17 @@ var deepMerge = function (origCfg, cfg) {
// - Deliver for each block the requested file under dist directory
//
//
var ConfigWriter = module.exports = function (flow, dirs) {
var ConfigWriter = module.exports = function (flow, dirs, options) {
var self = this;
this.flow = flow;
// FIXME: check dest and staging are furnished
this.root = dirs.root;
this.dest = dirs.dest;
this.staging = dirs.staging;

// optional hook to resolve source url
this.resolveSource = options && options.resolveSource;

this.steps = {};
this.postprocessors = [];
this.destinations = {};
Expand Down Expand Up @@ -152,6 +158,8 @@ ConfigWriter.prototype.forEachStep = function (blockType, cb) {
ConfigWriter.prototype.process = function (file, config) {
var self = this;
var lfile = file;
var rootPath = self.root || [];
if (!Array.isArray(rootPath)) { rootPath = [rootPath]; }

config = config || {};

Expand All @@ -160,16 +168,60 @@ ConfigWriter.prototype.process = function (file, config) {
}

lfile.blocks.forEach(function (block) {
// FIXME: support several searchPath...
// NOTE: initial context.inDir is only used by ./config/requirejs,
// everything else uses context.resolveInFile(),
// which checks entire searchPath.
var searchPath = block.searchPath.concat(rootPath, lfile.searchPath);
var context = {
inDir: self.root || lfile.searchPath[0],
inFiles: block.src,
outFiles: []
};

if (block.searchPath.length > 0) {
// FIXME: we must use all the furnished directories
context.inDir = block.searchPath[0];
function resolveInFile (fname) {
var source = null;
// if a resolveSource hook function is provided use it for file source
if (self.resolveSource) {
source = self.resolveSource(fname, lfile.dir, lfile.name, block.dest, searchPath);
if (source) {
if (!fs.existsSync(source)) {
grunt.fail.warn(_.template(
'usemin: resolveSource() returned non-existent path "<%= source %>"' +
' for source "<%= fname %>".')(
{
source: source,
fname: fname
}));
}
return source;
}
}
// default behavior to search file in provided search paths.
// * source being null meaning that no resolveSource hook provided
// * source being false meaning that
if (source !== false) {
for (var i = 0; i < searchPath.length; ++i) {
source = path.join(searchPath[i], fname);
if (fs.existsSync(source)) {
return source;
}
}
}
grunt.fail.warn(_.template(
'usemin: can\'t resolve source reference "<%= fname %>" ' +
'(file "<%= filepath %>", block "<%= block.dest %>").')(
{
fname: fname,
block: block,
filepath: path.join(lfile.dir, lfile.name)
}));
// we know it's not there, but return placeholder to match old behavior.
return path.join(searchPath[0], fname);
}
context.resolveInFile = resolveInFile;

function resolveTempFile(fname) {
return path.join(context.inDir, fname);
}

self.forEachStep(block.type, function (writer, last) {
Expand Down Expand Up @@ -207,15 +259,14 @@ ConfigWriter.prototype.process = function (file, config) {
}
context.inDir = context.outDir;
context.inFiles = context.outFiles;
context.resolveInFile = resolveTempFile;
context.outFiles = [];
context.options = null;
});

context.inDir = lfile.searchPath[0];
if (block.searchPath.length > 0) {
context.inDir = block.searchPath[0];
}
context.inDir = searchPath[0];
context.inFiles = block.src;
context.resolveInFile = resolveInFile;

if (self.postprocessors.hasOwnProperty(block.type)) {
self.postprocessors[block.type].forEach(function (pp) {
Expand Down
12 changes: 11 additions & 1 deletion tasks/usemin.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ module.exports = function (grunt) {
var blockReplacements = options.blockReplacements || {};

debug('Looking at %s target', this.target);

var patterns = [];
var type = this.target;

Expand All @@ -132,6 +133,11 @@ module.exports = function (grunt) {
nonull: true,
filter: 'isFile'
}, fileObj.src);

if (!files.length) {
grunt.fail.warn('No files found for target ' + type);
}

files.forEach(function (filename) {
debug('looking at file %s', filename);

Expand All @@ -158,6 +164,10 @@ module.exports = function (grunt) {
var staging = options.staging || '.tmp';
var root = options.root;

if (!this.filesSrc.length) {
grunt.fail.warn('No source file found.');
}

grunt.verbose
.writeln('Going through ' + grunt.log.wordlist(this.filesSrc) + ' to update the config')
.writeln('Looking for build script HTML comment blocks');
Expand All @@ -168,7 +178,7 @@ module.exports = function (grunt) {
root: root,
dest: dest,
staging: staging
});
}, options);

var cfgNames = [];
c.stepWriters().forEach(function (i) {
Expand Down
12 changes: 0 additions & 12 deletions test/fixtures/usemin.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,6 @@ <h3>Enjoy coding! - Yeoman</h3>
<!-- build:js /scripts/plugins.js -->
<script src="scripts/vendor/bootstrap/bootstrap-affix.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-alert.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-dropdown.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-tooltip.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-modal.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-transition.js"></script>

<script src="scripts/vendor/bootstrap/bootstrap-button.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-popover.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-typeahead.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-carousel.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-scrollspy.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-collapse.js"></script>
<script src="scripts/vendor/bootstrap/bootstrap-tab.js"></script>
<!-- endbuild -->

<a href="<?php echo URL::to('admin/create') ?>"><i class='icon-plus icon-white'></i>&nbsp;&nbsp;New</a>
Expand Down
16 changes: 16 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var rimraf = require('rimraf');
var mkdirp = require('mkdirp');
var _ = require('lodash');
var helpers = module.exports;
var grunt = require('grunt');

helpers.directory = function directory(dir) {
return function directory(done) {
Expand Down Expand Up @@ -139,3 +140,18 @@ helpers.normalize = function (object) {

return object;
};

var warn = grunt.fail.warn;

// mock grunt.fail.warn to avoid breaking test
helpers.mockGruntFailWarn = function (ctx, name) {
name = name || 'warnMessage';
grunt.fail.warn = function (message) {
ctx[name] = message;
};
};

// mock grunt.fail.warn to avoid breaking test
helpers.restoreGruntFailWarn = function () {
grunt.fail.warn = warn;
};
Loading

0 comments on commit dff7e20

Please sign in to comment.