diff --git a/packages/svelte/messages/client-errors/errors.md b/packages/svelte/messages/client-errors/errors.md
index bebf196bdd..8898af0a8c 100644
--- a/packages/svelte/messages/client-errors/errors.md
+++ b/packages/svelte/messages/client-errors/errors.md
@@ -1,3 +1,11 @@
+## bind_invalid_export
+
+> Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`)
+
+## bind_not_bindable
+
+> A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()`
+
## each_key_duplicate
> Keyed each block has duplicate key at indexes %a% and %b%
diff --git a/packages/svelte/src/internal/client/errors.js b/packages/svelte/src/internal/client/errors.js
index 1ecee03786..81a736100b 100644
--- a/packages/svelte/src/internal/client/errors.js
+++ b/packages/svelte/src/internal/client/errors.js
@@ -2,6 +2,44 @@
import { DEV } from 'esm-env';
+/**
+ * Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`)
+ * @param {string} component
+ * @param {string} key
+ * @param {string} name
+ * @returns {never}
+ */
+export function bind_invalid_export(component, key, name) {
+ if (DEV) {
+ const error = new Error(`${"bind_invalid_export"}\n${`Component ${component} has an export named \`${key}\` that a consumer component is trying to access using \`bind:${key}\`, which is disallowed. Instead, use \`bind:this\` (e.g. \`<${name} bind:this={component} />\`) and then access the property on the bound component instance (e.g. \`component.${key}\`)`}`);
+
+ error.name = 'Svelte error';
+ throw error;
+ } else {
+ // TODO print a link to the documentation
+ throw new Error("bind_invalid_export");
+ }
+}
+
+/**
+ * A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()`
+ * @param {string} key
+ * @param {string} component
+ * @param {string} name
+ * @returns {never}
+ */
+export function bind_not_bindable(key, component, name) {
+ if (DEV) {
+ const error = new Error(`${"bind_not_bindable"}\n${`A component is attempting to bind to a non-bindable property \`${key}\` belonging to ${component} (i.e. \`<${name} bind:${key}={...}>\`). To mark a property as bindable: \`let { ${key} = $bindable() } = $props()\``}`);
+
+ error.name = 'Svelte error';
+ throw error;
+ } else {
+ // TODO print a link to the documentation
+ throw new Error("bind_not_bindable");
+ }
+}
+
/**
* Keyed each block has duplicate key `%value%` at indexes %a% and %b%
* @param {string} a
diff --git a/packages/svelte/src/internal/client/validate.js b/packages/svelte/src/internal/client/validate.js
index a1799d42f9..2685e0c1ad 100644
--- a/packages/svelte/src/internal/client/validate.js
+++ b/packages/svelte/src/internal/client/validate.js
@@ -78,17 +78,11 @@ export function validate_prop_bindings($$props, bindable, exports, component) {
if (setter) {
if (exports.includes(key)) {
- throw new Error(
- `Component ${component.filename} has an export named ${key} that a consumer component is trying to access using bind:${key}, which is disallowed. ` +
- `Instead, use bind:this (e.g. <${name} bind:this={component} />) ` +
- `and then access the property on the bound component instance (e.g. component.${key}).`
- );
+ e.bind_invalid_export(component.filename, key, name);
}
+
if (!bindable.includes(key)) {
- throw new Error(
- `A component is binding to property ${key} of ${name}.svelte (i.e. <${name} bind:${key} />). This is disallowed because the property was not declared as bindable inside ${component.filename}. ` +
- `To mark a property as bindable, use the $bindable() rune in ${name}.svelte like this: \`let { ${key} = $bindable() } = $props()\``
- );
+ e.bind_not_bindable(key, component.filename, name);
}
}
}
diff --git a/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js b/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js
index 0f64998059..5f02769634 100644
--- a/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/export-binding/_config.js
@@ -5,6 +5,6 @@ export default test({
dev: true // to ensure we we catch the error
},
error:
- 'Component .../export-binding/counter/index.svelte has an export named increment that a consumer component is trying to access using bind:increment, which is disallowed. ' +
- 'Instead, use bind:this (e.g. ) and then access the property on the bound component instance (e.g. component.increment).'
+ 'bind_invalid_export\n' +
+ 'Component .../export-binding/counter/index.svelte has an export named `increment` that a consumer component is trying to access using `bind:increment`, which is disallowed. Instead, use `bind:this` (e.g. ``) and then access the property on the bound component instance (e.g. `component.increment`)'
});
diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js b/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js
index fc6b46d488..3cc17bd7b3 100644
--- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/props-not-bindable-spread/_config.js
@@ -4,9 +4,10 @@ export default test({
compileOptions: {
dev: true
},
+
+ html: '0',
+
error:
- 'A component is binding to property count of Counter.svelte (i.e. ). This is disallowed because the property was ' +
- 'not declared as bindable inside .../samples/props-not-bindable-spread/Counter.svelte. To mark a property as bindable, use the $bindable() rune ' +
- 'in Counter.svelte like this: `let { count = $bindable() } = $props()`',
- html: `0`
+ 'bind_not_bindable\n' +
+ 'A component is attempting to bind to a non-bindable property `count` belonging to .../samples/props-not-bindable-spread/Counter.svelte (i.e. ``). To mark a property as bindable: `let { count = $bindable() } = $props()`'
});
diff --git a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js b/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js
index b3dcc7f23e..34ab163829 100644
--- a/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/props-not-bindable/_config.js
@@ -4,9 +4,10 @@ export default test({
compileOptions: {
dev: true
},
+
+ html: '0',
+
error:
- 'A component is binding to property count of Counter.svelte (i.e. ). This is disallowed because the property was ' +
- 'not declared as bindable inside .../samples/props-not-bindable/Counter.svelte. To mark a property as bindable, use the $bindable() rune ' +
- 'in Counter.svelte like this: `let { count = $bindable() } = $props()`',
- html: `0`
+ 'bind_not_bindable\n' +
+ 'A component is attempting to bind to a non-bindable property `count` belonging to .../samples/props-not-bindable/Counter.svelte (i.e. ``). To mark a property as bindable: `let { count = $bindable() } = $props()`'
});