Skip to content

Commit

Permalink
feat: add colors flag to infrastructureLogging
Browse files Browse the repository at this point in the history
  • Loading branch information
KENNYSOFT committed Apr 4, 2021
1 parent f000617 commit 1f45499
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 72 deletions.
4 changes: 4 additions & 0 deletions declarations/WebpackOptions.d.ts
Expand Up @@ -1199,6 +1199,10 @@ export interface ExternalsPresets {
* Options for infrastructure level logging.
*/
export interface InfrastructureLogging {
/**
* Enables/Disables colorful output.
*/
colors?: boolean;
/**
* Enable debug logging for specific loggers.
*/
Expand Down
5 changes: 5 additions & 0 deletions lib/config/defaults.js
Expand Up @@ -1079,6 +1079,11 @@ const getResolveLoaderDefaults = ({ cache }) => {
const applyInfrastructureLoggingDefaults = infrastructureLogging => {
D(infrastructureLogging, "level", "info");
D(infrastructureLogging, "debug", false);
D(
infrastructureLogging,
"colors",
process.stderr.isTTY && process.env.TERM !== "dumb"
);
};

exports.applyWebpackOptionsBaseDefaults = applyWebpackOptionsBaseDefaults;
Expand Down
8 changes: 7 additions & 1 deletion lib/node/NodeEnvironmentPlugin.js
Expand Up @@ -24,12 +24,18 @@ class NodeEnvironmentPlugin {
* @returns {void}
*/
apply(compiler) {
const console = nodeConsole(
this.options.infrastructureLogging.colors !== undefined
? this.options.infrastructureLogging.colors
: process.stderr.isTTY && process.env.TERM !== "dumb"
);
delete this.options.infrastructureLogging.colors;
compiler.infrastructureLogger = createConsoleLogger(
Object.assign(
{
level: "info",
debug: false,
console: nodeConsole
console
},
this.options.infrastructureLogging
)
Expand Down
172 changes: 101 additions & 71 deletions lib/node/nodeConsole.js
Expand Up @@ -15,10 +15,10 @@ let hasStatusMessage = false;
let currentIndent = "";
let currentCollapsed = 0;

const indent = (str, prefix, colorPrefix, colorSuffix) => {
const indent = (colors, str, prefix, colorPrefix, colorSuffix) => {
if (str === "") return str;
prefix = currentIndent + prefix;
if (tty) {
if (colors) {
return (
prefix +
colorPrefix +
Expand Down Expand Up @@ -49,86 +49,116 @@ const writeStatusMessage = () => {
hasStatusMessage = true;
};

const writeColored = (prefix, colorPrefix, colorSuffix) => {
const writeColored = (colors, prefix, colorPrefix, colorSuffix) => {
return (...args) => {
if (currentCollapsed > 0) return;
clearStatusMessage();
const str = indent(util.format(...args), prefix, colorPrefix, colorSuffix);
const str = indent(
colors,
util.format(...args),
prefix,
colorPrefix,
colorSuffix
);
process.stderr.write(str + "\n");
writeStatusMessage();
};
};

const writeGroupMessage = writeColored(
"<-> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);
module.exports = colors => {
const writeGroupMessage = writeColored(
colors,
"<-> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);

const writeGroupCollapsedMessage = writeColored(
"<+> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);
const writeGroupCollapsedMessage = writeColored(
colors,
"<+> ",
"\u001b[1m\u001b[36m",
"\u001b[39m\u001b[22m"
);

module.exports = {
log: writeColored(" ", "\u001b[1m", "\u001b[22m"),
debug: writeColored(" ", "", ""),
trace: writeColored(" ", "", ""),
info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
logTime: writeColored("<t> ", "\u001b[1m\u001b[35m", "\u001b[39m\u001b[22m"),
group: (...args) => {
writeGroupMessage(...args);
if (currentCollapsed > 0) {
return {
log: writeColored(colors, " ", "\u001b[1m", "\u001b[22m"),
debug: writeColored(colors, " ", "", ""),
trace: writeColored(colors, " ", "", ""),
info: writeColored(
colors,
"<i> ",
"\u001b[1m\u001b[32m",
"\u001b[39m\u001b[22m"
),
warn: writeColored(
colors,
"<w> ",
"\u001b[1m\u001b[33m",
"\u001b[39m\u001b[22m"
),
error: writeColored(
colors,
"<e> ",
"\u001b[1m\u001b[31m",
"\u001b[39m\u001b[22m"
),
logTime: writeColored(
colors,
"<t> ",
"\u001b[1m\u001b[35m",
"\u001b[39m\u001b[22m"
),
group: (...args) => {
writeGroupMessage(...args);
if (currentCollapsed > 0) {
currentCollapsed++;
} else {
currentIndent += " ";
}
},
groupCollapsed: (...args) => {
writeGroupCollapsedMessage(...args);
currentCollapsed++;
} else {
currentIndent += " ";
}
},
groupCollapsed: (...args) => {
writeGroupCollapsedMessage(...args);
currentCollapsed++;
},
groupEnd: () => {
if (currentCollapsed > 0) currentCollapsed--;
else if (currentIndent.length >= 2)
currentIndent = currentIndent.slice(0, currentIndent.length - 2);
},
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profile: console.profile && (name => console.profile(name)),
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profileEnd: console.profileEnd && (name => console.profileEnd(name)),
clear:
tty &&
},
groupEnd: () => {
if (currentCollapsed > 0) currentCollapsed--;
else if (currentIndent.length >= 2)
currentIndent = currentIndent.slice(0, currentIndent.length - 2);
},
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear &&
(() => {
clearStatusMessage();
profile: console.profile && (name => console.profile(name)),
// eslint-disable-next-line node/no-unsupported-features/node-builtins
profileEnd: console.profileEnd && (name => console.profileEnd(name)),
clear:
tty &&
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear();
writeStatusMessage();
}),
status: tty
? (name, ...args) => {
args = args.filter(Boolean);
if (name === undefined && args.length === 0) {
clearStatusMessage();
currentStatusMessage = undefined;
} else if (
typeof name === "string" &&
name.startsWith("[webpack.Progress] ")
) {
currentStatusMessage = [name.slice(19), ...args];
writeStatusMessage();
} else if (name === "[webpack.Progress]") {
currentStatusMessage = [...args];
writeStatusMessage();
} else {
currentStatusMessage = [name, ...args];
writeStatusMessage();
}
}
: writeColored("<s> ", "", "")
console.clear &&
(() => {
clearStatusMessage();
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear();
writeStatusMessage();
}),
status: tty
? (name, ...args) => {
args = args.filter(Boolean);
if (name === undefined && args.length === 0) {
clearStatusMessage();
currentStatusMessage = undefined;
} else if (
typeof name === "string" &&
name.startsWith("[webpack.Progress] ")
) {
currentStatusMessage = [name.slice(19), ...args];
writeStatusMessage();
} else if (name === "[webpack.Progress]") {
currentStatusMessage = [...args];
writeStatusMessage();
} else {
currentStatusMessage = [name, ...args];
writeStatusMessage();
}
}
: writeColored(colors, "<s> ", "", "")
};
};
4 changes: 4 additions & 0 deletions schemas/WebpackOptions.json
Expand Up @@ -1211,6 +1211,10 @@
"type": "object",
"additionalProperties": false,
"properties": {
"colors": {
"description": "Enables/Disables colorful output.",
"type": "boolean"
},
"debug": {
"description": "Enable debug logging for specific loggers.",
"anyOf": [
Expand Down
70 changes: 70 additions & 0 deletions test/Compiler.test.js
Expand Up @@ -778,6 +778,12 @@ describe("Compiler", () => {
afterEach(() => {
capture.restore();
});
const escapeAnsi = stringRaw =>
stringRaw
.replace(/\u001b\[1m\u001b\[([0-9;]*)m/g, "<CLR=$1,BOLD>")
.replace(/\u001b\[1m/g, "<CLR=BOLD>")
.replace(/\u001b\[39m\u001b\[22m/g, "</CLR>")
.replace(/\u001b\[([0-9;]*)m/g, "<CLR=$1>");
class MyPlugin {
apply(compiler) {
const logger = compiler.getInfrastructureLogger("MyPlugin");
Expand Down Expand Up @@ -876,5 +882,69 @@ describe("Compiler", () => {
done();
});
});
it("should log to the console with colors (verbose)", done => {
const compiler = webpack({
context: path.join(__dirname, "fixtures"),
entry: "./a",
output: {
path: "/directory",
filename: "bundle.js"
},
infrastructureLogging: {
level: "verbose",
colors: true
},
plugins: [new MyPlugin()]
});
compiler.outputFileSystem = createFsFromVolume(new Volume());
compiler.run((err, stats) => {
expect(escapeAnsi(capture.toStringRaw()).replace(/[\d.]+ ms/, "X ms"))
.toMatchInlineSnapshot(`
"<-> <CLR=36,BOLD>[MyPlugin] Group</CLR>
<e> <CLR=31,BOLD>[MyPlugin] Error</CLR>
<w> <CLR=33,BOLD>[MyPlugin] Warning</CLR>
<i> <CLR=32,BOLD>[MyPlugin] Info</CLR>
<CLR=BOLD>[MyPlugin] Log<CLR=22>
<-> <CLR=36,BOLD>[MyPlugin] Collapsed group</CLR>
<CLR=BOLD>[MyPlugin] Log inside collapsed group<CLR=22>
<t> <CLR=35,BOLD>[MyPlugin] Time: X ms</CLR>
"
`);
done();
});
});
it("should log to the console with colors (debug mode)", done => {
const compiler = webpack({
context: path.join(__dirname, "fixtures"),
entry: "./a",
output: {
path: "/directory",
filename: "bundle.js"
},
infrastructureLogging: {
level: "error",
debug: /MyPlugin/,
colors: true
},
plugins: [new MyPlugin()]
});
compiler.outputFileSystem = createFsFromVolume(new Volume());
compiler.run((err, stats) => {
expect(escapeAnsi(capture.toStringRaw()).replace(/[\d.]+ ms/, "X ms"))
.toMatchInlineSnapshot(`
"<-> <CLR=36,BOLD>[MyPlugin] Group</CLR>
<e> <CLR=31,BOLD>[MyPlugin] Error</CLR>
<w> <CLR=33,BOLD>[MyPlugin] Warning</CLR>
<i> <CLR=32,BOLD>[MyPlugin] Info</CLR>
<CLR=BOLD>[MyPlugin] Log<CLR=22>
[MyPlugin] Debug
<-> <CLR=36,BOLD>[MyPlugin] Collapsed group</CLR>
<CLR=BOLD>[MyPlugin] Log inside collapsed group<CLR=22>
<t> <CLR=35,BOLD>[MyPlugin] Time: X ms</CLR>
"
`);
done();
});
});
});
});
1 change: 1 addition & 0 deletions test/Defaults.unittest.js
Expand Up @@ -109,6 +109,7 @@ describe("Defaults", () => {
"externalsType": "var",
"ignoreWarnings": undefined,
"infrastructureLogging": Object {
"colors": undefined,
"debug": false,
"level": "info",
},
Expand Down
5 changes: 5 additions & 0 deletions types.d.ts
Expand Up @@ -4184,6 +4184,11 @@ type ImportSource = undefined | null | string | SimpleLiteral | RegExpLiteral;
* Options for infrastructure level logging.
*/
declare interface InfrastructureLogging {
/**
* Enables/Disables colorful output.
*/
colors?: boolean;

/**
* Enable debug logging for specific loggers.
*/
Expand Down

0 comments on commit 1f45499

Please sign in to comment.