Skip to content

Commit 657a09a

Browse files
committed
first impl of $$uid
1 parent 7f8acb8 commit 657a09a

File tree

11 files changed

+71
-6
lines changed

11 files changed

+71
-6
lines changed

packages/svelte/src/ambient.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,5 @@ declare namespace $host {
500500
/** @deprecated */
501501
export const toString: never;
502502
}
503+
504+
declare const $$uid: string;

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ function get_component_name(filename) {
220220
return name[0].toUpperCase() + name.slice(1);
221221
}
222222

223-
const RESERVED = ['$$props', '$$restProps', '$$slots'];
223+
const RESERVED = ['$$props', '$$restProps', '$$slots', '$$uid'];
224224

225225
/**
226226
* @param {Program} ast

packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export function Identifier(node, context) {
3535
context.state.analysis.uses_slots = true;
3636
}
3737

38+
if (node.name === '$$uid') {
39+
context.state.analysis.uses_uid = true;
40+
}
41+
3842
if (context.state.analysis.runes) {
3943
if (
4044
is_rune(node.name) &&

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ export function client_component(analysis, options) {
565565
component_block.body.unshift(b.stmt(b.call('$.check_target', b.id('new.target'))));
566566
}
567567

568+
if (analysis.uses_uid) {
569+
component_block.body.unshift(b.const('$$uid', b.call('$.create_uid')));
570+
}
571+
568572
if (state.events.size > 0) {
569573
body.push(
570574
b.stmt(b.call('$.delegate', b.array(Array.from(state.events).map((name) => b.literal(name)))))

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ export function server_component(analysis, options) {
244244
.../** @type {Statement[]} */ (template.body)
245245
]);
246246

247+
if (analysis.uses_uid) {
248+
component_block.body.unshift(b.const('$$uid', b.call('$.create_uid', b.id('$$payload'))));
249+
}
250+
247251
let should_inject_context = dev || analysis.needs_context;
248252

249253
if (should_inject_context) {

packages/svelte/src/compiler/phases/types.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export interface ComponentAnalysis extends Analysis {
5050
uses_slots: boolean;
5151
uses_component_bindings: boolean;
5252
uses_render_tags: boolean;
53+
/** Whether the component uses `$$uid` */
54+
uses_uid: boolean;
5355
needs_context: boolean;
5456
needs_props: boolean;
5557
/** Set to the first event directive (on:x) found on a DOM element in the code */

packages/svelte/src/internal/client/dom/template.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,24 @@ export function append(anchor, dom) {
249249

250250
anchor.before(/** @type {Node} */ (dom));
251251
}
252+
253+
let NEXT_UID = 100;
254+
255+
/**
256+
* Create (or hydrate) an unique UID for the component instance.
257+
*/
258+
export function create_uid() {
259+
let uid;
260+
if (
261+
hydrating &&
262+
hydrate_node &&
263+
hydrate_node.nodeType === Node.COMMENT_NODE &&
264+
hydrate_node.textContent?.startsWith('#s')
265+
) {
266+
uid = hydrate_node.textContent.substring(1);
267+
hydrate_next();
268+
} else {
269+
uid = 'c' + NEXT_UID++;
270+
}
271+
return uid;
272+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ export {
9595
mathml_template,
9696
template,
9797
template_with_script,
98-
text
98+
text,
99+
create_uid
99100
} from './dom/template.js';
100101
export { derived, derived_safe_equal } from './reactivity/deriveds.js';
101102
export {

packages/svelte/src/internal/server/index.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ const INVALID_ATTR_NAME_CHAR_REGEX =
2828
* @param {Payload} to_copy
2929
* @returns {Payload}
3030
*/
31-
export function copy_payload({ out, css, head }) {
31+
export function copy_payload({ out, css, head, uid }) {
3232
return {
3333
out,
3434
css: new Set(css),
3535
head: {
3636
title: head.title,
3737
out: head.out
38-
}
38+
},
39+
uid
3940
};
4041
}
4142

@@ -48,6 +49,7 @@ export function copy_payload({ out, css, head }) {
4849
export function assign_payload(p1, p2) {
4950
p1.out = p2.out;
5051
p1.head = p2.head;
52+
p1.uid = p2.uid;
5153
}
5254

5355
/**
@@ -83,17 +85,27 @@ export function element(payload, tag, attributes_fn = noop, children_fn = noop)
8385
*/
8486
export let on_destroy = [];
8587

88+
function create_uid_generator() {
89+
let uid = 100;
90+
return () => 's' + uid++;
91+
}
92+
8693
/**
8794
* Only available on the server and when compiling with the `server` option.
8895
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
8996
* @template {Record<string, any>} Props
9097
* @param {import('svelte').Component<Props> | ComponentType<SvelteComponent<Props>>} component
91-
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }} [options]
98+
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any>, uid?: () => string }} [options]
9299
* @returns {RenderOutput}
93100
*/
94101
export function render(component, options = {}) {
95102
/** @type {Payload} */
96-
const payload = { out: '', css: new Set(), head: { title: '', out: '' } };
103+
const payload = {
104+
out: '',
105+
css: new Set(),
106+
head: { title: '', out: '' },
107+
uid: options.uid ?? create_uid_generator()
108+
};
97109

98110
const prev_on_destroy = on_destroy;
99111
on_destroy = [];
@@ -526,6 +538,17 @@ export function once(get_value) {
526538
};
527539
}
528540

541+
/**
542+
* Create an unique ID
543+
* @param {Payload} payload
544+
* @returns {string}
545+
*/
546+
export function create_uid(payload) {
547+
const UID = payload.uid();
548+
payload.out += '<!--#' + UID + '-->';
549+
return UID;
550+
}
551+
529552
export { attr, clsx };
530553

531554
export { html } from './blocks/html.js';

packages/svelte/src/internal/server/types.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export interface Payload {
1818
title: string;
1919
out: string;
2020
};
21+
/** Function that generates a unique ID */
22+
uid: () => string;
2123
}
2224

2325
export interface RenderOutput {

0 commit comments

Comments
 (0)