pre white space now remains intact, inliner executable supports more options on command line - in addition to optionally not base64 encoding images.

This commit is contained in:
remy 2011-06-11 12:41:19 +01:00
parent 1417f2d28e
commit 7c9b89f0a9
3 changed files with 110 additions and 45 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env node
var path = require('path'), fs = require('fs');
var path = require('path'), fs = require('fs'), querystring = require('querystring');
fs.realpath(__filename, function(error, script) {
var servedir, root, port;
@ -14,55 +14,109 @@ fs.realpath(__filename, function(error, script) {
'',
'Options:',
' --verbose echo on STDERR the progress of inlining',
// ' --share save the output on jsbin.com and return a shareable url',
' --nocompress don\'t compress CSS or HTML - useful for debugging',
' --images don\'t encode images - keeps files size small, but more requests',
' --version current inliner version',
' --help this usage',
'',
'For more details see http://github.com/remy/inliner/\n'
].join('\n');
if (process.argv[2] === undefined) {
console.log(usage);
process.exit();
}
function controlArg(args, label, fn) {
var i;
var callback = function (arg, i) {
args.splice(i, 1);
fn(arg, i);
};
if ((i = args.indexOf(label)) !== -1) {
fn(args[i], i);
callback(args[i], i);
} else if ((i = args.indexOf('-' + label.substr(0, 1))) !== -1) {
fn(args[i], i);
callback(args[i], i);
} else if ((i = args.indexOf('--' + label)) !== -1) {
fn(args[i], i);
callback(args[i], i);
}
}
var options,
verbose = false;
var options = Inliner.defaults,
verbose = false,
share = false;
controlArg(process.argv, 'help', function () {
console.log(usage);
process.exit();
});
controlArg(process.argv, 'version', function () {
console.log(Inliner.version);
process.exit();
controlArg(process.argv, 'nocompress', function (arg, i) {
options.compressCSS = false;
options.collapseWhitespace = false;
});
controlArg(process.argv, 'nocompress', function (arg, i) {
process.argv.splice(i, 1);
options = { compressCSS: false, collapseWhitespace: false };
controlArg(process.argv, 'share', function (arg, i) {
share = true;
// because JS Bin is a damn sight easier to debug when it's not all on one line
options.compressCSS = false;
options.collapseWhitespace = false;
});
controlArg(process.argv, 'images', function (arg, i) {
options.images = false;
});
// order counts here - so verbose can also use -v
if (process.argv.length == 3) {
controlArg(process.argv, 'version', function () {
console.log(Inliner.prototype.version);
process.exit();
});
}
controlArg(process.argv, 'verbose', function (arg, i) {
process.argv.splice(i, 1);
verbose = true;
});
var inliner = new Inliner(process.argv[2], options, function (html) {
console.log(html);
if (process.argv[2] === undefined) {
console.log(usage);
process.exit();
}
var url = process.argv[2];
if (url.indexOf('http') !== 0) {
url = 'http://' + url;
}
var inliner = new Inliner(url, options, function (html) {
if (share) {
// post to jsbin
var data = querystring.stringify({
html: html,
javascript: '',
format: 'plain',
method: 'save'
});
// note: when making a POST request using node, for PHP to pick it up, the content-type is crutial - I never knew that :(
var request = Inliner.makeRequest('http://jsbin.com/save', {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded', 'content-length': data.length, 'X-Requested-With' : 'XMLHttpRequest' }
});
request.on('response', function (res) {
var body = '';
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
console.log(body);
});
});
request.write(data);
request.end();
} else {
console.log(html);
}
});
if (verbose) {

View File

@ -11,18 +11,6 @@ var URL = require('url'),
https: require('https')
};
function makeRequest(url) {
var oURL = URL.parse(url),
options = {
host: oURL.hostname,
port: oURL.port === undefined ? (oURL.protocol+'').indexOf('https') === 0 ? 443 : 80 : oURL.port,
path: (oURL.pathname || '/') + (oURL.search || ''), // note 0.5.0pre doesn't fill pathname if missing
method: 'GET'
};
return http[oURL.protocol.slice(0, -1) || 'http'].request(options);
}
function compressCSS(css) {
return css
.replace(/\s+/g, ' ')
@ -56,9 +44,9 @@ function Inliner(url, options, callback) {
if (typeof options == 'function') {
callback = options;
options = inliner.defaults;
options = Inliner.defaults;
} else if (options === undefined) {
options = inliner.defaults;
options = Inliner.defaults;
}
inliner.options = options;
@ -84,8 +72,8 @@ function Inliner(url, options, callback) {
], function(errors, window) {
// remove jQuery that was included with jsdom
window.$('script:last').remove();
var todo = { scripts: true, images: true, links: true, styles: true },
var todo = { scripts: true, images: inliner.options.images, links: true, styles: true },
assets = {
scripts: window.$('script'),
images: window.$('img').filter(function(){ return this.src.indexOf('data:') == -1; }),
@ -102,17 +90,19 @@ function Inliner(url, options, callback) {
breakdown[key] = assets[key].length;
inliner.total += assets[key].length;
inliner.todo += assets[key].length;
} else {
assets[key] = [];
}
}
inliner.emit('jobs', (inliner.total - inliner.todo) + '/' + inliner.total);
function finished() {
var items = 0;
var items = 0,
html = '';
for (var key in breakdown) {
items += breakdown[key];
}
inliner.emit('jobs', (inliner.total - inliner.todo) + '/' + inliner.total);
if (items === 0) {
@ -120,9 +110,14 @@ function Inliner(url, options, callback) {
var els = removeComments(window.document.documentElement);
// collapse the white space
var html = window.document.innerHTML;
if (inliner.options.collapseWhitespace) {
html = html.replace(/\s+/g, ' ');
window.$('pre').html(function (i, html) {
return html.replace(/\n/g, '~~nl~~').replace(/\s/g, '~~s~~');
});
html = window.document.innerHTML;
html = html.replace(/\s+/g, ' ').replace(/~~nl~~/g, '\n').replace(/~~s~~/g, ' ');
} else {
html = window.document.innerHTML;
}
// console.log(html);
html = '<!DOCTYPE html>' + html;
@ -262,7 +257,7 @@ function Inliner(url, options, callback) {
assets.scripts.length == 0) {
finished();
}
/** Inliner jobs:
* 1. get all inline images and base64 encode
* 2. get all external style sheets and move to inline
@ -331,7 +326,7 @@ Inliner.prototype.get = function (url, options, callback) {
try {
compress = require('./node-compress/lib/compress/');
} catch (e) {
console.error('Failed to load node-compress - see http://github.com/remy/inliner for install directions. \nexiting');
console.error(url + ' sent gzipped header\nFailed to load node-compress - see http://github.com/remy/inliner for install directions. \nexiting');
process.exit();
}
}
@ -479,7 +474,23 @@ Inliner.prototype.getImportCSS = function (rooturl, css, callback) {
}
};
Inliner.prototype.defaults = { compressCSS: true, collapseWhitespace: true };
Inliner.defaults = { compressCSS: true, collapseWhitespace: true, images: true };
var makeRequest = Inliner.makeRequest = function (url, extraOptions) {
var oURL = URL.parse(url),
options = {
host: oURL.hostname,
port: oURL.port === undefined ? (oURL.protocol+'').indexOf('https') === 0 ? 443 : 80 : oURL.port,
path: (oURL.pathname || '/') + (oURL.search || ''), // note 0.5.0pre doesn't fill pathname if missing
method: 'GET'
};
for (var key in extraOptions) {
options[key] = extraOptions[key];
}
return http[oURL.protocol.slice(0, -1) || 'http'].request(options);
};
module.exports = Inliner;

View File

@ -1,6 +1,6 @@
{
"name": "inliner",
"version": "0.1.2",
"version": "0.1.3",
"description": "Utility to inline images, CSS and JavaScript for a web page - useful for mobile sites",
"homepage": "http://github.com/remy/inliner",
"main": "inliner",