mobx-vue-bridge 1.3.0 → 1.5.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/CHANGELOG.md +98 -0
- package/README.md +47 -0
- package/package.json +1 -1
- package/src/mobxVueBridge.js +169 -443
- package/src/utils/deepProxy.js +109 -0
- package/src/utils/equality.js +61 -0
- package/src/utils/helpers.js +395 -0
- package/src/utils/memberDetection.js +195 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,104 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.5.0] - 2026-01-13
|
|
9
|
+
|
|
10
|
+
### 🎯 Major Improvements
|
|
11
|
+
|
|
12
|
+
#### Declarative helper functions for improved readability
|
|
13
|
+
- **Feature**: Extracted bridge logic into self-documenting helper functions in `src/utils/helpers.js`
|
|
14
|
+
- **Structure**: 396 lines of declarative helpers organized by concern:
|
|
15
|
+
- Value reading & initialization
|
|
16
|
+
- Property type categorization
|
|
17
|
+
- Echo loop prevention
|
|
18
|
+
- Read-only detection
|
|
19
|
+
- Setter creation (lazy validated, read-only, write-only, two-way binding)
|
|
20
|
+
- MobX observation helpers
|
|
21
|
+
- **Benefit**: Code now reads like documentation with function names like `guardAgainstEchoLoop`, `createLazyValidatedSetter`, `safelyDisposeSubscription`
|
|
22
|
+
|
|
23
|
+
#### Improved circular reference handling in equality checks
|
|
24
|
+
- **Feature**: `isEqual()` now uses `Map` instead of `WeakSet` to track visited object pairs
|
|
25
|
+
- **Benefit**: Correctly compares objects where one has circular refs and the other doesn't
|
|
26
|
+
- **Previous bug**: `isEqual(circularObj, nonCircularObj)` incorrectly returned `true`
|
|
27
|
+
- **Fix**: Now tracks `(a, b)` pairs so revisiting `a` checks if it was paired with same `b`
|
|
28
|
+
|
|
29
|
+
### 🐛 Bug Fixes
|
|
30
|
+
|
|
31
|
+
#### Fixed deepObserve stale subscription after property reassignment
|
|
32
|
+
- **Issue**: When a property was reassigned to a new object/array, `deepObserve` continued watching the old value
|
|
33
|
+
- **Example**: After `store.items = newArray`, mutations to `newArray` weren't detected
|
|
34
|
+
- **Fix**: Added `onValueChanged` callback to `observeProperty` that re-subscribes `deepObserve` when property value changes
|
|
35
|
+
- **Result**: Nested mutations are now correctly detected even after complete property reassignment
|
|
36
|
+
|
|
37
|
+
#### Fixed -0 vs +0 edge case in equality comparison
|
|
38
|
+
- **Issue**: `Object.is(-0, +0)` returns `false`, causing unnecessary updates for equivalent values
|
|
39
|
+
- **Fix**: Added explicit number handling that treats `-0` and `+0` as equal while correctly handling `NaN === NaN`
|
|
40
|
+
|
|
41
|
+
#### Improved warning messages
|
|
42
|
+
- **Change**: Direct mutation warnings now include actionable guidance
|
|
43
|
+
- **Before**: `"Direct mutation of 'name' is disabled"`
|
|
44
|
+
- **After**: `"Direct mutation of 'name' is disabled. Use actions instead."`
|
|
45
|
+
|
|
46
|
+
### ✅ Testing
|
|
47
|
+
|
|
48
|
+
- **New test file**: `mobxVueBridgeBugVerification.test.js` - 10 tests verifying bug fixes
|
|
49
|
+
- Circular reference equality edge cases
|
|
50
|
+
- DeepObserve re-subscription after reassignment
|
|
51
|
+
- -0/+0 and NaN handling
|
|
52
|
+
- Single clone correctness
|
|
53
|
+
- Sibling nested array mutations
|
|
54
|
+
- Setter-only properties
|
|
55
|
+
- **New test file**: `mobxVueBridgeCrossClassComputed.test.js` - 3 tests for cross-class dependencies
|
|
56
|
+
- Computed properties depending on other class's computed properties
|
|
57
|
+
- Chain of three classes with computed dependencies
|
|
58
|
+
- Changes detected even when only bridging the dependent class
|
|
59
|
+
|
|
60
|
+
## [1.4.0] - 2025-11-25
|
|
61
|
+
|
|
62
|
+
### 🎯 Major Improvements
|
|
63
|
+
|
|
64
|
+
#### Zero-side-effect initialization with lazy detection
|
|
65
|
+
- **Feature**: Bridge no longer calls any setters during initialization, eliminating all side effects
|
|
66
|
+
- **Benefit**: Fixes production bugs where setter side effects (like `refreshDataOnTabChange()`) were triggered during bridge setup
|
|
67
|
+
- **Mechanism**: Lazy detection pattern - properties are optimistically marked as writable during init, tested on first actual write attempt
|
|
68
|
+
- **Caching**: `readOnlyDetected` Set caches detection results for O(1) lookups on subsequent writes
|
|
69
|
+
- **Impact**: User's `currentRoom` setter with side effects now works correctly - side effects only occur during actual user interactions
|
|
70
|
+
|
|
71
|
+
#### Modular architecture refactoring
|
|
72
|
+
- **Feature**: Core logic separated into focused utility modules
|
|
73
|
+
- **Structure**:
|
|
74
|
+
- `src/utils/memberDetection.js` (210 lines) - MobX member categorization without side effects
|
|
75
|
+
- `src/utils/equality.js` (47 lines) - Deep equality with circular reference protection
|
|
76
|
+
- `src/utils/deepProxy.js` (109 lines) - Nested reactivity with microtask batching
|
|
77
|
+
- **Main bridge**: Reduced from 523 lines → 321 lines (39% reduction)
|
|
78
|
+
- **Benefit**: Better maintainability, testability, and code organization
|
|
79
|
+
|
|
80
|
+
### 🐛 Bug Fixes
|
|
81
|
+
|
|
82
|
+
#### Fixed computed property detection with MobX synthetic setters
|
|
83
|
+
- **Issue**: MobX adds synthetic setters to computed-only properties that throw "not possible to assign" errors
|
|
84
|
+
- **Previous approach**: Tested setters during initialization (caused side effects)
|
|
85
|
+
- **New approach**: Check descriptor existence only (`descriptor.get && descriptor.set`), test lazily on first write
|
|
86
|
+
- **Detection**: Catch MobX error message during first write attempt, cache as read-only
|
|
87
|
+
- **Result**: Accurate detection without initialization side effects
|
|
88
|
+
|
|
89
|
+
#### Fixed test equality assertions
|
|
90
|
+
- **Issue**: One test expected reference equality for cloned objects
|
|
91
|
+
- **Fix**: Changed `.toBe()` to `.toStrictEqual()` for deep equality comparison
|
|
92
|
+
- **Context**: Bridge clones objects to prevent reference sharing between Vue and MobX
|
|
93
|
+
|
|
94
|
+
### ✅ Testing
|
|
95
|
+
|
|
96
|
+
- **Total tests**: 170 passing (was 168 + 2 skipped)
|
|
97
|
+
- **New active tests**: Unskipped and fixed 2 comprehensive two-way binding demo tests
|
|
98
|
+
- **Coverage**: All patterns verified including lazy detection, nested mutations, and error handling
|
|
99
|
+
|
|
100
|
+
### 📚 Documentation
|
|
101
|
+
|
|
102
|
+
- **Architecture notes**: Added inline documentation explaining lazy detection pattern
|
|
103
|
+
- **Comments**: Clear explanation of why setters aren't called during init
|
|
104
|
+
- **Examples**: Test files demonstrate proper usage patterns
|
|
105
|
+
|
|
8
106
|
## [1.2.0] - 2025-10-01
|
|
9
107
|
|
|
10
108
|
### ✨ New Features
|
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ A seamless bridge between MobX observables and Vue 3's reactivity system, enabli
|
|
|
14
14
|
- 🔒 **Type-safe bridging** between reactive systems
|
|
15
15
|
- 🚀 **Optimized performance** with intelligent change detection
|
|
16
16
|
- 🛡️ **Error handling** for edge cases and circular references
|
|
17
|
+
- ⚡ **Zero-side-effect initialization** with lazy detection (v1.4.0+)
|
|
18
|
+
- 📦 **Modular architecture** for better maintainability
|
|
17
19
|
|
|
18
20
|
## 📦 Installation
|
|
19
21
|
|
|
@@ -296,6 +298,51 @@ presenter.items.push(newItem)
|
|
|
296
298
|
console.log(presenter.items) // Immediately updated!
|
|
297
299
|
```
|
|
298
300
|
|
|
301
|
+
## 🏗️ Architecture & Implementation
|
|
302
|
+
|
|
303
|
+
### Modular Design (v1.4.0+)
|
|
304
|
+
|
|
305
|
+
The bridge uses a clean, modular architecture for better maintainability:
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
src/
|
|
309
|
+
├── mobxVueBridge.js # Main bridge (321 lines)
|
|
310
|
+
└── utils/
|
|
311
|
+
├── memberDetection.js # MobX property categorization (210 lines)
|
|
312
|
+
├── equality.js # Deep equality with circular protection (47 lines)
|
|
313
|
+
└── deepProxy.js # Nested reactivity with batching (109 lines)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Zero-Side-Effect Initialization
|
|
317
|
+
|
|
318
|
+
The bridge uses **lazy detection** to avoid calling setters during initialization:
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
class GuestPresenter {
|
|
322
|
+
get currentRoom() {
|
|
323
|
+
return this.repository.currentRoomId
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
set currentRoom(val) {
|
|
327
|
+
this.repository.currentRoomId = val
|
|
328
|
+
this.refreshDataOnTabChange() // Side effect!
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ✅ v1.4.0+: No side effects during bridge creation
|
|
333
|
+
const state = useMobxBridge(presenter) // refreshDataOnTabChange() NOT called
|
|
334
|
+
|
|
335
|
+
// ✅ Side effects only happen during actual mutations
|
|
336
|
+
state.currentRoom = 'room-123' // refreshDataOnTabChange() called here
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**How it works:**
|
|
340
|
+
1. **Detection phase**: Checks descriptor existence only (`descriptor.get && descriptor.set`)
|
|
341
|
+
2. **First write**: Tests if setter actually works by attempting the write
|
|
342
|
+
3. **Caching**: Results stored in `readOnlyDetected` Set for O(1) future lookups
|
|
343
|
+
|
|
344
|
+
This prevents bugs where setter side effects were triggered during bridge setup, while maintaining accurate runtime behavior.
|
|
345
|
+
|
|
299
346
|
### Error Handling
|
|
300
347
|
The bridge gracefully handles edge cases:
|
|
301
348
|
|
package/package.json
CHANGED