Skip to content

Commit 8a4dfb4

Browse files
authored
chore: move some code around (#10767)
* move <svelte:component> code * move <svelte:element> code * unused import * move <svelte:head> code * unused import * unused import * typo * move snippet code, remove blocks.js * move CSS props code * move html code * remove unused import --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 2781559 commit 8a4dfb4

File tree

10 files changed

+524
-488
lines changed

10 files changed

+524
-488
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1895,7 +1895,7 @@ export const template_visitors = {
18951895

18961896
if (is_reactive) {
18971897
context.state.after_update.push(
1898-
b.stmt(b.call('$.snippet_effect', b.thunk(snippet_function), ...args))
1898+
b.stmt(b.call('$.snippet', b.thunk(snippet_function), ...args))
18991899
);
19001900
} else {
19011901
context.state.after_update.push(

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

Lines changed: 0 additions & 93 deletions
This file was deleted.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { namespace_svg } from '../../../../constants.js';
2+
import { current_hydration_fragment, hydrate_block_anchor, hydrating } from '../../hydration.js';
3+
import { empty } from '../../operations.js';
4+
import { render_effect } from '../../reactivity/effects.js';
5+
import { insert, remove } from '../../reconciler.js';
6+
7+
/**
8+
* @param {Element | Text | Comment} anchor
9+
* @param {boolean} is_html
10+
* @param {() => Record<string, string>} props
11+
* @param {(anchor: Element | Text | Comment) => any} component
12+
* @returns {void}
13+
*/
14+
export function css_props(anchor, is_html, props, component) {
15+
hydrate_block_anchor(anchor);
16+
17+
/** @type {HTMLElement | SVGElement} */
18+
let tag;
19+
20+
/** @type {Text | Comment} */
21+
let component_anchor;
22+
23+
if (hydrating) {
24+
// Hydration: css props element is surrounded by a ssr comment ...
25+
tag = /** @type {HTMLElement | SVGElement} */ (current_hydration_fragment[0]);
26+
// ... and the child(ren) of the css props element is also surround by a ssr comment
27+
component_anchor = /** @type {Comment} */ (tag.firstChild);
28+
} else {
29+
if (is_html) {
30+
tag = document.createElement('div');
31+
tag.style.display = 'contents';
32+
} else {
33+
tag = document.createElementNS(namespace_svg, 'g');
34+
}
35+
36+
insert(tag, null, anchor);
37+
component_anchor = empty();
38+
tag.appendChild(component_anchor);
39+
}
40+
41+
component(component_anchor);
42+
43+
/** @type {Record<string, string>} */
44+
let current_props = {};
45+
46+
const effect = render_effect(() => {
47+
const next_props = props();
48+
49+
for (const key in current_props) {
50+
if (!(key in next_props)) {
51+
tag.style.removeProperty(key);
52+
}
53+
}
54+
55+
for (const key in next_props) {
56+
tag.style.setProperty(key, next_props[key]);
57+
}
58+
59+
current_props = next_props;
60+
});
61+
62+
effect.ondestroy = () => {
63+
remove(tag);
64+
};
65+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { render_effect } from '../../reactivity/effects.js';
2+
import { reconcile_html, remove } from '../../reconciler.js';
3+
4+
/**
5+
* @param {Element | Text | Comment} dom
6+
* @param {() => string} get_value
7+
* @param {boolean} svg
8+
* @returns {void}
9+
*/
10+
export function html(dom, get_value, svg) {
11+
/** @type {import('#client').TemplateNode | import('#client').TemplateNode[]} */
12+
let html_dom;
13+
14+
/** @type {string} */
15+
let value;
16+
17+
const effect = render_effect(() => {
18+
if (value !== (value = get_value())) {
19+
if (html_dom) remove(html_dom);
20+
html_dom = reconcile_html(dom, value, svg);
21+
}
22+
});
23+
24+
effect.ondestroy = () => {
25+
if (html_dom) {
26+
remove(html_dom);
27+
}
28+
};
29+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { SNIPPET_BLOCK } from '../../constants.js';
2+
import { render_effect } from '../../reactivity/effects.js';
3+
import { remove } from '../../reconciler.js';
4+
import { current_block, untrack } from '../../runtime.js';
5+
6+
/**
7+
* @param {() => Function | null | undefined} get_snippet
8+
* @param {Node} node
9+
* @param {(() => any)[]} args
10+
* @returns {void}
11+
*/
12+
export function snippet(get_snippet, node, ...args) {
13+
/** @type {import('#client').SnippetBlock} */
14+
const block = {
15+
// dom
16+
d: null,
17+
// parent
18+
p: /** @type {import('#client').Block} */ (current_block),
19+
// effect
20+
e: null,
21+
// transition
22+
r: null,
23+
// type
24+
t: SNIPPET_BLOCK
25+
};
26+
27+
render_effect(() => {
28+
// Only rerender when the snippet function itself changes,
29+
// not when an eagerly-read prop inside the snippet function changes
30+
const snippet = get_snippet();
31+
if (snippet) {
32+
untrack(() => snippet(node, ...args));
33+
}
34+
return () => {
35+
if (block.d !== null) {
36+
remove(block.d);
37+
}
38+
};
39+
}, block);
40+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { DYNAMIC_COMPONENT_BLOCK } from '../../constants.js';
2+
import { hydrate_block_anchor } from '../../hydration.js';
3+
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
4+
import { remove } from '../../reconciler.js';
5+
import { current_block, execute_effect } from '../../runtime.js';
6+
import { trigger_transitions } from '../../transitions.js';
7+
8+
/**
9+
* @template P
10+
* @param {Comment} anchor_node
11+
* @param {() => (props: P) => void} component_fn
12+
* @param {(component: (props: P) => void) => void} render_fn
13+
* @returns {void}
14+
*/
15+
export function component(anchor_node, component_fn, render_fn) {
16+
/** @type {import('#client').DynamicComponentBlock} */
17+
const block = {
18+
// dom
19+
d: null,
20+
// effect
21+
e: null,
22+
// parent
23+
p: /** @type {import('#client').Block} */ (current_block),
24+
// transition
25+
r: null,
26+
// type
27+
t: DYNAMIC_COMPONENT_BLOCK
28+
};
29+
30+
/** @type {null | import('#client').Render} */
31+
let current_render = null;
32+
hydrate_block_anchor(anchor_node);
33+
34+
/** @type {null | ((props: P) => void)} */
35+
let component = null;
36+
37+
block.r =
38+
/**
39+
* @param {import('#client').Transition} transition
40+
* @returns {void}
41+
*/
42+
(transition) => {
43+
const render = /** @type {import('#client').Render} */ (current_render);
44+
const transitions = render.s;
45+
transitions.add(transition);
46+
transition.f(() => {
47+
transitions.delete(transition);
48+
if (transitions.size === 0) {
49+
// If the current render has changed since, then we can remove the old render
50+
// effect as it's stale.
51+
if (current_render !== render && render.e !== null) {
52+
if (render.d !== null) {
53+
remove(render.d);
54+
render.d = null;
55+
}
56+
destroy_effect(render.e);
57+
render.e = null;
58+
}
59+
}
60+
});
61+
};
62+
63+
const create_render_effect = () => {
64+
/** @type {import('#client').Render} */
65+
const render = {
66+
d: null,
67+
e: null,
68+
s: new Set(),
69+
p: current_render
70+
};
71+
72+
// Managed effect
73+
render.e = render_effect(
74+
() => {
75+
const current = block.d;
76+
if (current !== null) {
77+
remove(current);
78+
block.d = null;
79+
}
80+
if (component) {
81+
render_fn(component);
82+
}
83+
render.d = block.d;
84+
block.d = null;
85+
},
86+
block,
87+
true
88+
);
89+
90+
current_render = render;
91+
};
92+
93+
const render = () => {
94+
const render = current_render;
95+
96+
if (render === null) {
97+
create_render_effect();
98+
return;
99+
}
100+
101+
const transitions = render.s;
102+
103+
if (transitions.size === 0) {
104+
if (render.d !== null) {
105+
remove(render.d);
106+
render.d = null;
107+
}
108+
if (render.e) {
109+
execute_effect(render.e);
110+
} else {
111+
create_render_effect();
112+
}
113+
} else {
114+
create_render_effect();
115+
trigger_transitions(transitions, 'out');
116+
}
117+
};
118+
119+
const component_effect = render_effect(
120+
() => {
121+
const next_component = component_fn();
122+
if (component !== next_component) {
123+
component = next_component;
124+
render();
125+
}
126+
},
127+
block,
128+
false
129+
);
130+
131+
component_effect.ondestroy = () => {
132+
let render = current_render;
133+
while (render !== null) {
134+
const dom = render.d;
135+
if (dom !== null) {
136+
remove(dom);
137+
}
138+
const effect = render.e;
139+
if (effect !== null) {
140+
destroy_effect(effect);
141+
}
142+
render = render.p;
143+
}
144+
};
145+
146+
block.e = component_effect;
147+
}

0 commit comments

Comments
 (0)