Skip to content

Commit 476f217

Browse files
fix: mark accessors and immutable as deprecated (#11277)
* fix: mark `accessors` and `immutable` as deprecated * add warnings for deprecated <svelte:options> attributes * disable accessors in runes mode * update tests * tidy up * the hell? * regenerate types * if I would get a dollar for every windows bug I fix I would be a millionaire by now * return instance _and_ props in runes mode, move flushSync into shared code, don't set accessors in runes mode * goddammit * note breaking change * fix * regenerate messages * Revert "return instance _and_ props in runes mode, move flushSync into shared code, don't set accessors in runes mode" This reverts commit a47827e. * pass instance to tests --------- Co-authored-by: Simon Holthausen <[email protected]>
1 parent 22b2c15 commit 476f217

File tree

29 files changed

+154
-56
lines changed

29 files changed

+154
-56
lines changed

.changeset/tiny-meals-deliver.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: mark `accessors` and `immutable` as deprecated

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
1717
## deprecated_event_handler
1818

19-
> Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.
19+
> Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## options_deprecated_accessors
2+
3+
The `accessors` option has been deprecated. It will have no effect in runes mode
4+
15
## options_deprecated_immutable
26

37
> The `immutable` option has been deprecated. It will have no effect in runes mode

packages/svelte/scripts/process-messages/index.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ for (const category of fs.readdirSync('messages')) {
1313
for (const file of fs.readdirSync(`messages/${category}`)) {
1414
if (!file.endsWith('.md')) continue;
1515

16-
const markdown = fs.readFileSync(`messages/${category}/${file}`, 'utf-8');
16+
const markdown = fs
17+
.readFileSync(`messages/${category}/${file}`, 'utf-8')
18+
.replace(/\r\n/g, '\n');
1719

1820
for (const match of markdown.matchAll(/## ([\w]+)\n\n([^]+?)(?=$|\n\n## )/g)) {
1921
const [_, code, text] = match;
@@ -33,7 +35,9 @@ for (const category of fs.readdirSync('messages')) {
3335
}
3436

3537
function transform(name, dest) {
36-
const source = fs.readFileSync(new URL(`./templates/${name}.js`, import.meta.url), 'utf-8');
38+
const source = fs
39+
.readFileSync(new URL(`./templates/${name}.js`, import.meta.url), 'utf-8')
40+
.replace(/\r\n/g, '\n');
3741

3842
const comments = [];
3943

@@ -217,7 +221,8 @@ function transform(name, dest) {
217221

218222
fs.writeFileSync(
219223
dest,
220-
`/* This file is generated by scripts/process-messages.js. Do not edit! */\n\n` + module.code,
224+
`/* This file is generated by scripts/process-messages/index.js. Do not edit! */\n\n` +
225+
module.code,
221226
'utf-8'
222227
);
223228
}

packages/svelte/src/compiler/errors.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* This file is generated by scripts/process-messages.js. Do not edit! */
1+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
22

33
/** @typedef {{ start?: number, end?: number }} NodeLike */
44
// interface is duplicated between here (used internally) and ./interfaces.js

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ export function analyze_component(root, source, options) {
374374
inject_styles: options.css === 'injected' || options.customElement,
375375
accessors: options.customElement
376376
? true
377-
: !!options.accessors ||
377+
: (runes ? false : !!options.accessors) ||
378378
// because $set method needs accessors
379379
!!options.legacy?.componentApi,
380380
reactive_statements: new Map(),
@@ -395,8 +395,20 @@ export function analyze_component(root, source, options) {
395395
source
396396
};
397397

398-
if (!options.customElement && root.options?.customElement) {
399-
w.options_missing_custom_element(root.options);
398+
if (root.options) {
399+
for (const attribute of root.options.attributes) {
400+
if (attribute.name === 'accessors') {
401+
w.options_deprecated_accessors(attribute);
402+
}
403+
404+
if (attribute.name === 'customElement' && !options.customElement) {
405+
w.options_missing_custom_element(attribute);
406+
}
407+
408+
if (attribute.name === 'immutable') {
409+
w.options_deprecated_immutable(attribute);
410+
}
411+
}
400412
}
401413

402414
if (analysis.runes) {

packages/svelte/src/compiler/types/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export interface CompileOptions extends ModuleCompileOptions {
9494
* If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`.
9595
*
9696
* @default false
97+
* @deprecated This will have no effect in runes mode
9798
*/
9899
accessors?: boolean;
99100
/**
@@ -107,6 +108,7 @@ export interface CompileOptions extends ModuleCompileOptions {
107108
* This allows it to be less conservative about checking whether values have changed.
108109
*
109110
* @default false
111+
* @deprecated This will have no effect in runes mode
110112
*/
111113
immutable?: boolean;
112114
/**

packages/svelte/src/compiler/validate-options.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const validate_component_options =
3939
object({
4040
...common,
4141

42-
accessors: boolean(false),
42+
accessors: deprecate(w.options_deprecated_accessors, boolean(false)),
4343

4444
css: validator('external', (input) => {
4545
if (input === true || input === false) {

packages/svelte/src/compiler/warnings.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* This file is generated by scripts/process-messages.js. Do not edit! */
1+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
22

33
import { getLocator } from 'locate-character';
44

@@ -544,6 +544,14 @@ export function invalid_self_closing_tag(node, name) {
544544
w(node, "invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use <${name} ...></${name}> rather than <${name} ... />`);
545545
}
546546

547+
/**
548+
* e `accessors` option has been deprecated. It will have no effect in runes mode
549+
* @param {null | NodeLike} node
550+
*/
551+
export function options_deprecated_accessors(node) {
552+
w(node, "options_deprecated_accessors", "e `accessors` option has been deprecated. It will have no effect in runes mode");
553+
}
554+
547555
/**
548556
* The `immutable` option has been deprecated. It will have no effect in runes mode
549557
* @param {null | NodeLike} node

packages/svelte/src/internal/client/errors.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* This file is generated by scripts/process-messages.js. Do not edit! */
1+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
22

33
import { DEV } from 'esm-env';
44

packages/svelte/src/internal/client/render.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export function mount(component, options) {
119119
* events?: { [Property in keyof Events]: (e: Events[Property]) => any };
120120
* context?: Map<any, any>;
121121
* intro?: boolean;
122-
* recover?: false;
122+
* recover?: boolean;
123123
* }} options
124124
* @returns {Exports}
125125
*/

packages/svelte/src/internal/client/warnings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* This file is generated by scripts/process-messages.js. Do not edit! */
1+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
22

33
import { DEV } from 'esm-env';
44

packages/svelte/src/internal/shared/warnings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* This file is generated by scripts/process-messages.js. Do not edit! */
1+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
22

33
import { DEV } from 'esm-env';
44

packages/svelte/tests/runtime-browser/test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ async function run_test(
9494

9595
write(`${test_dir}/_output/client/${path.basename(args.path)}.js`, compiled.js.code);
9696

97-
compiled.warnings.forEach((warning) => warnings.push(warning));
97+
compiled.warnings.forEach((warning) => {
98+
if (warning.code === 'options_deprecated_accessors') return;
99+
warnings.push(warning);
100+
});
98101

99102
if (compiled.css !== null) {
100103
compiled.js.code += `document.head.innerHTML += \`<style>${compiled.css.code}</style>\``;
@@ -179,6 +182,7 @@ async function run_test(
179182
);
180183
} else if (warnings.length) {
181184
/* eslint-disable no-unsafe-finally */
185+
console.warn(warnings);
182186
throw new Error('Received unexpected warnings');
183187
}
184188
}

packages/svelte/tests/runtime-legacy/shared.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as fs from 'node:fs';
22
import { setImmediate } from 'node:timers/promises';
33
import glob from 'tiny-glob/sync.js';
44
import { createClassComponent } from 'svelte/legacy';
5-
import { flushSync } from 'svelte';
5+
import { proxy } from 'svelte/internal/client';
6+
import { flushSync, hydrate, mount, unmount } from 'svelte';
67
import { render } from 'svelte/server';
78
import { afterAll, assert, beforeAll } from 'vitest';
89
import { compile_directory } from '../helpers.js';
@@ -43,6 +44,7 @@ export interface RuntimeTest<Props extends Record<string, any> = Record<string,
4344
component: Props & {
4445
[key: string]: any;
4546
};
47+
instance: Record<string, any>;
4648
mod: any;
4749
ok: typeof ok;
4850
raf: {
@@ -120,7 +122,7 @@ export function runtime_suite(runes: boolean) {
120122
return common_setup(cwd, runes, config);
121123
},
122124
async (config, cwd, variant, common) => {
123-
await run_test_variant(cwd, config, variant, common);
125+
await run_test_variant(cwd, config, variant, common, runes);
124126
}
125127
);
126128
}
@@ -148,7 +150,8 @@ async function run_test_variant(
148150
cwd: string,
149151
config: RuntimeTest,
150152
variant: 'dom' | 'hydrate' | 'ssr',
151-
compileOptions: CompileOptions
153+
compileOptions: CompileOptions,
154+
runes: boolean
152155
) {
153156
let unintended_error = false;
154157

@@ -289,15 +292,30 @@ async function run_test_variant(
289292
}
290293
};
291294

292-
const instance = createClassComponent({
293-
component: mod.default,
294-
props: config.props,
295-
target,
296-
immutable: config.immutable,
297-
intro: config.intro,
298-
recover: config.recover ?? false,
299-
hydrate: variant === 'hydrate'
300-
});
295+
let instance: any;
296+
let props: any;
297+
298+
if (runes) {
299+
props = proxy({ ...(config.props || {}) });
300+
301+
const render = variant === 'hydrate' ? hydrate : mount;
302+
instance = render(mod.default, {
303+
target,
304+
props,
305+
intro: config.intro,
306+
recover: config.recover ?? false
307+
});
308+
} else {
309+
instance = createClassComponent({
310+
component: mod.default,
311+
props: config.props,
312+
target,
313+
immutable: config.immutable,
314+
intro: config.intro,
315+
recover: config.recover ?? false,
316+
hydrate: variant === 'hydrate'
317+
});
318+
}
301319

302320
// eslint-disable-next-line no-console
303321
console.error = error;
@@ -327,7 +345,8 @@ async function run_test_variant(
327345
htmlEqualWithOptions: assert_html_equal_with_options
328346
},
329347
variant,
330-
component: instance,
348+
component: runes ? props : instance,
349+
instance,
331350
mod,
332351
target,
333352
snapshot,
@@ -344,7 +363,11 @@ async function run_test_variant(
344363
assert.fail('Expected a runtime error');
345364
}
346365
} finally {
347-
instance.$destroy();
366+
if (runes) {
367+
unmount(instance);
368+
} else {
369+
instance.$destroy();
370+
}
348371

349372
if (config.warnings) {
350373
assert.deepEqual(warnings, config.warnings);

packages/svelte/tests/runtime-runes/samples/each-bind-this-member/_config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { test } from '../../test';
22

33
export default test({
4+
get props() {
5+
return {
6+
items: [{ src: 'https://ds' }]
7+
};
8+
},
9+
410
async test({ assert, target, component }) {
511
assert.equal(target.querySelector('img'), component.items[0].img);
612
}

packages/svelte/tests/runtime-runes/samples/each-bind-this-member/main.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
2-
let { items = $bindable([{ src: 'https://ds' }]) } = $props();
2+
let { items } = $props();
33
</script>
44

55
{#each items as item, i}

packages/svelte/tests/runtime-runes/samples/lifecycle-render-order-for-children-2/_config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -27,7 +28,7 @@ export default test({
2728

2829
logs.length = 0;
2930

30-
component.n += 1;
31+
flushSync(() => (component.n += 1));
3132

3233
assert.deepEqual(logs, [
3334
'parent: $effect.pre 1',

packages/svelte/tests/runtime-runes/samples/lifecycle-render-order-for-children-3/_config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -22,7 +23,7 @@ export default test({
2223

2324
logs.length = 0;
2425

25-
component.n += 1;
26+
flushSync(() => (component.n += 1));
2627

2728
assert.deepEqual(logs, [
2829
'parent: render 1',

packages/svelte/tests/runtime-runes/samples/lifecycle-render-order-for-children-4/_config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -27,7 +28,7 @@ export default test({
2728

2829
logs.length = 0;
2930

30-
component.n += 1;
31+
flushSync(() => (component.n += 1));
3132

3233
assert.deepEqual(logs, [
3334
'parent: $effect.pre 1',

packages/svelte/tests/runtime-runes/samples/lifecycle-render-order-for-children-5/_config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -9,7 +10,7 @@ export default test({
910
assert.deepEqual(logs, ['$effect.pre 0', 'another $effect.pre 1', 'render n0', 'render i1']);
1011

1112
logs.length = 0;
12-
component.n += 1;
13+
flushSync(() => (component.n += 1));
1314

1415
assert.deepEqual(logs, ['$effect.pre 1', 'another $effect.pre 2', 'render n1', 'render i2']);
1516
}

packages/svelte/tests/runtime-runes/samples/lifecycle-render-order-for-children/_config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -23,7 +24,7 @@ export default test({
2324

2425
logs.length = 0;
2526

26-
component.n += 1;
27+
flushSync(() => (component.n += 1));
2728

2829
assert.deepEqual(logs, [
2930
'parent: $effect.pre 1',

0 commit comments

Comments
 (0)