balises 0.5.0 → 0.7.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/README.md +204 -56
- package/dist/balises.esm.js +148 -129
- package/dist/balises.esm.js.map +1 -1
- package/dist/balises.iife.js +147 -129
- package/dist/balises.iife.js.map +1 -1
- package/dist/balises.iife.min.js +1 -1
- package/dist/balises.iife.min.js.map +1 -1
- package/dist/esm/async.d.ts +64 -0
- package/dist/esm/async.d.ts.map +1 -0
- package/dist/esm/async.js +201 -0
- package/dist/esm/async.js.map +1 -0
- package/dist/esm/each.d.ts +67 -0
- package/dist/esm/each.d.ts.map +1 -0
- package/dist/esm/each.js +302 -0
- package/dist/esm/each.js.map +1 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/signals/computed.d.ts +3 -0
- package/dist/esm/signals/computed.d.ts.map +1 -1
- package/dist/esm/signals/computed.js +31 -33
- package/dist/esm/signals/computed.js.map +1 -1
- package/dist/esm/signals/context.d.ts +9 -0
- package/dist/esm/signals/context.d.ts.map +1 -1
- package/dist/esm/signals/context.js +6 -0
- package/dist/esm/signals/context.js.map +1 -1
- package/dist/esm/signals/index.d.ts +1 -1
- package/dist/esm/signals/index.d.ts.map +1 -1
- package/dist/esm/signals/index.js +5 -3
- package/dist/esm/signals/index.js.map +1 -1
- package/dist/esm/signals/signal.d.ts +29 -0
- package/dist/esm/signals/signal.d.ts.map +1 -1
- package/dist/esm/signals/signal.js +46 -3
- package/dist/esm/signals/signal.js.map +1 -1
- package/dist/esm/template.d.ts +35 -41
- package/dist/esm/template.d.ts.map +1 -1
- package/dist/esm/template.js +81 -119
- package/dist/esm/template.js.map +1 -1
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<img alt="balises" src="./assets/logo.svg" width="280">
|
|
5
5
|
</picture>
|
|
6
6
|
|
|
7
|
-
### A minimal reactive HTML templating library for building websites and web components. ~
|
|
7
|
+
### A minimal reactive HTML templating library for building websites and web components. ~2.8KB gzipped.
|
|
8
8
|
|
|
9
9
|
Balises gives you reactive signals and HTML templates without the framework overhead. Works great with custom elements, vanilla JavaScript projects, or anywhere you need dynamic UIs but don't want to pull in React.
|
|
10
10
|
|
|
@@ -29,10 +29,12 @@ Ultimately it turns out that I am quite happy with the result! It is quite perfo
|
|
|
29
29
|
|
|
30
30
|
- [Installation](#installation)
|
|
31
31
|
- [Quick Start](#quick-start)
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
32
|
+
- [Function Components](#function-components)
|
|
33
|
+
- [Async Generators](#async-generators)
|
|
34
|
+
- [DOM Preservation on Restart](#dom-preservation-on-restart)
|
|
34
35
|
- [Template Syntax](#template-syntax)
|
|
35
36
|
- [Reactivity API](#reactivity-api)
|
|
37
|
+
- [Web Components](#web-components)
|
|
36
38
|
- [Tree-Shaking / Modular Imports](#tree-shaking--modular-imports)
|
|
37
39
|
- [Benchmarks](#benchmarks)
|
|
38
40
|
|
|
@@ -61,9 +63,116 @@ document.body.appendChild(fragment);
|
|
|
61
63
|
// Call dispose() when done to clean up subscriptions
|
|
62
64
|
```
|
|
63
65
|
|
|
64
|
-
##
|
|
66
|
+
## Function Components
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
The recommended way to build UIs with balises is using function components - plain functions that receive props and return templates. This pattern is simpler than web components and better for composition.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { html, store } from "balises";
|
|
72
|
+
|
|
73
|
+
// Define a reusable component as a function
|
|
74
|
+
function Counter({ state, onIncrement }) {
|
|
75
|
+
return html`
|
|
76
|
+
<div class="counter">
|
|
77
|
+
<span>Count: ${() => state.count}</span>
|
|
78
|
+
<button @click=${onIncrement}>+1</button>
|
|
79
|
+
</div>
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Create shared state
|
|
84
|
+
const state = store({ count: 0 });
|
|
85
|
+
|
|
86
|
+
// Compose components together
|
|
87
|
+
const { fragment, dispose } = html`
|
|
88
|
+
<div class="app">
|
|
89
|
+
<h1>My App</h1>
|
|
90
|
+
${Counter({ state, onIncrement: () => state.count++ })}
|
|
91
|
+
${Counter({ state, onIncrement: () => (state.count += 10) })}
|
|
92
|
+
</div>
|
|
93
|
+
`.render();
|
|
94
|
+
|
|
95
|
+
document.body.appendChild(fragment);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Pass the store itself (not individual values) so reactivity works.
|
|
99
|
+
|
|
100
|
+
Wrap expressions in functions like `${() => state.count}` to track dependencies.
|
|
101
|
+
|
|
102
|
+
## Async Generators
|
|
103
|
+
|
|
104
|
+
Async generator functions handle loading states and async data flows. The generator automatically restarts when any tracked signal changes.
|
|
105
|
+
|
|
106
|
+
**Note:** Async generators are opt-in via `balises/async` to keep the base bundle small.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { html as baseHtml, signal } from "balises";
|
|
110
|
+
import asyncPlugin from "balises/async";
|
|
111
|
+
|
|
112
|
+
const html = baseHtml.with(asyncPlugin);
|
|
113
|
+
const userId = signal(1);
|
|
114
|
+
|
|
115
|
+
html`
|
|
116
|
+
${async function* () {
|
|
117
|
+
const id = userId.value; // Track dependency - restarts when userId changes
|
|
118
|
+
|
|
119
|
+
yield html`<div class="loading">Loading...</div>`;
|
|
120
|
+
|
|
121
|
+
const user = await fetch(`/api/users/${id}`).then((r) => r.json());
|
|
122
|
+
yield html`<div class="profile">${user.name}</div>`;
|
|
123
|
+
}}
|
|
124
|
+
`.render();
|
|
125
|
+
|
|
126
|
+
// Changing userId restarts the generator automatically
|
|
127
|
+
userId.value = 2;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Async generators replace the entire yielded content on each yield. For surgical updates within a stable DOM structure, use reactive bindings (`${() => state.value}`) instead.
|
|
131
|
+
|
|
132
|
+
### DOM Preservation on Restart
|
|
133
|
+
|
|
134
|
+
When a signal changes, the generator restarts and normally replaces the DOM. To preserve existing DOM and enable surgical updates via reactive bindings, return the `settled` parameter:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { html as baseHtml, signal, store } from "balises";
|
|
138
|
+
import asyncPlugin, { type RenderedContent } from "balises/async";
|
|
139
|
+
|
|
140
|
+
const html = baseHtml.with(asyncPlugin);
|
|
141
|
+
const userId = signal(1);
|
|
142
|
+
const state = store({ user: null, loading: false });
|
|
143
|
+
|
|
144
|
+
html`
|
|
145
|
+
${async function* (settled?: RenderedContent) {
|
|
146
|
+
const id = userId.value;
|
|
147
|
+
|
|
148
|
+
if (settled) {
|
|
149
|
+
// Restart: update state, preserve existing DOM
|
|
150
|
+
state.loading = true;
|
|
151
|
+
const user = await fetch(`/api/users/${id}`).then((r) => r.json());
|
|
152
|
+
state.user = user;
|
|
153
|
+
state.loading = false;
|
|
154
|
+
return settled;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// First load: render with reactive bindings
|
|
158
|
+
yield html`<div class="skeleton">Loading...</div>`;
|
|
159
|
+
const user = await fetch(`/api/users/${id}`).then((r) => r.json());
|
|
160
|
+
state.user = user;
|
|
161
|
+
return html`
|
|
162
|
+
<div class="profile">
|
|
163
|
+
<h2>${() => state.user?.name}</h2>
|
|
164
|
+
<span>${() => (state.loading ? "Updating..." : "")}</span>
|
|
165
|
+
</div>
|
|
166
|
+
`;
|
|
167
|
+
}}
|
|
168
|
+
`.render();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The `settled` parameter is `undefined` on first run, and contains an opaque handle to the previous render on restarts. Returning it preserves existing DOM nodes and reactive bindings.
|
|
172
|
+
|
|
173
|
+
## Web Components
|
|
174
|
+
|
|
175
|
+
For reusable widgets that need encapsulation or browser-native lifecycle, balises works naturally with the Web Components API:
|
|
67
176
|
|
|
68
177
|
```ts
|
|
69
178
|
import { html, signal, effect } from "balises";
|
|
@@ -109,21 +218,6 @@ Use it in your HTML:
|
|
|
109
218
|
|
|
110
219
|
You can build entire apps this way, or just add interactive widgets to existing pages. No build step required if you use it from a CDN.
|
|
111
220
|
|
|
112
|
-
## Composable Function Components
|
|
113
|
-
|
|
114
|
-
You can also use plain functions that return templates. Pass the store and access its properties in function wrappers to keep things reactive:
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
function Counter({ state }) {
|
|
118
|
-
return html`
|
|
119
|
-
<button @click=${() => state.count++}>${() => state.count}</button>
|
|
120
|
-
`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const state = store({ count: 0 });
|
|
124
|
-
html`<div>${Counter({ state })}</div>`.render();
|
|
125
|
-
```
|
|
126
|
-
|
|
127
221
|
## Template Syntax
|
|
128
222
|
|
|
129
223
|
The `html` tagged template creates reactive DOM fragments. When you interpolate a signal, that specific part of the DOM updates automatically when the signal changes.
|
|
@@ -170,44 +264,63 @@ html`
|
|
|
170
264
|
|
|
171
265
|
### Efficient List Rendering with `each()`
|
|
172
266
|
|
|
173
|
-
When rendering lists that change frequently, use `each()` for keyed reconciliation. It caches templates by key so items can be reordered, added, or removed without recreating the DOM nodes
|
|
267
|
+
When rendering lists that change frequently, use `each()` for keyed reconciliation. It caches templates by key so items can be reordered, added, or removed without recreating the DOM nodes.
|
|
268
|
+
|
|
269
|
+
**Note:** The `each()` function is opt-in via the `balises/each` import to keep the base bundle small. Use `html.with(eachPlugin)` to enable keyed list support.
|
|
270
|
+
|
|
271
|
+
**Two forms:**
|
|
272
|
+
|
|
273
|
+
1. **Two-arg form** (object reference as key): Render receives raw item. DOM reused only when same object reference appears.
|
|
274
|
+
2. **Three-arg form** (explicit key function): Render receives `ReadonlySignal<T>`. DOM reused when keys match, even with new object references.
|
|
174
275
|
|
|
175
276
|
```ts
|
|
176
|
-
import { html, signal
|
|
277
|
+
import { html as baseHtml, signal } from "balises";
|
|
278
|
+
import eachPlugin, { each } from "balises/each";
|
|
177
279
|
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
280
|
+
const html = baseHtml.with(eachPlugin);
|
|
281
|
+
|
|
282
|
+
// Three-arg form: explicit key, receives ReadonlySignal
|
|
283
|
+
// DOM is preserved when keys match (ideal for API data)
|
|
284
|
+
const users = signal([
|
|
285
|
+
{ id: 1, name: "Alice" },
|
|
286
|
+
{ id: 2, name: "Bob" },
|
|
181
287
|
]);
|
|
182
288
|
|
|
183
289
|
html`
|
|
184
290
|
<ul>
|
|
185
291
|
${each(
|
|
186
|
-
|
|
187
|
-
(
|
|
188
|
-
(
|
|
292
|
+
users,
|
|
293
|
+
(user) => user.id,
|
|
294
|
+
(userSignal) => html`<li>${() => userSignal.value.name}</li>`,
|
|
189
295
|
)}
|
|
190
296
|
</ul>
|
|
191
297
|
`.render();
|
|
192
298
|
|
|
193
|
-
//
|
|
194
|
-
|
|
299
|
+
// Refetch from API - DOM preserved, content updated via signal
|
|
300
|
+
users.value = [
|
|
301
|
+
{ id: 1, name: "Alicia" }, // Same key, new object - DOM preserved!
|
|
302
|
+
{ id: 2, name: "Bobby" },
|
|
303
|
+
{ id: 3, name: "Carol" }, // New key - new DOM created
|
|
304
|
+
];
|
|
195
305
|
|
|
196
|
-
//
|
|
197
|
-
items
|
|
306
|
+
// Two-arg form: object reference as key, receives raw item
|
|
307
|
+
const items = signal([{ name: "Item 1" }, { name: "Item 2" }]);
|
|
198
308
|
|
|
199
|
-
|
|
200
|
-
|
|
309
|
+
html`
|
|
310
|
+
<ul>
|
|
311
|
+
${each(items, (item) => html`<li>${item.name}</li>`)}
|
|
312
|
+
</ul>
|
|
313
|
+
`.render();
|
|
201
314
|
```
|
|
202
315
|
|
|
203
316
|
Signatures:
|
|
204
317
|
|
|
205
318
|
```ts
|
|
206
|
-
each(list, keyFn, renderFn); //
|
|
207
|
-
each(list, renderFn); //
|
|
319
|
+
each(list, keyFn, renderFn); // Three-arg: keyFn extracts key, renderFn receives ReadonlySignal<T>
|
|
320
|
+
each(list, renderFn); // Two-arg: object reference as key, renderFn receives raw T
|
|
208
321
|
```
|
|
209
322
|
|
|
210
|
-
|
|
323
|
+
**Important:** When using the three-arg form, access item properties through `itemSignal.value` and wrap in `() => ...` for reactive updates.
|
|
211
324
|
|
|
212
325
|
## Reactivity API
|
|
213
326
|
|
|
@@ -235,6 +348,16 @@ count.value = count.value + 1;
|
|
|
235
348
|
count.value = count.value * 2;
|
|
236
349
|
```
|
|
237
350
|
|
|
351
|
+
**Reading without tracking dependencies:**
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
const count = signal(0);
|
|
355
|
+
|
|
356
|
+
// peek() reads without creating a dependency
|
|
357
|
+
// Useful in event handlers where you don't want reactivity
|
|
358
|
+
button.onclick = () => console.log(count.peek());
|
|
359
|
+
```
|
|
360
|
+
|
|
238
361
|
### `computed<T>(fn)`
|
|
239
362
|
|
|
240
363
|
Derives a value from other signals. Automatically tracks dependencies.
|
|
@@ -414,7 +537,7 @@ doubled.dispose(); // Stops tracking, frees memory
|
|
|
414
537
|
You can import just what you need to keep bundle size down:
|
|
415
538
|
|
|
416
539
|
```ts
|
|
417
|
-
// Full library (~
|
|
540
|
+
// Full library (~2.8KB gzipped)
|
|
418
541
|
import { html, signal, computed, effect } from "balises";
|
|
419
542
|
|
|
420
543
|
// Signals only (no HTML templating - use in any JS project)
|
|
@@ -428,6 +551,31 @@ import { store } from "balises/signals/store";
|
|
|
428
551
|
import { batch, scope } from "balises/signals/context";
|
|
429
552
|
```
|
|
430
553
|
|
|
554
|
+
### Template Plugins
|
|
555
|
+
|
|
556
|
+
The `each()` and async generator features are provided as opt-in plugins to keep the base bundle minimal. Use `html.with()` to compose plugins:
|
|
557
|
+
|
|
558
|
+
```ts
|
|
559
|
+
// With each() support for keyed lists
|
|
560
|
+
import { html as baseHtml } from "balises";
|
|
561
|
+
import eachPlugin, { each } from "balises/each";
|
|
562
|
+
|
|
563
|
+
const html = baseHtml.with(eachPlugin);
|
|
564
|
+
|
|
565
|
+
// With async generator support
|
|
566
|
+
import { html as baseHtml } from "balises";
|
|
567
|
+
import asyncPlugin from "balises/async";
|
|
568
|
+
|
|
569
|
+
const html = baseHtml.with(asyncPlugin);
|
|
570
|
+
|
|
571
|
+
// With both plugins
|
|
572
|
+
import { html as baseHtml } from "balises";
|
|
573
|
+
import eachPlugin, { each } from "balises/each";
|
|
574
|
+
import asyncPlugin from "balises/async";
|
|
575
|
+
|
|
576
|
+
const html = baseHtml.with(eachPlugin, asyncPlugin);
|
|
577
|
+
```
|
|
578
|
+
|
|
431
579
|
### Using as a Standalone Signals Library
|
|
432
580
|
|
|
433
581
|
The reactivity system is completely independent of the HTML templating. You can use just the signals in Node.js, Electron, or any JavaScript environment:
|
|
@@ -541,23 +689,23 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
541
689
|
┌───────┬───────────────────┬───────┬───────────────┬──────────────────┐
|
|
542
690
|
│ Rank │ Library │ Score │ Avg Time (μs) │ vs Fastest │
|
|
543
691
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
544
|
-
│ #1 🏆 │ preact@1.12.1 │ 0.000 │
|
|
692
|
+
│ #1 🏆 │ preact@1.12.1 │ 0.000 │ 63.51 │ 1.00x (baseline) │
|
|
545
693
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
546
|
-
│ #2 │ balises@0.
|
|
694
|
+
│ #2 │ balises@0.6.0 │ 0.023 │ 86.17 │ 1.36x │
|
|
547
695
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
548
|
-
│ #3 │ vue@3.5.26 │ 0.
|
|
696
|
+
│ #3 │ vue@3.5.26 │ 0.093 │ 95.06 │ 1.50x │
|
|
549
697
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
550
|
-
│ #4 │ maverick@6.0.0 │ 0.
|
|
698
|
+
│ #4 │ maverick@6.0.0 │ 0.143 │ 122.79 │ 1.93x │
|
|
551
699
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
552
|
-
│ #5 │ usignal@0.10.0 │ 0.
|
|
700
|
+
│ #5 │ usignal@0.10.0 │ 0.180 │ 134.11 │ 2.11x │
|
|
553
701
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
554
|
-
│ #6 │ angular@19.2.17 │ 0.
|
|
702
|
+
│ #6 │ angular@19.2.17 │ 0.201 │ 154.19 │ 2.43x │
|
|
555
703
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
556
|
-
│ #7 │ solid@1.9.10 │ 0.
|
|
704
|
+
│ #7 │ solid@1.9.10 │ 0.340 │ 260.44 │ 4.10x │
|
|
557
705
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
558
|
-
│ #8 │ mobx@6.15.0 │ 0.
|
|
706
|
+
│ #8 │ mobx@6.15.0 │ 0.857 │ 896.48 │ 14.12x │
|
|
559
707
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
560
|
-
│ #9 │ hyperactiv@0.11.3 │ 1.000 │
|
|
708
|
+
│ #9 │ hyperactiv@0.11.3 │ 1.000 │ 1029.95 │ 16.22x │
|
|
561
709
|
└───────┴───────────────────┴───────┴───────────────┴──────────────────┘
|
|
562
710
|
```
|
|
563
711
|
|
|
@@ -567,21 +715,21 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
567
715
|
┌───────────────────┬───────────────┬─────────────┬────────────────┬────────────────────┬─────────────┬──────────────┬──────────┐
|
|
568
716
|
│ Library │ S1: 1: Layers │ S2: 2: Wide │ S3: 3: Diamond │ S4: 4: Conditional │ S5: 5: List │ S6: 6: Batch │ Avg Rank │
|
|
569
717
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
570
|
-
│ preact@1.12.1 │ #1 🏆 │ #
|
|
718
|
+
│ preact@1.12.1 │ #1 🏆 │ #2 │ #2 │ #1 🏆 │ #1 🏆 │ #2 │ 1.5 │
|
|
571
719
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
572
|
-
│ balises@0.
|
|
720
|
+
│ balises@0.6.0 │ #3 │ #1 🏆 │ #1 🏆 │ #2 │ #2 │ #1 🏆 │ 1.7 │
|
|
573
721
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
574
|
-
│ vue@3.5.26 │ #
|
|
722
|
+
│ vue@3.5.26 │ #2 │ #3 │ #5 │ #3 │ #3 │ #5 │ 3.5 │
|
|
575
723
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
576
|
-
│ maverick@6.0.0 │ #
|
|
724
|
+
│ maverick@6.0.0 │ #5 │ #5 │ #4 │ #4 │ #4 │ #4 │ 4.3 │
|
|
577
725
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
578
|
-
│ usignal@0.10.0 │ #
|
|
726
|
+
│ usignal@0.10.0 │ #4 │ #4 │ #3 │ #5 │ #8 │ #7 │ 5.2 │
|
|
579
727
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
580
|
-
│ angular@19.2.17 │ #6 │ #6 │ #
|
|
728
|
+
│ angular@19.2.17 │ #6 │ #6 │ #6 │ #6 │ #5 │ #3 │ 5.3 │
|
|
581
729
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
582
|
-
│ solid@1.9.10 │ #7 │ #8 │ #
|
|
730
|
+
│ solid@1.9.10 │ #7 │ #8 │ #7 │ #7 │ #7 │ #6 │ 7.0 │
|
|
583
731
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
584
|
-
│ mobx@6.15.0 │ #9 │ #7 │ #8 │ #8 │ #
|
|
732
|
+
│ mobx@6.15.0 │ #9 │ #7 │ #8 │ #8 │ #6 │ #8 │ 7.7 │
|
|
585
733
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
586
734
|
│ hyperactiv@0.11.3 │ #8 │ #9 │ #9 │ #9 │ #9 │ #9 │ 8.8 │
|
|
587
735
|
└───────────────────┴───────────────┴─────────────┴────────────────┴────────────────────┴─────────────┴──────────────┴──────────┘
|
|
@@ -602,7 +750,7 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
602
750
|
- These are synthetic benchmarks measuring pure reactivity - real apps should consider the whole picture (ecosystem, docs, community, etc.)
|
|
603
751
|
- Lower rank = better performance
|
|
604
752
|
|
|
605
|
-
_Last updated: 2026-01-
|
|
753
|
+
_Last updated: 2026-01-04_
|
|
606
754
|
|
|
607
755
|
<!-- BENCHMARK_RESULTS_END -->
|
|
608
756
|
|