Skip to content

Conversation

@dummdidumm
Copy link
Member

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

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

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-bot
Copy link

changeset-bot bot commented Feb 9, 2026

🦋 Changeset detected

Latest commit: dd221fc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

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

@dummdidumm dummdidumm temporarily deployed to Publish pkg.pr.new (maintainers) February 9, 2026 15:25 — with GitHub Actions Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

Playground

pnpm add https://pkg.pr.new/svelte@17662

@svelte-docs-bot
Copy link

@dummdidumm dummdidumm temporarily deployed to Publish pkg.pr.new (maintainers) February 9, 2026 19:49 — with GitHub Actions Inactive
}
}

const render_call = b.stmt(b.call('$$render', consequent_id, b.literal(index)));
Copy link
Member

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

Suggested change
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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function update_branch(key, fn) {
function update_branch(key = 0, fn) {

Comment on lines +45 to +53
// 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)
) {
Copy link
Member

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:

Suggested change
// 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}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The current rendering/hydration implementation leads to an early Maximum call stack size exceeded

2 participants