Skip to content

Commit 1377c40

Browse files
committed
Merge branch 'main' into print
2 parents a39ab49 + e896c55 commit 1377c40

File tree

16 files changed

+149
-121
lines changed

16 files changed

+149
-121
lines changed

.prettierignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ packages/**/config/*.js
77

88
# packages/svelte
99
packages/svelte/messages/**/*.md
10+
packages/svelte/scripts/_bundle.js
1011
packages/svelte/src/compiler/errors.js
1112
packages/svelte/src/compiler/warnings.js
1213
packages/svelte/src/internal/client/errors.js
@@ -25,8 +26,7 @@ packages/svelte/tests/hydration/samples/*/_expected.html
2526
packages/svelte/tests/hydration/samples/*/_override.html
2627
packages/svelte/types
2728
packages/svelte/compiler/index.js
28-
playgrounds/sandbox/input/**.svelte
29-
playgrounds/sandbox/output
29+
playgrounds/sandbox/src/*
3030

3131
# sites/svelte.dev
3232
sites/svelte.dev/static/svelte-app.json

documentation/docs/07-misc/03-typescript.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ If you're using tools like Rollup or Webpack instead, install their respective S
8383

8484
When using TypeScript, make sure your `tsconfig.json` is setup correctly.
8585

86-
- Use a [`target`](https://www.typescriptlang.org/tsconfig/#target) of at least `ES2022`, or a `target` of at least `ES2015` alongside [`useDefineForClassFields`](https://www.typescriptlang.org/tsconfig/#useDefineForClassFields). This ensures that rune declarations on class fields are not messed with, which would break the Svelte compiler
86+
- Use a [`target`](https://www.typescriptlang.org/tsconfig/#target) of at least `ES2015` so classes are not compiled to functions
8787
- Set [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) to `true` so that imports are left as-is
8888
- Set [`isolatedModules`](https://www.typescriptlang.org/tsconfig/#isolatedModules) to `true` so that each file is looked at in isolation. TypeScript has a few features which require cross-file analysis and compilation, which the Svelte compiler and tooling like Vite don't do.
8989

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export default [
8787
'**/*.d.ts',
8888
'**/tests',
8989
'packages/svelte/scripts/process-messages/templates/*.js',
90+
'packages/svelte/scripts/_bundle.js',
9091
'packages/svelte/src/compiler/errors.js',
9192
'packages/svelte/src/internal/client/errors.js',
9293
'packages/svelte/src/internal/client/warnings.js',

packages/svelte/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# svelte
22

3+
## 5.34.9
4+
5+
### Patch Changes
6+
7+
- fix: ensure unowned deriveds can add themselves as reactions while connected ([#16249](https://github.com/sveltejs/svelte/pull/16249))
8+
39
## 5.34.8
410

511
### Patch Changes

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.34.8",
5+
"version": "5.34.9",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/scripts/check-treeshakeability.js

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -118,36 +118,40 @@ const bundle = await bundle_code(
118118
).js.code
119119
);
120120

121-
if (!bundle.includes('hydrate_node') && !bundle.includes('hydrate_next')) {
122-
// eslint-disable-next-line no-console
123-
console.error(`✅ Hydration code treeshakeable`);
124-
} else {
125-
failed = true;
126-
// eslint-disable-next-line no-console
127-
console.error(`❌ Hydration code not treeshakeable`);
128-
}
121+
/**
122+
* @param {string} case_name
123+
* @param {string[]} strings
124+
*/
125+
function check_bundle(case_name, ...strings) {
126+
for (const string of strings) {
127+
const index = bundle.indexOf(string);
128+
if (index >= 0) {
129+
// eslint-disable-next-line no-console
130+
console.error(`❌ ${case_name} not treeshakeable`);
131+
failed = true;
129132

130-
if (!bundle.includes('component_context.l')) {
131-
// eslint-disable-next-line no-console
132-
console.error(`✅ Legacy code treeshakeable`);
133-
} else {
134-
failed = true;
133+
let lines = bundle.slice(index - 500, index + 500).split('\n');
134+
const target_line = lines.findIndex((line) => line.includes(string));
135+
// mark the failed line
136+
lines = lines
137+
.map((line, i) => (i === target_line ? `> ${line}` : `| ${line}`))
138+
.slice(target_line - 5, target_line + 6);
139+
// eslint-disable-next-line no-console
140+
console.error('The first failed line:\n' + lines.join('\n'));
141+
return;
142+
}
143+
}
135144
// eslint-disable-next-line no-console
136-
console.error(`❌ Legacy code not treeshakeable`);
145+
console.error(`${case_name} treeshakeable`);
137146
}
138147

139-
if (!bundle.includes(`'CreatedAt'`)) {
140-
// eslint-disable-next-line no-console
141-
console.error(`✅ $inspect.trace code treeshakeable`);
142-
} else {
143-
failed = true;
144-
// eslint-disable-next-line no-console
145-
console.error(`❌ $inspect.trace code not treeshakeable`);
146-
}
148+
check_bundle('Hydration code', 'hydrate_node', 'hydrate_next');
149+
check_bundle('Legacy code', 'component_context.l');
150+
check_bundle('$inspect.trace', `'CreatedAt'`);
147151

148152
if (failed) {
149153
// eslint-disable-next-line no-console
150-
console.error(bundle);
154+
console.error('Full bundle at', path.resolve('scripts/_bundle.js'));
151155
fs.writeFileSync('scripts/_bundle.js', bundle);
152156
}
153157

packages/svelte/src/compiler/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
/** @import { AST } from './public.js' */
44
import { walk as zimmerframe_walk } from 'zimmerframe';
55
import { convert } from './legacy.js';
6-
import { parse as parse_acorn } from './phases/1-parse/acorn.js';
76
import { parse as _parse } from './phases/1-parse/index.js';
87
import { remove_typescript_nodes } from './phases/1-parse/remove_typescript_nodes.js';
98
import { analyze_component, analyze_module } from './phases/2-analyze/index.js';

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,7 @@ import {
2222
build_set_style
2323
} from './shared/element.js';
2424
import { process_children } from './shared/fragment.js';
25-
import {
26-
build_render_statement,
27-
build_template_chunk,
28-
build_update_assignment,
29-
get_expression_id,
30-
memoize_expression
31-
} from './shared/utils.js';
25+
import { build_render_statement, build_template_chunk, get_expression_id } from './shared/utils.js';
3226
import { visit_event_attribute } from './shared/events.js';
3327

3428
/**
@@ -200,24 +194,23 @@ export function RegularElement(node, context) {
200194

201195
const node_id = context.state.node;
202196

197+
/** If true, needs `__value` for inputs */
198+
const needs_special_value_handling =
199+
node.name === 'option' ||
200+
node.name === 'select' ||
201+
bindings.has('group') ||
202+
bindings.has('checked');
203+
203204
if (has_spread) {
204205
build_attribute_effect(attributes, class_directives, style_directives, context, node, node_id);
205206
} else {
206-
/** If true, needs `__value` for inputs */
207-
const needs_special_value_handling =
208-
node.name === 'option' ||
209-
node.name === 'select' ||
210-
bindings.has('group') ||
211-
bindings.has('checked');
212-
213207
for (const attribute of /** @type {AST.Attribute[]} */ (attributes)) {
214208
if (is_event_attribute(attribute)) {
215209
visit_event_attribute(attribute, context);
216210
continue;
217211
}
218212

219213
if (needs_special_value_handling && attribute.name === 'value') {
220-
build_element_special_value_attribute(node.name, node_id, attribute, context);
221214
continue;
222215
}
223216

@@ -392,6 +385,15 @@ export function RegularElement(node, context) {
392385
context.state.update.push(b.stmt(b.assignment('=', dir, dir)));
393386
}
394387

388+
if (!has_spread && needs_special_value_handling) {
389+
for (const attribute of /** @type {AST.Attribute[]} */ (attributes)) {
390+
if (attribute.name === 'value') {
391+
build_element_special_value_attribute(node.name, node_id, attribute, context);
392+
break;
393+
}
394+
}
395+
}
396+
395397
context.state.template.pop_element();
396398
}
397399

@@ -622,12 +624,7 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
622624
element === 'select' && attribute.value !== true && !is_text_attribute(attribute);
623625

624626
const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
625-
metadata.has_call
626-
? // if is a select with value we will also invoke `init_select` which need a reference before the template effect so we memoize separately
627-
is_select_with_value
628-
? memoize_expression(state, value)
629-
: get_expression_id(state.expressions, value)
630-
: value
627+
metadata.has_call ? get_expression_id(state.expressions, value) : value
631628
);
632629

633630
const evaluated = context.state.scope.evaluate(value);
@@ -652,23 +649,21 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
652649
: inner_assignment
653650
);
654651

655-
if (is_select_with_value) {
656-
state.init.push(b.stmt(b.call('$.init_select', node_id, b.thunk(value))));
657-
}
658-
659652
if (has_state) {
660-
const id = state.scope.generate(`${node_id.name}_value`);
661-
build_update_assignment(
662-
state,
663-
id,
664-
// `<option>` is a special case: The value property reflects to the DOM. If the value is set to undefined,
665-
// that means the value should be set to the empty string. To be able to do that when the value is
666-
// initially undefined, we need to set a value that is guaranteed to be different.
667-
element === 'option' ? b.object([]) : undefined,
668-
value,
669-
update
670-
);
653+
const id = b.id(state.scope.generate(`${node_id.name}_value`));
654+
655+
// `<option>` is a special case: The value property reflects to the DOM. If the value is set to undefined,
656+
// that means the value should be set to the empty string. To be able to do that when the value is
657+
// initially undefined, we need to set a value that is guaranteed to be different.
658+
const init = element === 'option' ? b.object([]) : undefined;
659+
660+
state.init.push(b.var(id, init));
661+
state.update.push(b.if(b.binary('!==', id, b.assignment('=', id, value)), b.block([update])));
671662
} else {
672663
state.init.push(update);
673664
}
665+
666+
if (is_select_with_value) {
667+
state.init.push(b.stmt(b.call('$.init_select', node_id)));
668+
}
674669
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,6 @@ export function parse_directive_name(name) {
165165
return expression;
166166
}
167167

168-
/**
169-
* @param {ComponentClientTransformState} state
170-
* @param {string} id
171-
* @param {Expression | undefined} init
172-
* @param {Expression} value
173-
* @param {ExpressionStatement} update
174-
*/
175-
export function build_update_assignment(state, id, init, value, update) {
176-
state.init.push(b.var(id, init));
177-
state.update.push(
178-
b.if(b.binary('!==', b.id(id), b.assignment('=', b.id(id), value)), b.block([update]))
179-
);
180-
}
181-
182168
/**
183169
* Serializes `bind:this` for components and elements.
184170
* @param {Identifier | MemberExpression | SequenceExpression} expression

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { clsx } from '../../../shared/attributes.js';
2020
import { set_class } from './class.js';
2121
import { set_style } from './style.js';
2222
import { ATTACHMENT_KEY, NAMESPACE_HTML } from '../../../../constants.js';
23-
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
23+
import { block, branch, destroy_effect, effect } from '../../reactivity/effects.js';
2424
import { derived } from '../../reactivity/deriveds.js';
2525
import { init_select, select_option } from './bindings/select.js';
2626

@@ -513,10 +513,12 @@ export function attribute_effect(
513513
});
514514

515515
if (is_select) {
516-
init_select(
517-
/** @type {HTMLSelectElement} */ (element),
518-
() => /** @type {Record<string | symbol, any>} */ (prev).value
519-
);
516+
var select = /** @type {HTMLSelectElement} */ (element);
517+
518+
effect(() => {
519+
select_option(select, /** @type {Record<string | symbol, any>} */ (prev).value);
520+
init_select(select);
521+
});
520522
}
521523

522524
inited = true;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy