117 lines
3.1 KiB
JavaScript
117 lines
3.1 KiB
JavaScript
'use strict';
|
|
|
|
var fs = require('fs'),
|
|
Path = require('path'),
|
|
MAX_SIZE = 4096,
|
|
/* Adapted from https://gist.github.com/2594980 */
|
|
imgRegex = /url\s?\(['"]?(.*?)(?=['"]?\))/gi,
|
|
absoluteUrlRegex = /^\//,
|
|
externalUrlRegex = /http/,
|
|
mediatypes = {
|
|
'.eot' : 'application/vnd.ms-fontobject',
|
|
'.gif' : 'image/gif',
|
|
'.ico' : 'image/vnd.microsoft.icon',
|
|
'.jpg' : 'image/jpeg',
|
|
'.jpeg' : 'image/jpeg',
|
|
'.otf' : 'application/x-font-opentype',
|
|
'.png' : 'image/png',
|
|
'.svg' : 'image/svg+xml',
|
|
'.ttf' : 'application/x-font-ttf',
|
|
'.webp' : 'image/webp',
|
|
'.woff' : 'application/x-font-woff',
|
|
'.woff2' : 'application/font-woff2'
|
|
};
|
|
|
|
module.exports = {
|
|
fromFile: fromFile,
|
|
fromString: fromString
|
|
};
|
|
|
|
function fromString(css, relativePath, rootPath , options, cb) {
|
|
if(!cb) {
|
|
cb = options;
|
|
options = {maxSize: MAX_SIZE};
|
|
}
|
|
if(!css.replace && css.toString) css = css.toString();
|
|
var urls = [],
|
|
match = imgRegex.exec(css);
|
|
while(match) {
|
|
urls.push(match[1]);
|
|
match = imgRegex.exec(css)
|
|
}
|
|
forEachSeries(urls, base64img, function(err){
|
|
if(err) return cb(err, css);
|
|
cb(null, css);
|
|
});
|
|
|
|
function base64img(imageUrl, cb){
|
|
if(externalUrlRegex.test(imageUrl)) {
|
|
return cb(new Error('Skip ' + imageUrl + ' External file.'), css);
|
|
}
|
|
|
|
var imagePath;
|
|
if(absoluteUrlRegex.test(imageUrl)) {
|
|
imagePath = Path.join(rootPath, imageUrl.substr(1));
|
|
}else{
|
|
imagePath = Path.join(relativePath, imageUrl);
|
|
}
|
|
replaceUrlByB64(imageUrl, imagePath, css, options, function (err, newCss){
|
|
if(err) return cb(err, css);
|
|
css = newCss;
|
|
cb();
|
|
});
|
|
}
|
|
}
|
|
|
|
function fromFile(cssFile, root, options, cb) {
|
|
if(!cb) {
|
|
cb = options;
|
|
options = {maxSize: MAX_SIZE};
|
|
}
|
|
fs.readFile(cssFile, function(err, css){
|
|
if(err) return cb(err, css);
|
|
fromString(css.toString(), Path.dirname(cssFile), root, options, cb);
|
|
});
|
|
}
|
|
|
|
function replaceUrlByB64(imageUrl, imagePath, css, options, cb){
|
|
imagePath = imagePath.replace(/[?#].*/g, '');
|
|
fs.stat(imagePath, function(err, stat){
|
|
if(err) return cb(err, css);
|
|
if (stat.size > options.maxSize){
|
|
return cb(new Error('Skip ' + imageUrl + ' Exceed max size'), css);
|
|
}
|
|
fs.readFile(imagePath, 'base64', function(err, img){
|
|
if(err) return cb(err, css);
|
|
var ext = Path.extname(imagePath);
|
|
var newCss = css.replace(imageUrl, 'data:' + mediatypes[ext] + ';base64,' + img);
|
|
cb(null, newCss);
|
|
});
|
|
});
|
|
}
|
|
|
|
/* Adapted from async. Continue on error. */
|
|
function forEachSeries(arr, iterator, callback) {
|
|
callback = callback || function () {};
|
|
if (!arr.length) {
|
|
return callback();
|
|
}
|
|
var completed = 0, errs = [];
|
|
var iterate = function () {
|
|
iterator(arr[completed], function (err) {
|
|
if (err) {
|
|
errs.push(err);
|
|
}
|
|
completed += 1;
|
|
if (completed === arr.length) {
|
|
if(errs.length) return callback(errs);
|
|
callback(null);
|
|
}
|
|
else {
|
|
iterate();
|
|
}
|
|
});
|
|
};
|
|
iterate();
|
|
}
|