diff --git a/.changeset/breezy-pears-punch.md b/.changeset/breezy-pears-punch.md new file mode 100644 index 0000000000..e0ff7e746c --- /dev/null +++ b/.changeset/breezy-pears-punch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: add warning when you read object property within attachments in legacy mode diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index 7069f90206..3f2aa11618 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -556,6 +556,12 @@ Elements with ARIA roles must use a valid, non-abstract ARIA role. A reference t
``` +### attachment_legacy_member_access + +``` +Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. +``` + ### attribute_avoid_is ``` diff --git a/packages/svelte/messages/compile-warnings/template.md b/packages/svelte/messages/compile-warnings/template.md index c1675e5995..a62882a9cf 100644 --- a/packages/svelte/messages/compile-warnings/template.md +++ b/packages/svelte/messages/compile-warnings/template.md @@ -1,3 +1,7 @@ +## attachment_legacy_member_access + +> Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. + ## attribute_avoid_is > The "is" attribute is not supported cross-browser and should be avoided diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js index 1e318f228d..40333e9bd1 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AttachTag.js @@ -1,7 +1,9 @@ /** @import { AST } from '#compiler' */ /** @import { Context } from '../types' */ +import { walk } from 'zimmerframe'; import { mark_subtree_dynamic } from './shared/fragment.js'; +import * as w from '../../../warnings.js'; /** * @param {AST.AttachTag} node @@ -9,5 +11,16 @@ import { mark_subtree_dynamic } from './shared/fragment.js'; */ export function AttachTag(node, context) { mark_subtree_dynamic(context.path); + if (!context.state.analysis.runes) { + walk( + node.expression, + {}, + { + MemberExpression(node) { + w.attachment_legacy_member_access(node); + } + } + ); + } context.next({ ...context.state, expression: node.metadata.expression }); } diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index c281433213..4740bdaeb4 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -106,6 +106,7 @@ export const codes = [ 'state_referenced_locally', 'store_rune_conflict', 'css_unused_selector', + 'attachment_legacy_member_access', 'attribute_avoid_is', 'attribute_global_event_reference', 'attribute_illegal_colon', @@ -677,6 +678,14 @@ export function css_unused_selector(node, name) { w(node, 'css_unused_selector', `Unused CSS selector "${name}"\nhttps://svelte.dev/e/css_unused_selector`); } +/** + * Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object. + * @param {null | NodeLike} node + */ +export function attachment_legacy_member_access(node) { + w(node, 'attachment_legacy_member_access', `Using \`@attach\` with a function from an object can cause unnecessary reruns of the attachment function if you mutate that object in legacy mode.\nhttps://svelte.dev/e/attachment_legacy_member_access`); +} + /** * The "is" attribute is not supported cross-browser and should be avoided * @param {null | NodeLike} node diff --git a/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte new file mode 100644 index 0000000000..cc56759f13 --- /dev/null +++ b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/input.svelte @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json new file mode 100644 index 0000000000..ff981c4fff --- /dev/null +++ b/packages/svelte/tests/validator/samples/attachment-legacy-member-access/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "attachment_legacy_member_access", + "message": "Using `@attach` with a function from an object in legacy mode can cause unnecessary reruns of the attachment function if you mutate that object.", + "start": { + "line": 14, + "column": 14 + }, + "end": { + "line": 14, + "column": 30 + } + } +]