Skip to content

Commit

Permalink
chore: make if blocks tree-shakable (#14549)
Browse files Browse the repository at this point in the history
* chore: make if blocks dead code eliminable

* chore: make if blocks dead code eliminable

* chore: make if blocks dead code eliminable

* address feedback

* address feedback

* prettier

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
  • Loading branch information
trueadm and Rich-Harris authored Dec 4, 2024
1 parent 51c9eac commit a220330
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-windows-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

chore: make if blocks tree-shakable
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,44 @@ import * as b from '../../../../utils/builders.js';
*/
export function IfBlock(node, context) {
context.state.template.push('<!>');
const statements = [];

const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));
const consequent_id = context.state.scope.generate('consequent');

statements.push(b.var(b.id(consequent_id), b.arrow([b.id('$$anchor')], consequent)));

let alternate_id;

if (node.alternate) {
const alternate = /** @type {BlockStatement} */ (context.visit(node.alternate));
alternate_id = context.state.scope.generate('alternate');
statements.push(b.var(b.id(alternate_id), b.arrow([b.id('$$anchor')], alternate)));
}

/** @type {Expression[]} */
const args = [
context.state.node,
b.thunk(/** @type {Expression} */ (context.visit(node.test))),
b.arrow([b.id('$$anchor')], consequent)
b.arrow(
[b.id('$$render')],
b.block([
b.if(
/** @type {Expression} */ (context.visit(node.test)),
b.stmt(b.call(b.id('$$render'), b.id(consequent_id))),
alternate_id
? b.stmt(
b.call(
b.id('$$render'),
b.id(alternate_id),
node.alternate ? b.literal(false) : undefined
)
)
: undefined
)
])
)
];

if (node.alternate || node.elseif) {
args.push(
node.alternate
? b.arrow([b.id('$$anchor')], /** @type {BlockStatement} */ (context.visit(node.alternate)))
: b.literal(null)
);
}

if (node.elseif) {
// We treat this...
//
Expand All @@ -51,5 +72,7 @@ export function IfBlock(node, context) {
args.push(b.literal(true));
}

context.state.init.push(b.stmt(b.call('$.if', ...args)));
statements.push(b.stmt(b.call('$.if', ...args)));

context.state.init.push(b.block(statements));
}
36 changes: 26 additions & 10 deletions packages/svelte/src/internal/client/dom/blocks/if.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ import { HYDRATION_START_ELSE } from '../../../../constants.js';

/**
* @param {TemplateNode} node
* @param {() => boolean} get_condition
* @param {(anchor: Node) => void} consequent_fn
* @param {null | ((anchor: Node) => void)} [alternate_fn]
* @param {(branch: (fn: (anchor: Node) => void, flag?: boolean) => void) => void} fn
* @param {boolean} [elseif] True if this is an `{:else if ...}` block rather than an `{#if ...}`, as that affects which transitions are considered 'local'
* @returns {void}
*/
export function if_block(node, get_condition, consequent_fn, alternate_fn = null, elseif = false) {
export function if_block(node, fn, elseif = false) {
if (hydrating) {
hydrate_next();
}
Expand All @@ -37,8 +35,18 @@ export function if_block(node, get_condition, consequent_fn, alternate_fn = null

var flags = elseif ? EFFECT_TRANSPARENT : 0;

block(() => {
if (condition === (condition = !!get_condition())) return;
var has_branch = false;

const set_branch = (/** @type {(anchor: Node) => void} */ fn, flag = true) => {
has_branch = true;
update_branch(flag, fn);
};

const update_branch = (
/** @type {boolean | null} */ new_condition,
/** @type {null | ((anchor: Node) => void)} */ fn
) => {
if (condition === (condition = new_condition)) return;

/** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
let mismatch = false;
Expand All @@ -60,8 +68,8 @@ export function if_block(node, get_condition, consequent_fn, alternate_fn = null
if (condition) {
if (consequent_effect) {
resume_effect(consequent_effect);
} else {
consequent_effect = branch(() => consequent_fn(anchor));
} else if (fn) {
consequent_effect = branch(() => fn(anchor));
}

if (alternate_effect) {
Expand All @@ -72,8 +80,8 @@ export function if_block(node, get_condition, consequent_fn, alternate_fn = null
} else {
if (alternate_effect) {
resume_effect(alternate_effect);
} else if (alternate_fn) {
alternate_effect = branch(() => alternate_fn(anchor));
} else if (fn) {
alternate_effect = branch(() => fn(anchor));
}

if (consequent_effect) {
Expand All @@ -87,6 +95,14 @@ export function if_block(node, get_condition, consequent_fn, alternate_fn = null
// continue in hydration mode
set_hydrating(true);
}
};

block(() => {
has_branch = false;
fn(set_branch);
if (!has_branch) {
update_branch(null, null);
}
}, flags);

if (hydrating) {
Expand Down

0 comments on commit a220330

Please sign in to comment.