Skip to content

Commit 517d53c

Browse files
committed
Remove @vue/reactive
1 parent f2662b5 commit 517d53c

File tree

8 files changed

+104
-21
lines changed

8 files changed

+104
-21
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- Only ~6kb
66
- Vue-compatible template syntax
77
- DOM-based, mutates in place
8-
- Driven by `@vue/reactivity`
8+
- Driven by reactivity engine wrote by [Mark Backes](https://github.com/themarcba)
99

1010
## Status
1111

@@ -284,7 +284,7 @@ avoid flash rendreng which happen until `petite-vue` loaded, after it load it wi
284284

285285
### Global State Management
286286

287-
You can use the `reactive` method (re-exported from `@vue/reactivity`) to create global state singletons:
287+
You can use the `reactive` method to create global state singletons:
288288

289289
```html
290290
<script type="module">

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
},
3434
"homepage": "https://github.com/ws-rush/power-vue#readme",
3535
"devDependencies": {
36-
"@vue/reactivity": "^3.2.27",
3736
"@vue/shared": "^3.2.27",
3837
"chalk": "^4.1.1",
3938
"conventional-changelog-cli": "^2.1.1",

src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { reactive } from '@vue/reactivity'
1+
import { reactive } from './reactivity'
22
import { Block } from './block'
33
import { Directive } from './directives'
44
import { bindContextMethods, createContext } from './context'

src/block.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Context, createContext } from './context'
22
import { walk } from './walk'
33
import { remove } from '@vue/shared'
4-
import { stop } from '@vue/reactivity'
4+
// import { stop } from './reactivity'
55

66
export class Block {
77
template: Element | DocumentFragment
@@ -90,7 +90,8 @@ export class Block {
9090
this.ctx.blocks.forEach((child) => {
9191
child.teardown()
9292
})
93-
this.ctx.effects.forEach(stop)
93+
// here maybe we need loop on targetMap and depMap to stop
94+
// this.ctx.effects.forEach((effect) => stop)
9495
this.ctx.cleanups.forEach((fn) => fn())
9596
}
9697
}

src/context.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import {
2-
effect as rawEffect,
3-
reactive,
4-
ReactiveEffectRunner
5-
} from '@vue/reactivity'
1+
import { effect as rawEffect, reactive } from '@vue/reactivity'
62
import { Block } from './block'
73
import { Directive } from './directives'
84
import { queueJob } from './scheduler'
95
import { inOnce } from './walk'
6+
107
export interface Context {
118
key?: any
129
scope: Record<string, any>
1310
dirs: Record<string, Directive>
1411
blocks: Block[]
1512
effect: typeof rawEffect
16-
effects: ReactiveEffectRunner[]
13+
effects: (() => void)[]
1714
cleanups: (() => void)[]
1815
delimiters: [string, string]
1916
delimitersRE: RegExp
@@ -32,13 +29,13 @@ export const createContext = (parent?: Context): Context => {
3229
effect: (fn) => {
3330
if (inOnce) {
3431
queueJob(fn)
35-
return fn as any
32+
return fn
3633
}
37-
const e: ReactiveEffectRunner = rawEffect(fn, {
38-
scheduler: () => queueJob(e)
34+
const effect: any = rawEffect(fn, {
35+
scheduler: () => queueJob(effect)
3936
})
40-
ctx.effects.push(e)
41-
return e
37+
ctx.effects.push(effect)
38+
return effect
4239
}
4340
}
4441
return ctx
@@ -52,8 +49,6 @@ export const createScopedContext = (ctx: Context, data = {}): Context => {
5249
const reactiveProxy = reactive(
5350
new Proxy(mergedScope, {
5451
set(target, key, val, receiver) {
55-
// when setting a property that doesn't exist on current scope,
56-
// do not create it on the current scope and fallback to parent scope.
5752
if (receiver === reactiveProxy && !target.hasOwnProperty(key)) {
5853
return Reflect.set(parentScope, key, val)
5954
}

src/directives/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Context } from '../context'
2-
import { effect as rawEffect } from '@vue/reactivity'
2+
import { effect as rawEffect } from '../reactivity'
33
import { bind } from './bind'
44
import { on } from './on'
55
import { show } from './show'

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export { define } from './define'
22
export { createApp } from './app'
33
export { nextTick } from './scheduler'
4-
export { reactive } from '@vue/reactivity'
4+
export { reactive } from './reactivity'
55

66
import { createApp } from './app'
77

src/reactivity.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// ----------------------------------------------------------------
2+
// Vue 3 Reactivity
3+
// Marc Backes (@themarcba)
4+
// ----------------------------------------------------------------
5+
6+
let activeEffect: (() => void) | null = null;
7+
const targetMap = new WeakMap<object, Map<any, Set<() => void>>>();
8+
9+
// Register an effect
10+
function track(target: object, key: any) {
11+
// Get depsMap from targetMap
12+
let depsMap = targetMap.get(target);
13+
if (!depsMap) {
14+
// new depsMap if it doesn't exist yet
15+
depsMap = new Map();
16+
targetMap.set(target, depsMap);
17+
}
18+
19+
// Get dep from depsMap
20+
let dep = depsMap.get(key);
21+
if (!dep) {
22+
// new dep if it doesn't exist yet
23+
dep = new Set();
24+
depsMap.set(key, dep);
25+
}
26+
27+
// Add effect
28+
if (activeEffect) dep.add(activeEffect);
29+
}
30+
31+
// Execute all registered effects for the target/key combination
32+
function trigger(target: object, key: any) {
33+
// Get depsMap from targetMap
34+
const depsMap = targetMap.get(target);
35+
// If there is no depsMap, no need to resume
36+
if (!depsMap) return;
37+
38+
// Get dep from depsMap
39+
const dep = depsMap.get(key);
40+
// If there is no dep, no need to resume
41+
if (!dep) return;
42+
43+
// Execute all effects
44+
dep.forEach((effect) => effect());
45+
}
46+
47+
// Makes an object "reactive". Changes will be triggered once the property is tracked
48+
function reactive<T extends object>(target: T): T {
49+
const handler: ProxyHandler<T> = {
50+
// Intercept getter
51+
get(target, key, receiver) {
52+
const result = Reflect.get(target, key, receiver);
53+
track(target, key);
54+
return result;
55+
},
56+
// Intercept setter
57+
set(target, key, value, receiver) {
58+
const result = Reflect.set(target, key, value, receiver);
59+
trigger(target, key); // trigger a change in the target
60+
return result;
61+
},
62+
};
63+
64+
return new Proxy(target, handler);
65+
}
66+
67+
// Watcher
68+
function effect(fn: () => void) {
69+
activeEffect = fn;
70+
// Only execute when there is an activeEffect
71+
if (activeEffect) activeEffect();
72+
activeEffect = null;
73+
74+
// Return the function for easier cleanup
75+
return fn;
76+
77+
78+
}
79+
80+
// function stop(effect: () => void) {
81+
// for (const [target, depsMap] of targetMap) {
82+
// for (const depSet of depsMap.values()) {
83+
// depSet.delete(effect);
84+
// }
85+
// }
86+
// }
87+
88+
export { reactive, effect };

0 commit comments

Comments
 (0)