Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4b3eb72

Browse files
authoredJul 3, 2023
fix: shrink custom element baseline a bit (#8858)
- use shorter class property names as they are not minified - reuse some dom helper methods #8826
1 parent 2f5e371 commit 4b3eb72

File tree

2 files changed

+71
-70
lines changed

2 files changed

+71
-70
lines changed
 

‎.changeset/happy-cows-warn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: shrink custom element baseline a bit

‎packages/svelte/src/runtime/internal/Component.js

Lines changed: 66 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
start_hydrating,
1414
end_hydrating,
1515
get_custom_elements_slots,
16-
insert
16+
insert,
17+
element,
18+
attr
1719
} from './dom.js';
1820
import { transition_in } from './transitions.js';
1921

@@ -157,23 +159,29 @@ export let SvelteElement;
157159

158160
if (typeof HTMLElement === 'function') {
159161
SvelteElement = class extends HTMLElement {
160-
$$componentCtor;
161-
$$slots;
162-
$$component;
163-
$$connected = false;
164-
$$data = {};
165-
$$reflecting = false;
166-
/** @type {Record<string, CustomElementPropDefinition>} */
167-
$$props_definition = {};
168-
/** @type {Record<string, Function[]>} */
169-
$$listeners = {};
170-
/** @type {Map<Function, Function>} */
171-
$$listener_unsubscribe_fns = new Map();
162+
/** The Svelte component constructor */
163+
$$ctor;
164+
/** Slots */
165+
$$s;
166+
/** The Svelte component instance */
167+
$$c;
168+
/** Whether or not the custom element is connected */
169+
$$cn = false;
170+
/** Component props data */
171+
$$d = {};
172+
/** `true` if currently in the process of reflecting component props back to attributes */
173+
$$r = false;
174+
/** @type {Record<string, CustomElementPropDefinition>} Props definition (name, reflected, type etc) */
175+
$$p_d = {};
176+
/** @type {Record<string, Function[]>} Event listeners */
177+
$$l = {};
178+
/** @type {Map<Function, Function>} Event listener unsubscribe functions */
179+
$$l_u = new Map();
172180

173181
constructor($$componentCtor, $$slots, use_shadow_dom) {
174182
super();
175-
this.$$componentCtor = $$componentCtor;
176-
this.$$slots = $$slots;
183+
this.$$ctor = $$componentCtor;
184+
this.$$s = $$slots;
177185
if (use_shadow_dom) {
178186
this.attachShadow({ mode: 'open' });
179187
}
@@ -183,42 +191,42 @@ if (typeof HTMLElement === 'function') {
183191
// We can't determine upfront if the event is a custom event or not, so we have to
184192
// listen to both. If someone uses a custom event with the same name as a regular
185193
// browser event, this fires twice - we can't avoid that.
186-
this.$$listeners[type] = this.$$listeners[type] || [];
187-
this.$$listeners[type].push(listener);
188-
if (this.$$component) {
189-
const unsub = this.$$component.$on(type, listener);
190-
this.$$listener_unsubscribe_fns.set(listener, unsub);
194+
this.$$l[type] = this.$$l[type] || [];
195+
this.$$l[type].push(listener);
196+
if (this.$$c) {
197+
const unsub = this.$$c.$on(type, listener);
198+
this.$$l_u.set(listener, unsub);
191199
}
192200
super.addEventListener(type, listener, options);
193201
}
194202

195203
removeEventListener(type, listener, options) {
196204
super.removeEventListener(type, listener, options);
197-
if (this.$$component) {
198-
const unsub = this.$$listener_unsubscribe_fns.get(listener);
205+
if (this.$$c) {
206+
const unsub = this.$$l_u.get(listener);
199207
if (unsub) {
200208
unsub();
201-
this.$$listener_unsubscribe_fns.delete(listener);
209+
this.$$l_u.delete(listener);
202210
}
203211
}
204212
}
205213

206214
async connectedCallback() {
207-
this.$$connected = true;
208-
if (!this.$$component) {
215+
this.$$cn = true;
216+
if (!this.$$c) {
209217
// We wait one tick to let possible child slot elements be created/mounted
210218
await Promise.resolve();
211-
if (!this.$$connected) {
219+
if (!this.$$cn) {
212220
return;
213221
}
214222
function create_slot(name) {
215223
return () => {
216224
let node;
217225
const obj = {
218226
c: function create() {
219-
node = document.createElement('slot');
227+
node = element('slot');
220228
if (name !== 'default') {
221-
node.setAttribute('name', name);
229+
attr(node, 'name', name);
222230
}
223231
},
224232
/**
@@ -239,74 +247,64 @@ if (typeof HTMLElement === 'function') {
239247
}
240248
const $$slots = {};
241249
const existing_slots = get_custom_elements_slots(this);
242-
for (const name of this.$$slots) {
250+
for (const name of this.$$s) {
243251
if (name in existing_slots) {
244252
$$slots[name] = [create_slot(name)];
245253
}
246254
}
247255
for (const attribute of this.attributes) {
248256
// this.$$data takes precedence over this.attributes
249-
const name = this.$$get_prop_name(attribute.name);
250-
if (!(name in this.$$data)) {
251-
this.$$data[name] = get_custom_element_value(
252-
name,
253-
attribute.value,
254-
this.$$props_definition,
255-
'toProp'
256-
);
257+
const name = this.$$g_p(attribute.name);
258+
if (!(name in this.$$d)) {
259+
this.$$d[name] = get_custom_element_value(name, attribute.value, this.$$p_d, 'toProp');
257260
}
258261
}
259-
this.$$component = new this.$$componentCtor({
262+
this.$$c = new this.$$ctor({
260263
target: this.shadowRoot || this,
261264
props: {
262-
...this.$$data,
265+
...this.$$d,
263266
$$slots,
264267
$$scope: {
265268
ctx: []
266269
}
267270
}
268271
});
269-
for (const type in this.$$listeners) {
270-
for (const listener of this.$$listeners[type]) {
271-
const unsub = this.$$component.$on(type, listener);
272-
this.$$listener_unsubscribe_fns.set(listener, unsub);
272+
for (const type in this.$$l) {
273+
for (const listener of this.$$l[type]) {
274+
const unsub = this.$$c.$on(type, listener);
275+
this.$$l_u.set(listener, unsub);
273276
}
274277
}
275-
this.$$listeners = {};
278+
this.$$l = {};
276279
}
277280
}
278281

279282
// We don't need this when working within Svelte code, but for compatibility of people using this outside of Svelte
280283
// and setting attributes through setAttribute etc, this is helpful
281284
attributeChangedCallback(attr, _oldValue, newValue) {
282-
if (this.$$reflecting) return;
283-
attr = this.$$get_prop_name(attr);
284-
this.$$data[attr] = get_custom_element_value(
285-
attr,
286-
newValue,
287-
this.$$props_definition,
288-
'toProp'
289-
);
290-
this.$$component?.$set({ [attr]: this.$$data[attr] });
285+
if (this.$$r) return;
286+
attr = this.$$g_p(attr);
287+
this.$$d[attr] = get_custom_element_value(attr, newValue, this.$$p_d, 'toProp');
288+
this.$$c?.$set({ [attr]: this.$$d[attr] });
291289
}
292290

293291
disconnectedCallback() {
294-
this.$$connected = false;
292+
this.$$cn = false;
295293
// In a microtask, because this could be a move within the DOM
296294
Promise.resolve().then(() => {
297-
if (!this.$$connected) {
298-
this.$$component.$destroy();
299-
this.$$component = undefined;
295+
if (!this.$$cn) {
296+
this.$$c.$destroy();
297+
this.$$c = undefined;
300298
}
301299
});
302300
}
303301

304-
$$get_prop_name(attribute_name) {
302+
$$g_p(attribute_name) {
305303
return (
306-
Object.keys(this.$$props_definition).find(
304+
Object.keys(this.$$p_d).find(
307305
(key) =>
308-
this.$$props_definition[key].attribute === attribute_name ||
309-
(!this.$$props_definition[key].attribute && key.toLowerCase() === attribute_name)
306+
this.$$p_d[key].attribute === attribute_name ||
307+
(!this.$$p_d[key].attribute && key.toLowerCase() === attribute_name)
310308
) || attribute_name
311309
);
312310
}
@@ -371,7 +369,7 @@ export function create_custom_element(
371369
const Class = class extends SvelteElement {
372370
constructor() {
373371
super(Component, slots, use_shadow_dom);
374-
this.$$props_definition = props_definition;
372+
this.$$p_d = props_definition;
375373
}
376374
static get observedAttributes() {
377375
return Object.keys(props_definition).map((key) =>
@@ -382,16 +380,14 @@ export function create_custom_element(
382380
Object.keys(props_definition).forEach((prop) => {
383381
Object.defineProperty(Class.prototype, prop, {
384382
get() {
385-
return this.$$component && prop in this.$$component
386-
? this.$$component[prop]
387-
: this.$$data[prop];
383+
return this.$$c && prop in this.$$c ? this.$$c[prop] : this.$$d[prop];
388384
},
389385
set(value) {
390386
value = get_custom_element_value(prop, value, props_definition);
391-
this.$$data[prop] = value;
392-
this.$$component?.$set({ [prop]: value });
387+
this.$$d[prop] = value;
388+
this.$$c?.$set({ [prop]: value });
393389
if (props_definition[prop].reflect) {
394-
this.$$reflecting = true;
390+
this.$$r = true;
395391
const attribute_value = get_custom_element_value(
396392
prop,
397393
value,
@@ -403,15 +399,15 @@ export function create_custom_element(
403399
} else {
404400
this.setAttribute(props_definition[prop].attribute || prop, attribute_value);
405401
}
406-
this.$$reflecting = false;
402+
this.$$r = false;
407403
}
408404
}
409405
});
410406
});
411407
accessors.forEach((accessor) => {
412408
Object.defineProperty(Class.prototype, accessor, {
413409
get() {
414-
return this.$$component?.[accessor];
410+
return this.$$c?.[accessor];
415411
}
416412
});
417413
});

0 commit comments

Comments
 (0)