Skip to content

Commit

Permalink
first version
Browse files Browse the repository at this point in the history
  • Loading branch information
navyxie committed Jul 23, 2016
1 parent a748911 commit bb8cd06
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .coveralls.yml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,2 @@
service_name: travis-pro
repo_token: 8ijKDgHIO7DtTSrWY0ph3HYA8uAK21WQu
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules node_modules
coverage coverage
npm-debug.log npm-debug.log
.DS_Store
.test_dist_img
4 changes: 3 additions & 1 deletion .npmignore
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules node_modules
coverage coverage
npm-debug.log npm-debug.log
.DS_Store
.test_dist_img
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,14 @@
language: node_js

repo_token: 8ijKDgHIO7DtTSrWY0ph3HYA8uAK21WQu

node_js:

- 0.10.35

script: npm test

after_script: npm run cov

after_success:
"curl -L -l https://coveralls.io/repos/github/navyxie/gulp-custom-css-urls/badge.svg?branch=master"
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2016 navyxie <navyxie2010@mgail.com>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49 changes: 49 additions & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
@@ -1 +1,50 @@
# gulp-custom-css-urls # gulp-custom-css-urls

[![Build Status via Travis CI](https://travis-ci.org/navyxie/gulp-custom-css-urls.svg?branch=master)](https://travis-ci.org/navyxie/gulp-custom-css-urls) [![Coverage Status](https://coveralls.io/repos/github/navyxie/gulp-custom-css-urls/badge.svg?branch=master)](https://coveralls.io/github/navyxie/gulp-custom-css-urls?branch=master)

a plugin for gulp to custom you image url inline css file, and support output image file, then you can upload image file to Cloud CDN.

## usage

```js
var customCssUrls = require('gulp-custom-css-urls');
var gulp = require('gulp');
var path = require('path');
gulp.task('demo',function(){
return gulp.src('assets/**/*.css')
.pipe(customCssUrls({
/**
* static filepath relative absolute filepath's physical position.
* eg:
* image path inline css is '/images/demo.png',
* image absoulte filepath is '/Users/Navy/Desktop/code/demo/assets/images/demo.png',
* the process(process.cwd()) path is '/Users/Navy/Desktop/code/demo',
* so the image path relative website root path is 'assets/'
*/
staticfile_relative_website_rootpath: 'assets/',
outputImage: true, // output images file , default to false
outputImage_path: './.gulp_dist_output_images', // default to './.gulp_dist_output_images'
modify: function (imageRelativePath, cssFilePath, imageRelativeWebsiteRootPath, imgInfo) {
// modify image url before prepend or append
// the imgInfo param is object, {hash: 3503865059, width: 1782, height: 530, orgin_filename: 'custom.png'}
return path.join(imageRelativeWebsiteRootPath, path.basename(imageRelativePath)); //let the relative path become an absolute path
},
prepend: '', // prepend string before image url
append: '', // append string after image url
processPath: process.cwd() // custom process path , default to process.cwd()
}))
.pipe(gulp.dest('tmp/'));
})
gulp.task('default',['demo']);
```

//css file content, input:
> div{background-image: url('/images/example.png');}
// output filename formats: (filename + '_' + imgWidth + '_' + imgHeight + '.' + crc32 + ext)
> div{background-image: url('/images/example_width_height.hash.png');}

## test

- npm test
- npm run cov
132 changes: 131 additions & 1 deletion index.js
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,133 @@
module.export = function () { var through2 = require('through2');
var _ = require('lodash');
var rework = require('rework');
var reworkUrl = require('rework-plugin-url');
var bufferCrc32 = require('buffer-crc32');
var imageSize = require('image-size');
var fs = require('fs');
var path = require('path');
var vfs = require('vinyl-fs');
var rename = require('gulp-rename');


// Maximum buffer size, with a default of 128 kilobytes.
// TO-DO: make this adaptive based on the initial signature of the image
var MaxBufferSize = 128*1024;
function syncFileToBuffer (filepath) {
// read from the file, synchronously
var descriptor = fs.openSync(filepath, 'r');
var size = fs.fstatSync(descriptor).size;
var bufferSize = Math.min(size, MaxBufferSize);
var buffer = new Buffer(bufferSize);
fs.readSync(descriptor, buffer, 0, bufferSize, 0);
fs.closeSync(descriptor);
return buffer;
}


function customUrls (file, options, cb) {

// css
var filePath = file.path;
var fileContents = file.contents.toString();
var cssDirname = path.dirname(filePath);

// options
var modify = options.modify; // function you can modify return url before prepend or append
var prepend = options.prepend;
var append = options.append;
var outputImage = options.outputImage; // output images
var outputImage_path = options.outputImage_path || './.gulp_dist_output_images'; // output images filepath
var relative_root = options.staticfile_relative_website_rootpath || ''; //static filepath relative absolute filepath's physical position. (eg: /images/demo.png, absoulte filepath is /Users/Navy/Desktop/code/demo/assets/images/demo.png, process.cwd() is /Users/Navy/Desktop/code/demo, so the relative_root is assets)
var processPath = options.processPath || process.cwd();

// format images url inline css
var formattedContents = rework(fileContents).use(reworkUrl(function(url){
var formattedUrl = url; // image origin filepath
var imgAbsolutePath = formattedUrl; // image absolute filepath

//if images url is data:base64 , continue
if (formattedUrl.indexOf('data:') === 0) {
return formattedUrl;
}
// if images url is netword file , continue
if (/^(http|https|ftp|\/\/)/gi.test(formattedUrl)) {
return formattedUrl;
}

// image filepath is relative to website root
if (/^(\/)/gi.test(formattedUrl)) {
imgAbsolutePath = path.join(processPath, relative_root, formattedUrl);
} else {
// image filepath is a relative path
imgAbsolutePath = path.resolve(cssDirname, formattedUrl);
}

// images filename info
var imgExt = path.extname(formattedUrl);
var imgFileFullName = path.basename(formattedUrl);
var imgFileName = path.basename(formattedUrl, imgExt);
// image filepath relative website root path.
var img_relative_website_root_path = path.dirname(path.relative(relative_root, path.relative(processPath, imgAbsolutePath)));


// calculate image file crc32 value
var crc32 = bufferCrc32.unsigned(syncFileToBuffer(imgAbsolutePath));

// get image size info
var imgWH = imageSize(imgAbsolutePath);

//rename image, the format is ('imgFileName' + '_' + 'imageWidth' + '_' + 'imageHeight' + 'imageCrc32Value' + 'imageExt');
formattedUrl = imgFileName + '_' + imgWH.width + '_' + imgWH.height + '.' + crc32 + imgExt;

// if need to output match's images, do it.
if (outputImage) {
var outputBasename = path.basename(formattedUrl);
var outputDirname = path.join(outputImage_path, img_relative_website_root_path);
var outputFilepath = path.join(processPath, outputDirname, outputBasename);
console.info('output image file from: ', imgAbsolutePath, ' to: ', outputFilepath);
// copy image form imgAbsolutePath to outputFilepath
vfs.src(imgAbsolutePath).pipe(rename({basename:path.basename(outputFilepath, imgExt)})).pipe(vfs.dest(path.dirname(outputFilepath)));
}

// mofify url
if (_.isFunction(modify)) {
formattedUrl = modify(formattedUrl, filePath, '/' + img_relative_website_root_path, {hash: crc32, width: imgWH.width, height: imgWH.height, orgin_filename: imgFileFullName});
}

// prepend string
if (typeof prepend === 'string') {
formattedUrl = prepend + formattedUrl;
}

// append string
if (typeof append === 'string') {
formattedUrl += append;
}

return formattedUrl;

})).toString();

cb(null, formattedContents);
};

module.exports = function (options) {
if (!_.isObject(options)) {
options = {};
}
return through2.obj(function(file, enc, cb) {
var that = this;
if (file.isNull()) {
return cb(null, file);
}
var customedContents = customUrls(file, options, function (err, customedContents) {
if (err) {
return cb(err);
} else {
file.contents = new Buffer(customedContents);
that.push(file);
return cb(null, file);
}
});
});
} }
32 changes: 25 additions & 7 deletions package.json
Original file line number Original file line Diff line number Diff line change
@@ -1,24 +1,42 @@
{ {
"name": "gulp-custom-css-urls", "name": "gulp-custom-css-urls",
"version": "0.0.0", "version": "0.0.1",
"description": "a gulp plugin custom url inline in css", "description": "a gulp plugin custom image url inline in css",
"main": "index.js", "main": "index.js",
"scripts": {}, "scripts": {
"test": "npm install && mocha --recursive test/",
"cov": "npm install && ./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/navyxie/gulp-custom-css-urls.git" "url": "https://github.com/navyxie/gulp-custom-css-urls.git"
}, },
"keywords": [ "keywords": [
"gulp", "gulp",
"css", "css",
"image" "image",
"publish",
"web",
"frontend"
], ],
"dependencies": { "dependencies": {
"buffer-crc32": "^0.2.5", "buffer-crc32": "^0.2.5",
"gulp-rename": "^1.2.2",
"image-size": "^0.5.0", "image-size": "^0.5.0",
"reword": "^0.2.0", "lodash": "^4.13.1",
"rework-plugin-url": "^1.1.0", "rework": "^1.0.1",
"through2": "^2.0.1" "rework-plugin-url": "^1.0.1",
"through2": "2.0.1",
"vinyl-fs": "^2.4.3"
},
"devDependencies": {
"coveralls": "2.11.9",
"exec-sync": "^0.1.6",
"istanbul": "^0.4.3",
"mocha": "^2.2.5",
"should": "^7.0.2",
"through2": "2.0.1",
"vinyl-fs": "^2.4.3"
}, },
"author": { "author": {
"name": "navyxie" "name": "navyxie"
Expand Down
Binary file added test/assets/images/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions test/assets/styles/example1.css
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
div{background-image: url('/images/example.png');}
1 change: 1 addition & 0 deletions test/assets/styles/example2.css
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
div{background-image: url('../images/example.png');}
1 change: 1 addition & 0 deletions test/assets/styles/example3.css
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
div{background-image: url("data:image/jpeg;base64,JC")}
63 changes: 63 additions & 0 deletions test/test.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,63 @@
var should = require('should');
var vfs = require("vinyl-fs");
var customCssUrls = require('../index');
var through2 = require("through2");
var path = require('path');
var execSync = require('exec-sync');
var testBase64Data = [
'div {\n',
' background-image: url("data:image/jpeg;base64,JC");\n',
'}'
].join('');
function dataBase64() {
return through2.obj(function(file, encoding, cb) {
var fileContents = file.contents.toString();
fileContents.should.equal(testBase64Data);
file.contents = new Buffer(fileContents);
this.push(file);
cb();
});
}
describe('gulp-custom-css-urls', function() {
this.timeout(5000);
var staticfile_relative_website_rootpath = 'test/assets/';
it('should not change anything in fileContents if image url is data:base64', function () {
vfs.src('test/assets/styles/example3.css')
.pipe(customCssUrls())
.pipe(dataBase64())
});
it('should be ok if image url is relative to website root path', function (done) {
vfs.src('test/assets/styles/example1.css')
.pipe(customCssUrls({
staticfile_relative_website_rootpath: staticfile_relative_website_rootpath,
modify: function (imageRelativePath, cssFilePath, imageRelativeWebsiteRootPath, imgInfo) {
imageRelativePath.should.equal('example_1968_920.1373564769.png');
imageRelativeWebsiteRootPath.should.equal('/images');
imgInfo.should.have.properties({hash: 1373564769, width: 1968, height: 920, orgin_filename: 'example.png' });
done();
return imageRelativePath;
}
}))
});
it('should be ok if image url is relative to css file path', function (done) {
vfs.src('test/assets/styles/example2.css')
.pipe(customCssUrls({
staticfile_relative_website_rootpath: staticfile_relative_website_rootpath,
modify: function (imageRelativePath, cssFilePath, imageRelativeWebsiteRootPath, imgInfo) {
imageRelativePath.should.equal('example_1968_920.1373564769.png');
imageRelativeWebsiteRootPath.should.equal('/images');
imgInfo.should.have.properties({hash: 1373564769, width: 1968, height: 920, orgin_filename: 'example.png' });
setTimeout(function () {done()}, 2000);
return imageRelativePath;
},
outputImage: true,
outputImage_path: './.test_dist_img'
}))
});
after(function(done){
setTimeout(function () {
execSync("rm -r " + path.join(process.cwd(), './.test_dist_img'));
done();
},3000);
})
});

0 comments on commit bb8cd06

Please sign in to comment.