An extension for developers that enhances the console API by incorporating the ability to compare objects and adds a JSDiff
tab (parallel to Elements, Network panels) within your dev-tools for viewing the results.
- Available in Chrome Web Store as console.diff()
- Available in Firefox Add-ons as jsdiff.diff()
- Track object mutations during runtime and/or while debugging with intention to find expected or unexpected changes.
-
User interface:
- Hide / show unchanged properties.
- Copy changed properties in format of
jsondiffpatch
Delta object. - Clear current result.
- Search input to highlight patterns.
- If search query contains at least one upper-case letter - the search will be case-sensitive.
- Indicator of the last update time.
- Indicator of a fatal error (out of storage memory).
- DevTools light/dark color scheme support.
-
Compare objects between multiple [sub]domains, Chrome tabs, or single page reloads.
JSDiff
DevTools panel reflects current state of comparison, regardless the tab[s] it was opened from.
-
Fail-safe serialization of objects having security issues while accessing their properties or objects having
toJSON()
function; when instead of serialization of all object properties, - onlytoJSON()
return value is serialized, likeJSON.strigify()
does. -
Can be used from within online code editors like: codesandbox.io, coderpad.io, flems.io, codepen.io, jsfiddle.net, mdn playground.
-
Map keys like
0
and'0'
would be merged due toMap to Object
conversion. -
While paused in debug mode,
JSDiff
panel won't reflect the result until runtime is resumed (see #10). -
Compared objects, after being serialized, stored in
chrome.storage.local
which has 10 MB limit. -
In Firefox the API is under
jsdiff
object for now, cause extension API's not fully compatible.
- console.diff(left, right) - compare left and right arguments
console.diff({ a: 1, b: 1, c: 3 }, { a: 1, b: 2, d: 3 });
- console.diffPush(next) - shifts sides, right becomes left, next becomes right
console.diffPush(Date.now());
- console.diff(next) - shorthand for
diffPush
console.diff(Date.now());
- console.diffLeft(left) - update the old value only
console.diffLeft(Date.now());
- console.diffRight(right) - update the new value only
console.diffRight(Date.now());
Global Console interface declaration for quick copy/paste when used from typescript:
declare global {
interface Console {
diff(left: unknown, right?: unknown): void;
diffPush(next: unknown): void;
diffLeft(left: unknown): void;
diffRight(right: unknown): void;
}
}
Input | Output |
---|---|
XMLHttpRequest[1] | ƒ XMLHttpRequest⟪native⟫ |
function test(){}[1] | ƒ test⟪1374b28d22b674e53a044425556a9cd48b82fd5aba3bf19e3545d51704227b10⟫ |
document.body | {0001}[2,3] DOM⟪BODY⟫ |
±Infinity | Number⟪±Infinity⟫ |
NaN | Number⟪NaN⟫ |
98765432109876543210n | BigInt⟪98765432109876543210⟫ |
void 0 | ⟪undefined⟫ |
/example/i | RegExp⟪/example/i⟫ |
new URL('https://example.com/') | URL⟪https://example.com/⟫ |
Symbol('example') | {0001}[3] Symbol(example) |
Symbol.for('global') | Symbol(global) |
(obj = {key: 1}, {first: obj, second: obj}) | {"first": {"key": 1}, "second": "[0002][4] Object⟪♻️⟫"} |
(key2= {}, map = new Map([['key1', 1], [key2, 2]]), {first: map, second: map}) | {"first": {"[0003][4,5] Object⟪♻️⟫": 2, "key1": 1}, "second": "[0002][4] Map⟪♻️⟫"} |
(arr = [1], {first: arr, second: arr}) | {"first": [1], "second": "[0002][4] Array⟪♻️⟫"} |
(set = new Set([1]), {first: set, second: set}) | {"first: [1], "second": "[0002][4] Set⟪♻️⟫"} |
1 Functions included in comparison result in order to detect possible alterations, in form of a string combined from a function name (if present) and a hash of a function.toString()
body.
2 DOM element serialized by pseudo id
and nodeName
.
3 Notation {}
denotes pseudo id
from a Set of unique instances, which is assigned during serialization of compared sides and remains inside internal WeakMap
lookup catalog until its garbage collected or page is reloaded.
4 Notation []
denotes pseudo id
from a Multiset of recurring instances, which is assigned in the scope of serialization of a high level argument instance, while comparing left or right side; that means - if some object, having id
of [0001]
on the left side, is not guarantied to have same id
on the right side.
5 Map
key, unless it's a primitive type, serialized by his pseudo id
.
-
How to protect your site from this extension:
-
Tests in Chrome show that even
Content-Security-Policy: default-src 'none';
header won't prevent injection of extension content-scripts... -
Avoid assigning to
window
orglobalThis
any application object. See also accidental global variables and memory leaks. -
In general, you can incapacitate console functions:
for (const prop in console) { if (typeof console[prop] === 'function' && prop !== 'error') { console[prop] = function noop() {}; } }
-
- Linux
- node 22.14 (LTS)
make install # install dependencies
make all # build for prod and make extension.${browser}.zip
make tune2chrome # or tune2firefox for relevant manifest.json file
make dev # local development
- jsondiffpatch by Benjamín Eidelman
- vuejs by Evan You