@signaltree/core 2.0.3 → 3.0.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 +175 -134
- package/fesm2022/signaltree-core.mjs +1 -1
- package/fesm2022/signaltree-core.mjs.map +1 -1
- package/index.d.ts +15 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Foundation package for SignalTree. Provides recursive typing, deep nesting suppo
|
|
|
4
4
|
|
|
5
5
|
## What is @signaltree/core?
|
|
6
6
|
|
|
7
|
-
SignalTree Core is a lightweight
|
|
7
|
+
SignalTree Core is a lightweight package that provides:
|
|
8
8
|
|
|
9
9
|
- Recursive typing with deep nesting and accurate type inference
|
|
10
10
|
- Fast operations with sub‑millisecond measurements at 5–20+ levels
|
|
@@ -13,18 +13,42 @@ SignalTree Core is a lightweight (about 7.20KB gzipped) package that provides:
|
|
|
13
13
|
- Small API surface with zero-cost abstractions
|
|
14
14
|
- Compact bundle size suited for production
|
|
15
15
|
|
|
16
|
-
###
|
|
16
|
+
### Callable leaf signals (DX sugar only)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
SignalTree provides TypeScript support for callable syntax on leaf signals as developer experience sugar:
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
```typescript
|
|
21
|
+
// TypeScript accepts this syntax (with proper tooling):
|
|
22
|
+
tree.$.name('Jane'); // Set value
|
|
23
|
+
tree.$.count((n) => n + 1); // Update with function
|
|
24
|
+
|
|
25
|
+
// At build time, transforms convert to:
|
|
26
|
+
tree.$.name.set('Jane'); // Direct Angular signal API
|
|
27
|
+
tree.$.count.update((n) => n + 1); // Direct Angular signal API
|
|
28
|
+
|
|
29
|
+
// Reading always works directly:
|
|
30
|
+
const name = tree.$.name(); // No transform needed
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Key Points:**
|
|
34
|
+
|
|
35
|
+
- **Zero runtime overhead**: No Proxy wrappers or runtime hooks
|
|
36
|
+
- **Build-time only**: AST transform converts callable syntax to direct `.set/.update` calls
|
|
37
|
+
- **Optional**: Use `@signaltree/callable-syntax` transform or stick with direct `.set/.update`
|
|
38
|
+
- **Type-safe**: Full TypeScript support via module augmentation
|
|
39
|
+
|
|
40
|
+
**Function-valued leaves:**
|
|
41
|
+
When a leaf stores a function as its value, use direct `.set(fn)` to assign. Callable `sig(fn)` is treated as an updater.
|
|
42
|
+
|
|
43
|
+
**Setup:**
|
|
44
|
+
Install `@signaltree/callable-syntax` and configure your build tool to apply the transform. Without the transform, use `.set/.update` directly.
|
|
45
|
+
|
|
46
|
+
### Measuring performance and size
|
|
26
47
|
|
|
27
|
-
|
|
48
|
+
Performance and bundle size vary by app shape, build tooling, device, and runtime. To get meaningful results for your environment:
|
|
49
|
+
|
|
50
|
+
- Use the **Benchmark Orchestrator** in the demo app to run calibrated, scenario-based benchmarks across supported libraries with **real-world frequency weighting**. It applies research-based multipliers derived from 40,000+ developer surveys and GitHub analysis, reports statistical summaries (median/p95/p99/stddev), alternates runs to reduce bias, and can export CSV/JSON. When available, memory usage is also reported.
|
|
51
|
+
- Use the bundle analysis scripts in `scripts/` to measure your min+gz sizes. Sizes are approximate and depend on tree-shaking and configuration.
|
|
28
52
|
|
|
29
53
|
## Quick start
|
|
30
54
|
|
|
@@ -58,7 +82,6 @@ const tree = signalTree({
|
|
|
58
82
|
tests: {
|
|
59
83
|
extreme: {
|
|
60
84
|
depth: 15,
|
|
61
|
-
performance: 0.098, // ms (averaged)
|
|
62
85
|
typeInference: true,
|
|
63
86
|
},
|
|
64
87
|
},
|
|
@@ -79,9 +102,8 @@ const tree = signalTree({
|
|
|
79
102
|
});
|
|
80
103
|
|
|
81
104
|
// Type inference at deep nesting levels
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
console.log(`Performance: ${performance}ms`); // ~0.098ms (averaged)
|
|
105
|
+
const depth = tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth();
|
|
106
|
+
console.log(`Depth: ${depth}`);
|
|
85
107
|
|
|
86
108
|
// Type-safe updates at unlimited depth
|
|
87
109
|
tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth(25); // Perfect type safety!
|
|
@@ -159,6 +181,99 @@ effect(() => {
|
|
|
159
181
|
});
|
|
160
182
|
```
|
|
161
183
|
|
|
184
|
+
### Reactive computations with computed()
|
|
185
|
+
|
|
186
|
+
SignalTree works seamlessly with Angular's `computed()` for creating efficient reactive computations. These computations automatically update when their dependencies change and are memoized for optimal performance.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { computed, effect } from '@angular/core';
|
|
190
|
+
import { signalTree } from '@signaltree/core';
|
|
191
|
+
|
|
192
|
+
const tree = signalTree({
|
|
193
|
+
users: [
|
|
194
|
+
{ id: '1', name: 'Alice', active: true, role: 'admin' },
|
|
195
|
+
{ id: '2', name: 'Bob', active: false, role: 'user' },
|
|
196
|
+
{ id: '3', name: 'Charlie', active: true, role: 'user' },
|
|
197
|
+
],
|
|
198
|
+
filters: {
|
|
199
|
+
showActive: true,
|
|
200
|
+
role: 'all' as 'all' | 'admin' | 'user',
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Basic computed - automatically memoized
|
|
205
|
+
const userCount = computed(() => tree.$.users().length);
|
|
206
|
+
|
|
207
|
+
// Complex filtering computation
|
|
208
|
+
const filteredUsers = computed(() => {
|
|
209
|
+
const users = tree.$.users();
|
|
210
|
+
const filters = tree.$.filters();
|
|
211
|
+
|
|
212
|
+
return users.filter((user) => {
|
|
213
|
+
if (filters.showActive && !user.active) return false;
|
|
214
|
+
if (filters.role !== 'all' && user.role !== filters.role) return false;
|
|
215
|
+
return true;
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Derived computation from other computed values
|
|
220
|
+
const activeAdminCount = computed(() => filteredUsers().filter((user) => user.role === 'admin' && user.active).length);
|
|
221
|
+
|
|
222
|
+
// Performance-critical computation with complex logic
|
|
223
|
+
const userStatistics = computed(() => {
|
|
224
|
+
const users = tree.$.users();
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
total: users.length,
|
|
228
|
+
active: users.filter((u) => u.active).length,
|
|
229
|
+
admins: users.filter((u) => u.role === 'admin').length,
|
|
230
|
+
averageNameLength: users.reduce((acc, u) => acc + u.name.length, 0) / users.length,
|
|
231
|
+
};
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Dynamic computed functions (factory pattern)
|
|
235
|
+
const userById = (id: string) => computed(() => tree.$.users().find((user) => user.id === id));
|
|
236
|
+
|
|
237
|
+
// Usage in effects
|
|
238
|
+
effect(() => {
|
|
239
|
+
console.log(`Filtered users: ${filteredUsers().length}`);
|
|
240
|
+
console.log(`Statistics:`, userStatistics());
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Best Practices:
|
|
244
|
+
// 1. Use computed() for derived state that depends on signals
|
|
245
|
+
// 2. Keep computations pure - no side effects
|
|
246
|
+
// 3. Leverage automatic memoization for expensive operations
|
|
247
|
+
// 4. Chain computed values for complex transformations
|
|
248
|
+
// 5. Use factory functions for parameterized computations
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Performance optimization with memoization
|
|
252
|
+
|
|
253
|
+
When combined with `@signaltree/memoization`, computed values become even more powerful:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { withMemoization } from '@signaltree/memoization';
|
|
257
|
+
|
|
258
|
+
const tree = signalTree({
|
|
259
|
+
items: Array.from({ length: 10000 }, (_, i) => ({
|
|
260
|
+
id: i,
|
|
261
|
+
value: Math.random(),
|
|
262
|
+
category: `cat-${i % 10}`,
|
|
263
|
+
})),
|
|
264
|
+
}).with(withMemoization());
|
|
265
|
+
|
|
266
|
+
// Expensive computation - automatically cached by memoization enhancer
|
|
267
|
+
const expensiveComputation = computed(() => {
|
|
268
|
+
return tree.$.items()
|
|
269
|
+
.filter((item) => item.value > 0.5)
|
|
270
|
+
.reduce((acc, item) => acc + Math.sin(item.value * Math.PI), 0);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// The computation only runs when tree.$.items() actually changes
|
|
274
|
+
// Subsequent calls return cached result
|
|
275
|
+
```
|
|
276
|
+
|
|
162
277
|
### Advanced usage (full state tree)
|
|
163
278
|
|
|
164
279
|
```typescript
|
|
@@ -300,7 +415,7 @@ const activeUsers = computed(() => tree.$.users().filter((user) => user.active))
|
|
|
300
415
|
|
|
301
416
|
### 4) Manual async state management
|
|
302
417
|
|
|
303
|
-
Core provides basic state updates - async helpers
|
|
418
|
+
Core provides basic state updates - async helpers are now provided via `@signaltree/middleware` helpers:
|
|
304
419
|
|
|
305
420
|
```typescript
|
|
306
421
|
const tree = signalTree({
|
|
@@ -353,25 +468,25 @@ SignalTree Core provides the foundation, but its real power comes from composabl
|
|
|
353
468
|
|
|
354
469
|
**Performance Enhancers:**
|
|
355
470
|
|
|
356
|
-
- `@signaltree/batching`
|
|
357
|
-
- `@signaltree/memoization`
|
|
471
|
+
- `@signaltree/batching` - Batch updates to reduce recomputation and rendering
|
|
472
|
+
- `@signaltree/memoization` - Intelligent caching for expensive computations
|
|
358
473
|
|
|
359
474
|
**Data Management:**
|
|
360
475
|
|
|
361
|
-
- `@signaltree/entities`
|
|
362
|
-
- `@signaltree/
|
|
363
|
-
- `@signaltree/serialization`
|
|
476
|
+
- `@signaltree/entities` - Advanced CRUD operations for collections
|
|
477
|
+
- Async helpers are provided via `@signaltree/middleware` (createAsyncOperation / trackAsync)
|
|
478
|
+
- `@signaltree/serialization` - State persistence and SSR support
|
|
364
479
|
|
|
365
480
|
**Development Tools:**
|
|
366
481
|
|
|
367
|
-
- `@signaltree/devtools`
|
|
368
|
-
- `@signaltree/time-travel`
|
|
482
|
+
- `@signaltree/devtools` - Redux DevTools integration
|
|
483
|
+
- `@signaltree/time-travel` - Undo/redo functionality
|
|
369
484
|
|
|
370
485
|
**Integration:**
|
|
371
486
|
|
|
372
|
-
- `@signaltree/ng-forms`
|
|
373
|
-
- `@signaltree/middleware`
|
|
374
|
-
- `@signaltree/presets`
|
|
487
|
+
- `@signaltree/ng-forms` - Angular Forms integration
|
|
488
|
+
- `@signaltree/middleware` - State interceptors and logging
|
|
489
|
+
- `@signaltree/presets` - Pre-configured common patterns
|
|
375
490
|
|
|
376
491
|
#### Composition Patterns
|
|
377
492
|
|
|
@@ -418,7 +533,6 @@ products.selectBy((p) => p.category === 'electronics');
|
|
|
418
533
|
**Full-Stack Application:**
|
|
419
534
|
|
|
420
535
|
```typescript
|
|
421
|
-
import { withAsync } from '@signaltree/async';
|
|
422
536
|
import { withSerialization } from '@signaltree/serialization';
|
|
423
537
|
import { withTimeTravel } from '@signaltree/time-travel';
|
|
424
538
|
|
|
@@ -426,7 +540,7 @@ const tree = signalTree({
|
|
|
426
540
|
user: null as User | null,
|
|
427
541
|
preferences: { theme: 'light' },
|
|
428
542
|
}).with(
|
|
429
|
-
withAsync
|
|
543
|
+
// withAsync removed — API integration patterns are now covered by middleware helpers
|
|
430
544
|
withSerialization({
|
|
431
545
|
// Auto-save to localStorage
|
|
432
546
|
autoSave: true,
|
|
@@ -642,7 +756,7 @@ SignalTree Core is designed for modular composition. Start minimal and add featu
|
|
|
642
756
|
```typescript
|
|
643
757
|
import { signalTree } from '@signaltree/core';
|
|
644
758
|
|
|
645
|
-
// Core provides the foundation
|
|
759
|
+
// Core provides the foundation
|
|
646
760
|
const tree = signalTree({
|
|
647
761
|
users: [] as User[],
|
|
648
762
|
ui: { loading: false },
|
|
@@ -661,13 +775,13 @@ import { signalTree } from '@signaltree/core';
|
|
|
661
775
|
import { withBatching } from '@signaltree/batching';
|
|
662
776
|
import { withMemoization } from '@signaltree/memoization';
|
|
663
777
|
|
|
664
|
-
// Add performance optimizations
|
|
778
|
+
// Add performance optimizations
|
|
665
779
|
const tree = signalTree({
|
|
666
780
|
products: [] as Product[],
|
|
667
781
|
filters: { category: '', search: '' },
|
|
668
782
|
}).with(
|
|
669
|
-
withBatching(), //
|
|
670
|
-
withMemoization() //
|
|
783
|
+
withBatching(), // Batch updates for optimal rendering
|
|
784
|
+
withMemoization() // Cache expensive computations
|
|
671
785
|
);
|
|
672
786
|
|
|
673
787
|
// Now supports batched updates
|
|
@@ -689,7 +803,6 @@ const filteredProducts = computed(() => {
|
|
|
689
803
|
```typescript
|
|
690
804
|
import { signalTree } from '@signaltree/core';
|
|
691
805
|
import { withEntities } from '@signaltree/entities';
|
|
692
|
-
import { withAsync } from '@signaltree/async';
|
|
693
806
|
|
|
694
807
|
// Add data management capabilities (+2.77KB total)
|
|
695
808
|
const tree = signalTree({
|
|
@@ -697,8 +810,7 @@ const tree = signalTree({
|
|
|
697
810
|
posts: [] as Post[],
|
|
698
811
|
ui: { loading: false, error: null },
|
|
699
812
|
}).with(
|
|
700
|
-
withEntities()
|
|
701
|
-
withAsync() // Async state management
|
|
813
|
+
withEntities() // Advanced CRUD operations
|
|
702
814
|
);
|
|
703
815
|
|
|
704
816
|
// Advanced entity operations
|
|
@@ -721,12 +833,11 @@ const fetchUsers = tree.asyncAction(async () => api.getUsers(), {
|
|
|
721
833
|
import { signalTree } from '@signaltree/core';
|
|
722
834
|
import { withBatching } from '@signaltree/batching';
|
|
723
835
|
import { withEntities } from '@signaltree/entities';
|
|
724
|
-
import { withAsync } from '@signaltree/async';
|
|
725
836
|
import { withSerialization } from '@signaltree/serialization';
|
|
726
837
|
import { withTimeTravel } from '@signaltree/time-travel';
|
|
727
838
|
import { withDevtools } from '@signaltree/devtools';
|
|
728
839
|
|
|
729
|
-
// Full development stack (
|
|
840
|
+
// Full development stack (example)
|
|
730
841
|
const tree = signalTree({
|
|
731
842
|
app: {
|
|
732
843
|
user: null as User | null,
|
|
@@ -736,7 +847,7 @@ const tree = signalTree({
|
|
|
736
847
|
}).with(
|
|
737
848
|
withBatching(), // Performance
|
|
738
849
|
withEntities(), // Data management
|
|
739
|
-
withAsync
|
|
850
|
+
// withAsync removed — use middleware helpers for API integration
|
|
740
851
|
withSerialization({
|
|
741
852
|
// State persistence
|
|
742
853
|
autoSave: true,
|
|
@@ -766,14 +877,13 @@ tree.save(); // Persistence
|
|
|
766
877
|
import { signalTree } from '@signaltree/core';
|
|
767
878
|
import { withBatching } from '@signaltree/batching';
|
|
768
879
|
import { withEntities } from '@signaltree/entities';
|
|
769
|
-
import { withAsync } from '@signaltree/async';
|
|
770
880
|
import { withSerialization } from '@signaltree/serialization';
|
|
771
881
|
|
|
772
882
|
// Production build (no dev tools)
|
|
773
883
|
const tree = signalTree(initialState).with(
|
|
774
884
|
withBatching(), // Performance optimization
|
|
775
885
|
withEntities(), // Data management
|
|
776
|
-
withAsync
|
|
886
|
+
// withAsync removed — use middleware helpers for API integration
|
|
777
887
|
withSerialization({
|
|
778
888
|
// User preferences
|
|
779
889
|
autoSave: true,
|
|
@@ -829,16 +939,9 @@ const dashboardTree = dashboardPreset({
|
|
|
829
939
|
// Includes: batching, memoization, devtools
|
|
830
940
|
```
|
|
831
941
|
|
|
832
|
-
###
|
|
942
|
+
### Measuring bundle size
|
|
833
943
|
|
|
834
|
-
|
|
835
|
-
| ------------------------ | ----------- | ------------------------------ |
|
|
836
|
-
| Core only | 7.25KB | Simple state, prototypes |
|
|
837
|
-
| + Batching + Memoization | 10.32KB | Performance-critical apps |
|
|
838
|
-
| + Entities + Async | 13.09KB | Data-driven applications |
|
|
839
|
-
| + Serialization | 17.71KB | Persistent state, SSR |
|
|
840
|
-
| + DevTools + TimeTravel | 21.95KB | Development (disabled in prod) |
|
|
841
|
-
| Full ecosystem | 27.55KB | Feature-rich applications |
|
|
944
|
+
Bundle sizes depend on your build, tree-shaking, and which enhancers you include. Use the scripts in `scripts/` to analyze min+gz for your configuration.
|
|
842
945
|
|
|
843
946
|
### Migration Strategy
|
|
844
947
|
|
|
@@ -855,7 +958,7 @@ const tree2 = tree.with(withBatching());
|
|
|
855
958
|
const tree3 = tree2.with(withEntities());
|
|
856
959
|
|
|
857
960
|
// Phase 4: Add async for API integration
|
|
858
|
-
|
|
961
|
+
// withAsync removed — no explicit async enhancer; use middleware helpers instead
|
|
859
962
|
|
|
860
963
|
// Each phase is fully functional and production-ready
|
|
861
964
|
```
|
|
@@ -910,71 +1013,9 @@ class AppStateService {
|
|
|
910
1013
|
}
|
|
911
1014
|
```
|
|
912
1015
|
|
|
913
|
-
##
|
|
914
|
-
|
|
915
|
-
> Sub‑millisecond operations across common core functions
|
|
916
|
-
|
|
917
|
-
### Recursive depth scaling (illustrative)
|
|
1016
|
+
## Measuring performance
|
|
918
1017
|
|
|
919
|
-
|
|
920
|
-
| -------------------------- | ------------------ | ------------------ | ------------------ | ---------------- |
|
|
921
|
-
| **Basic (5 levels)** | 0.012ms | 1.0x (baseline) | ✅ Perfect | ~1.1MB |
|
|
922
|
-
| **Medium (10 levels)** | 0.015ms | 1.25x | ✅ Perfect | ~1.2MB |
|
|
923
|
-
| **Extreme (15 levels)** | **0.021ms** | **1.75x** | ✅ Perfect | ~1.3MB |
|
|
924
|
-
| **Unlimited (20+ levels)** | 0.023ms | 1.92x | ✅ Perfect | ~1.4MB |
|
|
925
|
-
|
|
926
|
-
Note: Scaling depends on state shape and hardware.
|
|
927
|
-
|
|
928
|
-
### Example operation timings
|
|
929
|
-
|
|
930
|
-
| Operation | SignalTree Core | Notes |
|
|
931
|
-
| --------------------------- | --------------- | ---------------- |
|
|
932
|
-
| Tree initialization (small) | **0.031ms** | 27 nodes |
|
|
933
|
-
| Tree initialization (large) | **0.745ms** | 341 nodes |
|
|
934
|
-
| Single update | **0.188ms** | Property update |
|
|
935
|
-
| Nested update (5 levels) | **0.188ms** | Deep tree update |
|
|
936
|
-
| Computation (cached) | **0.094ms** | Memoized result |
|
|
937
|
-
| Memory per 1K entities | **1.2MB** | Measured usage |
|
|
938
|
-
|
|
939
|
-
### Feature impact
|
|
940
|
-
|
|
941
|
-
| Feature | SignalTree Core | With Extensions | Notes |
|
|
942
|
-
| ------------------- | ------------------ | ---------------------- | ---------------------- |
|
|
943
|
-
| Batching efficiency | Standard | **455.8x improvement** | vs non-batched |
|
|
944
|
-
| Memoization speedup | Basic | **197.9x speedup** | vs non-memoized |
|
|
945
|
-
| Memory efficiency | **Optimized** | **Further optimized** | Lazy signals + cleanup |
|
|
946
|
-
| Bundle impact | **7.25KB gzipped** | **+20KB max** | Tree-shakeable |
|
|
947
|
-
|
|
948
|
-
### Developer experience (core)
|
|
949
|
-
|
|
950
|
-
| Metric | SignalTree Core | Traditional State Mgmt | **Improvement** |
|
|
951
|
-
| ----------------------- | --------------- | ---------------------- | --------------- |
|
|
952
|
-
| Lines of code (counter) | **4 lines** | 18-32 lines | **68-88% less** |
|
|
953
|
-
| Files required | **1 file** | 3-4 files | **75% fewer** |
|
|
954
|
-
| Setup complexity | **Minimal** | Complex | **Simplified** |
|
|
955
|
-
| API surface | **Small** | Large | **Focused** |
|
|
956
|
-
|
|
957
|
-
### Memory usage comparison
|
|
958
|
-
|
|
959
|
-
| Operation | SignalTree Core | NgRx | Akita | Native Signals |
|
|
960
|
-
| ------------------------ | --------------- | ------ | ------ | -------------- |
|
|
961
|
-
| 1K entities | 1.2MB | 4.2MB | 3.5MB | 2.3MB |
|
|
962
|
-
| 10K entities | 8.1MB | 28.5MB | 22.1MB | 15.2MB |
|
|
963
|
-
| Deep nesting (10 levels) | 145KB | 890KB | 720KB | 340KB |
|
|
964
|
-
|
|
965
|
-
### TypeScript inference speed
|
|
966
|
-
|
|
967
|
-
```typescript
|
|
968
|
-
// SignalTree: Instant inference
|
|
969
|
-
const tree = signalTree({
|
|
970
|
-
deeply: { nested: { state: { with: { types: 'instant' } } } }
|
|
971
|
-
});
|
|
972
|
-
tree.$.deeply.nested.state.with.types.set('updated'); // ✅ <1ms
|
|
973
|
-
|
|
974
|
-
// Manual typing required with other solutions
|
|
975
|
-
interface State { deeply: { nested: { state: { with: { types: string } } } } }
|
|
976
|
-
const store: Store<State> = ...; // Requires manual interface definition
|
|
977
|
-
```
|
|
1018
|
+
For fair, reproducible measurements that reflect your app and hardware, use the **Benchmark Orchestrator** in the demo. It calibrates runs per scenario and library, applies **real-world frequency weighting** based on research analysis, reports robust statistics, and supports CSV/JSON export. Avoid copying fixed numbers from docs; results vary.
|
|
978
1019
|
|
|
979
1020
|
## Example
|
|
980
1021
|
|
|
@@ -1204,7 +1245,7 @@ tree.destroy(); // Cleanup resources
|
|
|
1204
1245
|
|
|
1205
1246
|
// Extended features (require additional packages)
|
|
1206
1247
|
tree.entities<T>(key); // Entity helpers (requires @signaltree/entities)
|
|
1207
|
-
tree.asyncAction(fn, config?)
|
|
1248
|
+
// tree.asyncAction(fn, config?) example removed — use middleware helpers instead
|
|
1208
1249
|
tree.asyncAction(fn, config?); // Create async action
|
|
1209
1250
|
```
|
|
1210
1251
|
|
|
@@ -1224,16 +1265,16 @@ const tree = signalTree(initialState).with(withBatching(), withMemoization(), wi
|
|
|
1224
1265
|
|
|
1225
1266
|
### Available extensions
|
|
1226
1267
|
|
|
1227
|
-
- **@signaltree/batching**
|
|
1228
|
-
- **@signaltree/memoization**
|
|
1229
|
-
- **@signaltree/middleware**
|
|
1230
|
-
-
|
|
1231
|
-
- **@signaltree/entities**
|
|
1232
|
-
- **@signaltree/devtools**
|
|
1233
|
-
- **@signaltree/time-travel**
|
|
1234
|
-
- **@signaltree/ng-forms**
|
|
1235
|
-
- **@signaltree/serialization**
|
|
1236
|
-
- **@signaltree/presets**
|
|
1268
|
+
- **@signaltree/batching** - Batch multiple updates
|
|
1269
|
+
- **@signaltree/memoization** - Intelligent caching & performance
|
|
1270
|
+
- **@signaltree/middleware** - Middleware system & taps
|
|
1271
|
+
- Async helpers moved to `@signaltree/middleware` - advanced async operations & loading states
|
|
1272
|
+
- **@signaltree/entities** - Advanced entity management
|
|
1273
|
+
- **@signaltree/devtools** - Redux DevTools integration
|
|
1274
|
+
- **@signaltree/time-travel** - Undo/redo functionality
|
|
1275
|
+
- **@signaltree/ng-forms** - Complete Angular forms integration
|
|
1276
|
+
- **@signaltree/serialization** - State persistence & SSR support
|
|
1277
|
+
- **@signaltree/presets** - Environment-based configurations
|
|
1237
1278
|
|
|
1238
1279
|
## When to use core only
|
|
1239
1280
|
|
|
@@ -1284,7 +1325,7 @@ async loadUsers() {
|
|
|
1284
1325
|
}
|
|
1285
1326
|
}
|
|
1286
1327
|
|
|
1287
|
-
// Or use async actions
|
|
1328
|
+
// Or use middleware helpers for async actions (createAsyncOperation / trackAsync)
|
|
1288
1329
|
loadUsers = tree.asyncAction(() => api.getUsers(), {
|
|
1289
1330
|
onSuccess: (users) => ({ users }),
|
|
1290
1331
|
});
|
|
@@ -1367,23 +1408,23 @@ Extend the core with optional feature packages:
|
|
|
1367
1408
|
### Performance & Optimization
|
|
1368
1409
|
|
|
1369
1410
|
- **[@signaltree/batching](../batching)** (+1.27KB gzipped) - Batch multiple updates for better performance
|
|
1370
|
-
- **[@signaltree/memoization](../memoization)** (+
|
|
1411
|
+
- **[@signaltree/memoization](../memoization)** (+2.33KB gzipped) - Intelligent caching & performance optimization
|
|
1371
1412
|
|
|
1372
1413
|
### Advanced Features
|
|
1373
1414
|
|
|
1374
|
-
- **[@signaltree/middleware](../middleware)** (+1.
|
|
1375
|
-
-
|
|
1376
|
-
- **[@signaltree/entities](../entities)** (+
|
|
1415
|
+
- **[@signaltree/middleware](../middleware)** (+1.89KB gzipped) - Middleware system & state interceptors
|
|
1416
|
+
- Async helpers moved to middleware package (see `packages/middleware`)
|
|
1417
|
+
- **[@signaltree/entities](../entities)** (+0.97KB gzipped) - Enhanced CRUD operations & entity management
|
|
1377
1418
|
|
|
1378
1419
|
### Development Tools
|
|
1379
1420
|
|
|
1380
|
-
- **[@signaltree/devtools](../devtools)** (+2.
|
|
1381
|
-
- **[@signaltree/time-travel](../time-travel)** (+1.
|
|
1421
|
+
- **[@signaltree/devtools](../devtools)** (+2.49KB gzipped) - Development tools & Redux DevTools integration
|
|
1422
|
+
- **[@signaltree/time-travel](../time-travel)** (+1.75KB gzipped) - Undo/redo functionality & state history
|
|
1382
1423
|
|
|
1383
1424
|
### Integration & Convenience
|
|
1384
1425
|
|
|
1385
|
-
- **[@signaltree/presets](../presets)** (+0.
|
|
1386
|
-
- **[@signaltree/ng-forms](../ng-forms)** (+3.
|
|
1426
|
+
- **[@signaltree/presets](../presets)** (+0.84KB gzipped) - Pre-configured setups for common patterns
|
|
1427
|
+
- **[@signaltree/ng-forms](../ng-forms)** (+3.38KB gzipped) - Complete Angular Forms integration
|
|
1387
1428
|
|
|
1388
1429
|
### Quick Start with Extensions
|
|
1389
1430
|
|
|
@@ -1395,7 +1436,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization
|
|
|
1395
1436
|
npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/devtools @signaltree/time-travel
|
|
1396
1437
|
|
|
1397
1438
|
# All packages (full-featured)
|
|
1398
|
-
npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/
|
|
1439
|
+
npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/entities @signaltree/devtools @signaltree/time-travel @signaltree/presets @signaltree/ng-forms
|
|
1399
1440
|
```
|
|
1400
1441
|
|
|
1401
1442
|
## Links
|
|
@@ -1116,5 +1116,5 @@ function applyEnhancer(tree, enhancer) {
|
|
|
1116
1116
|
return enhancer(tree);
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
|
-
export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree
|
|
1119
|
+
export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree };
|
|
1120
1120
|
//# sourceMappingURL=signaltree-core.mjs.map
|