mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-29 07:00:16 +02:00
v0.9.2 — 🐛 types, ⚡ on.defer and other small ⚡ (#36)
* 🔤 ⚡ T now uses DocumentFragment * 🔤 * 🔤 ⚡ * 🐛 lint * ⚡ cleanup * ⚡ 🔤 lib download * ⚡ 🔤 ui * ⚡ reorganize files * ⚡ on.host * 🐛 on.* types * ⚡ 🔤 cdn * 🔤 converter * 🐛 signal.set(value, force) * ⚡ 🔤 * 🔤 ⚡ converter - convert also comments * ⚡ bs/build * 🔤 ui p14 * 🔤 * 🔤 Examples * 🔤 * 🐛 now only el(..., string|number) * 🐛 fixes #38 * 🔤 * ⚡ on.host → on.defer * 🔤 * 📺
This commit is contained in:
@@ -17,28 +17,41 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
Debugging is an essential part of application development. This guide provides techniques
|
||||
and best practices for debugging applications built with dd<el>, with a focus on signals.
|
||||
`),
|
||||
|
||||
el(h3, t`Debugging signals`),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
Signals are reactive primitives that update the UI when their values change. When debugging signals,
|
||||
you need to track their values, understand their dependencies, and identify why updates are or aren't happening.
|
||||
you need to track their values, understand their dependencies, and identify why updates are or aren’t
|
||||
happening.
|
||||
`),
|
||||
|
||||
el("h4", t`Inspecting signal values`),
|
||||
el("p").append(...T`
|
||||
The simplest way to debug a signal is to log its current value by calling the get method:
|
||||
el("p").append(T`
|
||||
The simplest way to debug a signal is to log its current value by calling the get or valueOf method:
|
||||
`),
|
||||
el(code, { content: `
|
||||
const signal = S(0);
|
||||
console.log('Current value:', signal.get());
|
||||
// without triggering updates
|
||||
console.log('Current value:', signal.valueOf());
|
||||
`, page_id }),
|
||||
el("p").append(...T`
|
||||
el("div", { className: "warning" }).append(
|
||||
el("p").append(T`
|
||||
${el("code", "signal.get")} is OK, but in some situations may lead to unexpected results:
|
||||
`),
|
||||
el(code, { content: `
|
||||
const signal = S(0);
|
||||
const derived = S(()=> {
|
||||
console.log('Current value:', signal.get());
|
||||
// ↑ in rare cases this will register unwanted dependency
|
||||
// but typically this is fine ↓
|
||||
return signal.get() + 1;
|
||||
});
|
||||
` })
|
||||
),
|
||||
el("p").append(T`
|
||||
You can also monitor signal changes by adding a listener:
|
||||
`),
|
||||
el(code, { content: `
|
||||
@@ -47,7 +60,7 @@ export function page({ pkg, info }){
|
||||
`, page_id }),
|
||||
|
||||
el("h4", t`Debugging derived signals`),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
With derived signals (created with ${el("code", "S(() => computation))")}), debugging is a bit more complex
|
||||
because the value depends on other signals. To understand why a derived signal isn’t updating correctly:
|
||||
`),
|
||||
@@ -58,6 +71,43 @@ export function page({ pkg, info }){
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/debugging/consoleLog.js"), page_id }),
|
||||
|
||||
el("h4", t`Examining signal via DevTools`),
|
||||
el("p").append(T`
|
||||
${el("code", "<signal>.__dde_signal")} - A Symbol property used to identify and store the internal state of
|
||||
signal objects. It contains the following information:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li", t`listeners: A Set of functions called when the signal value changes`),
|
||||
el("li", t`actions: Custom actions that can be performed on the signal`),
|
||||
el("li", t`onclear: Functions to run when the signal is cleared`),
|
||||
el("li", t`host: Reference to the host element/scope`),
|
||||
el("li", t`defined: Stack trace information for debugging`),
|
||||
el("li", t`readonly: Boolean flag indicating if the signal is read-only`)
|
||||
),
|
||||
el("p").append(T`
|
||||
…to determine the current value of the signal, call ${el("code", "signal.valueOf()")}. Don’t hesitate to
|
||||
use the debugger to inspect the signal object.
|
||||
`),
|
||||
|
||||
el("h4", t`Debugging with breakpoints`),
|
||||
el("p").append(T`
|
||||
Effective use of breakpoints can help track signal flow:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li").append(T`
|
||||
Set breakpoints in signal update methods to track when values change
|
||||
`),
|
||||
el("li").append(T`
|
||||
Use conditional breakpoints to only break when specific signals change to certain values
|
||||
`),
|
||||
el("li").append(T`
|
||||
Set breakpoints in your signal computation functions to see when derived signals recalculate
|
||||
`),
|
||||
el("li").append(T`
|
||||
Use performance profiling to identify bottlenecks in signal updates
|
||||
`)
|
||||
),
|
||||
|
||||
el(h3, t`Common signal debugging issues`),
|
||||
el("h4", t`Signal updates not triggering UI changes`),
|
||||
el("p", t`If signal updates aren’t reflected in the UI, check:`),
|
||||
@@ -69,9 +119,10 @@ export function page({ pkg, info }){
|
||||
el(code, { src: fileURL("./components/examples/debugging/mutations.js"), page_id }),
|
||||
|
||||
el("h4", t`Memory leaks with signal listeners`),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
Signal listeners can cause memory leaks if not properly cleaned up. Always use AbortSignal
|
||||
to cancel listeners.
|
||||
to cancel listeners when they are used ouside the dd<el> knowledge (el, assign, S.el, … auto cleanup
|
||||
unnecessarily signals automatically).
|
||||
`),
|
||||
|
||||
el("h4", t`Performance issues with frequently updating signals`),
|
||||
@@ -83,74 +134,39 @@ export function page({ pkg, info }){
|
||||
),
|
||||
el(code, { src: fileURL("./components/examples/debugging/debouncing.js"), page_id }),
|
||||
|
||||
el(h3, t`Browser DevTools tips for dd<el>`),
|
||||
el("p").append(...T`
|
||||
el(h3, t`Browser DevTools tips for components and reactivity`),
|
||||
el("p").append(T`
|
||||
When debugging in the browser, dd<el> provides several helpful DevTools-friendly features:
|
||||
`),
|
||||
|
||||
el("h4", t`Identifying components in the DOM`),
|
||||
el("p").append(...T`
|
||||
dd<el> marks components in the DOM with special comment nodes to help you identify component boundaries.
|
||||
Components created with ${el("code", "el(ComponentFunction)")} are marked with comment nodes
|
||||
${el("code", `<!--<dde:mark type="component" name="MyComponent" host="parentElement"/>-->`)} and
|
||||
includes:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li", t`type - Identifies the type of marker ("component", "reactive", or "later")`),
|
||||
el("li", t`name - The name of the component function`),
|
||||
el("li", t`host - Indicates whether the host is "this" (for DocumentFragments) or "parentElement"`),
|
||||
),
|
||||
|
||||
el("h4", t`Finding reactive elements in the DOM`),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
When using ${el("code", "S.el()")}, dd<el> creates reactive elements in the DOM
|
||||
that are automatically updated when signal values change. These elements are wrapped in special
|
||||
comment nodes for debugging (to be true they are also used internally, so please do not edit them by hand):
|
||||
`),
|
||||
el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.html"), page_id }),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
This is particularly useful when debugging why a reactive section isn’t updating as expected.
|
||||
You can inspect the elements between the comment nodes to see their current state and the
|
||||
signal connections through \`__dde_reactive\` of the host element.
|
||||
`),
|
||||
|
||||
el("h4", t`DOM inspection properties`),
|
||||
el("p").append(...T`
|
||||
Elements created with the dd<el> library have special properties to aid in debugging:
|
||||
`),
|
||||
el("p").append(...T`
|
||||
${el("code", "<element>.__dde_reactive")} - An array property on DOM elements that tracks signal-to-element
|
||||
relationships. This allows you to quickly identify which elements are reactive and what signals they’re
|
||||
bound to. Each entry in the array contains:
|
||||
el("h4", t`Identifying components in the DOM`),
|
||||
el("p").append(T`
|
||||
dd<el> marks components in the DOM with special comment nodes to help you identify component boundaries.
|
||||
Components created with ${el("code", "el(MyComponent)")} are marked with comment nodes
|
||||
${el("code", `<!--<dde:mark type="component" name="MyComponent" host="parentElement"/>-->`)} and
|
||||
includes:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li", t`A pair of signal and listener function: [signal, listener]`),
|
||||
el("li", t`Additional context information about the element or attribute`),
|
||||
el("li", t`Automatically managed by signal.el(), signal.observedAttributes(), and processReactiveAttribute()`)
|
||||
el("li", t`type - Identifies the type of marker ("component", "reactive", …)`),
|
||||
el("li", t`name - The name of the component function`),
|
||||
el("li", t`host - Indicates whether the host is "this" (for DocumentFragments) or "parentElement"`),
|
||||
),
|
||||
el("p").append(...T`
|
||||
These properties make it easier to understand the reactive structure of your application when inspecting
|
||||
elements.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }),
|
||||
|
||||
el("h4", t`Examining signal connections`),
|
||||
el("p").append(...T`
|
||||
${el("code", "<signal>.__dde_signal")} - A Symbol property used to identify and store the internal state of
|
||||
signal objects. It contains the following information:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li", t`listeners: A Set of functions called when the signal value changes`),
|
||||
el("li", t`actions: Custom actions that can be performed on the signal`),
|
||||
el("li", t`onclear: Functions to run when the signal is cleared`),
|
||||
el("li", t`host: Reference to the host element/scope`),
|
||||
el("li", t`defined: Stack trace information for debugging`),
|
||||
el("li", t`readonly: Boolean flag indicating if the signal is read-only`)
|
||||
),
|
||||
el("p").append(...T`
|
||||
…to determine the current value of the signal, call ${el("code", "signal.valueOf()")}.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
el("h4", t`Identifying reactive elements in the DOM`),
|
||||
el("p").append(T`
|
||||
You can inspect (host) element relationships and bindings with signals in the DevTools console using
|
||||
${el("code", "$0.__dde_reactive")} (for currently selected element). In the console you will see a list of
|
||||
${el("code", `[ [ signal, listener ], element, property ]`)}, where:
|
||||
@@ -161,29 +177,41 @@ export function page({ pkg, info }){
|
||||
el("li", t`element — the DOM element that is bound to the signal`),
|
||||
el("li", t`property — the attribute or property name which is changing based on the signal`),
|
||||
),
|
||||
el("p").append(...T`
|
||||
el("p").append(T`
|
||||
…the structure of \`__dde_reactive\` utilizes the browser’s behavior of packing the first field,
|
||||
so you can see the element and property that changes in the console right away.
|
||||
so you can see the element and property that changes in the console right away. These properties make it
|
||||
easier to understand the reactive structure of your application when inspecting elements.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }),
|
||||
|
||||
el("p", { className: "note" }).append(T`
|
||||
${el("code", "<element>.__dde_reactive")} - An array property on DOM elements that tracks signal-to-element
|
||||
relationships. This allows you to quickly identify which elements are reactive and what signals they’re
|
||||
bound to. Each entry in the array contains:
|
||||
`),
|
||||
|
||||
el("h4", t`Debugging with breakpoints`),
|
||||
el("p").append(...T`
|
||||
Effective use of breakpoints can help track signal flow:
|
||||
el("h4", t`Inspecting events and listeners in DevTools`),
|
||||
el("p").append(T`
|
||||
Modern browser DevTools provide built-in tools for inspecting event listeners attached to DOM elements.
|
||||
For example, in Firefox and Chrome, you can:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li").append(...T`
|
||||
Set breakpoints in signal update methods to track when values change
|
||||
`),
|
||||
el("li").append(...T`
|
||||
Use conditional breakpoints to only break when specific signals change to certain values
|
||||
`),
|
||||
el("li").append(...T`
|
||||
Set breakpoints in your signal computation functions to see when derived signals recalculate
|
||||
`),
|
||||
el("li").append(...T`
|
||||
Use performance profiling to identify bottlenecks in signal updates
|
||||
`)
|
||||
el("ol").append(
|
||||
el("li", t`Select an element in the Elements/Inspector panel`),
|
||||
el("li", t`Look for the "Event Listeners" tab or section`),
|
||||
el("li", t`See all event listeners attached to the element, including those added by dd<el>`)
|
||||
),
|
||||
el("p").append(T`
|
||||
Additionally, dd<el> provides special markers in the DOM that help identify debug information.
|
||||
Look for comments with ${el("code", "dde:mark")}, ${el("code", "dde:disconnected")} and ${el("code",
|
||||
"__dde_reactive")} which indicate components, reactive regions, and other internal relationships:
|
||||
`),
|
||||
el("figure").append(
|
||||
el("img", {
|
||||
src: "./assets/devtools.png",
|
||||
alt: "Screenshot of DevTools showing usage of “event” button to inspect event listeners",
|
||||
}),
|
||||
el("figcaption", t`Firefox DevTools showing dd<el> debugging information with event listeners and reactive
|
||||
markers`)
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user