From d18d833b5e51a92afe7484e682363b2b90647c01 Mon Sep 17 00:00:00 2001 From: sladex Date: Tue, 9 Sep 2014 15:28:33 +0600 Subject: [PATCH 1/3] dropCwd option, fixes #15 --- tasks/filerev.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tasks/filerev.js b/tasks/filerev.js index 3363dcf..45e1a24 100644 --- a/tasks/filerev.js +++ b/tasks/filerev.js @@ -10,10 +10,12 @@ module.exports = function (grunt) { var options = this.options({ encoding: 'utf8', algorithm: 'md5', - length: 8 + length: 8, + dropCwd: false }); var target = this.target; var filerev = grunt.filerev || {summary: {}}; + var cwd = this.data.cwd || ''; eachAsync(this.files, function (el, i, next) { var move = true; @@ -60,13 +62,24 @@ module.exports = function (grunt) { grunt.file.copy(file, resultPath); } - filerev.summary[path.normalize(file)] = path.join(dirname, newName); + filerev.summary[fixPath(path.normalize(file))] = fixPath(path.join(dirname, newName)); grunt.log.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName); }); next(); }, this.async()); + function fixPath (path) { + // Drop cwd from path if relative option is set to true + if (options.dropCwd === true && cwd.length) { + var pos = path.indexOf(cwd); + if (pos === 0) { + path = path.slice(cwd.length); + } + } + return path; + } + grunt.filerev = filerev; }); }; From bf3e8f06770dc106faf8e965dc82f7f06ba2a1b4 Mon Sep 17 00:00:00 2001 From: sladex Date: Sat, 29 Nov 2014 22:13:01 +0500 Subject: [PATCH 2/3] merge master --- Gruntfile.js | 8 +++++++- README.md | 15 +++++++------- package.json | 4 ++-- tasks/filerev.js | 31 ++++++++++++++++++++++++---- test/fixtures/math.js | 2 ++ test/fixtures/math.js.map | 1 + test/fixtures/physics.js | 2 ++ test/test.js | 43 +++++++++++++++++++++++++++++++-------- 8 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 test/fixtures/math.js create mode 100644 test/fixtures/math.js.map create mode 100644 test/fixtures/physics.js diff --git a/Gruntfile.js b/Gruntfile.js index 088b307..0986aa2 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -51,6 +51,12 @@ module.exports = function (grunt) { }, src: ['test/fixtures/file.png', 'test/fixtures/another.png'], dest: 'test/tmp' + }, + withSourceMaps: { + expand: true, + cwd: 'test/fixtures', + src: ['*.js'], + dest: 'test/tmp/withSourceMaps' } }, simplemocha: { @@ -81,7 +87,7 @@ module.exports = function (grunt) { grunt.registerTask('checkSummary', 'Check that summary attribute is correctly created', function () { var src = path.normalize('test/fixtures/file.png'); - var expected = path.normalize('test/tmp/file.a0539763.png'); + var expected = path.normalize('test/tmp/file.26365248.png'); assert.equal(grunt.filerev.summary[src], expected); }); }; diff --git a/README.md b/README.md index 0ed651e..0cd3004 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ This task will revision your files based on its contents. You should then set th grunt.initConfig({ filerev: { options: { - encoding: 'utf8', algorithm: 'md5', length: 8 }, @@ -40,13 +39,6 @@ grunt.initConfig({ ### Options -#### options.encoding - -Type: `string` -Default: `'utf8'` - -The file encoding. - #### options.algorithm Type: `string` @@ -73,6 +65,7 @@ filerev: { } } ``` + #### Summary The task keeps track of all files created and its sources in a summary that is @@ -100,6 +93,12 @@ the content `grunt.filerev.summary` could look like that: } ``` +#### Source Maps + +The task will ensure that any source map for `.css` or `.js` file is revisioned with the same revision as the source file. + +For example, `js/main.js` revisioned to `js/main.9d713a59.js` will also have `js/main.js.map` revisioned to the same hash `js/main.9d713a59.js.map`. + ## License [BSD license](http://opensource.org/licenses/bsd-license.php) and copyright Google diff --git a/package.json b/package.json index ad01e4c..da75f57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grunt-filerev", - "version": "1.0.0", + "version": "2.1.2", "description": "Asset revisioning by using file content hashing", "keywords": [ "gruntplugin", @@ -24,7 +24,7 @@ ], "dependencies": { "chalk": "^0.5.1", - "each-async": "0.1.0" + "each-async": "^0.1.3" }, "devDependencies": { "grunt": "^0.4.5", diff --git a/tasks/filerev.js b/tasks/filerev.js index 45e1a24..60e6e06 100644 --- a/tasks/filerev.js +++ b/tasks/filerev.js @@ -8,7 +8,6 @@ var eachAsync = require('each-async'); module.exports = function (grunt) { grunt.registerMultiTask('filerev', 'File revisioning based on content hashing', function () { var options = this.options({ - encoding: 'utf8', algorithm: 'md5', length: 8, dropCwd: false @@ -33,7 +32,7 @@ module.exports = function (grunt) { grunt.fail.fatal('Destination ' + el.dest + ' for target ' + target + ' is not a directory'); } } catch (err) { - grunt.log.writeln('Destination dir ' + el.dest + ' does not exists for target ' + target + ': creating'); + grunt.verbose.writeln('Destination dir ' + el.dest + ' does not exists for target ' + target + ': creating'); grunt.file.mkdir(el.dest); } // We need to copy file as we now have a dest different from the src @@ -46,7 +45,7 @@ module.exports = function (grunt) { } var dirname; - var hash = crypto.createHash(options.algorithm).update(grunt.file.read(file), options.encoding).digest('hex'); + var hash = crypto.createHash(options.algorithm).update(fs.readFileSync(file)).digest('hex'); var suffix = hash.slice(0, options.length); var ext = path.extname(file); var newName = [path.basename(file, ext), suffix, ext.slice(1)].join('.'); @@ -62,10 +61,34 @@ module.exports = function (grunt) { grunt.file.copy(file, resultPath); } + // Source maps + var sourceMap = false; + if (ext === '.js' || ext === '.css') { + var map = file + '.map'; + resultPath += '.map'; + if (grunt.file.exists(map)) { + if (move) { + fs.renameSync(map, resultPath); + } else { + grunt.file.copy(map, resultPath); + } + sourceMap = true; + } + } + filerev.summary[fixPath(path.normalize(file))] = fixPath(path.join(dirname, newName)); - grunt.log.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName); + grunt.verbose.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName); + if (sourceMap) { + filerev.summary[fixPath(path.normalize(file + '.map'))] = fixPath(path.join(dirname, newName + '.map')); + grunt.verbose.writeln(chalk.green('✔ ') + file + '.map' + chalk.gray(' changed to ') + newName + '.map'); + } + }); + grunt.log.writeln('Revved ' + chalk.cyan(el.src.length) + ' ' + + (el.src.length === 1 ? 'file' : 'files') + ); + next(); }, this.async()); diff --git a/test/fixtures/math.js b/test/fixtures/math.js new file mode 100644 index 0000000..93a77c8 --- /dev/null +++ b/test/fixtures/math.js @@ -0,0 +1,2 @@ +'use strict';window.sqrt=Math.sqrt; +//# sourceMappingURL=math.js.map diff --git a/test/fixtures/math.js.map b/test/fixtures/math.js.map new file mode 100644 index 0000000..121a082 --- /dev/null +++ b/test/fixtures/math.js.map @@ -0,0 +1 @@ +{"version":3,"file":"math.js","sources":["../../app/assets/javascripts/math.js"],"names":["window","sqrt","Math"],"mappings":"AAAA,YACAA,QAAOC,KAAOC,KAAKD"} diff --git a/test/fixtures/physics.js b/test/fixtures/physics.js new file mode 100644 index 0000000..672c09a --- /dev/null +++ b/test/fixtures/physics.js @@ -0,0 +1,2 @@ +'use strict'; +window.f = function(m, a) { return m*a; }; diff --git a/test/test.js b/test/test.js index 91553ca..1692408 100644 --- a/test/test.js +++ b/test/test.js @@ -2,26 +2,53 @@ var fs = require('fs'); var assert = require('assert'); +var hashes = { + 'test/fixtures/file.png' : 'test/tmp/file.26365248.png', + 'test/fixtures/cfgfile.png' : 'test/tmp/cfgfile.da63.png', + 'test/fixtures/math.js' : 'test/tmp/withSourceMaps/math.2f56179e.js', + 'test/fixtures/math.js.map' : 'test/tmp/withSourceMaps/math.2f56179e.js.map', + 'test/fixtures/physics.js' : 'test/tmp/withSourceMaps/physics.14a0a482.js' +}; + it('should revision files based on content', function () { - var original = fs.statSync('test/fixtures/file.png').size; - var revisioned= fs.statSync('test/tmp/file.a0539763.png').size; + var file = 'test/fixtures/file.png'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; assert(revisioned === original); }); it('should accept options', function () { - var original = fs.statSync('test/fixtures/cfgfile.png').size; - var revisioned= fs.statSync('test/tmp/cfgfile.f64f.png').size; + var file = 'test/fixtures/cfgfile.png'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; assert(revisioned === original); }); it('should allow a dest directory option', function () { - var original = fs.statSync('test/fixtures/file.png').size; - var revisioned= fs.statSync('test/tmp/dest/file.a0539763.png').size; + var file = 'test/fixtures/file.png'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; assert(revisioned === original); }); it('should allow sources defined with expand', function () { - var original = fs.statSync('test/fixtures/file.png').size; - var revisioned= fs.statSync('test/tmp/expand/file.a0539763.png').size; + var file = 'test/fixtures/file.png'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; + assert(revisioned === original); +}); + +it('should use same revision as .js source for the .map', function () { + var file = 'test/fixtures/math.js.map'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; assert(revisioned === original); }); + +it('should revision .js file ok without any .map', function () { + var file = 'test/fixtures/physics.js'; + var original = fs.statSync(file).size; + var revisioned = fs.statSync(hashes[file]).size; + assert(revisioned === original); +}); + From 8289350272cce03789eedef6fb361ec3672420bc Mon Sep 17 00:00:00 2001 From: sladex Date: Sun, 30 Nov 2014 00:34:08 +0500 Subject: [PATCH 3/3] dropCwd rewritten using path function + add tests --- Gruntfile.js | 12 ++++++++++++ tasks/filerev.js | 23 ++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 0986aa2..cc7a0c4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -45,6 +45,15 @@ module.exports = function (grunt) { src: ['*'], dest: 'test/tmp/expand' }, + withDropCwd: { + options: { + dropCwd: true + }, + expand: true, + cwd: 'test/fixtures', + src: ['file.png'], + dest: 'test/tmp/withDropCwd' + }, withSummaryAttributeName: { options: { summary: 'foo' @@ -89,5 +98,8 @@ module.exports = function (grunt) { var src = path.normalize('test/fixtures/file.png'); var expected = path.normalize('test/tmp/file.26365248.png'); assert.equal(grunt.filerev.summary[src], expected); + src = path.normalize('file.png'); + expected = path.normalize('tmp/withDropCwd/file.26365248.png'); + assert.equal(grunt.filerev.summary[src], expected); }); }; diff --git a/tasks/filerev.js b/tasks/filerev.js index 60e6e06..f1f18e9 100644 --- a/tasks/filerev.js +++ b/tasks/filerev.js @@ -76,10 +76,10 @@ module.exports = function (grunt) { } } - filerev.summary[fixPath(path.normalize(file))] = fixPath(path.join(dirname, newName)); + filerev.summary[dropCwd(path.normalize(file))] = dropCwd(path.join(dirname, newName)); grunt.verbose.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName); if (sourceMap) { - filerev.summary[fixPath(path.normalize(file + '.map'))] = fixPath(path.join(dirname, newName + '.map')); + filerev.summary[dropCwd(path.normalize(file + '.map'))] = dropCwd(path.join(dirname, newName + '.map')); grunt.verbose.writeln(chalk.green('✔ ') + file + '.map' + chalk.gray(' changed to ') + newName + '.map'); } @@ -92,15 +92,20 @@ module.exports = function (grunt) { next(); }, this.async()); - function fixPath (path) { - // Drop cwd from path if relative option is set to true - if (options.dropCwd === true && cwd.length) { - var pos = path.indexOf(cwd); - if (pos === 0) { - path = path.slice(cwd.length); + // Drop cwd from path if relative option is set to true + function dropCwd (file) { + if (options.dropCwd === true && cwd) { + var filePath = file.split(path.sep), + cwdPath = path.normalize(cwd).split(path.sep), + pos = 0; + for (var i = 0; i < cwdPath.length; i++) { + if (filePath[i] === cwdPath[i]) { + pos = i + 1; + } } + file = filePath.slice(pos).join(path.sep); } - return path; + return file; } grunt.filerev = filerev;