@barefootjs/client 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -2
- package/dist/profiler-events.d.ts +36 -0
- package/dist/profiler-events.d.ts.map +1 -0
- package/dist/reactive.d.ts +84 -4
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +87 -10
- package/dist/runtime/dynamic-text.d.ts +5 -0
- package/dist/runtime/dynamic-text.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +72 -11
- package/dist/runtime/insert.d.ts +1 -1
- package/dist/runtime/insert.d.ts.map +1 -1
- package/dist/runtime/map-array.d.ts +2 -2
- package/dist/runtime/map-array.d.ts.map +1 -1
- package/dist/runtime/standalone.js +148 -19
- package/package.json +2 -2
- package/src/index.ts +13 -0
- package/src/profiler-events.ts +89 -0
- package/src/reactive.ts +196 -8
- package/src/runtime/dynamic-text.ts +30 -5
- package/src/runtime/index.ts +13 -0
- package/src/runtime/insert.ts +3 -2
- package/src/runtime/map-array.ts +4 -2
package/dist/runtime/index.js
CHANGED
|
@@ -8,9 +8,55 @@ import {
|
|
|
8
8
|
onCleanup,
|
|
9
9
|
onMount,
|
|
10
10
|
untrack as untrack3,
|
|
11
|
-
batch
|
|
11
|
+
batch,
|
|
12
|
+
setProfilerSink,
|
|
13
|
+
beginTurn,
|
|
14
|
+
endTurn,
|
|
15
|
+
__bfReportOutput as __bfReportOutput2
|
|
12
16
|
} from "@barefootjs/client/reactive";
|
|
13
17
|
|
|
18
|
+
// src/profiler-events.ts
|
|
19
|
+
function createRecordingSink() {
|
|
20
|
+
const events = [];
|
|
21
|
+
const turnStack = [];
|
|
22
|
+
let seq = 0;
|
|
23
|
+
let turnCounter = 0;
|
|
24
|
+
const top = () => turnStack.length > 0 ? turnStack[turnStack.length - 1] : null;
|
|
25
|
+
const push = (e) => {
|
|
26
|
+
const t = top();
|
|
27
|
+
events.push({ seq: seq++, turn: t?.handlerId ?? null, turnSeq: t?.turnSeq ?? null, ...e });
|
|
28
|
+
};
|
|
29
|
+
const sink = {
|
|
30
|
+
signalSet: (id, batched) => push({ type: "signalSet", signal: id, batched }),
|
|
31
|
+
subscribeAdd: (signal, subscriber) => push({ type: "subscribeAdd", signal, subscriber }),
|
|
32
|
+
subscribeRemove: (signal, subscriber) => push({ type: "subscribeRemove", signal, subscriber }),
|
|
33
|
+
effectCreate: (id, kind) => push({ type: "effectCreate", subscriber: id, kind }),
|
|
34
|
+
effectEnter: (id) => push({ type: "effectEnter", subscriber: id }),
|
|
35
|
+
effectExit: (id, dur) => push({ type: "effectExit", subscriber: id, dur }),
|
|
36
|
+
effectOutput: (id, changed) => push({ type: "effectOutput", subscriber: id, changed }),
|
|
37
|
+
effectDispose: (id) => push({ type: "effectDispose", subscriber: id }),
|
|
38
|
+
batchBegin: (depth) => push({ type: "batchBegin", depth }),
|
|
39
|
+
batchFlush: (flushed) => push({ type: "batchFlush", flushed }),
|
|
40
|
+
turnBegin: (handlerId, loc) => {
|
|
41
|
+
push({ type: "turnBegin", handlerId, loc });
|
|
42
|
+
turnStack.push({ handlerId, turnSeq: ++turnCounter });
|
|
43
|
+
},
|
|
44
|
+
turnEnd: () => {
|
|
45
|
+
turnStack.pop();
|
|
46
|
+
push({ type: "turnEnd" });
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
sink,
|
|
51
|
+
events,
|
|
52
|
+
reset() {
|
|
53
|
+
events.length = 0;
|
|
54
|
+
turnStack.length = 0;
|
|
55
|
+
seq = 0;
|
|
56
|
+
turnCounter = 0;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
14
60
|
// src/split-props.ts
|
|
15
61
|
function splitProps(props, keys) {
|
|
16
62
|
const keySet = new Set(keys);
|
|
@@ -1640,7 +1686,7 @@ function createItemScope(item, index, renderItem, existingPrimary, existingExtra
|
|
|
1640
1686
|
});
|
|
1641
1687
|
return { startMarker, primaryEl, extras, dispose, setItem };
|
|
1642
1688
|
}
|
|
1643
|
-
function mapArray(accessor, container, getKey, renderItem, markerId) {
|
|
1689
|
+
function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
1644
1690
|
if (!container)
|
|
1645
1691
|
return;
|
|
1646
1692
|
const scopes = new Map;
|
|
@@ -1760,7 +1806,7 @@ function mapArray(accessor, container, getKey, renderItem, markerId) {
|
|
|
1760
1806
|
insertScope(scope, container, anchor);
|
|
1761
1807
|
}
|
|
1762
1808
|
}
|
|
1763
|
-
});
|
|
1809
|
+
}, bfId);
|
|
1764
1810
|
}
|
|
1765
1811
|
var ITEM_PREFIX = `${BF_LOOP_ITEM}:`;
|
|
1766
1812
|
function isItemAnchor(node) {
|
|
@@ -1823,7 +1869,7 @@ function createAnchorScope(item, index, key, renderItem, existingAnchor) {
|
|
|
1823
1869
|
}
|
|
1824
1870
|
return { anchor, pending: frag, dispose, setItem };
|
|
1825
1871
|
}
|
|
1826
|
-
function mapArrayAnchored(accessor, container, getKey, renderItem, markerId) {
|
|
1872
|
+
function mapArrayAnchored(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
1827
1873
|
if (!container)
|
|
1828
1874
|
return;
|
|
1829
1875
|
const scopes = new Map;
|
|
@@ -1904,7 +1950,7 @@ function mapArrayAnchored(accessor, container, getKey, renderItem, markerId) {
|
|
|
1904
1950
|
placeAnchorScope(scope, container, end, end);
|
|
1905
1951
|
}
|
|
1906
1952
|
}
|
|
1907
|
-
});
|
|
1953
|
+
}, bfId);
|
|
1908
1954
|
}
|
|
1909
1955
|
// src/runtime/apply-rest-attrs.ts
|
|
1910
1956
|
import { createEffect as createEffect2 } from "@barefootjs/client/reactive";
|
|
@@ -2075,7 +2121,7 @@ function normalizeTemplate(value) {
|
|
|
2075
2121
|
function evalBranchTemplate(branch) {
|
|
2076
2122
|
return untrack2(() => normalizeTemplate(branch.template()));
|
|
2077
2123
|
}
|
|
2078
|
-
function insert(scope, id, conditionFn, whenTrue, whenFalse) {
|
|
2124
|
+
function insert(scope, id, conditionFn, whenTrue, whenFalse, bfId) {
|
|
2079
2125
|
if (!scope)
|
|
2080
2126
|
return;
|
|
2081
2127
|
const region = makeRegion(scope);
|
|
@@ -2163,7 +2209,7 @@ function insert(scope, id, conditionFn, whenTrue, whenFalse) {
|
|
|
2163
2209
|
const cleanup = branch.bindEvents(region.bindScope, { isFirstRun: false });
|
|
2164
2210
|
branchCleanup = typeof cleanup === "function" ? cleanup : null;
|
|
2165
2211
|
autoFocusConditionalElement(region, id);
|
|
2166
|
-
});
|
|
2212
|
+
}, bfId);
|
|
2167
2213
|
}
|
|
2168
2214
|
function autoFocusConditionalElement(region, id) {
|
|
2169
2215
|
requestAnimationFrame(() => {
|
|
@@ -2282,15 +2328,20 @@ function __bfSlot(value, slots) {
|
|
|
2282
2328
|
return escapeText(value);
|
|
2283
2329
|
}
|
|
2284
2330
|
// src/runtime/dynamic-text.ts
|
|
2331
|
+
import { __bfReportOutput } from "@barefootjs/client/reactive";
|
|
2285
2332
|
var END_MARKER = "/";
|
|
2286
2333
|
function clearSlotRegion(start, keep) {
|
|
2334
|
+
let removed = false;
|
|
2287
2335
|
let n = start.nextSibling;
|
|
2288
2336
|
while (n && !(n.nodeType === Node.COMMENT_NODE && n.nodeValue === END_MARKER)) {
|
|
2289
2337
|
const next = n.nextSibling;
|
|
2290
|
-
if (n !== keep)
|
|
2338
|
+
if (n !== keep) {
|
|
2291
2339
|
n.parentNode?.removeChild(n);
|
|
2340
|
+
removed = true;
|
|
2341
|
+
}
|
|
2292
2342
|
n = next;
|
|
2293
2343
|
}
|
|
2344
|
+
return removed;
|
|
2294
2345
|
}
|
|
2295
2346
|
function slotStart(node) {
|
|
2296
2347
|
let n = node.previousSibling;
|
|
@@ -2304,9 +2355,12 @@ function __bfText(current, value) {
|
|
|
2304
2355
|
if (value != null && value.__isSlot)
|
|
2305
2356
|
return current;
|
|
2306
2357
|
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
2307
|
-
if (value === current)
|
|
2358
|
+
if (value === current) {
|
|
2359
|
+
__bfReportOutput(false);
|
|
2308
2360
|
return current;
|
|
2361
|
+
}
|
|
2309
2362
|
const start2 = current.previousSibling;
|
|
2363
|
+
__bfReportOutput(true);
|
|
2310
2364
|
if (start2 && start2.nodeType === Node.COMMENT_NODE) {
|
|
2311
2365
|
clearSlotRegion(start2);
|
|
2312
2366
|
start2.parentNode?.insertBefore(value, start2.nextSibling);
|
|
@@ -2317,12 +2371,14 @@ function __bfText(current, value) {
|
|
|
2317
2371
|
}
|
|
2318
2372
|
const text = String(value ?? "");
|
|
2319
2373
|
if (current.nodeType === Node.TEXT_NODE) {
|
|
2374
|
+
const textChanged = current.nodeValue !== text;
|
|
2320
2375
|
current.nodeValue = text;
|
|
2321
2376
|
const start2 = slotStart(current);
|
|
2322
|
-
|
|
2323
|
-
|
|
2377
|
+
const clearedStale = start2 != null && start2.nodeType === Node.COMMENT_NODE && clearSlotRegion(start2, current);
|
|
2378
|
+
__bfReportOutput(textChanged || clearedStale);
|
|
2324
2379
|
return current;
|
|
2325
2380
|
}
|
|
2381
|
+
__bfReportOutput(true);
|
|
2326
2382
|
const start = current.previousSibling;
|
|
2327
2383
|
const textNode = (current.ownerDocument ?? document).createTextNode(text);
|
|
2328
2384
|
if (start && start.nodeType === Node.COMMENT_NODE) {
|
|
@@ -2437,6 +2493,7 @@ export {
|
|
|
2437
2493
|
spreadAttrs,
|
|
2438
2494
|
splitProps,
|
|
2439
2495
|
setupStreaming,
|
|
2496
|
+
setProfilerSink,
|
|
2440
2497
|
setCurrentScope,
|
|
2441
2498
|
renderChild,
|
|
2442
2499
|
render,
|
|
@@ -2475,9 +2532,11 @@ export {
|
|
|
2475
2532
|
find,
|
|
2476
2533
|
escapeText,
|
|
2477
2534
|
escapeAttr,
|
|
2535
|
+
endTurn,
|
|
2478
2536
|
cssEscape,
|
|
2479
2537
|
createSignal2 as createSignal,
|
|
2480
2538
|
createRoot2 as createRoot,
|
|
2539
|
+
createRecordingSink,
|
|
2481
2540
|
createPortal,
|
|
2482
2541
|
createMemo,
|
|
2483
2542
|
createEffect4 as createEffect,
|
|
@@ -2485,12 +2544,14 @@ export {
|
|
|
2485
2544
|
createContext,
|
|
2486
2545
|
createComponent,
|
|
2487
2546
|
cleanupPortalPlaceholder,
|
|
2547
|
+
beginTurn,
|
|
2488
2548
|
batch,
|
|
2489
2549
|
applyRestAttrs,
|
|
2490
2550
|
__slot,
|
|
2491
2551
|
__bf_swap,
|
|
2492
2552
|
__bfText,
|
|
2493
2553
|
__bfSlot,
|
|
2554
|
+
__bfReportOutput2 as __bfReportOutput,
|
|
2494
2555
|
$t,
|
|
2495
2556
|
$c,
|
|
2496
2557
|
$
|
package/dist/runtime/insert.d.ts
CHANGED
|
@@ -71,5 +71,5 @@ export interface BranchConfig {
|
|
|
71
71
|
* @param whenTrue - Branch config for when condition is true
|
|
72
72
|
* @param whenFalse - Branch config for when condition is false
|
|
73
73
|
*/
|
|
74
|
-
export declare function insert(scope: Element | Comment | null, id: string, conditionFn: () => boolean, whenTrue: BranchConfig, whenFalse: BranchConfig): void;
|
|
74
|
+
export declare function insert(scope: Element | Comment | null, id: string, conditionFn: () => boolean, whenTrue: BranchConfig, whenFalse: BranchConfig, bfId?: string): void;
|
|
75
75
|
//# sourceMappingURL=insert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../src/runtime/insert.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmFH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,IAAI,EAAE,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,QAAQ,EAAE,MAAM,MAAM,GAAG,oBAAoB,CAAA;IAE7C;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CACrF;AAyBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,EAC/B,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,OAAO,EAC1B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../src/runtime/insert.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmFH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,IAAI,EAAE,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,QAAQ,EAAE,MAAM,MAAM,GAAG,oBAAoB,CAAA;IAE7C;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CACrF;AAyBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,EAC/B,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,OAAO,EAC1B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,YAAY,EACvB,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CA+IN"}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* When `existing` is passed, initializes the SSR-rendered element and returns it.
|
|
29
29
|
* When `existing` is undefined, creates a new element and returns it.
|
|
30
30
|
*/
|
|
31
|
-
export declare function mapArray<T>(accessor: () => T[], container: HTMLElement | null, getKey: ((item: T, index: number) => string) | null, renderItem: (item: () => T, index: number, existing?: HTMLElement) => HTMLElement, markerId?: string): void;
|
|
31
|
+
export declare function mapArray<T>(accessor: () => T[], container: HTMLElement | null, getKey: ((item: T, index: number) => string) | null, renderItem: (item: () => T, index: number, existing?: HTMLElement) => HTMLElement, markerId?: string, bfId?: string): void;
|
|
32
32
|
/**
|
|
33
33
|
* Per-item scoped list rendering for whole-item conditionals (#1665).
|
|
34
34
|
*
|
|
@@ -37,5 +37,5 @@ export declare function mapArray<T>(accessor: () => T[], container: HTMLElement
|
|
|
37
37
|
* (hydration). Items may render zero elements; the anchor is the stable
|
|
38
38
|
* identity and position.
|
|
39
39
|
*/
|
|
40
|
-
export declare function mapArrayAnchored<T>(accessor: () => T[], container: HTMLElement | null, getKey: ((item: T, index: number) => string) | null, renderItem: (item: () => T, index: number, existing?: Comment) => DocumentFragment | Comment, markerId?: string): void;
|
|
40
|
+
export declare function mapArrayAnchored<T>(accessor: () => T[], container: HTMLElement | null, getKey: ((item: T, index: number) => string) | null, renderItem: (item: () => T, index: number, existing?: Comment) => DocumentFragment | Comment, markerId?: string, bfId?: string): void;
|
|
41
41
|
//# sourceMappingURL=map-array.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map-array.d.ts","sourceRoot":"","sources":["../../src/runtime/map-array.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA6LH;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,EAAE,EACnB,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,WAAW,EACjF,QAAQ,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"map-array.d.ts","sourceRoot":"","sources":["../../src/runtime/map-array.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA6LH;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,EAAE,EACnB,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,WAAW,EACjF,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAwKN;AAqHD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,QAAQ,EAAE,MAAM,CAAC,EAAE,EACnB,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,EACnD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,gBAAgB,GAAG,OAAO,EAC5F,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CA+FN"}
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
// src/reactive.ts
|
|
2
|
+
var profilerSink = null;
|
|
3
|
+
var signalSeq = 0;
|
|
4
|
+
var subscriberSeq = 0;
|
|
5
|
+
function setProfilerSink(sink) {
|
|
6
|
+
profilerSink = sink;
|
|
7
|
+
}
|
|
8
|
+
function beginTurn(handlerId, loc) {
|
|
9
|
+
if (profilerSink)
|
|
10
|
+
profilerSink.turnBegin(handlerId, loc);
|
|
11
|
+
}
|
|
12
|
+
function endTurn() {
|
|
13
|
+
if (profilerSink)
|
|
14
|
+
profilerSink.turnEnd();
|
|
15
|
+
}
|
|
16
|
+
function __bfReportOutput(changed) {
|
|
17
|
+
if (!profilerSink || !Owner)
|
|
18
|
+
return;
|
|
19
|
+
Owner.outputReported = true;
|
|
20
|
+
if (changed)
|
|
21
|
+
Owner.outputChanged = true;
|
|
22
|
+
}
|
|
2
23
|
var Owner = null;
|
|
3
24
|
var Listener = null;
|
|
4
25
|
var MAX_EFFECT_RUNS = 100;
|
|
5
26
|
var BatchDepth = 0;
|
|
6
27
|
var PendingEffects = new Set;
|
|
7
|
-
function createSignal(initialValue) {
|
|
28
|
+
function createSignal(initialValue, __bfId) {
|
|
8
29
|
let value = initialValue;
|
|
9
30
|
const subscribers = new Set;
|
|
31
|
+
const id = __bfId ?? (profilerSink ? `s${++signalSeq}` : "");
|
|
32
|
+
subscribers.__bfSignalId = id;
|
|
10
33
|
const get = () => {
|
|
11
34
|
if (Listener) {
|
|
12
35
|
subscribers.add(Listener);
|
|
13
36
|
Listener.dependencies.add(subscribers);
|
|
37
|
+
if (profilerSink)
|
|
38
|
+
profilerSink.subscribeAdd(id, Listener.id);
|
|
14
39
|
}
|
|
15
40
|
return value;
|
|
16
41
|
};
|
|
@@ -20,6 +45,8 @@ function createSignal(initialValue) {
|
|
|
20
45
|
return;
|
|
21
46
|
}
|
|
22
47
|
value = newValue;
|
|
48
|
+
if (profilerSink)
|
|
49
|
+
profilerSink.signalSet(id, BatchDepth > 0);
|
|
23
50
|
if (BatchDepth > 0) {
|
|
24
51
|
for (const effect of subscribers) {
|
|
25
52
|
PendingEffects.add(effect);
|
|
@@ -33,7 +60,7 @@ function createSignal(initialValue) {
|
|
|
33
60
|
};
|
|
34
61
|
return [get, set];
|
|
35
62
|
}
|
|
36
|
-
function createEffect(fn) {
|
|
63
|
+
function createEffect(fn, __bfId, __bfKind = "effect") {
|
|
37
64
|
const effect = {
|
|
38
65
|
fn,
|
|
39
66
|
cleanup: null,
|
|
@@ -41,8 +68,14 @@ function createEffect(fn) {
|
|
|
41
68
|
owner: Owner,
|
|
42
69
|
children: [],
|
|
43
70
|
disposed: false,
|
|
44
|
-
runCount: 0
|
|
71
|
+
runCount: 0,
|
|
72
|
+
id: __bfId ?? (profilerSink ? `e${++subscriberSeq}` : ""),
|
|
73
|
+
kind: __bfKind,
|
|
74
|
+
outputReported: false,
|
|
75
|
+
outputChanged: false
|
|
45
76
|
};
|
|
77
|
+
if (profilerSink)
|
|
78
|
+
profilerSink.effectCreate(effect.id, effect.kind);
|
|
46
79
|
if (Owner)
|
|
47
80
|
Owner.children.push(effect);
|
|
48
81
|
runEffect(effect);
|
|
@@ -55,18 +88,25 @@ function runEffect(effect) {
|
|
|
55
88
|
effect.runCount = 0;
|
|
56
89
|
throw new Error(`Circular dependency detected: effect re-entered itself ${MAX_EFFECT_RUNS} times.`);
|
|
57
90
|
}
|
|
91
|
+
if (profilerSink)
|
|
92
|
+
profilerSink.effectEnter(effect.id);
|
|
58
93
|
if (effect.cleanup) {
|
|
59
94
|
effect.cleanup();
|
|
60
95
|
effect.cleanup = null;
|
|
61
96
|
}
|
|
62
97
|
for (const dep of effect.dependencies) {
|
|
63
98
|
dep.delete(effect);
|
|
99
|
+
if (profilerSink)
|
|
100
|
+
profilerSink.subscribeRemove(dep.__bfSignalId ?? "", effect.id);
|
|
64
101
|
}
|
|
65
102
|
effect.dependencies.clear();
|
|
66
103
|
const prevOwner = Owner;
|
|
67
104
|
const prevListener = Listener;
|
|
68
105
|
Owner = effect;
|
|
69
106
|
Listener = effect;
|
|
107
|
+
effect.outputReported = false;
|
|
108
|
+
effect.outputChanged = false;
|
|
109
|
+
const start = profilerSink ? performance.now() : 0;
|
|
70
110
|
try {
|
|
71
111
|
const result = effect.fn();
|
|
72
112
|
if (typeof result === "function") {
|
|
@@ -76,6 +116,11 @@ function runEffect(effect) {
|
|
|
76
116
|
Owner = prevOwner;
|
|
77
117
|
Listener = prevListener;
|
|
78
118
|
effect.runCount--;
|
|
119
|
+
if (profilerSink) {
|
|
120
|
+
profilerSink.effectExit(effect.id, performance.now() - start);
|
|
121
|
+
if (effect.outputReported)
|
|
122
|
+
profilerSink.effectOutput?.(effect.id, effect.outputChanged);
|
|
123
|
+
}
|
|
79
124
|
}
|
|
80
125
|
}
|
|
81
126
|
function disposeSubtree(effect) {
|
|
@@ -92,8 +137,12 @@ function disposeSubtree(effect) {
|
|
|
92
137
|
}
|
|
93
138
|
for (const dep of effect.dependencies) {
|
|
94
139
|
dep.delete(effect);
|
|
140
|
+
if (profilerSink)
|
|
141
|
+
profilerSink.subscribeRemove(dep.__bfSignalId ?? "", effect.id);
|
|
95
142
|
}
|
|
96
143
|
effect.dependencies.clear();
|
|
144
|
+
if (profilerSink)
|
|
145
|
+
profilerSink.effectDispose(effect.id);
|
|
97
146
|
effect.owner = null;
|
|
98
147
|
}
|
|
99
148
|
function disposeEffect(effect) {
|
|
@@ -114,8 +163,14 @@ function createRoot(fn) {
|
|
|
114
163
|
owner: Owner,
|
|
115
164
|
children: [],
|
|
116
165
|
disposed: false,
|
|
117
|
-
runCount: 0
|
|
166
|
+
runCount: 0,
|
|
167
|
+
id: profilerSink ? `r${++subscriberSeq}` : "",
|
|
168
|
+
kind: "root",
|
|
169
|
+
outputReported: false,
|
|
170
|
+
outputChanged: false
|
|
118
171
|
};
|
|
172
|
+
if (profilerSink)
|
|
173
|
+
profilerSink.effectCreate(root.id, "root");
|
|
119
174
|
if (Owner)
|
|
120
175
|
Owner.children.push(root);
|
|
121
176
|
const prevOwner = Owner;
|
|
@@ -129,7 +184,7 @@ function createRoot(fn) {
|
|
|
129
184
|
Listener = prevListener;
|
|
130
185
|
}
|
|
131
186
|
}
|
|
132
|
-
function createDisposableEffect(fn) {
|
|
187
|
+
function createDisposableEffect(fn, __bfId) {
|
|
133
188
|
let disposed = false;
|
|
134
189
|
const effect = {
|
|
135
190
|
fn: () => {
|
|
@@ -142,8 +197,14 @@ function createDisposableEffect(fn) {
|
|
|
142
197
|
owner: Owner,
|
|
143
198
|
children: [],
|
|
144
199
|
disposed: false,
|
|
145
|
-
runCount: 0
|
|
200
|
+
runCount: 0,
|
|
201
|
+
id: __bfId ?? (profilerSink ? `e${++subscriberSeq}` : ""),
|
|
202
|
+
kind: "effect",
|
|
203
|
+
outputReported: false,
|
|
204
|
+
outputChanged: false
|
|
146
205
|
};
|
|
206
|
+
if (profilerSink)
|
|
207
|
+
profilerSink.effectCreate(effect.id, effect.kind);
|
|
147
208
|
if (Owner)
|
|
148
209
|
Owner.children.push(effect);
|
|
149
210
|
runEffect(effect);
|
|
@@ -173,6 +234,8 @@ function untrack(fn) {
|
|
|
173
234
|
}
|
|
174
235
|
function batch(fn) {
|
|
175
236
|
BatchDepth++;
|
|
237
|
+
if (profilerSink)
|
|
238
|
+
profilerSink.batchBegin(BatchDepth);
|
|
176
239
|
try {
|
|
177
240
|
return fn();
|
|
178
241
|
} finally {
|
|
@@ -186,6 +249,8 @@ function flushEffects() {
|
|
|
186
249
|
while (PendingEffects.size > 0) {
|
|
187
250
|
const effects = [...PendingEffects];
|
|
188
251
|
PendingEffects.clear();
|
|
252
|
+
if (profilerSink)
|
|
253
|
+
profilerSink.batchFlush(effects.length);
|
|
189
254
|
for (const effect of effects) {
|
|
190
255
|
runEffect(effect);
|
|
191
256
|
}
|
|
@@ -194,14 +259,64 @@ function flushEffects() {
|
|
|
194
259
|
function onMount(fn) {
|
|
195
260
|
createEffect(() => untrack(fn));
|
|
196
261
|
}
|
|
197
|
-
function createMemo(fn) {
|
|
198
|
-
const
|
|
262
|
+
function createMemo(fn, __bfId) {
|
|
263
|
+
const id = __bfId ?? (profilerSink ? `m${++subscriberSeq}` : "");
|
|
264
|
+
const [value, setValue] = createSignal(undefined, id);
|
|
265
|
+
let prev;
|
|
266
|
+
let hasPrev = false;
|
|
199
267
|
createEffect(() => {
|
|
200
268
|
const result = fn();
|
|
269
|
+
if (profilerSink) {
|
|
270
|
+
__bfReportOutput(!hasPrev || !Object.is(prev, result));
|
|
271
|
+
prev = result;
|
|
272
|
+
hasPrev = true;
|
|
273
|
+
}
|
|
201
274
|
setValue(() => result);
|
|
202
|
-
});
|
|
275
|
+
}, id, "memo");
|
|
203
276
|
return value;
|
|
204
277
|
}
|
|
278
|
+
// src/profiler-events.ts
|
|
279
|
+
function createRecordingSink() {
|
|
280
|
+
const events = [];
|
|
281
|
+
const turnStack = [];
|
|
282
|
+
let seq = 0;
|
|
283
|
+
let turnCounter = 0;
|
|
284
|
+
const top = () => turnStack.length > 0 ? turnStack[turnStack.length - 1] : null;
|
|
285
|
+
const push = (e) => {
|
|
286
|
+
const t = top();
|
|
287
|
+
events.push({ seq: seq++, turn: t?.handlerId ?? null, turnSeq: t?.turnSeq ?? null, ...e });
|
|
288
|
+
};
|
|
289
|
+
const sink = {
|
|
290
|
+
signalSet: (id, batched) => push({ type: "signalSet", signal: id, batched }),
|
|
291
|
+
subscribeAdd: (signal, subscriber) => push({ type: "subscribeAdd", signal, subscriber }),
|
|
292
|
+
subscribeRemove: (signal, subscriber) => push({ type: "subscribeRemove", signal, subscriber }),
|
|
293
|
+
effectCreate: (id, kind) => push({ type: "effectCreate", subscriber: id, kind }),
|
|
294
|
+
effectEnter: (id) => push({ type: "effectEnter", subscriber: id }),
|
|
295
|
+
effectExit: (id, dur) => push({ type: "effectExit", subscriber: id, dur }),
|
|
296
|
+
effectOutput: (id, changed) => push({ type: "effectOutput", subscriber: id, changed }),
|
|
297
|
+
effectDispose: (id) => push({ type: "effectDispose", subscriber: id }),
|
|
298
|
+
batchBegin: (depth) => push({ type: "batchBegin", depth }),
|
|
299
|
+
batchFlush: (flushed) => push({ type: "batchFlush", flushed }),
|
|
300
|
+
turnBegin: (handlerId, loc) => {
|
|
301
|
+
push({ type: "turnBegin", handlerId, loc });
|
|
302
|
+
turnStack.push({ handlerId, turnSeq: ++turnCounter });
|
|
303
|
+
},
|
|
304
|
+
turnEnd: () => {
|
|
305
|
+
turnStack.pop();
|
|
306
|
+
push({ type: "turnEnd" });
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
sink,
|
|
311
|
+
events,
|
|
312
|
+
reset() {
|
|
313
|
+
events.length = 0;
|
|
314
|
+
turnStack.length = 0;
|
|
315
|
+
seq = 0;
|
|
316
|
+
turnCounter = 0;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
205
320
|
// src/split-props.ts
|
|
206
321
|
function splitProps(props, keys) {
|
|
207
322
|
const keySet = new Set(keys);
|
|
@@ -1829,7 +1944,7 @@ function createItemScope(item, index, renderItem, existingPrimary, existingExtra
|
|
|
1829
1944
|
});
|
|
1830
1945
|
return { startMarker, primaryEl, extras, dispose, setItem };
|
|
1831
1946
|
}
|
|
1832
|
-
function mapArray(accessor, container, getKey, renderItem, markerId) {
|
|
1947
|
+
function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
1833
1948
|
if (!container)
|
|
1834
1949
|
return;
|
|
1835
1950
|
const scopes = new Map;
|
|
@@ -1949,7 +2064,7 @@ function mapArray(accessor, container, getKey, renderItem, markerId) {
|
|
|
1949
2064
|
insertScope(scope, container, anchor);
|
|
1950
2065
|
}
|
|
1951
2066
|
}
|
|
1952
|
-
});
|
|
2067
|
+
}, bfId);
|
|
1953
2068
|
}
|
|
1954
2069
|
var ITEM_PREFIX = `${BF_LOOP_ITEM}:`;
|
|
1955
2070
|
function isItemAnchor(node) {
|
|
@@ -2012,7 +2127,7 @@ function createAnchorScope(item, index, key, renderItem, existingAnchor) {
|
|
|
2012
2127
|
}
|
|
2013
2128
|
return { anchor, pending: frag, dispose, setItem };
|
|
2014
2129
|
}
|
|
2015
|
-
function mapArrayAnchored(accessor, container, getKey, renderItem, markerId) {
|
|
2130
|
+
function mapArrayAnchored(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
2016
2131
|
if (!container)
|
|
2017
2132
|
return;
|
|
2018
2133
|
const scopes = new Map;
|
|
@@ -2093,7 +2208,7 @@ function mapArrayAnchored(accessor, container, getKey, renderItem, markerId) {
|
|
|
2093
2208
|
placeAnchorScope(scope, container, end, end);
|
|
2094
2209
|
}
|
|
2095
2210
|
}
|
|
2096
|
-
});
|
|
2211
|
+
}, bfId);
|
|
2097
2212
|
}
|
|
2098
2213
|
// src/runtime/style.ts
|
|
2099
2214
|
function styleToCss(value) {
|
|
@@ -2260,7 +2375,7 @@ function normalizeTemplate(value) {
|
|
|
2260
2375
|
function evalBranchTemplate(branch) {
|
|
2261
2376
|
return untrack(() => normalizeTemplate(branch.template()));
|
|
2262
2377
|
}
|
|
2263
|
-
function insert(scope, id, conditionFn, whenTrue, whenFalse) {
|
|
2378
|
+
function insert(scope, id, conditionFn, whenTrue, whenFalse, bfId) {
|
|
2264
2379
|
if (!scope)
|
|
2265
2380
|
return;
|
|
2266
2381
|
const region = makeRegion(scope);
|
|
@@ -2348,7 +2463,7 @@ function insert(scope, id, conditionFn, whenTrue, whenFalse) {
|
|
|
2348
2463
|
const cleanup = branch.bindEvents(region.bindScope, { isFirstRun: false });
|
|
2349
2464
|
branchCleanup = typeof cleanup === "function" ? cleanup : null;
|
|
2350
2465
|
autoFocusConditionalElement(region, id);
|
|
2351
|
-
});
|
|
2466
|
+
}, bfId);
|
|
2352
2467
|
}
|
|
2353
2468
|
function autoFocusConditionalElement(region, id) {
|
|
2354
2469
|
requestAnimationFrame(() => {
|
|
@@ -2469,13 +2584,17 @@ function __bfSlot(value, slots) {
|
|
|
2469
2584
|
// src/runtime/dynamic-text.ts
|
|
2470
2585
|
var END_MARKER = "/";
|
|
2471
2586
|
function clearSlotRegion(start, keep) {
|
|
2587
|
+
let removed = false;
|
|
2472
2588
|
let n = start.nextSibling;
|
|
2473
2589
|
while (n && !(n.nodeType === Node.COMMENT_NODE && n.nodeValue === END_MARKER)) {
|
|
2474
2590
|
const next = n.nextSibling;
|
|
2475
|
-
if (n !== keep)
|
|
2591
|
+
if (n !== keep) {
|
|
2476
2592
|
n.parentNode?.removeChild(n);
|
|
2593
|
+
removed = true;
|
|
2594
|
+
}
|
|
2477
2595
|
n = next;
|
|
2478
2596
|
}
|
|
2597
|
+
return removed;
|
|
2479
2598
|
}
|
|
2480
2599
|
function slotStart(node) {
|
|
2481
2600
|
let n = node.previousSibling;
|
|
@@ -2489,9 +2608,12 @@ function __bfText(current, value) {
|
|
|
2489
2608
|
if (value != null && value.__isSlot)
|
|
2490
2609
|
return current;
|
|
2491
2610
|
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
2492
|
-
if (value === current)
|
|
2611
|
+
if (value === current) {
|
|
2612
|
+
__bfReportOutput(false);
|
|
2493
2613
|
return current;
|
|
2614
|
+
}
|
|
2494
2615
|
const start2 = current.previousSibling;
|
|
2616
|
+
__bfReportOutput(true);
|
|
2495
2617
|
if (start2 && start2.nodeType === Node.COMMENT_NODE) {
|
|
2496
2618
|
clearSlotRegion(start2);
|
|
2497
2619
|
start2.parentNode?.insertBefore(value, start2.nextSibling);
|
|
@@ -2502,12 +2624,14 @@ function __bfText(current, value) {
|
|
|
2502
2624
|
}
|
|
2503
2625
|
const text = String(value ?? "");
|
|
2504
2626
|
if (current.nodeType === Node.TEXT_NODE) {
|
|
2627
|
+
const textChanged = current.nodeValue !== text;
|
|
2505
2628
|
current.nodeValue = text;
|
|
2506
2629
|
const start2 = slotStart(current);
|
|
2507
|
-
|
|
2508
|
-
|
|
2630
|
+
const clearedStale = start2 != null && start2.nodeType === Node.COMMENT_NODE && clearSlotRegion(start2, current);
|
|
2631
|
+
__bfReportOutput(textChanged || clearedStale);
|
|
2509
2632
|
return current;
|
|
2510
2633
|
}
|
|
2634
|
+
__bfReportOutput(true);
|
|
2511
2635
|
const start = current.previousSibling;
|
|
2512
2636
|
const textNode = (current.ownerDocument ?? document).createTextNode(text);
|
|
2513
2637
|
if (start && start.nodeType === Node.COMMENT_NODE) {
|
|
@@ -2622,6 +2746,7 @@ export {
|
|
|
2622
2746
|
spreadAttrs,
|
|
2623
2747
|
splitProps,
|
|
2624
2748
|
setupStreaming,
|
|
2749
|
+
setProfilerSink,
|
|
2625
2750
|
setCurrentScope,
|
|
2626
2751
|
renderChild,
|
|
2627
2752
|
render,
|
|
@@ -2660,9 +2785,11 @@ export {
|
|
|
2660
2785
|
find,
|
|
2661
2786
|
escapeText,
|
|
2662
2787
|
escapeAttr,
|
|
2788
|
+
endTurn,
|
|
2663
2789
|
cssEscape,
|
|
2664
2790
|
createSignal,
|
|
2665
2791
|
createRoot,
|
|
2792
|
+
createRecordingSink,
|
|
2666
2793
|
createPortal,
|
|
2667
2794
|
createMemo,
|
|
2668
2795
|
createEffect,
|
|
@@ -2670,12 +2797,14 @@ export {
|
|
|
2670
2797
|
createContext,
|
|
2671
2798
|
createComponent,
|
|
2672
2799
|
cleanupPortalPlaceholder,
|
|
2800
|
+
beginTurn,
|
|
2673
2801
|
batch,
|
|
2674
2802
|
applyRestAttrs,
|
|
2675
2803
|
__slot,
|
|
2676
2804
|
__bf_swap,
|
|
2677
2805
|
__bfText,
|
|
2678
2806
|
__bfSlot,
|
|
2807
|
+
__bfReportOutput,
|
|
2679
2808
|
$t,
|
|
2680
2809
|
$c,
|
|
2681
2810
|
$
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "BarefootJS client package: reactive primitives (SSR-safe) plus browser runtime under the `/runtime` subpath (compiler target)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/client"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.
|
|
58
|
+
"@barefootjs/shared": "0.11.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0"
|
package/src/index.ts
CHANGED
|
@@ -11,13 +11,26 @@ export {
|
|
|
11
11
|
onMount,
|
|
12
12
|
untrack,
|
|
13
13
|
batch,
|
|
14
|
+
setProfilerSink,
|
|
15
|
+
beginTurn,
|
|
16
|
+
endTurn,
|
|
17
|
+
__bfReportOutput,
|
|
14
18
|
type Reactive,
|
|
15
19
|
type Signal,
|
|
16
20
|
type Memo,
|
|
17
21
|
type CleanupFn,
|
|
18
22
|
type EffectFn,
|
|
23
|
+
type ProfilerEventSink,
|
|
24
|
+
type SubscriberKind,
|
|
19
25
|
} from '@barefootjs/client/reactive'
|
|
20
26
|
|
|
27
|
+
export {
|
|
28
|
+
createRecordingSink,
|
|
29
|
+
type ProfilerEvent,
|
|
30
|
+
type ProfilerEventType,
|
|
31
|
+
type RecordingSink,
|
|
32
|
+
} from './profiler-events.ts'
|
|
33
|
+
|
|
21
34
|
export { splitProps } from './split-props.ts'
|
|
22
35
|
|
|
23
36
|
export { __slot, type SlotMarker } from './slot.ts'
|