@signaltree/core 1.1.9 β 2.0.1
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 +138 -106
- package/fesm2022/signaltree-core.mjs +688 -326
- package/fesm2022/signaltree-core.mjs.map +1 -1
- package/index.d.ts +102 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SignalTree Core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Foundation package for SignalTree. Provides recursive typing, deep nesting support, and strong performance.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## What is @signaltree/core?
|
|
6
6
|
|
|
7
|
-
SignalTree Core is
|
|
7
|
+
SignalTree Core is a lightweight (about 7.25KB gzipped) package that provides:
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
9
|
+
- Recursive typing with deep nesting and accurate type inference
|
|
10
|
+
- Fast operations with subβmillisecond measurements at 5β20+ levels
|
|
11
|
+
- Strong TypeScript safety across nested structures
|
|
12
|
+
- Memory efficiency via structural sharing and lazy signals
|
|
13
|
+
- Small API surface with zero-cost abstractions
|
|
14
|
+
- Compact bundle size suited for production
|
|
15
15
|
|
|
16
|
-
###
|
|
16
|
+
### Depth performance (Sept 2025, averaged)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Indicative measurements across different depths:
|
|
19
19
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
20
|
+
| Depth level | Avg time | Type safety | Range |
|
|
21
|
+
| ----------- | -------- | ----------- | ------------- |
|
|
22
|
+
| 5 levels | 0.061ms | β
| 0.041β0.133ms |
|
|
23
|
+
| 10 levels | 0.109ms | β
| 0.060β0.181ms |
|
|
24
|
+
| 15 levels | 0.098ms | β
| 0.088β0.126ms |
|
|
25
|
+
| 20+ levels | 0.103ms | β
| 0.100β0.106ms |
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Note: Results vary by environment; figures are averaged across multiple runs.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Quick start
|
|
30
30
|
|
|
31
31
|
### Installation
|
|
32
32
|
|
|
@@ -34,12 +34,12 @@ _Revolutionary achievement: Performance remains sub-millisecond with consistent
|
|
|
34
34
|
npm install @signaltree/core
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
###
|
|
37
|
+
### Deep nesting example
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
40
|
import { signalTree } from '@signaltree/core';
|
|
41
41
|
|
|
42
|
-
//
|
|
42
|
+
// Strong type inference at deep nesting levels
|
|
43
43
|
const tree = signalTree({
|
|
44
44
|
enterprise: {
|
|
45
45
|
divisions: {
|
|
@@ -58,7 +58,7 @@ const tree = signalTree({
|
|
|
58
58
|
tests: {
|
|
59
59
|
extreme: {
|
|
60
60
|
depth: 15,
|
|
61
|
-
performance: 0.
|
|
61
|
+
performance: 0.098, // ms (averaged)
|
|
62
62
|
typeInference: true,
|
|
63
63
|
},
|
|
64
64
|
},
|
|
@@ -78,21 +78,24 @@ const tree = signalTree({
|
|
|
78
78
|
},
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
//
|
|
81
|
+
// Type inference at deep nesting levels
|
|
82
82
|
const performance = tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.performance();
|
|
83
83
|
|
|
84
|
-
console.log(`
|
|
84
|
+
console.log(`Performance: ${performance}ms`); // ~0.098ms (averaged)
|
|
85
85
|
|
|
86
86
|
// Type-safe updates at unlimited depth
|
|
87
|
-
tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth
|
|
88
|
-
|
|
89
|
-
Note: Prefer calling signals to read their current value (e.g. `tree.$.path.to.value()`). The older `unwrap()` helper is still present for compatibility but using the callable signal form is the recommended approach for new code and examples.
|
|
87
|
+
tree.$.enterprise.divisions.technology.departments.engineering.teams.frontend.projects.signaltree.releases.v1.features.recursiveTyping.validation.tests.extreme.depth(25); // Perfect type safety!
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
### Basic
|
|
90
|
+
### Basic usage
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { signalTree } from '@signaltree/core';
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
// Create a simple tree
|
|
96
|
+
const tree = signalTree({
|
|
97
|
+
count: 0,
|
|
98
|
+
message: 'Hello World',
|
|
96
99
|
});
|
|
97
100
|
|
|
98
101
|
// Read values (these are Angular signals)
|
|
@@ -100,26 +103,25 @@ console.log(tree.$.count()); // 0
|
|
|
100
103
|
console.log(tree.$.message()); // 'Hello World'
|
|
101
104
|
|
|
102
105
|
// Update values
|
|
103
|
-
tree.$.count
|
|
104
|
-
tree.$.message
|
|
106
|
+
tree.$.count(5);
|
|
107
|
+
tree.$.message('Updated!');
|
|
105
108
|
|
|
106
|
-
// Use in Angular
|
|
109
|
+
// Use in an Angular component
|
|
107
110
|
@Component({
|
|
108
|
-
template: `
|
|
111
|
+
template: ` <div>Count: {{ tree.$.count() }}</div>
|
|
109
112
|
<div>Message: {{ tree.$.message() }}</div>
|
|
110
113
|
<button (click)="increment()">+1</button>`,
|
|
111
114
|
})
|
|
112
115
|
class SimpleComponent {
|
|
113
|
-
tree = tree;
|
|
116
|
+
tree = tree;
|
|
114
117
|
|
|
115
|
-
increment() {
|
|
116
|
-
this.tree.$.count
|
|
117
|
-
}
|
|
118
|
+
increment() {
|
|
119
|
+
this.tree.$.count((n) => n + 1);
|
|
120
|
+
}
|
|
118
121
|
}
|
|
122
|
+
```
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
### Intermediate Usage (Nested State)
|
|
124
|
+
### Intermediate usage (nested state)
|
|
123
125
|
|
|
124
126
|
```typescript
|
|
125
127
|
// Create hierarchical state
|
|
@@ -139,9 +141,9 @@ const tree = signalTree({
|
|
|
139
141
|
});
|
|
140
142
|
|
|
141
143
|
// Access nested signals with full type safety
|
|
142
|
-
tree.$.user.name
|
|
143
|
-
tree.$.user.preferences.theme
|
|
144
|
-
tree.$.ui.loading
|
|
144
|
+
tree.$.user.name('Jane Doe');
|
|
145
|
+
tree.$.user.preferences.theme('light');
|
|
146
|
+
tree.$.ui.loading(true);
|
|
145
147
|
|
|
146
148
|
// Computed values from nested state
|
|
147
149
|
const userDisplayName = computed(() => {
|
|
@@ -155,9 +157,9 @@ effect(() => {
|
|
|
155
157
|
console.log('Loading started...');
|
|
156
158
|
}
|
|
157
159
|
});
|
|
158
|
-
|
|
160
|
+
```
|
|
159
161
|
|
|
160
|
-
### Advanced
|
|
162
|
+
### Advanced usage (full state tree)
|
|
161
163
|
|
|
162
164
|
```typescript
|
|
163
165
|
interface AppState {
|
|
@@ -185,39 +187,41 @@ const tree = signalTree<AppState>({
|
|
|
185
187
|
auth: {
|
|
186
188
|
user: null,
|
|
187
189
|
token: null,
|
|
188
|
-
isAuthenticated: false
|
|
190
|
+
isAuthenticated: false,
|
|
189
191
|
},
|
|
190
192
|
data: {
|
|
191
193
|
users: [],
|
|
192
194
|
posts: [],
|
|
193
|
-
cache: {}
|
|
195
|
+
cache: {},
|
|
194
196
|
},
|
|
195
197
|
ui: {
|
|
196
198
|
theme: 'light',
|
|
197
199
|
sidebar: { open: true, width: 250 },
|
|
198
|
-
notifications: []
|
|
199
|
-
}
|
|
200
|
+
notifications: [],
|
|
201
|
+
},
|
|
200
202
|
});
|
|
201
203
|
|
|
202
204
|
// Complex updates with type safety
|
|
203
|
-
tree
|
|
205
|
+
tree((state) => ({
|
|
204
206
|
auth: {
|
|
205
207
|
...state.auth,
|
|
206
208
|
user: { id: '1', name: 'John' },
|
|
207
|
-
isAuthenticated: true
|
|
209
|
+
isAuthenticated: true,
|
|
208
210
|
},
|
|
209
211
|
ui: {
|
|
210
212
|
...state.ui,
|
|
211
|
-
notifications: [
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
notifications: [...state.ui.notifications, { id: '1', message: 'Welcome!', type: 'success' }],
|
|
214
|
+
},
|
|
215
|
+
}));
|
|
216
|
+
|
|
217
|
+
// Get entire state as plain object
|
|
218
|
+
const currentState = tree();
|
|
215
219
|
console.log('Current app state:', currentState);
|
|
216
220
|
```
|
|
217
221
|
|
|
218
|
-
##
|
|
222
|
+
## Core features
|
|
219
223
|
|
|
220
|
-
### 1
|
|
224
|
+
### 1) Hierarchical signal trees
|
|
221
225
|
|
|
222
226
|
Create deeply nested reactive state with automatic type inference:
|
|
223
227
|
|
|
@@ -234,7 +238,7 @@ tree.$.settings.theme.set('light'); // type-checked value
|
|
|
234
238
|
tree.$.todos.update((todos) => [...todos, newTodo]); // array operations
|
|
235
239
|
```
|
|
236
240
|
|
|
237
|
-
### 2
|
|
241
|
+
### 2) TypeScript inference
|
|
238
242
|
|
|
239
243
|
SignalTree provides complete type inference without manual typing:
|
|
240
244
|
|
|
@@ -260,7 +264,7 @@ tree.$.config.theme.set('light'); // β Type error ('dark' const)
|
|
|
260
264
|
tree.$.config.settings.nested.set(false); // β
boolean
|
|
261
265
|
```
|
|
262
266
|
|
|
263
|
-
### 3
|
|
267
|
+
### 3) Manual state management
|
|
264
268
|
|
|
265
269
|
Core provides basic state updates - entity management requires `@signaltree/entities`:
|
|
266
270
|
|
|
@@ -294,7 +298,7 @@ const userById = (id: string) => computed(() => tree.$.users().find((user) => us
|
|
|
294
298
|
const activeUsers = computed(() => tree.$.users().filter((user) => user.active));
|
|
295
299
|
```
|
|
296
300
|
|
|
297
|
-
### 4
|
|
301
|
+
### 4) Manual async state management
|
|
298
302
|
|
|
299
303
|
Core provides basic state updates - async helpers require `@signaltree/async`:
|
|
300
304
|
|
|
@@ -339,7 +343,35 @@ class UsersComponent {
|
|
|
339
343
|
}
|
|
340
344
|
```
|
|
341
345
|
|
|
342
|
-
### 5
|
|
346
|
+
### 5) Performance considerations
|
|
347
|
+
|
|
348
|
+
### 6) Enhancers and composition
|
|
349
|
+
|
|
350
|
+
Enhancers are optional, treeβshakable extensions that augment a `SignalTree` via `tree.with(...)`.
|
|
351
|
+
|
|
352
|
+
- `createEnhancer(meta, fn)` attaches metadata to an enhancer function
|
|
353
|
+
- Metadata fields: `name`, `requires`, `provides`
|
|
354
|
+
- Enhancers may mutate the passed tree (preferred) or return a new object
|
|
355
|
+
- A topological sort orders enhancers that declare metadata; on cycles, fallback to user order in debug mode
|
|
356
|
+
|
|
357
|
+
Examples:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
import { signalTree } from '@signaltree/core';
|
|
361
|
+
import { withBatching } from '@signaltree/batching';
|
|
362
|
+
import { withDevtools } from '@signaltree/devtools';
|
|
363
|
+
|
|
364
|
+
// Apply in explicit order
|
|
365
|
+
const tree = signalTree({ count: 0 }).with(withBatching, withDevtools);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Presets can provide composed enhancers for quicker onboarding:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { createDevTree } from '@signaltree/presets';
|
|
372
|
+
const { enhancer } = createDevTree();
|
|
373
|
+
const tree = signalTree({ count: 0 }).with(enhancer);
|
|
374
|
+
```
|
|
343
375
|
|
|
344
376
|
Core includes several performance optimizations:
|
|
345
377
|
|
|
@@ -374,9 +406,9 @@ tree.update((state) => ({
|
|
|
374
406
|
}));
|
|
375
407
|
```
|
|
376
408
|
|
|
377
|
-
##
|
|
409
|
+
## Error handling examples
|
|
378
410
|
|
|
379
|
-
### Manual
|
|
411
|
+
### Manual async error handling
|
|
380
412
|
|
|
381
413
|
```typescript
|
|
382
414
|
const tree = signalTree({
|
|
@@ -437,7 +469,7 @@ class ErrorHandlingComponent {
|
|
|
437
469
|
}
|
|
438
470
|
```
|
|
439
471
|
|
|
440
|
-
### State
|
|
472
|
+
### State update error handling
|
|
441
473
|
|
|
442
474
|
```typescript
|
|
443
475
|
const tree = signalTree({
|
|
@@ -475,7 +507,7 @@ function safeUpdateItem(id: string, updates: Partial<Item>) {
|
|
|
475
507
|
}
|
|
476
508
|
```
|
|
477
509
|
|
|
478
|
-
##
|
|
510
|
+
## Package composition patterns
|
|
479
511
|
|
|
480
512
|
### Basic Composition
|
|
481
513
|
|
|
@@ -487,33 +519,33 @@ const tree = signalTree({
|
|
|
487
519
|
state: 'initial',
|
|
488
520
|
});
|
|
489
521
|
|
|
490
|
-
// Extend with additional packages via
|
|
491
|
-
const enhancedTree = tree.
|
|
522
|
+
// Extend with additional packages via .with(...)
|
|
523
|
+
const enhancedTree = tree.with(
|
|
492
524
|
// Add features as needed
|
|
493
525
|
someFeatureFunction()
|
|
494
526
|
);
|
|
495
527
|
```
|
|
496
528
|
|
|
497
|
-
### Modular
|
|
529
|
+
### Modular enhancement pattern
|
|
498
530
|
|
|
499
531
|
```typescript
|
|
500
532
|
// Start minimal, add features as needed
|
|
501
533
|
let tree = signalTree(initialState);
|
|
502
534
|
|
|
503
535
|
if (isDevelopment) {
|
|
504
|
-
tree = tree.
|
|
536
|
+
tree = tree.with(withDevTools());
|
|
505
537
|
}
|
|
506
538
|
|
|
507
539
|
if (needsPerformance) {
|
|
508
|
-
tree = tree.
|
|
540
|
+
tree = tree.with(withBatching(), withMemoization());
|
|
509
541
|
}
|
|
510
542
|
|
|
511
543
|
if (needsTimeTravel) {
|
|
512
|
-
tree = tree.
|
|
544
|
+
tree = tree.with(withTimeTravel());
|
|
513
545
|
}
|
|
514
546
|
```
|
|
515
547
|
|
|
516
|
-
### Service-
|
|
548
|
+
### Service-based pattern
|
|
517
549
|
|
|
518
550
|
```typescript
|
|
519
551
|
@Injectable()
|
|
@@ -546,11 +578,11 @@ class AppStateService {
|
|
|
546
578
|
}
|
|
547
579
|
```
|
|
548
580
|
|
|
549
|
-
##
|
|
581
|
+
## Performance benchmarks
|
|
550
582
|
|
|
551
|
-
>
|
|
583
|
+
> Subβmillisecond operations across common core functions
|
|
552
584
|
|
|
553
|
-
### Recursive
|
|
585
|
+
### Recursive depth scaling (illustrative)
|
|
554
586
|
|
|
555
587
|
| **Depth Level** | **Execution Time** | **Scaling Factor** | **Type Inference** | **Memory Usage** |
|
|
556
588
|
| -------------------------- | ------------------ | ------------------ | ------------------ | ---------------- |
|
|
@@ -559,9 +591,9 @@ class AppStateService {
|
|
|
559
591
|
| **Extreme (15 levels)** | **0.021ms** | **1.75x** | β
Perfect | ~1.3MB |
|
|
560
592
|
| **Unlimited (20+ levels)** | 0.023ms | 1.92x | β
Perfect | ~1.4MB |
|
|
561
593
|
|
|
562
|
-
|
|
594
|
+
Note: Scaling depends on state shape and hardware.
|
|
563
595
|
|
|
564
|
-
###
|
|
596
|
+
### Example operation timings
|
|
565
597
|
|
|
566
598
|
| Operation | SignalTree Core | Notes |
|
|
567
599
|
| --------------------------- | --------------- | ---------------- |
|
|
@@ -572,16 +604,16 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
|
|
|
572
604
|
| Computation (cached) | **0.094ms** | Memoized result |
|
|
573
605
|
| Memory per 1K entities | **1.2MB** | Measured usage |
|
|
574
606
|
|
|
575
|
-
###
|
|
607
|
+
### Feature impact
|
|
576
608
|
|
|
577
609
|
| Feature | SignalTree Core | With Extensions | Notes |
|
|
578
610
|
| ------------------- | ----------------- | ---------------------- | ---------------------- |
|
|
579
611
|
| Batching efficiency | Standard | **455.8x improvement** | vs non-batched |
|
|
580
612
|
| Memoization speedup | Basic | **197.9x speedup** | vs non-memoized |
|
|
581
613
|
| Memory efficiency | **Optimized** | **Further optimized** | Lazy signals + cleanup |
|
|
582
|
-
| Bundle impact | **
|
|
614
|
+
| Bundle impact | **7.1KB gzipped** | **+15KB max** | Tree-shakeable |
|
|
583
615
|
|
|
584
|
-
### Developer
|
|
616
|
+
### Developer experience (core)
|
|
585
617
|
|
|
586
618
|
| Metric | SignalTree Core | Traditional State Mgmt | **Improvement** |
|
|
587
619
|
| ----------------------- | --------------- | ---------------------- | --------------- |
|
|
@@ -590,7 +622,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
|
|
|
590
622
|
| Setup complexity | **Minimal** | Complex | **Simplified** |
|
|
591
623
|
| API surface | **Small** | Large | **Focused** |
|
|
592
624
|
|
|
593
|
-
### Memory
|
|
625
|
+
### Memory usage comparison
|
|
594
626
|
|
|
595
627
|
| Operation | SignalTree Core | NgRx | Akita | Native Signals |
|
|
596
628
|
| ------------------------ | --------------- | ------ | ------ | -------------- |
|
|
@@ -598,7 +630,7 @@ _Exceptional scaling: Only 92% performance overhead for 4x depth increase_
|
|
|
598
630
|
| 10K entities | 8.1MB | 28.5MB | 22.1MB | 15.2MB |
|
|
599
631
|
| Deep nesting (10 levels) | 145KB | 890KB | 720KB | 340KB |
|
|
600
632
|
|
|
601
|
-
### TypeScript
|
|
633
|
+
### TypeScript inference speed
|
|
602
634
|
|
|
603
635
|
```typescript
|
|
604
636
|
// SignalTree: Instant inference
|
|
@@ -612,7 +644,7 @@ interface State { deeply: { nested: { state: { with: { types: string } } } } }
|
|
|
612
644
|
const store: Store<State> = ...; // Requires manual interface definition
|
|
613
645
|
```
|
|
614
646
|
|
|
615
|
-
##
|
|
647
|
+
## Example
|
|
616
648
|
|
|
617
649
|
```typescript
|
|
618
650
|
// Complete user management component
|
|
@@ -730,16 +762,16 @@ class UserManagerComponent implements OnInit {
|
|
|
730
762
|
}));
|
|
731
763
|
|
|
732
764
|
// Get entire state as plain object
|
|
733
|
-
const currentState = tree
|
|
765
|
+
const currentState = tree.unwrap();
|
|
734
766
|
console.log('Current app state:', currentState);
|
|
735
767
|
|
|
736
768
|
```
|
|
737
769
|
});
|
|
738
770
|
```
|
|
739
771
|
|
|
740
|
-
##
|
|
772
|
+
## Core features
|
|
741
773
|
|
|
742
|
-
### Hierarchical
|
|
774
|
+
### Hierarchical signal trees
|
|
743
775
|
|
|
744
776
|
```typescript
|
|
745
777
|
const tree = signalTree({
|
|
@@ -754,7 +786,7 @@ tree.$.settings.theme.set('light');
|
|
|
754
786
|
tree.$.todos.update((todos) => [...todos, newTodo]);
|
|
755
787
|
```
|
|
756
788
|
|
|
757
|
-
### Manual
|
|
789
|
+
### Manual entity management
|
|
758
790
|
|
|
759
791
|
```typescript
|
|
760
792
|
// Manual CRUD operations
|
|
@@ -780,7 +812,7 @@ const allTodos = computed(() => tree.$.todos());
|
|
|
780
812
|
const todoCount = computed(() => tree.$.todos().length);
|
|
781
813
|
```
|
|
782
814
|
|
|
783
|
-
### Manual
|
|
815
|
+
### Manual async state management
|
|
784
816
|
|
|
785
817
|
```typescript
|
|
786
818
|
async function loadUsers() {
|
|
@@ -802,7 +834,7 @@ async function handleLoadUsers() {
|
|
|
802
834
|
}
|
|
803
835
|
```
|
|
804
836
|
|
|
805
|
-
### Reactive
|
|
837
|
+
### Reactive effects
|
|
806
838
|
|
|
807
839
|
```typescript
|
|
808
840
|
// Create reactive effects
|
|
@@ -816,7 +848,7 @@ const unsubscribe = tree.subscribe((state) => {
|
|
|
816
848
|
});
|
|
817
849
|
```
|
|
818
850
|
|
|
819
|
-
##
|
|
851
|
+
## Core API reference
|
|
820
852
|
|
|
821
853
|
### signalTree()
|
|
822
854
|
|
|
@@ -830,7 +862,7 @@ const tree = signalTree(initialState, config?);
|
|
|
830
862
|
// State access
|
|
831
863
|
tree.$.property(); // Read signal value
|
|
832
864
|
tree.$.property.set(value); // Update signal
|
|
833
|
-
//
|
|
865
|
+
tree.unwrap(); // Get plain object
|
|
834
866
|
|
|
835
867
|
// Tree operations
|
|
836
868
|
tree.update(updater); // Update entire tree
|
|
@@ -844,7 +876,7 @@ tree.asyncAction(fn, config?); // Async actions (requires @signaltree/async)
|
|
|
844
876
|
tree.asyncAction(fn, config?); // Create async action
|
|
845
877
|
```
|
|
846
878
|
|
|
847
|
-
##
|
|
879
|
+
## Extending with optional packages
|
|
848
880
|
|
|
849
881
|
SignalTree Core can be extended with additional features:
|
|
850
882
|
|
|
@@ -854,11 +886,11 @@ import { withBatching } from '@signaltree/batching';
|
|
|
854
886
|
import { withMemoization } from '@signaltree/memoization';
|
|
855
887
|
import { withTimeTravel } from '@signaltree/time-travel';
|
|
856
888
|
|
|
857
|
-
// Compose features using
|
|
858
|
-
const tree = signalTree(initialState).
|
|
889
|
+
// Compose features using .with(...)
|
|
890
|
+
const tree = signalTree(initialState).with(withBatching(), withMemoization(), withTimeTravel());
|
|
859
891
|
```
|
|
860
892
|
|
|
861
|
-
### Available
|
|
893
|
+
### Available extensions
|
|
862
894
|
|
|
863
895
|
- **@signaltree/batching** (+1.1KB gzipped) - Batch multiple updates
|
|
864
896
|
- **@signaltree/memoization** (+1.7KB gzipped) - Intelligent caching & performance
|
|
@@ -869,9 +901,9 @@ const tree = signalTree(initialState).pipe(withBatching(), withMemoization(), wi
|
|
|
869
901
|
- **@signaltree/time-travel** (+1.5KB gzipped) - Undo/redo functionality
|
|
870
902
|
- **@signaltree/ng-forms** (+3.4KB gzipped) - Complete Angular forms integration
|
|
871
903
|
- **@signaltree/serialization** (+3.6KB gzipped) - State persistence & SSR support
|
|
872
|
-
- **@signaltree/presets** (+0.
|
|
904
|
+
- **@signaltree/presets** (+0.8KB gzipped) - Environment-based configurations
|
|
873
905
|
|
|
874
|
-
##
|
|
906
|
+
## When to use core only
|
|
875
907
|
|
|
876
908
|
Perfect for:
|
|
877
909
|
|
|
@@ -888,7 +920,7 @@ Consider extensions when you need:
|
|
|
888
920
|
- π Complex forms (ng-forms)
|
|
889
921
|
- π§ Middleware patterns (middleware)
|
|
890
922
|
|
|
891
|
-
##
|
|
923
|
+
## Migration from NgRx
|
|
892
924
|
|
|
893
925
|
```typescript
|
|
894
926
|
// Step 1: Create parallel tree
|
|
@@ -904,7 +936,7 @@ users = this.tree.$.users;
|
|
|
904
936
|
// Step 3: Replace effects with manual async operations
|
|
905
937
|
// Before (NgRx)
|
|
906
938
|
loadUsers$ = createEffect(() =>
|
|
907
|
-
this.actions$.
|
|
939
|
+
this.actions$.with(
|
|
908
940
|
ofType(loadUsers),
|
|
909
941
|
switchMap(() => this.api.getUsers())
|
|
910
942
|
)
|
|
@@ -926,7 +958,7 @@ loadUsers = tree.asyncAction(() => api.getUsers(), {
|
|
|
926
958
|
});
|
|
927
959
|
```
|
|
928
960
|
|
|
929
|
-
##
|
|
961
|
+
## Examples
|
|
930
962
|
|
|
931
963
|
### Simple Counter
|
|
932
964
|
|
|
@@ -996,7 +1028,7 @@ class UsersComponent {
|
|
|
996
1028
|
}
|
|
997
1029
|
```
|
|
998
1030
|
|
|
999
|
-
##
|
|
1031
|
+
## Available extension packages
|
|
1000
1032
|
|
|
1001
1033
|
Extend the core with optional feature packages:
|
|
1002
1034
|
|
|
@@ -1018,7 +1050,7 @@ Extend the core with optional feature packages:
|
|
|
1018
1050
|
|
|
1019
1051
|
### Integration & Convenience
|
|
1020
1052
|
|
|
1021
|
-
- **[@signaltree/presets](../presets)** (+0.
|
|
1053
|
+
- **[@signaltree/presets](../presets)** (+0.8KB gzipped) - Pre-configured setups for common patterns
|
|
1022
1054
|
- **[@signaltree/ng-forms](../ng-forms)** (+3.4KB gzipped) - Complete Angular Forms integration
|
|
1023
1055
|
|
|
1024
1056
|
### Quick Start with Extensions
|
|
@@ -1034,7 +1066,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
|
|
|
1034
1066
|
npm install @signaltree/core @signaltree/batching @signaltree/memoization @signaltree/middleware @signaltree/async @signaltree/entities @signaltree/devtools @signaltree/time-travel @signaltree/presets @signaltree/ng-forms
|
|
1035
1067
|
```
|
|
1036
1068
|
|
|
1037
|
-
##
|
|
1069
|
+
## Links
|
|
1038
1070
|
|
|
1039
1071
|
- [SignalTree Documentation](https://signaltree.io)
|
|
1040
1072
|
- [GitHub Repository](https://github.com/JBorgia/signaltree)
|
|
@@ -1043,7 +1075,7 @@ npm install @signaltree/core @signaltree/batching @signaltree/memoization @signa
|
|
|
1043
1075
|
|
|
1044
1076
|
## π License
|
|
1045
1077
|
|
|
1046
|
-
MIT License - see the [LICENSE](../../LICENSE) file for details.
|
|
1078
|
+
MIT License with AI Training Restriction - see the [LICENSE](../../LICENSE) file for details.
|
|
1047
1079
|
|
|
1048
1080
|
---
|
|
1049
1081
|
|