Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow ignoring runtime warnings #12608

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b43c22b
feat: allow ignoring binding_property_non_reactive
paoloricciuti Jul 25, 2024
cedc6d4
chore: add comments before `to_ignore`
paoloricciuti Jul 25, 2024
3e0f6c1
chore: fix warnings regeneration
paoloricciuti Jul 25, 2024
1e1dc39
Merge remote-tracking branch 'upstream/main' into allow-ignoring-bind…
paoloricciuti Jul 29, 2024
4eaf118
chore: include client warnings code in svelte ignore extract
paoloricciuti Jul 29, 2024
dc53654
feat: allow ignoring state_snapshot_uncloneable
paoloricciuti Jul 29, 2024
ca7aa51
chore: abstract ignore into function
paoloricciuti Jul 29, 2024
e1595c0
feat: allow skipping of `hydration_attribute_changed`
paoloricciuti Jul 29, 2024
d9dadd5
feat: allow skip of `hydration_html_changed`
paoloricciuti Jul 29, 2024
6f92da4
feat: allow skipping `ownership_invalid_binding`
paoloricciuti Jul 29, 2024
3b7f279
chore: revert extracting codes and use hardcoded list
paoloricciuti Jul 29, 2024
b3ec018
chore: update changeset
paoloricciuti Jul 29, 2024
ec3ae41
feat: allow skipping `ownership_invalid_mutation`
paoloricciuti Jul 30, 2024
ea9ca18
Merge branch 'main' into pr/12608
Rich-Harris Jul 30, 2024
e21c4cc
is_to_ignore -> is_ignored
Rich-Harris Jul 30, 2024
7fda79a
make is_ignored type safe
Rich-Harris Jul 30, 2024
aa62e2a
tweak
Rich-Harris Jul 30, 2024
02115ec
tweak naming
Rich-Harris Jul 30, 2024
4e20b24
tweak
Rich-Harris Jul 30, 2024
c12fe44
remove extra args
Rich-Harris Jul 30, 2024
19000d1
comment is redundant, code contains enough information
Rich-Harris Jul 30, 2024
f85d491
remove more unwanted args
Rich-Harris Jul 30, 2024
57e4543
only add ignore code in dev
Rich-Harris Jul 31, 2024
2aad265
lint
Rich-Harris Jul 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-emus-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: allow ignoring runtime warnings
70 changes: 48 additions & 22 deletions packages/svelte/src/compiler/phases/3-transform/client/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
PROPS_IS_RUNES,
PROPS_IS_UPDATED
} from '../../../../constants.js';
import { dev } from '../../../state.js';
import { is_ignored, dev } from '../../../state.js';

/**
* @template {ClientTransformState} State
Expand Down Expand Up @@ -282,6 +282,22 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
);
}

/**
* @param {any} serialized
* @returns
*/
function maybe_skip_ownership_validation(serialized) {
if (is_ignored(node, 'ownership_invalid_mutation')) {
return b.call('$.skip_ownership_validation', b.thunk(serialized));
}

return serialized;
}

if (binding.kind === 'derived') {
return maybe_skip_ownership_validation(fallback());
}

const is_store = binding.kind === 'store_sub';
const left_name = is_store ? left.name.slice(1) : left.name;

Expand Down Expand Up @@ -382,45 +398,55 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
return /** @type {Expression} */ (visit(node));
}

return b.call(
'$.store_mutate',
serialize_get_binding(b.id(left_name), state),
b.assignment(node.operator, /** @type {Pattern}} */ (visit_node(node.left)), value),
b.call('$.untrack', b.id('$' + left_name))
return maybe_skip_ownership_validation(
b.call(
'$.store_mutate',
serialize_get_binding(b.id(left_name), state),
b.assignment(node.operator, /** @type {Pattern}} */ (visit_node(node.left)), value),
b.call('$.untrack', b.id('$' + left_name))
)
);
} else if (
!state.analysis.runes ||
// this condition can go away once legacy mode is gone; only necessary for interop with legacy parent bindings
(binding.mutated && binding.kind === 'bindable_prop')
) {
if (binding.kind === 'bindable_prop') {
return b.call(
left,
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value),
b.true
return maybe_skip_ownership_validation(
b.call(
left,
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value),
b.true
)
);
} else {
return b.call(
'$.mutate',
b.id(left_name),
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value)
return maybe_skip_ownership_validation(
b.call(
'$.mutate',
b.id(left_name),
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value)
)
);
}
} else if (
node.right.type === 'Literal' &&
prefix != null &&
(node.operator === '+=' || node.operator === '-=')
) {
return b.update(
node.operator === '+=' ? '++' : '--',
/** @type {Expression} */ (visit(node.left)),
prefix
return maybe_skip_ownership_validation(
b.update(
node.operator === '+=' ? '++' : '--',
/** @type {Expression} */ (visit(node.left)),
prefix
)
);
} else {
return b.assignment(
node.operator,
/** @type {Pattern} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right))
return maybe_skip_ownership_validation(
b.assignment(
node.operator,
/** @type {Pattern} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right))
)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import is_reference from 'is-reference';
import { serialize_get_binding, serialize_set_binding } from '../utils.js';
import * as b from '../../../../utils/builders.js';
import { is_ignored } from '../../../../state.js';

/** @type {Visitors} */
export const global_visitors = {
Expand Down Expand Up @@ -115,6 +116,15 @@ export const global_visitors = {

return b.call(fn, ...args);
} else {
/** @param {any} serialized */
function maybe_skip_ownership_validation(serialized) {
if (is_ignored(node, 'ownership_invalid_mutation')) {
return b.call('$.skip_ownership_validation', b.thunk(serialized));
}

return serialized;
}

// turn it into an IIFEE assignment expression: i++ -> (() => { const $$value = i; i+=1; return $$value; })
const assignment = b.assignment(
node.operator === '++' ? '+=' : '-=',
Expand All @@ -130,9 +140,9 @@ export const global_visitors = {
const value = /** @type {Expression} */ (visit(argument));
if (serialized_assignment === assignment) {
// No change to output -> nothing to transform -> we can keep the original update expression
return next();
return maybe_skip_ownership_validation(next());
} else if (context.state.analysis.runes) {
return serialized_assignment;
return maybe_skip_ownership_validation(serialized_assignment);
} else {
/** @type {Statement[]} */
let statements;
Expand All @@ -146,7 +156,7 @@ export const global_visitors = {
b.return(b.id(tmp_id))
];
}
return b.call(b.thunk(b.block(statements)));
return maybe_skip_ownership_validation(b.call(b.thunk(b.block(statements))));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
/** @import { CallExpression, Expression, Identifier, Literal, MethodDefinition, PrivateIdentifier, PropertyDefinition, VariableDeclarator } from 'estree' */
/** @import { Binding } from '#compiler' */
/** @import { ComponentVisitors, StateField } from '../types.js' */
import { dev, is_ignored } from '../../../../state.js';
import * as assert from '../../../../utils/assert.js';
import { extract_paths } from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';
import { get_rune } from '../../../scope.js';
import { is_hoistable_function, transform_inspect_rune } from '../../utils.js';
import * as b from '../../../../utils/builders.js';
import * as assert from '../../../../utils/assert.js';
import {
get_prop_source,
is_prop_source,
is_state_source,
serialize_proxy_reassignment,
should_proxy_or_freeze
} from '../utils.js';
import { extract_paths } from '../../../../utils/ast.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';
import { dev } from '../../../../state.js';

/** @type {ComponentVisitors} */
export const javascript_visitors_runes = {
Expand Down Expand Up @@ -197,7 +197,9 @@ export const javascript_visitors_runes = {
b.call(
'$.add_owner',
b.call('$.get', b.member(b.this, b.private_id(name))),
b.id('owner')
b.id('owner'),
b.literal(false),
is_ignored(node, 'ownership_invalid_binding') && b.true
)
)
),
Expand Down Expand Up @@ -446,7 +448,11 @@ export const javascript_visitors_runes = {
}

if (rune === '$state.snapshot') {
return b.call('$.snapshot', /** @type {Expression} */ (context.visit(node.arguments[0])));
return b.call(
'$.snapshot',
/** @type {Expression} */ (context.visit(node.arguments[0])),
is_ignored(node, 'state_snapshot_uncloneable') && b.true
);
}

if (rune === '$state.is') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
/** @import { SourceLocation } from '#shared' */
/** @import { Scope } from '../../../scope.js' */
/** @import { ComponentClientTransformState, ComponentContext, ComponentVisitors } from '../types.js' */
import is_reference from 'is-reference';
import { walk } from 'zimmerframe';
import {
AttributeAliases,
DOMBooleanAttributes,
EACH_INDEX_REACTIVE,
EACH_IS_ANIMATED,
EACH_IS_CONTROLLED,
EACH_IS_STRICT_EQUALS,
EACH_ITEM_REACTIVE,
EACH_KEYED,
is_capture_event,
TEMPLATE_FRAGMENT,
TEMPLATE_USE_IMPORT_NODE,
TRANSITION_GLOBAL,
TRANSITION_IN,
TRANSITION_OUT
} from '../../../../../constants.js';
import { escape_html } from '../../../../../escaping.js';
import { dev, is_ignored, locator } from '../../../../state.js';
import {
extract_identifiers,
extract_paths,
Expand All @@ -13,48 +33,28 @@ import {
object,
unwrap_optional
} from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js';
import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
import { binding_properties } from '../../../bindings.js';
import { clean_nodes, determine_namespace_for_children, infer_namespace } from '../../utils.js';
import {
DOMProperties,
LoadErrorElements,
PassiveEvents,
VoidElements
} from '../../../constants.js';
import { is_custom_element_node, is_element_node } from '../../../nodes.js';
import * as b from '../../../../utils/builders.js';
import { regex_is_valid_identifier } from '../../../patterns.js';
import { clean_nodes, determine_namespace_for_children, infer_namespace } from '../../utils.js';
import {
with_loc,
create_derived,
create_derived_block_argument,
function_visitor,
get_assignment_value,
serialize_get_binding,
serialize_set_binding,
create_derived,
create_derived_block_argument
with_loc
} from '../utils.js';
import {
AttributeAliases,
DOMBooleanAttributes,
EACH_INDEX_REACTIVE,
EACH_IS_ANIMATED,
EACH_IS_CONTROLLED,
EACH_IS_STRICT_EQUALS,
EACH_ITEM_REACTIVE,
EACH_KEYED,
is_capture_event,
TEMPLATE_FRAGMENT,
TEMPLATE_USE_IMPORT_NODE,
TRANSITION_GLOBAL,
TRANSITION_IN,
TRANSITION_OUT
} from '../../../../../constants.js';
import { escape_html } from '../../../../../escaping.js';
import { regex_is_valid_identifier } from '../../../patterns.js';
import { javascript_visitors_runes } from './javascript-runes.js';
import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
import { walk } from 'zimmerframe';
import { dev, locator } from '../../../../state.js';
import is_reference from 'is-reference';

/**
* @param {RegularElement | SvelteElement} element
Expand Down Expand Up @@ -324,7 +324,8 @@ function serialize_element_spread_attributes(
b.id(id),
b.object(values),
lowercase_attributes,
b.literal(context.state.analysis.css.hash)
b.literal(context.state.analysis.css.hash),
is_ignored(element, 'hydration_attribute_changed') && b.true
)
)
);
Expand Down Expand Up @@ -489,7 +490,15 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu

// The foreign namespace doesn't have any special handling, everything goes through the attr function
if (context.state.metadata.namespace === 'foreign') {
const statement = b.stmt(b.call('$.set_attribute', node_id, b.literal(name), value));
const statement = b.stmt(
b.call(
'$.set_attribute',
node_id,
b.literal(name),
value,
is_ignored(element, 'hydration_attribute_changed') && b.true
)
);

if (attribute.metadata.expression.has_state) {
const id = state.scope.generate(`${node_id.name}_${name}`);
Expand Down Expand Up @@ -525,7 +534,15 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu
update = b.stmt(b.assignment('=', b.member(node_id, b.id(name)), value));
} else {
const callee = name.startsWith('xlink') ? '$.set_xlink_attribute' : '$.set_attribute';
update = b.stmt(b.call(callee, node_id, b.literal(name), value));
update = b.stmt(
b.call(
callee,
node_id,
b.literal(name),
value,
is_ignored(element, 'hydration_attribute_changed') && b.true
)
);
}

if (attribute.metadata.expression.has_state) {
Expand Down Expand Up @@ -780,7 +797,12 @@ function serialize_inline_component(node, component_name, context, anchor = cont
} else if (attribute.type === 'BindDirective') {
const expression = /** @type {Expression} */ (context.visit(attribute.expression));

if (dev && expression.type === 'MemberExpression' && context.state.analysis.runes) {
if (
dev &&
expression.type === 'MemberExpression' &&
context.state.analysis.runes &&
!is_ignored(node, 'binding_property_non_reactive')
) {
context.state.init.push(serialize_validate_binding(context.state, attribute, expression));
}

Expand All @@ -789,7 +811,14 @@ function serialize_inline_component(node, component_name, context, anchor = cont
} else {
if (dev) {
binding_initializers.push(
b.stmt(b.call(b.id('$.add_owner_effect'), b.thunk(expression), b.id(component_name)))
b.stmt(
b.call(
b.id('$.add_owner_effect'),
b.thunk(expression),
b.id(component_name),
is_ignored(node, 'ownership_invalid_binding') && b.true
)
)
);
}

Expand Down Expand Up @@ -1811,7 +1840,8 @@ export const template_visitors = {
context.state.node,
b.thunk(/** @type {Expression} */ (context.visit(node.expression))),
b.literal(context.state.metadata.namespace === 'svg'),
b.literal(context.state.metadata.namespace === 'mathml')
b.literal(context.state.metadata.namespace === 'mathml'),
is_ignored(node, 'hydration_html_changed') && b.true
)
)
);
Expand Down Expand Up @@ -2903,7 +2933,8 @@ export const template_visitors = {
type === 'KeyBlock'
)) &&
dev &&
context.state.analysis.runes
context.state.analysis.runes &&
!is_ignored(node, 'binding_property_non_reactive')
) {
context.state.init.push(
serialize_validate_binding(
Expand Down
Loading
Loading