Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active March 27, 2024 03:37
Show Gist options
  • Save dfkaye/d3c7d0d59cb03616ad2eee8eec1141a5 to your computer and use it in GitHub Desktop.
Save dfkaye/d3c7d0d59cb03616ad2eee8eec1141a5 to your computer and use it in GitHub Desktop.
Saving your console work in the browser, using one of two approaches.
// 22 July 2022
// Save() function for saving your console script experiments.
// See the long explanation on this gist at
// https://gist.github.com/dfkaye/d3c7d0d59cb03616ad2eee8eec1141a5#file-save-your-console-work-js
// Save() takes an array of script functions and fragments,
// and prints them as a single text block to the console,
// and attempts to download the text block to your browser's
// downloads folder.
function Save(scripts) {
// You can change the start and end fragments to your liking.
var script = `/* scripts */\n`
+ scripts.join(";\n\n")
+ `// comment out dangling debugger text -> `;
var blob = new Blob([script], { type: "text/plain"});
var url = URL.createObjectURL(blob);
fetch(url)
.then(res => res.text())
.then(text => {
// Clear out previous console statements.
// Note that this writes "console was cleared" at the top of the log.
// You'll need to remove or comment this line from the saved file if
// you try the right+click and "Save All Messages" approach.
console.clear();
// Print out the script text.
console.log(text);
})
.then(text => {
// Create and run command to download blob as text file.
var a = document.createElement("a");
a.href = url;
a.target = "_new";
a.download = "console-test_" + performance.now() + ".js.txt";
a.click();
})
.catch(hmm => console.error("err", hmm));
}
/* Example usage */
// Our sample function.
function add (a, b) {
return a + b;
}
// Tests for our function. This function runs various tests, collects results,
// then batches up the sample function, the test function, a script command as
// a string, and the test results as a JSON string.
function test() {
var results = [];
var tests = [
[1,2],
[3,"4"],
[5n, 6.2e-1],
[null, undefined]
];
tests.forEach((pair, i, result) => {
try {
result = add.apply({}, pair);
}
catch (hmm) {
result = hmm;
}
finally {
results.push({
pair: pair.toString(),
result: result.toString()
});
}
});
return results;
};
// Our test run returns an array of functions and script strings.
var results = test();
// Collect any functions and script fragment strings (even test results)
// that we wish to preserve in an array.
var scripts = [
add,
test,
`test()`,
`/*\n ${JSON.stringify(results, null, 2)}\n*/`,
];
// And finally, send scripts to be saved.
Save(scripts);
// 21-22 July 2022
// Save your console work in the browser, using one of two approaches.
// If you're like me you do a lot of testing in the JavaScript console
// in your web browser. When I want to save the whole thing once it's
// ready for preserving, I usually just make a new gist on GitHub, copy
// everything out, and save it there.
// If you'd rather save your console work to a local file, you can use one
// of two patterns outlined below.
// 1. Save by console statement link click.
// 2. Download blob automatically from an off-the-DOM anchor element.
// Both patterns involve creating a blob from a set of functions and strings
// of JavaScript, creating an object URL from the blob, then use the fetch()
// function to retrieve all the script text you want to preserve.
// That sounds roundabout but allows you to execute the functions before
// they are printed back out, and prints out only those functions you
// want to preserve.
//---------------------------------------------------------------------------
// Pattern 1: Save by console statement link click.
//---------------------------------------------------------------------------
// Because they are printed by console statements, you can right+click on
// the debugger link that appears in the console above each statement, then
// select "Save All Messages to File" to open the file browser, change the
// name you'd like to save to, select the directory for saving, and press OK.
// Caveat: This does not work when you use the console on a running site with
// a strict Content Security Policy that contains a script-src or script-src-elem
// directive that does *not* include `blob:` as one of the schemes or domains.
// This example runs on google.com, e.g., but not on github.com.
// Caveat 2: The example results in a "console was cleared" statement at the top
// of the generated console output. When saving the file, you'll need to comment
// it or remove it, and possibly some "debugger eval ..." indicators.
// The following example defines a function under development, called "add",
// a test function that executes different input pairs against it, then a
// series of statements for converting functions and fragments we want to
// preserve into a blob URL that we (eventually) fetch() and log to the console,
// after clearing the console first.
// Our sample function.
function add (a, b) {
return a + b;
}
// Tests for our function. This function runs various tests, collects results,
// then batches up the sample function, the test function, a script command as
// a string, and the test results as a JSON string.
function test() {
var results = [];
var tests = [
[1,2],
[3,"4"],
[5n, 6.2e-1],
[null, undefined]
];
tests.forEach((pair, i, result) => {
try {
result = add.apply({}, pair);
}
catch (hmm) {
result = hmm;
}
finally {
results.push({
pair: pair.toString(),
result: result.toString()
});
}
});
return results;
};
// Our test run returns an array of functions and script strings.
var results = test();
// Collect any functions and script fragment strings (even test results)
// that we wish to preserve in an array.
var scripts = [
`/* scripts */`,
add,
test,
`test()`,
`/*\n ${JSON.stringify(results, null, 2)}\n*/`,
`// comment out dangling debugger text -> `
];
// Join the array into a string. Joining itself treats the function bodies
// as strings.
var script = scripts.join(";\n\n");
// We then create a text blob from that.
var blob = new Blob([script], { type: "text/plain"});
// Create an object URL from the blob.
var url = URL.createObjectURL(blob);
// Use fetch() on that URL and print the concatenated script text in the console.
fetch(url)
.then(res => res.text())
.then(text => {
// Clear out previous console statements.
// Note that this writes "console was cleared" at the top of the log.
// You'll need to remove or comment this line from the saved file if
// you try the right+click and "Save All Messages" approach.
console.clear();
// Print out the script text.
console.log(text);
})
.catch(hmm => console.error("err", hmm));
// You should be able to save the fetched text as console output from
// the debugger link at upper right - link text is something like
// "debugger eval code 21:23" - by a right+click on the link, selecting
// "Save Messages to File", select your file name and directory, and done!
// When you run this full script in the browser console, you should see
// your script text, followed by test run results below.
// Here's what I get running all this in my console in Firefox,
// set off with back ticks so you can copy+paste this entire gist into
// the console and run it...
`
Console was cleared. debugger eval code:112:13
/* scripts */;
function add (a, b) {
return a + b;
};
function test() {
var results = [];
var tests = [
[1,2],
[3,"4"],
[5n, 6.2e-1],
[null, undefined]
];
tests.forEach((pair, i, result) => {
try {
result = add.apply({}, pair);
}
catch (hmm) {
result = hmm;
}
finally {
results.push({
pair: pair.toString(),
result: result.toString()
});
}
});
return results;
};
test();
/*
[
{
"pair": "1,2",
"result": "3"
},
{
"pair": "3,4",
"result": "34"
},
{
"pair": "5,0.62",
"result": "TypeError: can't convert BigInt to number"
},
{
"pair": ",",
"result": "NaN"
}
]
*/;
// comment out dangling debugger text -> debugger eval code:115:13
`
//---------------------------------------------------------------------------
// Pattern 2: Download blob automatically from an off-the-DOM anchor element.
//---------------------------------------------------------------------------
// I find Pattern 1 to be a hassle because of the lingering "Console was cleared"
// text and the dangling "debugger" link text, and mainly, that I have to do
// **any** clicking to initiate saving as a separate step from running the code.
// Turns out we can just download the script text from the blob URL automatically,
// per the example below. The strategy is to create an anchor element with a download
// name, href set to the blob URL, and target set to "_new".
fetch(url)
.then(res => res.text())
.then(text => {
// Create and run command to download blob as text file.
var a = document.createElement("a");
a.href = url;
a.target = "_new";
a.download = "console-test_" + performance.now() + ".js.txt";
a.click();
})
.catch(hmm => console.error("err", hmm));
// The same URL access restrictions apply if you are working on a live web
// site with a strong Content Security Policy. However, because we are saving
// the file as plain text, malware detection software in your browser should
// permit the download automatically.
// As always, find a groove that works for you.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment