A duplicate of this question came up on meta.SO where I suggested a solution, copied here:
I whole-heartedly agree. If the point of these snippets is to enable us to demo functionality and display its output inline, the output pane needs to be adapted to (optionally) mirror logged messages.
Why should we bother avoiding document.write()
?
- We certainly don't want
document.write()
in the middle of what should be a node.js function. document.write()
is not what we're using to debug (I hope)document.write()
shouldn't even be suggested to the novice user without a littany of caveatsdocument.write()
's serialization isn't exactly robust, e.g.:String(value)
. Forget objects...- Our debugging messages deserve more love than that from our demo tool. We can do much, much better.
My Temporary Hack
I've created a small script to include via the html snippet:<!-- results pane console output; see http://meta.stackexchange.com/a/242491 -->
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
Here's a demo:
// sample script to generate output
var values = [
["a", "b", "c"],
function foo() {
return "bar";
},
document.createElement("a"),
{ foo: "bar" },
false,
"foo",
new Date()
];
// log each value with a delay
values.forEach(function(v, i) {
setTimeout(function() {
// call our custom log method... logging to both the DOM and the console
console.log("i: %d, type: %s, value: %o", i, typeof v, v);
}, 500 * i);
});
// throw an error
setTimeout(function(){
throw new Error("test!");
}, 3500);
<!-- results pane console output; see http://meta.stackexchange.com/a/242491 -->
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
Notes:
- All calls to
console.log()
(info()
,warn()
,error()
, andclear()
) are passed along to the actual console - Loosely imitates Chrome's output (colors and styles excluded)
- Objects are printed using a variation of
JSON.stringify()
(including functions, regex, undefined, etc) with custom handling forHTMLElement
- Works by injecting elements into the page... so, it obviously pollutes the DOM.
- The number of entries is now limited to 50 by default. You can modify this limit by calling
console.config({maxEntries:25})
. Older entries will be removed to make room for newer entries. - Logs unhandled errors.
- Handles circular references.
- Minified version available here: https://gh-canon.github.io/stack-snippet-console/console.min.js
- Unminified version available here: https://github.com/gh-canon/stack-snippet-console/blob/master/console.js
I've added some handling for circular references. We essentially leave a reference marker in a comment at the beginning of each object so we can refer back to it when it's referenced later. If those markers are never referenced, we remove them from the output. You could even serialize window
; though, I wouldn't recommend that.
var obj = {a: "x"};
console.log("without nesting: %o", obj);
obj.b = obj;
console.log("with nesting: %o", obj);
<!-- results pane console output; see http://meta.stackexchange.com/a/242491 -->
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
A Real Solution
Disclaimer: this section has rotted in the 1.5 years since I posted the answer. The backing code is not up to date.
While my temporary hack above certainly works... what I'd really like to see is something which:
- Is truly integrated, i.e.: doesn't link to my external script
- Keeps the console's DOM separate from the snippet's DOM
- Allows the author to opt in or out of the console wrapper
If we nest the snippet another frame down we can keep the console DOM separate from the snippet.
Page
┕ Console Frame
┕ Snippet Frame
Here's a demo. Click the button to log some mouse events.
The console page must have access to the snippet's window
before we can overwrite the snippet's console
. So, you'll need to inject the following into the snippet (as early as possible) in order to intercept subsequent calls to console.log()
:
<script>window.parent.attachConsole();</script>
Opting in/out?
Perhaps we can manage the injection via the snippet comments (and corresponding checkbox on the editor)...<!-- begin snippet: js hide: false console: true -->
That could also control whether or not we need to nest the snippet in a containing frame for the console.