diff --git a/cli/index.js b/cli/index.js index dcaaa3e..8e2dddb 100755 --- a/cli/index.js +++ b/cli/index.js @@ -2,6 +2,7 @@ var readFileSync = require('fs').readFileSync; var Promise = require('es6-promise').Promise; // jshint ignore:line +var ansi = require('ansi-escapes'); main(); @@ -48,6 +49,7 @@ function main() { }); } + var time = process.hrtime(); p.then(function (source) { var inliner = new Inliner(source, argv, function result(error, html) { if (error) { @@ -76,19 +78,66 @@ function main() { pkg: defaults(pkg, { version: '0.0.0' }), }).notify(); - inliner.on('warning', function progress(event) { - console.warn('warning: ' + event); - }); - if (argv.verbose) { - inliner.on('progress', function progress(event) { - console.error(event); + var styles = require('ansi-styles'); + console.warn(ansi.cursorHide + '\n\n' + ansi.cursorUp() + + ansi.cursorSavePosition); + + var jobs = {}; + var progress = ''; + var update = function () { + var remaining = jobs.breakdown.join(', '); + if (remaining) { + remaining = ' remaining: ' + remaining; + } + + var str = styles.green.open + + (100 - (jobs.todo / jobs.total * 100 | 0)) + '%' + + styles.green.close + + remaining + + styles.gray.open + + '\nLast job: ' + progress + + styles.gray.close; + + process.stderr.write( + ansi.cursorRestorePosition + + ansi.cursorLeft + + ansi.eraseLines(2) + + str.trim() + '\n'); + }; + + inliner.on('progress', function progressEvent(event) { + progress = event; + update(); }); - inliner.on('jobs', function jobs(event) { - console.error(event); + inliner.on('jobs', function jobsEvent(event) { + jobs = event; + update(); + }); + + inliner.on('warning', function warningEvent(event) { + progress = event; + update(); + }); + + inliner.on('end', function () { + var diff = process.hrtime(time); + process.stderr.write(styles.green.open + 'Time: ' + diff[0] + 's ' + + (diff[1] / 1e6).toFixed(3) + 'ms\n' + styles.green.close); + process.stderr.write(ansi.cursorShow); + }); + + 'exit SIGINT SIGTERM'.split(' ').map(function (event) { + process.once(event, function () { + process.stderr.write(ansi.cursorShow); // put the cursor back + try { process.kill(process.pid, event); } catch (e) {} + }); + }); + } else { + inliner.on('warning', function progress(event) { + console.warn('warning: ' + event); }); } }); - -} \ No newline at end of file +} diff --git a/cli/options.js b/cli/options.js index cb82b88..316f0e5 100644 --- a/cli/options.js +++ b/cli/options.js @@ -48,5 +48,7 @@ function options(args) { argv.useStdin = !process.stdin.isTTY; + argv.verbose = !process.stdout.isTTY; + return argv; } diff --git a/lib/image.js b/lib/image.js index db7fcd6..248a8c5 100644 --- a/lib/image.js +++ b/lib/image.js @@ -18,7 +18,8 @@ function image(url) { debug('image loaded: %s', url); // if the url is SVG, let's compress and use the XML directly - if (mime.lookup(url) === 'image/svg+xml' && !inliner.options.nosvg) { + if (res.body && mime.lookup(url) === 'image/svg+xml' && + !inliner.options.nosvg) { return new Promise(function (resolve, reject) { svgo.optimize(res.body.toString(), function (result) { debug('optimising svg'); @@ -48,4 +49,4 @@ function image(url) { debug('image %s failed to load', url, error); throw error; }); -} \ No newline at end of file +} diff --git a/lib/index.js b/lib/index.js index ec9d62c..90a9d5d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -311,6 +311,7 @@ function main() { }) .then(function then(html) { inliner.callback(null, html); + inliner.emit('end'); }) .catch(function errHandler(error) { debug('fail', error.stack); @@ -371,7 +372,18 @@ function updateTodo() { return acc + jobs.breakdown[key]; }, 0); - this.emit('jobs', (jobs.total - jobs.todo) + '/' + jobs.total); + var breakdown = Object.keys(jobs.breakdown).map(function (key) { + if (jobs.breakdown[key]) { + return key + '(' + jobs.breakdown[key] + ')'; + } + return false; + }).filter(Boolean); + + this.emit('jobs', { + total: jobs.total, + todo: jobs.todo, + breakdown: breakdown, + }); } function addJob(type) { diff --git a/lib/javascript.js b/lib/javascript.js index 08dbfc2..415dce8 100644 --- a/lib/javascript.js +++ b/lib/javascript.js @@ -9,6 +9,7 @@ function uglify(source) { source = source.trim(); if (source === '') { + this.jobs.done.js(); return ''; } @@ -25,5 +26,7 @@ function uglify(source) { result = source; } + this.jobs.done.js(); + return result; } diff --git a/lib/tasks/js.js b/lib/tasks/js.js index 405727b..0048c9d 100644 --- a/lib/tasks/js.js +++ b/lib/tasks/js.js @@ -24,12 +24,14 @@ function resolve(inliner, todo, $) { if (isMinified && !inliner.options.inlinemin) { debug('skipping pre-minified script'); inliner.emit('progress', 'skipping minified script ' + src); + inliner.jobs.done.js(); // ignore scripts with .min. in them - i.e. avoid minify // scripts that are already minifed return false; } else if (src.indexOf('google-analytics') !== -1) { debug('skipping analytics'); inliner.emit('progress', 'skipping analytics script'); + inliner.jobs.done.js(); // ignore analytics return false; } else if (inliner.options.skipAbsoluteUrls && diff --git a/lib/tasks/style-attrs.js b/lib/tasks/style-attrs.js index ba3703b..1b24923 100644 --- a/lib/tasks/style-attrs.js +++ b/lib/tasks/style-attrs.js @@ -9,7 +9,8 @@ function resolve(inliner, todo, $) { return inliner.cssImports(inliner.url, css) .then(inliner.cssImages.bind(inliner, inliner.url)) .then(function then(css) { + inliner.jobs.done['style-attrs'](); $(style).attr('style', css); }); }); -} \ No newline at end of file +} diff --git a/package.json b/package.json index aa2462b..30cb94f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,9 @@ }, "author": "Remy Sharp", "dependencies": { + "ansi-escapes": "^1.4.0", + "ansi-styles": "^2.2.1", + "chalk": "^1.1.3", "charset": "^1.0.0", "cheerio": "^0.19.0", "debug": "^2.2.0", @@ -38,10 +41,10 @@ "lodash.foreach": "^3.0.3", "mime": "^1.3.4", "minimist": "^1.1.3", - "request": "^2.60.0", + "request": "^2.72.0", "svgo": "^0.5.6", "then-fs": "^2.0.0", - "uglify-js": "^2.4.24", + "uglify-js": "^2.6.2", "update-notifier": "^0.5.0" }, "repository": {