diff --git a/CHANGELOG.md b/CHANGELOG.md
index 406f2a591ad7..759aabfd7dc1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
## Unreleased
* Fix indirect bindings involving elements with spreads ([#3680](https://github.com/sveltejs/svelte/issues/3680))
+* Warn when using `` and `Foo` is dynamic ([#4331](https://github.com/sveltejs/svelte/issues/4331))
* Fix unneeded updating of keyed each blocks ([#4373](https://github.com/sveltejs/svelte/issues/4373))
## 3.18.2
diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
index 631c172576d9..f1c57ed09415 100644
--- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
+++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
@@ -106,11 +106,28 @@ export default class InlineComponentWrapper extends Wrapper {
block.add_outro();
}
+ warn_if_reactive() {
+ const { name } = this.node;
+ const variable = this.renderer.component.var_lookup.get(name);
+ if (!variable) {
+ return;
+ }
+
+ if (variable.reassigned || variable.export_name || variable.is_reactive_dependency) {
+ this.renderer.component.warn(this.node, {
+ code: 'reactive-component',
+ message: `<${name}/> will not be reactive if ${name} changes. Use if you want this reactivity.`,
+ });
+ }
+ }
+
render(
block: Block,
parent_node: Identifier,
parent_nodes: Identifier
) {
+ this.warn_if_reactive();
+
const { renderer } = this;
const { component } = renderer;
diff --git a/test/validator/index.js b/test/validator/index.js
index 8bf0400d7c53..9bce5e149b4a 100644
--- a/test/validator/index.js
+++ b/test/validator/index.js
@@ -20,6 +20,7 @@ describe("validate", () => {
const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, "utf-8").replace(/\s+$/, "");
const expected_warnings = tryToLoadJson(`${__dirname}/samples/${dir}/warnings.json`) || [];
const expected_errors = tryToLoadJson(`${__dirname}/samples/${dir}/errors.json`);
+ const options = tryToLoadJson(`${__dirname}/samples/${dir}/options.json`);
let error;
@@ -28,7 +29,8 @@ describe("validate", () => {
dev: config.dev,
legacy: config.legacy,
generate: false,
- customElement: config.customElement
+ customElement: config.customElement,
+ ...options,
});
assert.deepEqual(warnings.map(w => ({
diff --git a/test/validator/samples/component-dynamic/input.svelte b/test/validator/samples/component-dynamic/input.svelte
new file mode 100644
index 000000000000..f591a84fe14c
--- /dev/null
+++ b/test/validator/samples/component-dynamic/input.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/validator/samples/component-dynamic/options.json b/test/validator/samples/component-dynamic/options.json
new file mode 100644
index 000000000000..3a50892ebab1
--- /dev/null
+++ b/test/validator/samples/component-dynamic/options.json
@@ -0,0 +1,3 @@
+{
+ "generate": true
+}
\ No newline at end of file
diff --git a/test/validator/samples/component-dynamic/warnings.json b/test/validator/samples/component-dynamic/warnings.json
new file mode 100644
index 000000000000..457ef11a1ed7
--- /dev/null
+++ b/test/validator/samples/component-dynamic/warnings.json
@@ -0,0 +1,47 @@
+[
+ {
+ "code": "reactive-component",
+ "message": " will not be reactive if Let changes. Use if you want this reactivity.",
+ "pos": 190,
+ "end": {
+ "character": 197,
+ "column": 7,
+ "line": 15
+ },
+ "start": {
+ "character": 190,
+ "column": 0,
+ "line": 15
+ }
+ },
+ {
+ "message": " will not be reactive if ExportLet changes. Use if you want this reactivity.",
+ "code": "reactive-component",
+ "pos": 198,
+ "end": {
+ "character": 211,
+ "column": 13,
+ "line": 16
+ },
+ "start": {
+ "character": 198,
+ "column": 0,
+ "line": 16
+ }
+ },
+ {
+ "message": " will not be reactive if Reactive changes. Use if you want this reactivity.",
+ "code": "reactive-component",
+ "pos": 212,
+ "end": {
+ "character": 224,
+ "column": 12,
+ "line": 17
+ },
+ "start": {
+ "character": 212,
+ "column": 0,
+ "line": 17
+ }
+ }
+]