1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
/**
* timeRequire - measure the time to load all the subsequnt modules by hoocking require() calls
*
* @author Ciprian Popa (cyparu)
* @since 0.0.1
* @version 0.0.1
*/
"use strict";
var // setup vars
requireData = [],
write = process.stdout.write.bind(process.stdout),
relative = require("path").relative,
cwd = process.cwd(),
// require hooker should be first module loaded so all the other requires should count as well
/* jshint -W003 */
hook = require("./requireHook")(_hooker),
table = require("text-table"),
dateTime = require("date-time"),
prettyMs = require("pretty-ms"),
chalk = require("chalk"),
// extra locals
DEFAULT_COLUMNS = 80,
BAR_CHAR = process.platform === "win32" ? "■" : "▇",
sorted = hasArg("--sorted") || hasArg("--s"),
treshold = (hasArg("--verbose") || hasArg("--V")) ? 0.0: 0.01, // TODO - configure treshold using CLI ?
EXTRA_COLUMNS = sorted ? 24 : 20;
function hasArg(arg) {
return process.argv.indexOf(arg) !== -1;
}
function pad(count, seq) {
return (count > 1) ? new Array(count).join(seq) : "";
}
function log(str) {
write(str + "\n", "utf8");
}
/**
* Callback/listener used by requireHook hook to collect all the modules in their loading order
*/
function _hooker(data) {
var filename = relative(cwd, data.filename);
// use the shortest name
if (filename.length > data.filename) {
filename = data.filename;
}
requireData.push({
order: requireData.length, // loading order
time: data.startedIn, // time
label: data.name + " (" + filename + ")"
// name: data.name,
// filename: filename
});
}
function formatTable(tableData, totalTime) {
var NAME_FILE_REX = /(.+)( \(.+\))/,
maxColumns = process.stdout.columns || DEFAULT_COLUMNS,
validCount = 0,
longestRequire = tableData.reduce(function(acc, data) {
var avg = data.time / totalTime;
if (avg < treshold) {
return acc;
}
validCount++;
return Math.max(acc, data.label.length);
}, 0),
maxBarWidth = (longestRequire > maxColumns / 2) ? ((maxColumns - EXTRA_COLUMNS) / 2) : (maxColumns - (longestRequire + EXTRA_COLUMNS)),
processedTableData = [],
counter, maxOrderChars;
function shorten(name) {
var nameLength = name.length,
partLength, start, end;
if (name.length < maxBarWidth) {
return name;
}
partLength = Math.floor((maxBarWidth - 3) / 2);
start = name.substr(0, partLength + 1);
end = name.substr(nameLength - partLength);
return start.trim() + "..." + end.trim();
}
function createBar(percentage) {
var rounded = Math.round(percentage * 100);
return ((rounded === 0) ? "0" : (pad(Math.ceil(maxBarWidth * percentage) + 1, BAR_CHAR) + " " + rounded)) + "%";
}
// sort the data if needed
if (sorted) {
tableData.sort(function(e1, e2) {
return e2.time - e1.time;
});
}
// initialize the counter
counter = 1;
// get num ber of chars for padding
maxOrderChars = tableData.length.toString().length;
// push the header
processedTableData.push(["#" + (sorted ? " [order]" : ""), "module", "time", "%"]);
tableData.forEach(function(data) {
var avg = data.time / totalTime,
counterLabel, label, match;
// slect just data over the threshold
if (avg >= treshold) {
counterLabel = counter++;
// for sorted collumns show the order loading with padding
if (sorted) {
counterLabel += pad(maxOrderChars - data.order.toString().length + 1, " ") + " [" + data.order + "]";
}
label = shorten(data.label);
match = label.match(NAME_FILE_REX);
if (match) {
label = chalk.green(match[1]) + match[2];
}
processedTableData.push([counterLabel, label, chalk.yellow(prettyMs(data.time)), chalk.blue(createBar(avg))]);
}
});
return table(processedTableData, {
align: ["r", "l", "r", "l"],
stringLength: function(str) {
return chalk.stripColor(str).length;
}
});
}
// hook process exit to display the report at the end
process.once("exit", function() {
var startTime = hook.hookedAt,
totalTime = Date.now() - startTime.getTime();
log("\n\n" + chalk.underline("Start time: " + chalk.yellow("(" + dateTime(startTime) + ")") + " [treshold=" + (treshold * 100) + "%" + (sorted ? ",sorted" : "") + "]"));
log(formatTable(requireData, totalTime));
log(chalk.bold.blue("Total require(): ") + chalk.yellow(requireData.length));
log(chalk.bold.blue("Total time: ") + chalk.yellow(prettyMs(totalTime)));
});
|