Skip to content

Commit

Permalink
feat: provide guidance in browser console when logging $state objects
Browse files Browse the repository at this point in the history
Wrap console.log/warn/error statements in DEV mode with a check whether or not they contain state objects. Closes #13123

This is an alternative or enhancement to #13070. Alternative if we deem it the better solution. Enhancement because it's not as robust as a custom formatter: We only check the top level of each entry (though we could maybe traverse a few levels), and if you're logging class instances, snapshot currently stops at the boundaries there and so you don't get snapshotted values for these (arguably this is a more general problem of $inspect and $state.snapshot), whereas with custom formatter it doesn't matter at which level you come across it.
  • Loading branch information
dummdidumm committed Sep 5, 2024
1 parent e1448f2 commit 4833ac4
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-taxis-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: provide guidance in browser console when logging $state objects
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,25 @@ export function CallExpression(node, context) {
return transform_inspect_rune(node, context);
}

if (
context.state.options.dev &&
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'console' &&
context.state.scope.get('console') === null &&
node.callee.property.type === 'Identifier' &&
['log', 'warn', 'error'].includes(node.callee.property.name)
) {
return b.call(
node.callee,
b.spread(
b.call(
'$.log_if_contains_state',
.../** @type {Expression[]} */ (node.arguments.map((arg) => context.visit(arg)))
)
)
);
}

context.next();
}
29 changes: 29 additions & 0 deletions packages/svelte/src/internal/client/dev/console-log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { STATE_SYMBOL } from '../constants.js';
import { snapshot } from '../../shared/clone.js';

/**
* @param {...any} objects
*/
export function log_if_contains_state(...objects) {
let has_state = false;
const transformed = [];

for (const obj of objects) {
if (obj && typeof obj === 'object' && STATE_SYMBOL in obj) {
transformed.push(snapshot(obj, true));
has_state = true;
} else {
transformed.push(obj);
}
}

if (has_state) {
console.log(

Check failure on line 21 in packages/svelte/src/internal/client/dev/console-log.js

View workflow job for this annotation

GitHub Actions / Lint

Unexpected console statement
'Your console.log contained $state objects. We recommend using $inspect or $state.snapshot when logging these for better results. The snapshotted value is:\n',
...transformed,
'\nThe original value is:\n'
);
}

return objects;
}
1 change: 1 addition & 0 deletions packages/svelte/src/internal/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,4 @@ export {
validate_void_dynamic_element
} from '../shared/validate.js';
export { strict_equals, equals } from './dev/equality.js';
export { log_if_contains_state } from './dev/console-log.js';
6 changes: 3 additions & 3 deletions packages/svelte/src/internal/shared/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ const empty = [];
* @returns {Snapshot<T>}
*/
export function snapshot(value, skip_warning = false) {
if (DEV) {
if (DEV && !skip_warning) {
/** @type {string[]} */
const paths = [];

const copy = clone(value, new Map(), '', paths);
if (paths.length === 1 && paths[0] === '' && !skip_warning) {
if (paths.length === 1 && paths[0] === '') {
// value could not be cloned
w.state_snapshot_uncloneable();
} else if (paths.length > 0 && !skip_warning) {
} else if (paths.length > 0) {
// some properties could not be cloned
const slice = paths.length > 10 ? paths.slice(0, 7) : paths.slice(0, 10);
const excess = paths.length - slice.length;
Expand Down

0 comments on commit 4833ac4

Please sign in to comment.