├── .gitignore
├── .jshint
├── .travis.yml
├── LICENSE.md
├── README.md
├── expected
├── montserrat-light-webfont.woff
├── montserrat-light-webfont.woff2
├── rev-manifest.json
├── script.js
└── styles.css
├── fixtures
├── fonts
│ ├── montserrat-light-webfont.woff
│ └── montserrat-light-webfont.woff2
├── images
│ └── dummy.jpg
├── scripts
│ ├── application.js
│ └── script.js
└── styles
│ └── styles.css
├── gulpfile.js
├── index.js
├── package.json
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | results
--------------------------------------------------------------------------------
/.jshint:
--------------------------------------------------------------------------------
1 | {
2 | // JSHint Default Configuration File (as on JSHint website)
3 | // See http://jshint.com/docs/ for more details
4 |
5 | "maxerr" : 10, // {int} Maximum error before stopping
6 |
7 | // Enforcing
8 | "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.)
9 | "camelcase" : false, // true: Identifiers must be in camelCase
10 | "curly" : true, // true: Require {} for every new block or scope
11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison
12 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
13 | "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
14 | "indent" : 4, // {int} Number of spaces to use for indentation
15 | "latedef" : true, // true: Require variables/functions to be defined before being used
16 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
17 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
18 | "noempty" : true, // true: Prohibit use of empty blocks
19 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
20 | "plusplus" : false, // true: Prohibit use of `++` & `--`
21 | "quotmark" : "single", // Quotation mark consistency:
22 | // false : do nothing (default)
23 | // true : ensure whatever is used is consistent
24 | // "single" : require single quotes
25 | // "double" : require double quotes
26 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
27 | "unused" : true, // true: Require all defined variables be used
28 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode
29 | "trailing" : true, // true: Prohibit trailing whitespaces
30 | "maxparams" : false, // {int} Max number of formal params allowed per function
31 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
32 | "maxstatements" : false, // {int} Max number statements per function
33 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
34 | "maxlen" : 120, // {int} Max number of characters per line
35 |
36 | // Relaxing
37 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
38 | "boss" : false, // true: Tolerate assignments where comparisons would be expected
39 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
40 | "eqnull" : true, // true: Tolerate use of `== null`
41 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
42 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
43 | // (ex: `for each`, multiple try/catch, function expression…)
44 | "evil" : false, // true: Tolerate use of `eval` and `new Function()`
45 | "expr" : true, // true: Tolerate `ExpressionStatement` as Programs
46 | "funcscope" : false, // true: Tolerate defining variables inside control statements"
47 | "globalstrict" : true, // true: Allow global "use strict" (also enables 'strict')
48 | "iterator" : false, // true: Tolerate using the `__iterator__` property
49 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
50 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
51 | "laxcomma" : false, // true: Tolerate comma-first style coding
52 | "loopfunc" : false, // true: Tolerate functions being defined in loops
53 | "multistr" : false, // true: Tolerate multi-line strings
54 | "proto" : false, // true: Tolerate using the `__proto__` property
55 | "scripturl" : false, // true: Tolerate script-targeted URLs
56 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
57 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
58 | "sub" : true, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
59 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
60 | "validthis" : false, // true: Tolerate using this in a non-constructor function
61 |
62 | // Environments
63 | "browser" : true, // Web Browser (window, document, etc)
64 | "couch" : false, // CouchDB
65 | "devel" : true, // Development/debugging (alert, confirm, etc)
66 | "dojo" : false, // Dojo Toolkit
67 | "jquery" : true, // jQuery
68 | "mootools" : false, // MooTools
69 | "node" : false, // Node.js
70 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
71 | "prototypejs" : false, // Prototype and Scriptaculous
72 | "rhino" : false, // Rhino
73 | "worker" : true, // Web Workers
74 | "wsh" : false, // Windows Scripting Host
75 | "yui" : false, // Yahoo User Interface
76 |
77 | // Legacy
78 | "nomen" : true, // true: Prohibit dangling `_` in variables
79 | "onevar" : false, // true: Allow only one `var` statement per function
80 | "passfail" : false, // true: Stop on first error
81 | "white" : false, // true: Check against strict whitespace and indentation rules
82 |
83 | // Custom Globals
84 | "globals" : {
85 |
86 | // Glopart
87 | "DEBUG": true,
88 | "module": true,
89 | "require": true,
90 |
91 | // Angular
92 | "angular": true,
93 |
94 | // mocha
95 | "describe": true,
96 | "beforeEach": true,
97 | "afterEach": true,
98 | "before": true,
99 | "after": true,
100 | "it": true,
101 |
102 | //chai
103 | "expect": true
104 | }
105 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.11"
4 | - "0.10"
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Galkin Rostislav
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CSS-URL [](https://travis-ci.org/galkinrost/gulp-rev-css-url)
2 | =========
3 |
4 | The lightweight plugin to override urls in css files to hashed after gulp-rev
5 |
6 | What is the result?
7 | --
8 | See here
9 |
10 | Install
11 | --
12 | ```sh
13 | npm install gulp-rev-css-url
14 | ```
15 |
16 | Usage
17 | --
18 |
19 | ```javascript
20 | var gulp=require('gulp');
21 | var rev=require('gulp-rev');
22 | var override=require('gulp-rev-css-url');
23 |
24 | gulp.task('rev',function(){
25 | return gulp.src('./app/**/*')
26 | .pipe(rev())
27 | .pipe(override())
28 | .pipe(gulp.dest('./build/'))
29 | .pipe(rev.manifest())
30 | .pipe(gulp.dest('./build/'));
31 | });
32 |
33 | ```
34 | AND
35 | ```sh
36 | gulp rev
37 | ```
38 |
39 | Tests
40 | --
41 | ```sh
42 | npm test
43 | ```
44 |
45 | License
46 | ----
47 |
48 | MIT
49 |
--------------------------------------------------------------------------------
/expected/montserrat-light-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/galkinrost/gulp-rev-css-url/ee88aaa8044670396e83976d36030e1a11783a5d/expected/montserrat-light-webfont.woff
--------------------------------------------------------------------------------
/expected/montserrat-light-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/galkinrost/gulp-rev-css-url/ee88aaa8044670396e83976d36030e1a11783a5d/expected/montserrat-light-webfont.woff2
--------------------------------------------------------------------------------
/expected/rev-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "images/dummy.jpg": "images/dummy-0849cad9cc.jpg",
3 | "scripts/application.js": "scripts/application-5c2dec9780.js",
4 | "scripts/script.js": "scripts/script-382f58fea6.js",
5 | "styles/styles.css": "styles/styles-d329971534.css",
6 | "fonts/montserrat-light-webfont.woff": "fonts/montserrat-light-webfont-b2f7c06e09.woff",
7 | "fonts/montserrat-light-webfont.woff2": "fonts/montserrat-light-webfont-86efde6016.woff2"
8 | }
9 |
--------------------------------------------------------------------------------
/expected/script.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var img = new Image();
3 | img.src = '/images/dummy-0849cad9cc.jpg';
--------------------------------------------------------------------------------
/expected/styles.css:
--------------------------------------------------------------------------------
1 | .background-image {
2 | background-image: url('../images/dummy-0849cad9cc.jpg');
3 | }
4 |
5 | .background-image-2 {
6 | background-image: url('../images/dummy-0849cad9cc.jpg');
7 | }
8 |
9 | @font-face {
10 | font-family: "font";
11 | font-style: normal;
12 | font-weight: 300;
13 | src: url('../fonts/montserrat-light-webfont-b2f7c06e09.woff') format('woff'),
14 | url('../fonts/montserrat-light-webfont-86efde6016.woff2') format('woff2');
15 | }
16 |
--------------------------------------------------------------------------------
/fixtures/fonts/montserrat-light-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/galkinrost/gulp-rev-css-url/ee88aaa8044670396e83976d36030e1a11783a5d/fixtures/fonts/montserrat-light-webfont.woff
--------------------------------------------------------------------------------
/fixtures/fonts/montserrat-light-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/galkinrost/gulp-rev-css-url/ee88aaa8044670396e83976d36030e1a11783a5d/fixtures/fonts/montserrat-light-webfont.woff2
--------------------------------------------------------------------------------
/fixtures/images/dummy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/galkinrost/gulp-rev-css-url/ee88aaa8044670396e83976d36030e1a11783a5d/fixtures/images/dummy.jpg
--------------------------------------------------------------------------------
/fixtures/scripts/application.js:
--------------------------------------------------------------------------------
1 | var someFunction = function() {
2 | $.ajax({
3 | url: 'someurl',
4 | type:"POST",
5 | data:data,
6 | contentType:"application/json; charset=utf-8",
7 | dataType:"json",
8 | success: function(){}
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/fixtures/scripts/script.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var img = new Image();
3 | img.src = '/images/dummy.jpg';
--------------------------------------------------------------------------------
/fixtures/styles/styles.css:
--------------------------------------------------------------------------------
1 | .background-image {
2 | background-image: url('../images/dummy.jpg');
3 | }
4 |
5 | .background-image-2 {
6 | background-image: url('../images/dummy.jpg');
7 | }
8 |
9 | @font-face {
10 | font-family: "font";
11 | font-style: normal;
12 | font-weight: 300;
13 | src: url('../fonts/montserrat-light-webfont.woff') format('woff'),
14 | url('../fonts/montserrat-light-webfont.woff2') format('woff2');
15 | }
16 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var jshint = require('gulp-jshint');
3 |
4 | var src = ['index.js', 'test.js', 'gulpfile.js'];
5 |
6 | gulp.task('lint', function () {
7 | return gulp.src(src)
8 | .pipe(jshint())
9 | .pipe(jshint.reporter('default'));
10 | });
11 |
12 | gulp.task('watch', function () {
13 | gulp.watch(src, ['lint']);
14 | });
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var through = require('through2');
2 | var crypto = require('crypto');
3 | var gutil = require('gulp-util');
4 | var path = require('path');
5 |
6 | module.exports = function override() {
7 | var allowedPathRegExp = /\.(css|js)$/;
8 |
9 | function md5(str) {
10 | return crypto.createHash('md5').update(str, 'utf8').digest('hex');
11 | }
12 |
13 | function relPath(base, filePath) {
14 | if (filePath.indexOf(base) !== 0) {
15 | return filePath;
16 | }
17 | var newPath = filePath.substr(base.length);
18 | if (newPath[0] === path.sep) {
19 | return newPath.substr(1);
20 | } else {
21 | return newPath;
22 | }
23 | }
24 |
25 | var f = [];
26 |
27 | return through.obj(function (file, enc, cb) {
28 | var firstFile = null;
29 |
30 | if (file.path && file.revOrigPath) {
31 | firstFile = firstFile || file;
32 | var _relPath = relPath(path.resolve(firstFile.revOrigBase), file.revOrigPath);
33 |
34 | f.push({
35 | origPath: _relPath,
36 | hashedPath: relPath(path.resolve(firstFile.base), file.path),
37 | file: file
38 | });
39 | }
40 | cb();
41 | }, function (cb) {
42 | var self = this;
43 |
44 | // sort by filename length to not replace the common part(s) of several filenames
45 | var longestFirst = f.slice().sort(function (a, b) {
46 | if(a.origPath.length > b.origPath.length) return -1;
47 | if(a.origPath.length < b.origPath.length) return 1;
48 | return 0;
49 | });
50 |
51 | f.forEach(function (_f) {
52 | var file = _f.file;
53 |
54 | if ((allowedPathRegExp.test(file.revOrigPath) ) && file.contents) {
55 | var contents = file.contents.toString();
56 | longestFirst.forEach(function (__f) {
57 | var origPath = __f.origPath.replace(new RegExp('\\' + path.sep, 'g'), '/').replace(/\./g, '\\.');
58 | var hashedPath = __f.hashedPath.replace(new RegExp('\\' + path.sep, 'g'), '/');
59 | contents = contents.replace(
60 | new RegExp(origPath, 'g'),
61 | hashedPath);
62 | });
63 |
64 | file.contents = new Buffer(contents);
65 |
66 | // update file's hash as it does in gulp-rev plugin
67 | var hash = file.revHash = md5(contents).slice(0, 10);
68 | var ext = path.extname(file.path);
69 | var filename = path.basename(file.revOrigPath, ext) + '-' + hash + ext;
70 | file.path = path.join(path.dirname(file.path), filename);
71 |
72 | }
73 | self.push(file);
74 | });
75 | cb();
76 | });
77 | };
78 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-rev-css-url",
3 | "version": "0.1.0",
4 | "description": "The lightweight plugin to override urls in css files to hashed after gulp-rev",
5 | "repository": {
6 | "type": "git",
7 | "url": "git://github.com/galkinrost/gulp-rev-css-url"
8 | },
9 | "author": {
10 | "name": "Galkin Rostislav",
11 | "email": "galkinrost@gmail.com",
12 | "url": "http://github.com/galkinrost"
13 | },
14 | "keywords": [
15 | "gulpplugin",
16 | "rev",
17 | "revision",
18 | "hash",
19 | "optimize",
20 | "version",
21 | "versioning",
22 | "cache",
23 | "expire",
24 | "static",
25 | "asset",
26 | "assets",
27 | "gulp-rev"
28 | ],
29 | "devDependencies": {
30 | "gulp": "~3.6.2",
31 | "gulp-rev": "~5.0.0",
32 | "mocha": "~1.20.0",
33 | "gulp-jshint": "~1.6.1",
34 | "fs-extra": "~0.9.1",
35 | "chai": "~1.9.1"
36 | },
37 | "dependencies": {
38 | "crypto": "0.0.3",
39 | "gulp-util": "~2.2.14",
40 | "through2": "~0.4.2"
41 | },
42 | "scripts": {
43 | "test": "mocha test.js -R list"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | var rev = require('gulp-rev');
2 | var fs = require('fs');
3 | var gulp = require('gulp');
4 | var fse = require('fs-extra');
5 | var override = require('./index');
6 | var expect = require('chai').expect;
7 | var through = require('through2');
8 |
9 | describe('gulp-rev-css-url', function () {
10 | beforeEach(function (done) {
11 | fse.remove('./results', done);
12 | })
13 |
14 | it('Should override urls in css and js', function (done) {
15 | var expectedCSS = fs.readFileSync('./expected/styles.css', 'utf-8'),
16 | expectedJs = fs.readFileSync('./expected/script.js', 'utf-8'),
17 | expectedFont1 = fs.readFileSync('./expected/montserrat-light-webfont.woff', 'utf-8'),
18 | expectedFont2 = fs.readFileSync('./expected/montserrat-light-webfont.woff2', 'utf-8'),
19 | expectedManifest = require('./expected/rev-manifest.json', 'utf-8');
20 | gulp.src('./fixtures/**/*')
21 | .pipe(rev())
22 | .pipe(override())
23 | .pipe(gulp.dest('./results/'))
24 | .pipe(rev.manifest())
25 | .pipe(gulp.dest('./results/'))
26 | .on('end', function () {
27 | // load results
28 | var css = fs.readFileSync('./results/styles/styles-d329971534.css', 'utf-8'),
29 | js = fs.readFileSync('./results/scripts/script-382f58fea6.js', 'utf-8'),
30 | font1 = fs.readFileSync('./results/fonts/montserrat-light-webfont-b2f7c06e09.woff', 'utf-8'),
31 | font2 = fs.readFileSync('./results/fonts/montserrat-light-webfont-86efde6016.woff2', 'utf-8'),
32 | manifest = require('./results/rev-manifest.json', 'utf-8');
33 |
34 | // check files' content
35 | expect(css).to.equal(expectedCSS);
36 | expect(js).to.equal(expectedJs);
37 | expect(expectedFont1).to.equal(font1);
38 | expect(expectedFont2).to.equal(font2);
39 |
40 | // check manifest
41 | expect(manifest).to.deep.equal(expectedManifest);
42 |
43 | done();
44 | });
45 | });
46 |
47 | it('Should not replace application/json with application.js', function(done) {
48 | gulp.src('./fixtures/scripts/application.js')
49 | .pipe(rev())
50 | .pipe(override())
51 | .pipe(gulp.dest('./results/'))
52 | .on('end', function () {
53 | var js = fs.readFileSync(
54 | './results/application-5c2dec9780.js',
55 | 'utf-8');
56 | expect(js).to.contain('application/json');
57 | done();
58 | });
59 | });
60 |
61 | it('Should not reorder the pipeline', function (done) {
62 | var outputOrder = [];
63 | gulp.src(['./fixtures/scripts/script.js', './fixtures/scripts/application.js'])
64 | .pipe(rev())
65 | .pipe(override())
66 | .pipe(through.obj(
67 | function (file, enc, cb) {
68 | outputOrder.push(file.revOrigPath.replace(file.revOrigBase, ''));
69 | cb(null, file);
70 | },
71 | function (cb) {
72 | expect(outputOrder).to.deep.equal(['script.js', 'application.js']);
73 | done();
74 | }
75 | ));
76 | });
77 |
78 | });
79 |
80 |
--------------------------------------------------------------------------------