@barefootjs/client 0.17.1 → 0.18.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/build.d.ts +16 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +3 -1
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +59 -26
- package/dist/runtime/component.d.ts +13 -3
- package/dist/runtime/component.d.ts.map +1 -1
- package/dist/runtime/index.js +128 -46
- package/dist/runtime/map-array.d.ts.map +1 -1
- package/dist/runtime/standalone.js +187 -72
- package/package.json +2 -2
- package/src/build.ts +16 -0
- package/src/reactive.ts +167 -32
- package/src/runtime/component.ts +14 -3
- package/src/runtime/map-array.ts +172 -29
|
@@ -209,6 +209,11 @@ function __bfReportOutput(changed) {
|
|
|
209
209
|
var Owner = null;
|
|
210
210
|
var Listener = null;
|
|
211
211
|
var MAX_EFFECT_RUNS = 100;
|
|
212
|
+
function registerChild(owner, child) {
|
|
213
|
+
if (!owner.children)
|
|
214
|
+
owner.children = new Set;
|
|
215
|
+
owner.children.add(child);
|
|
216
|
+
}
|
|
212
217
|
var BatchDepth = 0;
|
|
213
218
|
var PendingEffects = new Set;
|
|
214
219
|
function createSignal(initialValue, __bfId) {
|
|
@@ -218,10 +223,18 @@ function createSignal(initialValue, __bfId) {
|
|
|
218
223
|
subscribers.__bfSignalId = id;
|
|
219
224
|
const get = () => {
|
|
220
225
|
if (Listener) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
if (profilerSink) {
|
|
227
|
+
subscribers.add(Listener);
|
|
228
|
+
subscribers.__bfSnapshot = null;
|
|
229
|
+
Listener.dependencies.set(subscribers, Listener.gen);
|
|
224
230
|
profilerSink.subscribeAdd(id, Listener.id);
|
|
231
|
+
} else if (!Listener.dependencies.has(subscribers)) {
|
|
232
|
+
subscribers.add(Listener);
|
|
233
|
+
subscribers.__bfSnapshot = null;
|
|
234
|
+
Listener.dependencies.set(subscribers, Listener.gen);
|
|
235
|
+
} else {
|
|
236
|
+
Listener.dependencies.set(subscribers, Listener.gen);
|
|
237
|
+
}
|
|
225
238
|
}
|
|
226
239
|
return value;
|
|
227
240
|
};
|
|
@@ -238,9 +251,12 @@ function createSignal(initialValue, __bfId) {
|
|
|
238
251
|
PendingEffects.add(effect);
|
|
239
252
|
}
|
|
240
253
|
} else {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
254
|
+
let snapshot = subscribers.__bfSnapshot;
|
|
255
|
+
if (!snapshot) {
|
|
256
|
+
snapshot = subscribers.__bfSnapshot = [...subscribers];
|
|
257
|
+
}
|
|
258
|
+
for (let i = 0;i < snapshot.length; i++) {
|
|
259
|
+
runEffect(snapshot[i]);
|
|
244
260
|
}
|
|
245
261
|
}
|
|
246
262
|
};
|
|
@@ -250,9 +266,10 @@ function createEffect(fn, __bfId, __bfKind = "effect") {
|
|
|
250
266
|
const effect = {
|
|
251
267
|
fn,
|
|
252
268
|
cleanup: null,
|
|
253
|
-
dependencies: new
|
|
269
|
+
dependencies: new Map,
|
|
270
|
+
gen: 0,
|
|
254
271
|
owner: Owner,
|
|
255
|
-
children:
|
|
272
|
+
children: null,
|
|
256
273
|
disposed: false,
|
|
257
274
|
runCount: 0,
|
|
258
275
|
id: __bfId ?? (profilerSink ? `e${++subscriberSeq}` : ""),
|
|
@@ -263,7 +280,7 @@ function createEffect(fn, __bfId, __bfKind = "effect") {
|
|
|
263
280
|
if (profilerSink)
|
|
264
281
|
profilerSink.effectCreate(effect.id, effect.kind);
|
|
265
282
|
if (Owner)
|
|
266
|
-
Owner
|
|
283
|
+
registerChild(Owner, effect);
|
|
267
284
|
runEffect(effect);
|
|
268
285
|
}
|
|
269
286
|
function runEffect(effect) {
|
|
@@ -274,22 +291,26 @@ function runEffect(effect) {
|
|
|
274
291
|
effect.runCount = 0;
|
|
275
292
|
throw new Error(`Circular dependency detected: effect re-entered itself ${MAX_EFFECT_RUNS} times.`);
|
|
276
293
|
}
|
|
294
|
+
const isOutermostRun = effect.runCount === 1;
|
|
277
295
|
if (profilerSink)
|
|
278
296
|
profilerSink.effectEnter(effect.id);
|
|
279
297
|
if (effect.cleanup) {
|
|
280
298
|
effect.cleanup();
|
|
281
299
|
effect.cleanup = null;
|
|
282
300
|
}
|
|
283
|
-
|
|
284
|
-
dep.
|
|
285
|
-
|
|
301
|
+
if (profilerSink) {
|
|
302
|
+
for (const dep of effect.dependencies.keys()) {
|
|
303
|
+
dep.delete(effect);
|
|
304
|
+
dep.__bfSnapshot = null;
|
|
286
305
|
profilerSink.subscribeRemove(dep.__bfSignalId ?? "", effect.id);
|
|
306
|
+
}
|
|
307
|
+
effect.dependencies.clear();
|
|
287
308
|
}
|
|
288
|
-
effect.dependencies.clear();
|
|
289
309
|
const prevOwner = Owner;
|
|
290
310
|
const prevListener = Listener;
|
|
291
311
|
Owner = effect;
|
|
292
312
|
Listener = effect;
|
|
313
|
+
effect.gen++;
|
|
293
314
|
effect.outputReported = false;
|
|
294
315
|
effect.outputChanged = false;
|
|
295
316
|
const start = profilerSink ? performance.now() : 0;
|
|
@@ -302,6 +323,15 @@ function runEffect(effect) {
|
|
|
302
323
|
Owner = prevOwner;
|
|
303
324
|
Listener = prevListener;
|
|
304
325
|
effect.runCount--;
|
|
326
|
+
if (!profilerSink && isOutermostRun) {
|
|
327
|
+
for (const [dep, gen] of effect.dependencies) {
|
|
328
|
+
if (gen !== effect.gen) {
|
|
329
|
+
effect.dependencies.delete(dep);
|
|
330
|
+
dep.delete(effect);
|
|
331
|
+
dep.__bfSnapshot = null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
305
335
|
if (profilerSink) {
|
|
306
336
|
profilerSink.effectExit(effect.id, performance.now() - start);
|
|
307
337
|
if (effect.outputReported)
|
|
@@ -313,16 +343,19 @@ function disposeSubtree(effect) {
|
|
|
313
343
|
if (effect.disposed)
|
|
314
344
|
return;
|
|
315
345
|
effect.disposed = true;
|
|
316
|
-
|
|
317
|
-
|
|
346
|
+
if (effect.children) {
|
|
347
|
+
for (const child of effect.children) {
|
|
348
|
+
disposeSubtree(child);
|
|
349
|
+
}
|
|
350
|
+
effect.children.clear();
|
|
318
351
|
}
|
|
319
|
-
effect.children.length = 0;
|
|
320
352
|
if (effect.cleanup) {
|
|
321
353
|
effect.cleanup();
|
|
322
354
|
effect.cleanup = null;
|
|
323
355
|
}
|
|
324
|
-
for (const dep of effect.dependencies) {
|
|
356
|
+
for (const dep of effect.dependencies.keys()) {
|
|
325
357
|
dep.delete(effect);
|
|
358
|
+
dep.__bfSnapshot = null;
|
|
326
359
|
if (profilerSink)
|
|
327
360
|
profilerSink.subscribeRemove(dep.__bfSignalId ?? "", effect.id);
|
|
328
361
|
}
|
|
@@ -335,9 +368,7 @@ function disposeEffect(effect) {
|
|
|
335
368
|
if (effect.disposed)
|
|
336
369
|
return;
|
|
337
370
|
if (effect.owner) {
|
|
338
|
-
|
|
339
|
-
if (idx >= 0)
|
|
340
|
-
effect.owner.children.splice(idx, 1);
|
|
371
|
+
effect.owner.children?.delete(effect);
|
|
341
372
|
}
|
|
342
373
|
disposeSubtree(effect);
|
|
343
374
|
}
|
|
@@ -345,9 +376,10 @@ function createRoot(fn) {
|
|
|
345
376
|
const root = {
|
|
346
377
|
fn: () => {},
|
|
347
378
|
cleanup: null,
|
|
348
|
-
dependencies: new
|
|
379
|
+
dependencies: new Map,
|
|
380
|
+
gen: 0,
|
|
349
381
|
owner: Owner,
|
|
350
|
-
children:
|
|
382
|
+
children: null,
|
|
351
383
|
disposed: false,
|
|
352
384
|
runCount: 0,
|
|
353
385
|
id: profilerSink ? `r${++subscriberSeq}` : "",
|
|
@@ -358,7 +390,7 @@ function createRoot(fn) {
|
|
|
358
390
|
if (profilerSink)
|
|
359
391
|
profilerSink.effectCreate(root.id, "root");
|
|
360
392
|
if (Owner)
|
|
361
|
-
Owner
|
|
393
|
+
registerChild(Owner, root);
|
|
362
394
|
const prevOwner = Owner;
|
|
363
395
|
const prevListener = Listener;
|
|
364
396
|
Owner = root;
|
|
@@ -379,9 +411,10 @@ function createDisposableEffect(fn, __bfId) {
|
|
|
379
411
|
return fn();
|
|
380
412
|
},
|
|
381
413
|
cleanup: null,
|
|
382
|
-
dependencies: new
|
|
414
|
+
dependencies: new Map,
|
|
415
|
+
gen: 0,
|
|
383
416
|
owner: Owner,
|
|
384
|
-
children:
|
|
417
|
+
children: null,
|
|
385
418
|
disposed: false,
|
|
386
419
|
runCount: 0,
|
|
387
420
|
id: __bfId ?? (profilerSink ? `e${++subscriberSeq}` : ""),
|
|
@@ -392,7 +425,7 @@ function createDisposableEffect(fn, __bfId) {
|
|
|
392
425
|
if (profilerSink)
|
|
393
426
|
profilerSink.effectCreate(effect.id, effect.kind);
|
|
394
427
|
if (Owner)
|
|
395
|
-
Owner
|
|
428
|
+
registerChild(Owner, effect);
|
|
396
429
|
runEffect(effect);
|
|
397
430
|
return () => {
|
|
398
431
|
disposeEffect(effect);
|
|
@@ -1574,6 +1607,8 @@ function escapeAttr(value) {
|
|
|
1574
1607
|
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1575
1608
|
}
|
|
1576
1609
|
function escapeText(value) {
|
|
1610
|
+
if (value == null)
|
|
1611
|
+
return "";
|
|
1577
1612
|
return escapeAttr(value);
|
|
1578
1613
|
}
|
|
1579
1614
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
@@ -1993,7 +2028,7 @@ function findLoopMarkers2(container, markerId) {
|
|
|
1993
2028
|
if (markerId) {
|
|
1994
2029
|
const startVal = loopStartMarker(markerId);
|
|
1995
2030
|
const endVal = loopEndMarker(markerId);
|
|
1996
|
-
for (
|
|
2031
|
+
for (let node = container.firstChild;node; node = node.nextSibling) {
|
|
1997
2032
|
if (node.nodeType !== Node.COMMENT_NODE)
|
|
1998
2033
|
continue;
|
|
1999
2034
|
const value = node.nodeValue;
|
|
@@ -2005,7 +2040,7 @@ function findLoopMarkers2(container, markerId) {
|
|
|
2005
2040
|
} else {
|
|
2006
2041
|
const startPrefix = `${BF_LOOP_START}:`;
|
|
2007
2042
|
const endPrefix = `${BF_LOOP_END}:`;
|
|
2008
|
-
for (
|
|
2043
|
+
for (let node = container.firstChild;node; node = node.nextSibling) {
|
|
2009
2044
|
if (node.nodeType !== Node.COMMENT_NODE)
|
|
2010
2045
|
continue;
|
|
2011
2046
|
const value = node.nodeValue ?? "";
|
|
@@ -2045,12 +2080,44 @@ function findItemRanges(start, end) {
|
|
|
2045
2080
|
}
|
|
2046
2081
|
return ranges.filter((r) => r.primaryEl !== null);
|
|
2047
2082
|
}
|
|
2048
|
-
function insertScope(scope,
|
|
2083
|
+
function insertScope(scope, target, anchor) {
|
|
2049
2084
|
if (scope.startMarker)
|
|
2050
|
-
|
|
2051
|
-
|
|
2085
|
+
target.insertBefore(scope.startMarker, anchor);
|
|
2086
|
+
target.insertBefore(scope.primaryEl, anchor);
|
|
2052
2087
|
for (const ex of scope.extras)
|
|
2053
|
-
|
|
2088
|
+
target.insertBefore(ex, anchor);
|
|
2089
|
+
}
|
|
2090
|
+
function longestIncreasingSubsequenceIndices(arr) {
|
|
2091
|
+
const n = arr.length;
|
|
2092
|
+
if (n === 0)
|
|
2093
|
+
return [];
|
|
2094
|
+
const tails = [];
|
|
2095
|
+
const predecessors = new Array(n).fill(-1);
|
|
2096
|
+
for (let i = 0;i < n; i++) {
|
|
2097
|
+
const value = arr[i];
|
|
2098
|
+
let lo = 0;
|
|
2099
|
+
let hi = tails.length;
|
|
2100
|
+
while (lo < hi) {
|
|
2101
|
+
const mid = lo + hi >>> 1;
|
|
2102
|
+
if (arr[tails[mid]] < value)
|
|
2103
|
+
lo = mid + 1;
|
|
2104
|
+
else
|
|
2105
|
+
hi = mid;
|
|
2106
|
+
}
|
|
2107
|
+
if (lo > 0)
|
|
2108
|
+
predecessors[i] = tails[lo - 1];
|
|
2109
|
+
if (lo === tails.length)
|
|
2110
|
+
tails.push(i);
|
|
2111
|
+
else
|
|
2112
|
+
tails[lo] = i;
|
|
2113
|
+
}
|
|
2114
|
+
const result = new Array(tails.length);
|
|
2115
|
+
let k = tails[tails.length - 1];
|
|
2116
|
+
for (let i = tails.length - 1;i >= 0; i--) {
|
|
2117
|
+
result[i] = k;
|
|
2118
|
+
k = predecessors[k];
|
|
2119
|
+
}
|
|
2120
|
+
return result;
|
|
2054
2121
|
}
|
|
2055
2122
|
function removeScope(scope) {
|
|
2056
2123
|
if (scope.startMarker?.parentNode)
|
|
@@ -2093,37 +2160,48 @@ function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
|
2093
2160
|
return;
|
|
2094
2161
|
const scopes = new Map;
|
|
2095
2162
|
let hydrated = false;
|
|
2163
|
+
let cachedStart = null;
|
|
2164
|
+
let cachedEnd = null;
|
|
2165
|
+
const resolveMarkers = () => {
|
|
2166
|
+
if (cachedStart && cachedEnd && cachedStart.isConnected && cachedEnd.isConnected) {
|
|
2167
|
+
return { start: cachedStart, end: cachedEnd };
|
|
2168
|
+
}
|
|
2169
|
+
const found = findLoopMarkers2(container, markerId);
|
|
2170
|
+
cachedStart = found.start;
|
|
2171
|
+
cachedEnd = found.end;
|
|
2172
|
+
return found;
|
|
2173
|
+
};
|
|
2096
2174
|
createEffect(() => {
|
|
2097
2175
|
const items = accessor();
|
|
2098
2176
|
if (!items)
|
|
2099
2177
|
return;
|
|
2100
|
-
const { start: startMarker, end: endMarker } =
|
|
2178
|
+
const { start: startMarker, end: endMarker } = resolveMarkers();
|
|
2101
2179
|
const anchor = endMarker ?? null;
|
|
2102
2180
|
if (!hydrated) {
|
|
2103
2181
|
hydrated = true;
|
|
2104
2182
|
const existingRanges = startMarker ? findItemRanges(startMarker, endMarker) : Array.from(container.children).map((el) => ({ startMarker: null, primaryEl: el, extras: [] }));
|
|
2105
2183
|
const needsHydration = existingRanges.length > 0 && (!existingRanges[0]?.primaryEl.hasAttribute("data-key") || scopes.size === 0);
|
|
2106
2184
|
if (needsHydration) {
|
|
2107
|
-
for (let
|
|
2108
|
-
const range = existingRanges[
|
|
2109
|
-
const item = items[
|
|
2110
|
-
const key = getKey ? getKey(item,
|
|
2185
|
+
for (let i2 = 0;i2 < existingRanges.length && i2 < items.length; i2++) {
|
|
2186
|
+
const range = existingRanges[i2];
|
|
2187
|
+
const item = items[i2];
|
|
2188
|
+
const key = getKey ? getKey(item, i2) : String(i2);
|
|
2111
2189
|
range.primaryEl.setAttribute(BF_KEY, key);
|
|
2112
|
-
const scope = createItemScope(item,
|
|
2190
|
+
const scope = createItemScope(item, i2, renderItem, range.primaryEl, range.extras, range.startMarker);
|
|
2113
2191
|
scopes.set(key, scope);
|
|
2114
2192
|
hydratedScopes.add(range.primaryEl);
|
|
2115
2193
|
}
|
|
2116
|
-
for (let
|
|
2117
|
-
const item = items[
|
|
2118
|
-
const key = getKey ? getKey(item,
|
|
2119
|
-
const scope = createItemScope(item,
|
|
2194
|
+
for (let i2 = existingRanges.length;i2 < items.length; i2++) {
|
|
2195
|
+
const item = items[i2];
|
|
2196
|
+
const key = getKey ? getKey(item, i2) : String(i2);
|
|
2197
|
+
const scope = createItemScope(item, i2, renderItem);
|
|
2120
2198
|
if (!scope.primaryEl.dataset.key)
|
|
2121
2199
|
scope.primaryEl.setAttribute(BF_KEY, key);
|
|
2122
2200
|
scopes.set(key, scope);
|
|
2123
2201
|
insertScope(scope, container, anchor);
|
|
2124
2202
|
}
|
|
2125
|
-
for (let
|
|
2126
|
-
const range = existingRanges[
|
|
2203
|
+
for (let i2 = items.length;i2 < existingRanges.length; i2++) {
|
|
2204
|
+
const range = existingRanges[i2];
|
|
2127
2205
|
if (range.startMarker?.parentNode)
|
|
2128
2206
|
range.startMarker.remove();
|
|
2129
2207
|
if (range.primaryEl.parentNode)
|
|
@@ -2151,12 +2229,40 @@ function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
|
2151
2229
|
}
|
|
2152
2230
|
}
|
|
2153
2231
|
}
|
|
2232
|
+
if (items.length === 0) {
|
|
2233
|
+
if (scopes.size > 0) {
|
|
2234
|
+
for (const scope of scopes.values())
|
|
2235
|
+
scope.dispose();
|
|
2236
|
+
if (startMarker && endMarker) {
|
|
2237
|
+
const range = document.createRange();
|
|
2238
|
+
range.setStartAfter(startMarker);
|
|
2239
|
+
range.setEndBefore(endMarker);
|
|
2240
|
+
range.deleteContents();
|
|
2241
|
+
} else {
|
|
2242
|
+
let expectedNodeCount = 0;
|
|
2243
|
+
for (const scope of scopes.values()) {
|
|
2244
|
+
expectedNodeCount += 1 + scope.extras.length + (scope.startMarker ? 1 : 0);
|
|
2245
|
+
}
|
|
2246
|
+
let actualNodeCount = 0;
|
|
2247
|
+
for (let node = container.firstChild;node; node = node.nextSibling)
|
|
2248
|
+
actualNodeCount++;
|
|
2249
|
+
if (actualNodeCount === expectedNodeCount) {
|
|
2250
|
+
container.textContent = "";
|
|
2251
|
+
} else {
|
|
2252
|
+
for (const scope of scopes.values())
|
|
2253
|
+
removeScope(scope);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
scopes.clear();
|
|
2257
|
+
}
|
|
2258
|
+
return;
|
|
2259
|
+
}
|
|
2154
2260
|
const newKeys = new Set;
|
|
2155
2261
|
const warnedKeys = new Set;
|
|
2156
2262
|
const desiredOrder = [];
|
|
2157
|
-
for (let
|
|
2158
|
-
const item = items[
|
|
2159
|
-
const key = getKey ? getKey(item,
|
|
2263
|
+
for (let i2 = 0;i2 < items.length; i2++) {
|
|
2264
|
+
const item = items[i2];
|
|
2265
|
+
const key = getKey ? getKey(item, i2) : String(i2);
|
|
2160
2266
|
if (newKeys.has(key) && !warnedKeys.has(key)) {
|
|
2161
2267
|
warnedKeys.add(key);
|
|
2162
2268
|
console.warn(`[BarefootJS] mapArray: duplicate key "${key}" — items with this key collapse to a single DOM scope, ` + `so only the last one renders. Use a per-item identifier (e.g. \`key={item.id}\`) for correct reconciliation.`);
|
|
@@ -2167,7 +2273,7 @@ function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
|
2167
2273
|
existing.setItem(item);
|
|
2168
2274
|
desiredOrder.push(existing);
|
|
2169
2275
|
} else {
|
|
2170
|
-
const scope = createItemScope(item,
|
|
2276
|
+
const scope = createItemScope(item, i2, renderItem);
|
|
2171
2277
|
if (!scope.primaryEl.dataset.key)
|
|
2172
2278
|
scope.primaryEl.setAttribute(BF_KEY, key);
|
|
2173
2279
|
scopes.set(key, scope);
|
|
@@ -2181,32 +2287,41 @@ function mapArray(accessor, container, getKey, renderItem, markerId, bfId) {
|
|
|
2181
2287
|
scopes.delete(key);
|
|
2182
2288
|
}
|
|
2183
2289
|
}
|
|
2184
|
-
|
|
2185
|
-
let
|
|
2186
|
-
|
|
2187
|
-
while (checkNode && checkNode.nodeType !== Node.ELEMENT_NODE)
|
|
2188
|
-
checkNode = checkNode.nextSibling;
|
|
2189
|
-
if (checkNode !== scope.primaryEl) {
|
|
2190
|
-
inOrder = false;
|
|
2191
|
-
break;
|
|
2192
|
-
}
|
|
2193
|
-
checkNode = checkNode.nextSibling;
|
|
2194
|
-
for (let i = 0;i < scope.extras.length; i++) {
|
|
2195
|
-
while (checkNode && checkNode.nodeType !== Node.ELEMENT_NODE)
|
|
2196
|
-
checkNode = checkNode.nextSibling;
|
|
2197
|
-
if (checkNode !== scope.extras[i]) {
|
|
2198
|
-
inOrder = false;
|
|
2199
|
-
break;
|
|
2200
|
-
}
|
|
2201
|
-
checkNode = checkNode.nextSibling;
|
|
2202
|
-
}
|
|
2203
|
-
if (!inOrder)
|
|
2204
|
-
break;
|
|
2290
|
+
const primaryElToDesiredIndex = new Map;
|
|
2291
|
+
for (let i2 = 0;i2 < desiredOrder.length; i2++) {
|
|
2292
|
+
primaryElToDesiredIndex.set(desiredOrder[i2].primaryEl, i2);
|
|
2205
2293
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2294
|
+
const domOrderIndices = [];
|
|
2295
|
+
for (let node = startMarker ? startMarker.nextSibling : container.firstChild;node && node !== anchor; node = node.nextSibling) {
|
|
2296
|
+
if (node.nodeType !== Node.ELEMENT_NODE)
|
|
2297
|
+
continue;
|
|
2298
|
+
const idx = primaryElToDesiredIndex.get(node);
|
|
2299
|
+
if (idx !== undefined)
|
|
2300
|
+
domOrderIndices.push(idx);
|
|
2301
|
+
}
|
|
2302
|
+
const stationary = new Array(desiredOrder.length).fill(false);
|
|
2303
|
+
for (const pos of longestIncreasingSubsequenceIndices(domOrderIndices)) {
|
|
2304
|
+
stationary[domOrderIndices[pos]] = true;
|
|
2305
|
+
}
|
|
2306
|
+
let i = 0;
|
|
2307
|
+
while (i < desiredOrder.length) {
|
|
2308
|
+
if (stationary[i]) {
|
|
2309
|
+
i++;
|
|
2310
|
+
continue;
|
|
2311
|
+
}
|
|
2312
|
+
let j = i;
|
|
2313
|
+
while (j < desiredOrder.length && !stationary[j])
|
|
2314
|
+
j++;
|
|
2315
|
+
const before = j < desiredOrder.length ? desiredOrder[j].startMarker ?? desiredOrder[j].primaryEl : anchor;
|
|
2316
|
+
if (j - i === 1) {
|
|
2317
|
+
insertScope(desiredOrder[i], container, before);
|
|
2318
|
+
} else {
|
|
2319
|
+
const runFragment = document.createDocumentFragment();
|
|
2320
|
+
for (let k = i;k < j; k++)
|
|
2321
|
+
insertScope(desiredOrder[k], runFragment, null);
|
|
2322
|
+
container.insertBefore(runFragment, before);
|
|
2209
2323
|
}
|
|
2324
|
+
i = j;
|
|
2210
2325
|
}
|
|
2211
2326
|
}, bfId);
|
|
2212
2327
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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.18.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0"
|
package/src/build.ts
CHANGED
|
@@ -58,6 +58,20 @@ export interface CSRBuildOptions {
|
|
|
58
58
|
adapter?: TemplateAdapter
|
|
59
59
|
/** Options forwarded to the default `CSRAdapter`. Ignored when `adapter` is set. */
|
|
60
60
|
adapterOptions?: CSRAdapterOptions
|
|
61
|
+
/**
|
|
62
|
+
* How the CLI produces `barefoot.js`. Defaults to `'treeshake'`, which
|
|
63
|
+
* bundles only the runtime exports this project's compiled client JS
|
|
64
|
+
* actually imports (plus the always-kept public mount API). Set to
|
|
65
|
+
* `'full'` to copy the entire prebuilt runtime bundle verbatim, matching
|
|
66
|
+
* pre-tree-shaking behavior.
|
|
67
|
+
*/
|
|
68
|
+
runtimeBundle?: 'treeshake' | 'full'
|
|
69
|
+
/**
|
|
70
|
+
* Extra `@barefootjs/client*` export names to force-keep in `barefoot.js`
|
|
71
|
+
* under `runtimeBundle: 'treeshake'` — for names only ever referenced
|
|
72
|
+
* from hand-written page scripts the CLI never compiles.
|
|
73
|
+
*/
|
|
74
|
+
runtimeKeep?: string[]
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
/**
|
|
@@ -85,6 +99,8 @@ export function createConfig(options: CSRBuildOptions = {}) {
|
|
|
85
99
|
bundleEntries: options.bundleEntries,
|
|
86
100
|
outputLayout: options.outputLayout,
|
|
87
101
|
postBuild: options.postBuild,
|
|
102
|
+
runtimeBundle: options.runtimeBundle,
|
|
103
|
+
runtimeKeep: options.runtimeKeep,
|
|
88
104
|
}
|
|
89
105
|
}
|
|
90
106
|
|