-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix: reduce if block nesting #17662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: reduce if block nesting #17662
Conversation
This reduces if block nesting similar to how we did it in #15250 (which got lost during the `await` feature introduction): If the if expression doesn't contain an await expression or is not dependent on a blocker that is not already resolved, then we can avoid creating a separate `$.if()` statement. The one trade-off is that we'll do re-invocations for all the conditions leading up to the condition that matches. Therefore non-simple if expressions are wrapper in `$.derived` to avoid excessive recomputations. closes #17659 (~320 markers in prod mode possible now; less in dev because of our "wrap this component with devtime info" method) helps with #15200
🦋 Changeset detectedLatest commit: dd221fc The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
| } | ||
| } | ||
|
|
||
| const render_call = b.stmt(b.call('$$render', consequent_id, b.literal(index))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we give this argument a default value we can generate smaller code in the common case where there's no else-if
| const render_call = b.stmt(b.call('$$render', consequent_id, b.literal(index))); | |
| const render_call = b.stmt(b.call('$$render', consequent_id, index > 0 && b.literal(index))); |
| * @param {null | ((anchor: Node) => void)} fn | ||
| */ | ||
| function update_branch(condition, fn) { | ||
| function update_branch(key, fn) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| function update_branch(key, fn) { | |
| function update_branch(key = 0, fn) { |
| // Wrap complex expressions (anything beyond a simple identifier) in $.derived() for memoization. | ||
| // TODO check expression content more thoroughly to avoid wrapping for stuff like `foo > 1` or `foo.length` | ||
| if ( | ||
| branch.test.type !== 'Identifier' && | ||
| branch.test.type !== 'Literal' && | ||
| (branch.test.type !== 'MemberExpression' || | ||
| // foo.bar is fine but foo[bar] is not | ||
| branch.metadata.expression.dependencies.size > 1) | ||
| ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In analogous situations we use this check instead:
| // Wrap complex expressions (anything beyond a simple identifier) in $.derived() for memoization. | |
| // TODO check expression content more thoroughly to avoid wrapping for stuff like `foo > 1` or `foo.length` | |
| if ( | |
| branch.test.type !== 'Identifier' && | |
| branch.test.type !== 'Literal' && | |
| (branch.test.type !== 'MemberExpression' || | |
| // foo.bar is fine but foo[bar] is not | |
| branch.metadata.expression.dependencies.size > 1) | |
| ) { | |
| if (branch.metadata.expression.has_call) { |
For example a component like this
<Foo x={a.b.c} y={fn()} />yields this:
{
let $0 = $.derived(() => $$props.fn());
Foo($$anchor, {
get x() {
return $$props.a.b.c;
},
get y() {
return $.get($0);
}
});
}I think that's probably better even if it means there's a possibility of additional computation in some cases — no need to create deriveds here, for example:
{#if color === 'red'}
<p>red</p>
{:else if color === 'blue'}
<p>blue</p>
{:else if color === 'green'}
<p>green</p>
{/if}
This reduces if block nesting similar to how we did it in #15250 (which got lost during the
awaitfeature introduction): If the if expression doesn't contain an await expression or is not dependent on a blocker that is not already resolved, then we can avoid creating a separate$.if()statement. The one trade-off is that we'll do re-invocations for all the conditions leading up to the condition that matches. Therefore non-simple if expressions are wrapper in$.derivedto avoid excessive recomputations.closes #17659 (~320 markers in prod mode possible now; less in dev because of our "wrap this component with devtime info" method) helps with #15200
Before submitting the PR, please make sure you do the following
feat:,fix:,chore:, ordocs:.packages/svelte/src, add a changeset (npx changeset).Tests and linting
pnpm testand lint the project withpnpm lint