diff --git a/README.md b/README.md index 10e3381..69e9893 100644 --- a/README.md +++ b/README.md @@ -93,20 +93,23 @@ SpeedMeasurePlugin.wrapPlugins(pluginMap, options); ### `options.outputFormat` -Type: `String`
+Type: `String|Function`
Default: `"human"` Determines in what format this plugin prints its measurements * `"json"` - produces a JSON blob * `"human"` - produces a human readable output + * `"humanVerbose"` - produces a more verbose version of the human readable output + * If a function, it will call the function with the JSON blob being the first parameter, and just the response of the function as the output ### `options.outputTarget` -Type: `String`
-Default: `undefined` +Type: `String|Function`
+Default: `console.log` -Specifies the path to a file to output to. If undefined, then output will print to `console.log` +* If a string, it specifies the path to a file to output to. +* If a function, it will call the function with the output as the first parameter ### `options.disable` diff --git a/colours.js b/colours.js index a1e9b93..ab2bac8 100644 --- a/colours.js +++ b/colours.js @@ -1,16 +1,19 @@ -const green = "\x1b[32m"; -const yellow = "\x1b[33m"; -const red = "\x1b[31m"; +const greenFg = "\x1b[32m"; +const yellowFg = "\x1b[33m"; +const redFg = "\x1b[31m"; +const blackBg = "\x1b[40m"; const bold = "\x1b[1m"; const end = "\x1b[0m"; -module.exports.b = (text, time) => { +module.exports.fg = (text, time) => { let colour; - if (time >= 0) colour = green; - if (time > 2000) colour = yellow; - if (time > 10000) colour = red; + if (time >= 0) colour = greenFg; + if (time > 2000) colour = yellowFg; + if (time > 10000) colour = redFg; return (colour || "") + bold + text + end; }; +module.exports.bg = text => blackBg + greenFg + bold + text + end; + module.exports.stripColours = text => text.replace(/\x1b\[[0-9]+m/g, ""); diff --git a/index.js b/index.js index dcd49bd..3d6c266 100644 --- a/index.js +++ b/index.js @@ -55,9 +55,13 @@ module.exports = class SpeedMeasurePlugin { if (this.timeEventData.loaders) outputObj.loaders = getLoadersOutput(this.timeEventData.loaders); - return this.options.outputFormat === "json" - ? JSON.stringify(outputObj, null, 2) - : getHumanOutput(outputObj); + if (this.options.outputFormat === "json") + return JSON.stringify(outputObj, null, 2); + if (typeof this.options.outputFormat === "function") + return this.options.outputFormat(outputObj); + return getHumanOutput(outputObj, { + verbose: this.options.outputFormat === "humanVerbose", + }); } addTimeEvent(category, event, eventType, data = {}) { @@ -99,7 +103,7 @@ module.exports = class SpeedMeasurePlugin { this.addTimeEvent("misc", "compile", "end"); const output = this.getOutput(); - if (this.options.outputTarget) { + if (typeof this.options.outputTarget === "string") { const strippedOutput = stripColours(output); const writeMethod = fs.existsSync(this.options.outputTarget) ? fs.appendFile @@ -109,7 +113,8 @@ module.exports = class SpeedMeasurePlugin { console.log("Outputted timing info to " + this.options.outputTarget); }); } else { - console.log(output); + const outputFunc = this.options.outputTarget || console.log; + outputFunc(output); } this.timeEventData = {}; diff --git a/output.js b/output.js index 3fa578b..4dfcd6c 100644 --- a/output.js +++ b/output.js @@ -1,67 +1,94 @@ -const { b } = require("./colours"); +const MS_IN_MINUTE = 60000; +const MS_IN_SECOND = 1000; + +const { fg, bg } = require("./colours"); const { groupBy, getAverages, getTotalActiveTime } = require("./utils"); -const humanTime = ms => { - const hours = ms / 3600000; - const minutes = ms / 60000; - const seconds = ms / 1000; +const humanTime = (ms, options = {}) => { + if (options.verbose) { + return ms.toLocaleString() + " ms"; + } + + const minutes = Math.floor(ms / MS_IN_MINUTE); + const secondsRaw = (ms - minutes * MS_IN_MINUTE) / MS_IN_SECOND; + const secondsWhole = Math.floor(secondsRaw); + const remainderPrecision = secondsWhole > 0 ? 2 : 3; + const secondsRemainder = Math.min(secondsRaw - secondsWhole, 0.99); + const seconds = + secondsWhole + + secondsRemainder + .toPrecision(remainderPrecision) + .replace(/^0/, "") + .replace(/0+$/, "") + .replace(/^\.$/, ""); + + let time = ""; + + if (minutes > 0) time += minutes + " mins, "; + time += seconds + " secs"; - if (hours > 0.5) return hours.toFixed(2) + " hours"; - if (minutes > 0.5) return minutes.toFixed(2) + " minutes"; - if (seconds > 0.5) return seconds.toFixed(2) + " seconds"; - return ms.toFixed(0) + " milliseconds"; + return time; }; -module.exports.getHumanOutput = outputObj => { - const delim = "----------------------------"; - let output = delim + "\n"; +module.exports.getHumanOutput = (outputObj, options = {}) => { + const hT = x => humanTime(x, options); + const smpTag = bg(" SMP ") + " ⏱ "; + let output = "\n\n" + smpTag + "\n"; if (outputObj.misc) { output += "General output time took " + - b(humanTime(outputObj.misc.compileTime), outputObj.misc.compileTime); + fg(hT(outputObj.misc.compileTime, options), outputObj.misc.compileTime); output += "\n\n"; } if (outputObj.plugins) { - Object.keys(outputObj.plugins).forEach(pluginName => { - output += - b(pluginName) + - " took " + - b( - humanTime(outputObj.plugins[pluginName]), - outputObj.plugins[pluginName] - ); - output += "\n"; - }); + output += smpTag + " Plugins\n"; + Object.keys(outputObj.plugins) + .sort( + (name1, name2) => outputObj.plugins[name2] - outputObj.plugins[name1] + ) + .forEach(pluginName => { + output += + fg(pluginName) + + " took " + + fg(hT(outputObj.plugins[pluginName]), outputObj.plugins[pluginName]); + output += "\n"; + }); output += "\n"; } if (outputObj.loaders) { - outputObj.loaders.build.forEach(loaderObj => { - output += - loaderObj.loaders.map(b).join(", and \n") + - " took " + - b(humanTime(loaderObj.activeTime), loaderObj.activeTime); - output += "\n"; - output += - " median = " + humanTime(loaderObj.averages.median) + ",\n"; - output += - " mean = " + humanTime(loaderObj.averages.mean) + ",\n"; - if (typeof loaderObj.averages.variance === "number") + output += smpTag + " Loaders\n"; + outputObj.loaders.build + .sort((obj1, obj2) => obj2.activeTime - obj1.activeTime) + .forEach(loaderObj => { output += - " s.d = " + - humanTime(Math.sqrt(loaderObj.averages.variance)) + - ", \n"; - output += - " range = (" + - humanTime(loaderObj.averages.range.start) + - ", " + - humanTime(loaderObj.averages.range.end) + - "), \n"; - output += " module count = " + loaderObj.averages.dataPoints + "\n"; - }); + loaderObj.loaders.map(fg).join(", and \n") + + " took " + + fg(hT(loaderObj.activeTime), loaderObj.activeTime) + + "\n"; + + if (options.verbose) { + output += + " median = " + hT(loaderObj.averages.median) + ",\n"; + output += " mean = " + hT(loaderObj.averages.mean) + ",\n"; + if (typeof loaderObj.averages.variance === "number") + output += + " s.d = " + + hT(Math.sqrt(loaderObj.averages.variance)) + + ", \n"; + output += + " range = (" + + hT(loaderObj.averages.range.start) + + " --> " + + hT(loaderObj.averages.range.end) + + "), \n"; + } + + output += " module count = " + loaderObj.averages.dataPoints + "\n"; + }); } - output += delim + "\n"; + output += "\n\n"; return output; }; diff --git a/package.json b/package.json index e5bba5c..a59d6fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "speed-measure-webpack-plugin", - "version": "0.2.2", + "version": "0.3.0", "description": "Measure + analyse the speed of your webpack loaders and plugins", "main": "index.js", "repository": { diff --git a/preview.png b/preview.png index b7c1877..8c0b375 100644 Binary files a/preview.png and b/preview.png differ