Skip to content

Commit 37488fa

Browse files
fix: warn when using rest or identifier in custom elements without props option (#16003)
* fix: warn when using rest or identifier in custom elements without props option * chore: update message * tweak message * update tests --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 4e3ff09 commit 37488fa

File tree

11 files changed

+121
-0
lines changed

11 files changed

+121
-0
lines changed

.changeset/mighty-rabbits-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: warn when using rest or identifier in custom elements without props option

documentation/docs/98-reference/.generated/compile-warnings.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,12 @@ In some situations a selector may target an element that is not 'visible' to the
632632
</style>
633633
```
634634

635+
### custom_element_props_identifier
636+
637+
```
638+
Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
639+
```
640+
635641
### element_implicitly_closed
636642

637643
```

packages/svelte/messages/compile-warnings/script.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## custom_element_props_identifier
2+
3+
> Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
4+
15
## export_let_unused
26

37
> Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`

packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { get_rune } from '../../scope.js';
55
import { ensure_no_module_import_conflict, validate_identifier_name } from './shared/utils.js';
66
import * as e from '../../../errors.js';
7+
import * as w from '../../../warnings.js';
78
import { extract_paths } from '../../../utils/ast.js';
89
import { equal } from '../../../utils/assert.js';
910

@@ -52,6 +53,19 @@ export function VariableDeclarator(node, context) {
5253
e.props_invalid_identifier(node);
5354
}
5455

56+
if (
57+
context.state.analysis.custom_element &&
58+
context.state.options.customElementOptions?.props == null
59+
) {
60+
let warn_on;
61+
if (
62+
node.id.type === 'Identifier' ||
63+
(warn_on = node.id.properties.find((p) => p.type === 'RestElement')) != null
64+
) {
65+
w.custom_element_props_identifier(warn_on ?? node.id);
66+
}
67+
}
68+
5569
context.state.analysis.needs_props = true;
5670

5771
if (node.id.type === 'Identifier') {

packages/svelte/src/compiler/warnings.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export const codes = [
9696
'options_removed_hydratable',
9797
'options_removed_loop_guard_timeout',
9898
'options_renamed_ssr_dom',
99+
'custom_element_props_identifier',
99100
'export_let_unused',
100101
'legacy_component_creation',
101102
'non_reactive_update',
@@ -592,6 +593,14 @@ export function options_renamed_ssr_dom(node) {
592593
w(node, 'options_renamed_ssr_dom', `\`generate: "dom"\` and \`generate: "ssr"\` options have been renamed to "client" and "server" respectively\nhttps://svelte.dev/e/options_renamed_ssr_dom`);
593594
}
594595

596+
/**
597+
* Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
598+
* @param {null | NodeLike} node
599+
*/
600+
export function custom_element_props_identifier(node) {
601+
w(node, 'custom_element_props_identifier', `Using a rest element or a non-destructured declaration with \`$props()\` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the \`customElement.props\` option.\nhttps://svelte.dev/e/custom_element_props_identifier`);
602+
}
603+
595604
/**
596605
* Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
597606
* @param {null | NodeLike} node
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<svelte:options customElement={{
2+
props: {}
3+
}} />
4+
5+
<script>
6+
let props = $props();
7+
</script>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"code": "options_missing_custom_element",
4+
"end": {
5+
"column": 2,
6+
"line": 3
7+
},
8+
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
9+
"start": {
10+
"column": 16,
11+
"line": 1
12+
}
13+
}
14+
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<svelte:options customElement={{}} />
2+
3+
<script>
4+
let { ...props } = $props();
5+
</script>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"code": "options_missing_custom_element",
4+
"end": {
5+
"column": 34,
6+
"line": 1
7+
},
8+
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
9+
"start": {
10+
"column": 16,
11+
"line": 1
12+
}
13+
},
14+
{
15+
"code": "custom_element_props_identifier",
16+
"end": {
17+
"column": 15,
18+
"line": 4
19+
},
20+
"message": "Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.",
21+
"start": {
22+
"column": 7,
23+
"line": 4
24+
}
25+
}
26+
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<svelte:options customElement={{}} />
2+
3+
<script>
4+
let props = $props();
5+
</script>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"code": "options_missing_custom_element",
4+
"end": {
5+
"column": 34,
6+
"line": 1
7+
},
8+
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
9+
"start": {
10+
"column": 16,
11+
"line": 1
12+
}
13+
},
14+
{
15+
"code": "custom_element_props_identifier",
16+
"end": {
17+
"column": 10,
18+
"line": 4
19+
},
20+
"message": "Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.",
21+
"start": {
22+
"column": 5,
23+
"line": 4
24+
}
25+
}
26+
]

0 commit comments

Comments
 (0)