refactor: remove dead code
This commit is contained in:
parent
9690fa8f68
commit
63daf6e314
4 changed files with 10 additions and 19 deletions
|
|
@ -5,6 +5,6 @@ slug: library-size
|
|||
|
||||
All the functions and the base class in the library are minimalist by design and only contains what is needed for their purpose.
|
||||
|
||||
The `WebComponent` base class is **2.01 kB** (min + brotli) according to [size-limit](http://github.com/ai/size-limit).
|
||||
The `WebComponent` base class is **1.98 kB** (min + brotli) according to [size-limit](http://github.com/ai/size-limit).
|
||||
|
||||
Every change that moves this number is recorded in [`size-change-log.md`](https://github.com/ayo-run/wcb/blob/main/size-change-log.md), with the reason the bytes were spent and the benefit they bought.
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ A running record of how each correctness/feature change affects the `WebComponen
|
|||
| Reflect boolean props as bare attributes (WCB-REQ-07, **breaking**) | 1.93 kB (+0.12 kB) | 1.85 → 1.95 kB | **`toggleAttribute()` and `[attr]` CSS selectors work again.** Booleans reflected as the strings `flag="true"`/`flag="false"`, so the attribute always existed: `el.toggleAttribute('flag', true)` was a silent no-op (it only adds/removes, never rewrites a value — no `attributeChangedCallback`, no re-render), and presence selectors like `:host([flag])` matched the stamped `flag="false"` too, painting "on" styles onto elements whose prop was `false`. Boolean props now follow HTML in both directions: reflecting `true` sets the **bare** attribute, `false` **removes** it, and attribute removal means `false` rather than the declared default. Reads are strict — **any present value is `true`**, including the literal `flag="false"`, exactly like native `disabled="false"`. **Breaking:** `setAttribute(name, String(bool))` now always means `true`; migrate those call sites to `toggleAttribute(name, bool)`. Two dev warnings carry most of the cost and make the migration safe: one when a boolean attribute is written as a literal `"true"`/`"false"` string (the silent inversion), and one once-per-class when a boolean prop declares a `true` default (HTML has no true-default boolean attribute — absence must mean both "false" and "default"). `applyProp` also stops stamping `"false"` for boolean vnode props with no matching DOM property, which a nested `WebComponent` would otherwise read back as `true`. Limit raised to fit the warnings. |
|
||||
| Overrideable `toAttribute` / `fromAttribute` converters (#56) | 1.96 kB (+0.03 kB) | 1.95 → 2 kB | **An escape hatch for the edge cases strict boolean semantics create.** The reflection and parsing rules were hardcoded, so a prop needing custom serialization (a `Date`, a delimited list, an enumerated `"true"`/`"false"` attribute) had no seam to hook into. Two overrideable methods now own both directions — `toAttribute(name, value)` returns the attribute value, where **`null` removes the attribute**, and `fromAttribute(name, value)` parses a present attribute back into a prop value. Both take the camelCase prop key, matching `static props` and `onChanges`'s `property`. The existing behavior became the default implementations (pure code movement — boolean presence/absence is now simply `toAttribute` returning `''` or `null`), so subclasses customize one prop and delegate the rest to `super`. Cheaper than a per-prop converter map, which would cost a lookup on every prop even for the vast majority of components that never need one. Limit raised for the two non-manglable public method names. |
|
||||
| Don't reconcile a nested component's own light DOM | 2.01 kB (+0.05 kB) | 2 → 2.05 kB | **Nested components stop erasing each other.** The in-place reconciler recursed into every same-tag element it reused, including nested custom elements. A parent's vnode never describes what a nested light-DOM component rendered *for itself*, so the trailing-node trim in `patchChildren` deleted that content on every ancestor re-render — and since the child only re-renders when its own props change, it stayed blank. Any `WebComponent` that renders another `WebComponent` (without shadow DOM) lost the inner subtree the first time the outer one re-rendered, even for an unrelated prop. `patchNode` now treats a custom element that has no open shadow root as opaque: it still patches the element's props (that is how data flows down) but leaves the children to the child. Shadow-DOM components are exempt — their own content lives in the shadow root, invisible to the parent, so any *light* children are genuine parent-authored slot content that must still be reconciled. Limit raised 50 B to fit the one-line guard. |
|
||||
| Remove unreachable branches from `render()` and `createElement` | 1.98 kB (−0.03 kB) | 2.05 kB | **Dead-code cleanup, no behavior change.** Three guards could never take their other branch: `render()`'s first-render path tested `Array.isArray(el)` and truthiness on the `createElement` return, but `createElement` only ever returns a `DocumentFragment`, a text node or an `Element` — a multi-root template already arrives as a fragment, which `replaceChildren` splices in, so one unguarded call covers both shapes; `#initializeProps` guarded the proxy creation with `if (!this.#props)` although it runs only from the constructor, where the private field is always `undefined`; and `createElement` filtered its own recursive return through `instanceof Node`, which always holds. V8 coverage had flagged all three (`WebComponent.js` lines 307, 376–377 and `create-element.mjs` line 29); with them gone both files report 100 % statement coverage and `create-element.mjs` reaches 100 % branch coverage. Limit left at 2.05 kB. |
|
||||
|
|
|
|||
|
|
@ -304,12 +304,10 @@ export class WebComponent extends HTMLElement {
|
|||
Object.keys(initialProps).forEach((camelCase) => {
|
||||
this.#typeMap[camelCase] = typeof initialProps[camelCase]
|
||||
})
|
||||
if (!this.#props) {
|
||||
this.#props = new Proxy(
|
||||
initialProps,
|
||||
this.#handler((key, value) => this.#reflect(key, value), this)
|
||||
)
|
||||
}
|
||||
this.#props = new Proxy(
|
||||
initialProps,
|
||||
this.#handler((key, value) => this.#reflect(key, value), this)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -371,12 +369,9 @@ export class WebComponent extends HTMLElement {
|
|||
* - resolve prop values
|
||||
* - attach event listeners
|
||||
*/
|
||||
const el = createElement(template)
|
||||
|
||||
if (el) {
|
||||
if (Array.isArray(el)) this.#host.replaceChildren(...el)
|
||||
else this.#host.replaceChildren(el)
|
||||
}
|
||||
// a multi-root template comes back as a DocumentFragment, which
|
||||
// replaceChildren splices in — so one call covers both shapes
|
||||
this.#host.replaceChildren(createElement(template))
|
||||
} else {
|
||||
// re-render: reconcile in place so focus, caret/selection, an
|
||||
// uncommitted <input> value, :hover and running transitions survive
|
||||
|
|
|
|||
|
|
@ -24,12 +24,7 @@ export function createElement(tree) {
|
|||
/**
|
||||
* handle children
|
||||
*/
|
||||
tree.children?.forEach((child) => {
|
||||
const childEl = createElement(child)
|
||||
if (childEl instanceof Node) {
|
||||
el.appendChild(childEl)
|
||||
}
|
||||
})
|
||||
tree.children?.forEach((child) => el.appendChild(createElement(child)))
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue