@mpxjs/core 2.10.17-beta.6 → 2.10.17-beta.8-effect-log

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.10.17-beta.6",
3
+ "version": "2.10.17-beta.8-effect-log",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
package/src/core/proxy.js CHANGED
@@ -166,6 +166,7 @@ export default class MpxProxy {
166
166
  }
167
167
 
168
168
  created () {
169
+ console.log('[mpx] create proxy instance')
169
170
  if (__mpx_dynamic_runtime__) {
170
171
  // 缓存上下文,在 destoryed 阶段删除
171
172
  contextMap.set(this.uid, this.target)
@@ -752,6 +753,13 @@ export default class MpxProxy {
752
753
  const moduleId = this.target.__moduleId
753
754
  const dynamicTarget = this.target.__dynamic
754
755
 
756
+ const debugConfig = typeof global.__getMpxRenderEffectDebugRules === 'function'
757
+ ? global.__getMpxRenderEffectDebugRules(this.options?.mpxFileResource)
758
+ : {
759
+ debug: 1,
760
+ name: `MpxRenderEffect-${this.options?.mpxFileResource || 'unknown'}`
761
+ }
762
+
755
763
  const effect = this.effect = new ReactiveEffect(() => {
756
764
  // pre render for props update
757
765
  if (this.propsUpdatedFlag) {
@@ -781,8 +789,9 @@ export default class MpxProxy {
781
789
  } else {
782
790
  this.render()
783
791
  }
784
- }, () => queueJob(update), this.scope)
792
+ }, () => queueJob(update), this.scope, this.scope, debugConfig.debug, debugConfig.name)
785
793
 
794
+ console.log(`[mpx] ${this.options?.mpxFileResource} will initRender`)
786
795
  const update = this.update = effect.run.bind(effect)
787
796
  update.id = this.uid
788
797
  // render effect允许自触发
@@ -32,7 +32,7 @@ export const arrayMethods = Object.create(arrayProto)
32
32
  }
33
33
  if (inserted) ob.observeArray(inserted)
34
34
  // notify change
35
- ob.dep.notify()
35
+ ob.dep.notify(method, '[Array Method]', '[Array Method]', new Error('此时被通知变更').stack)
36
36
  }
37
37
  return result
38
38
  })
@@ -3,7 +3,7 @@ import Dep from './dep'
3
3
  import { createRef } from './ref'
4
4
  import { ReactiveEffect } from './effect'
5
5
 
6
- export function computed (getterOrOptions) {
6
+ export function computed (getterOrOptions, options = {}) {
7
7
  let getter, setter
8
8
  if (isFunction(getterOrOptions)) {
9
9
  getter = getterOrOptions
@@ -17,7 +17,7 @@ export function computed (getterOrOptions) {
17
17
  let value
18
18
  const effect = new ReactiveEffect(getter, () => {
19
19
  dirty = true
20
- })
20
+ }, undefined, options.debug || 0, options.name || 'anonymous computed')
21
21
 
22
22
  return createRef({
23
23
  get: () => {
@@ -7,30 +7,50 @@ let uid = 0
7
7
  * directives subscribing to it.
8
8
  */
9
9
  export default class Dep {
10
- constructor () {
10
+ constructor (key) {
11
11
  this.id = uid++
12
12
  this.subs = []
13
+ this.addSubStacks = new Map()
14
+ this.key = key
13
15
  }
14
16
 
15
17
  addSub (sub) {
18
+ const addSubStack = new Error('此时被添加到订阅者列表').stack
19
+ this.addSubStacks.set(sub, addSubStack)
16
20
  this.subs.push(sub)
17
21
  }
18
22
 
19
23
  removeSub (sub) {
20
24
  remove(this.subs, sub)
25
+ this.addSubStacks.delete(sub)
21
26
  }
22
27
 
23
- depend () {
28
+ depend (key, value) {
24
29
  if (Dep.target) {
25
- Dep.target.addDep(this)
30
+ // if (this.key === 'link_params' || key === 'link_params') console.log(new Error('此时被依赖').stack)
31
+ Dep.target.addDep(this, key, value)
26
32
  }
27
33
  }
28
34
 
29
- notify () {
35
+ notify (key, value, oldvalue, stack) {
30
36
  // stabilize the subscriber list first
31
37
  const subs = this.subs.slice()
38
+ try {
39
+ console.log('[Mpx Dep] notify ' +
40
+ this.subs.length +
41
+ ' subs, from ' +
42
+ key +
43
+ ': ' +
44
+ (typeof oldvalue === 'object' ? JSON.stringify(oldvalue) : oldvalue) +
45
+ ' -> ' +
46
+ (typeof value === 'object' ? JSON.stringify(value) : value) +
47
+ ', subs: ' +
48
+ subs.map(s => `id:${s.id} name:${s.name}`).join(', '))
49
+ } catch (e) {
50
+ // do nothing
51
+ }
32
52
  for (let i = 0, l = subs.length; i < l; i++) {
33
- subs[i].update()
53
+ subs[i].update(key, value, oldvalue, stack, this.addSubStacks.get(subs[i]))
34
54
  }
35
55
  }
36
56
  }
@@ -17,6 +17,8 @@ export function resetTracking () {
17
17
  shouldTrack = last === undefined ? true : last
18
18
  }
19
19
 
20
+ global.__setMpxReactiveEffect = (value) => {}
21
+
20
22
  export class ReactiveEffect {
21
23
  active = true
22
24
  deps = []
@@ -24,15 +26,45 @@ export class ReactiveEffect {
24
26
  depIds = new Set()
25
27
  newDepIds = new Set()
26
28
  allowRecurse = false
29
+ debug = 0
30
+ name = 'no-name'
27
31
 
28
32
  constructor (
29
33
  fn,
30
34
  scheduler,
31
- scope
35
+ scope,
36
+ debug,
37
+ name
32
38
  ) {
39
+ this.debug = debug || 0
40
+ this.name = name || 'no-name'
33
41
  this.id = ++uid
34
- this.fn = fn
35
- this.scheduler = scheduler
42
+ this.fn = (...args) => {
43
+ this.debug > 0 && console.log(`[Mpx Effect] id:${this.id} name: ${this.name} will run`)
44
+ this.debug > 1 && console.log(new Error('此时触发了run').stack)
45
+ const t = global.__setMpxReactiveEffect
46
+ global.__setMpxReactiveEffect = (option) => {
47
+ Object.entries(option).forEach(([key, value]) => {
48
+ this[key] = value
49
+ })
50
+ }
51
+ const result = fn(...args)
52
+ global.__setMpxReactiveEffect = t
53
+ return result
54
+ }
55
+ this.scheduler = (...args) => {
56
+ this.debug > 0 && console.log(`[Mpx Effect] id:${this.id} name: ${this.name} will scheduled`)
57
+ this.debug > 1 && console.log(new Error('此时触发scheduler').stack)
58
+ const t = global.__setMpxReactiveEffect
59
+ global.__setMpxReactiveEffect = (option) => {
60
+ Object.entries(option).forEach(([key, value]) => {
61
+ this[key] = value
62
+ })
63
+ }
64
+ const result = scheduler(...args)
65
+ global.__setMpxReactiveEffect = t
66
+ return result
67
+ }
36
68
  this.pausedState = PausedState.resumed
37
69
  recordEffectScope(this, scope)
38
70
  }
@@ -53,14 +85,14 @@ export class ReactiveEffect {
53
85
  }
54
86
 
55
87
  // add dependency to this
56
- addDep (dep) {
88
+ addDep (dep, key, value) {
57
89
  if (!shouldTrack) return
58
90
  const id = dep.id
59
91
  if (!this.newDepIds.has(id)) {
60
92
  this.newDepIds.add(id)
61
93
  this.newDeps.push(dep)
62
94
  if (!this.depIds.has(id)) {
63
- dep.addSub(this)
95
+ dep.addSub(this, key, value)
64
96
  }
65
97
  }
66
98
  }
@@ -85,12 +117,20 @@ export class ReactiveEffect {
85
117
  }
86
118
 
87
119
  // same as trigger
88
- update () {
120
+ update (key, value, stack, fromAddSubStack) {
121
+ const debugOptions = global.__getMpxReactiveEffectDebugRules?.(key, value)
122
+ const debug = debugOptions ? debugOptions.debug : this.debug
89
123
  // avoid dead cycle
90
124
  if (Dep.target !== this || this.allowRecurse) {
91
125
  if (this.pausedState !== PausedState.resumed) {
126
+ debug > 0 && console.log(`[Mpx Effect] id:${this.id} name: ${this.name} pausedState will set to dirty with, from ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}`)
127
+ debug > 1 && console.log(stack)
128
+ debug > 2 && console.log(fromAddSubStack)
92
129
  this.pausedState = PausedState.dirty
93
130
  } else {
131
+ debug > 0 && console.log(`[Mpx Effect] id:${this.id} name: ${this.name} will updated, from ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}`)
132
+ debug > 1 && console.log(stack)
133
+ debug > 2 && console.log(fromAddSubStack)
94
134
  this.scheduler ? this.scheduler() : this.run()
95
135
  }
96
136
  }
@@ -110,7 +110,7 @@ function observe (value, shallow) {
110
110
  * Define a reactive property on an Object.
111
111
  */
112
112
  export function defineReactive (obj, key, val, shallow) {
113
- const dep = new Dep()
113
+ const dep = new Dep(key)
114
114
 
115
115
  const property = Object.getOwnPropertyDescriptor(obj, key)
116
116
  if (property && property.configurable === false) {
@@ -121,6 +121,8 @@ export function defineReactive (obj, key, val, shallow) {
121
121
  const getter = property && property.get
122
122
  const setter = property && property.set
123
123
 
124
+ const stack = new Error().stack
125
+
124
126
  let childOb = shallow ? getObserver(val) : observe(val)
125
127
  Object.defineProperty(obj, key, {
126
128
  enumerable: true,
@@ -128,9 +130,9 @@ export function defineReactive (obj, key, val, shallow) {
128
130
  get: function reactiveGetter () {
129
131
  const value = getter ? getter.call(obj) : val
130
132
  if (Dep.target) {
131
- dep.depend()
133
+ dep.depend(key, value)
132
134
  if (childOb) {
133
- childOb.dep.depend()
135
+ childOb.dep.depend(key, value)
134
136
  if (Array.isArray(value)) {
135
137
  dependArray(value)
136
138
  }
@@ -140,10 +142,12 @@ export function defineReactive (obj, key, val, shallow) {
140
142
  },
141
143
  set: function reactiveSetter (newVal) {
142
144
  const value = getter ? getter.call(obj) : val
145
+ let oldVal = value
143
146
  if (!(shallow && isForceTrigger) && !hasChanged(newVal, value)) {
144
147
  return
145
148
  }
146
149
  if (!shallow && isRef(value) && !isRef(newVal)) {
150
+ oldVal = value.value
147
151
  value.value = newVal
148
152
  } else if (setter) {
149
153
  setter.call(obj, newVal)
@@ -151,7 +155,7 @@ export function defineReactive (obj, key, val, shallow) {
151
155
  val = newVal
152
156
  }
153
157
  childOb = shallow ? getObserver(newVal) : observe(newVal)
154
- dep.notify()
158
+ dep.notify(key, newVal, oldVal, stack)
155
159
  }
156
160
  })
157
161
  }
@@ -176,8 +180,9 @@ export function set (target, key, val) {
176
180
  target[key] = val
177
181
  return val
178
182
  }
183
+ const oldVal = target[key]
179
184
  defineReactive(ob.value, key, val, ob.shallow)
180
- ob.dep.notify()
185
+ ob.dep.notify(key, val, oldVal, new Error('此时被通知变更').stack)
181
186
  return val
182
187
  }
183
188
 
@@ -193,11 +198,12 @@ export function del (target, key) {
193
198
  if (!hasOwn(target, key)) {
194
199
  return
195
200
  }
201
+ const oldVal = target[key]
196
202
  delete target[key]
197
203
  if (!ob) {
198
204
  return
199
205
  }
200
- ob.dep.notify()
206
+ ob.dep.notify(key, undefined, oldVal, new Error('此时被通知变更').stack)
201
207
  }
202
208
 
203
209
  /**
@@ -208,7 +214,7 @@ function dependArray (arr) {
208
214
  for (let i = 0, l = arr.length; i < l; i++) {
209
215
  const item = arr[i]
210
216
  const ob = getObserver(item)
211
- ob && ob.dep.depend()
217
+ ob && ob.dep.depend(i, item)
212
218
  if (Array.isArray(item)) {
213
219
  dependArray(item)
214
220
  }
@@ -137,7 +137,7 @@ export function watch (source, cb, options = {}) {
137
137
 
138
138
  job.allowRecurse = !!cb
139
139
 
140
- const effect = new ReactiveEffect(getter, scheduler)
140
+ const effect = new ReactiveEffect(getter, scheduler, undefined, options.debug || 0, options.name || 'anonymous watch')
141
141
 
142
142
  if (cb) {
143
143
  if (immediate) {
@@ -1,7 +1,7 @@
1
1
  import { createNativeStackNavigator } from '@react-navigation/native-stack'
2
2
  import { NavigationContainer, StackActions } from '@react-navigation/native'
3
3
  import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
4
- import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
4
+ import { SafeAreaProvider, useSafeAreaInsets, initialWindowMetrics } from 'react-native-safe-area-context'
5
5
  import { GestureHandlerRootView } from 'react-native-gesture-handler'
6
6
 
7
7
  export {
@@ -11,5 +11,6 @@ export {
11
11
  GestureHandlerRootView,
12
12
  PortalHost,
13
13
  SafeAreaProvider,
14
- useSafeAreaInsets
14
+ useSafeAreaInsets,
15
+ initialWindowMetrics
15
16
  }
@@ -16,7 +16,7 @@ import {
16
16
  ProviderContext,
17
17
  RouteContext
18
18
  } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
19
- import { PortalHost, useSafeAreaInsets } from '../env/navigationHelper'
19
+ import { PortalHost, useSafeAreaInsets, initialWindowMetrics } from '../env/navigationHelper'
20
20
  import { useInnerHeaderHeight } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-nav'
21
21
 
22
22
  function getSystemInfo () {
@@ -33,12 +33,13 @@ function getSystemInfo () {
33
33
  }
34
34
  }
35
35
 
36
- function createEffect (proxy, componentsMap) {
36
+ function createEffect (proxy, componentsMap, rawOptions) {
37
37
  const update = proxy.update = () => {
38
38
  // react update props in child render(async), do not need exec pre render
39
39
  // if (proxy.propsUpdatedFlag) {
40
40
  // proxy.updatePreRender()
41
41
  // }
42
+ // console.log(`[mpx] ${proxy.options?.mpxFileResource} 组件render响应时数据变更,开始修改stateVersion,驱动组件更新`)
42
43
  if (proxy.isMounted()) {
43
44
  proxy.callHook(BEFOREUPDATE)
44
45
  proxy.pendingUpdatedFlag = true
@@ -61,11 +62,18 @@ function createEffect (proxy, componentsMap) {
61
62
  return createElement(type, ...rest)
62
63
  }
63
64
 
65
+ const debugConfig = typeof global.__getMpxRenderEffectDebugRules === 'function'
66
+ ? global.__getMpxRenderEffectDebugRules(rawOptions.mpxFileResource)
67
+ : {
68
+ debug: 1,
69
+ name: `MpxRenderEffect-${rawOptions.mpxFileResource || 'unknown'}`
70
+ }
71
+
64
72
  proxy.effect = new ReactiveEffect(() => {
65
73
  // reset instance
66
74
  proxy.target.__resetInstance()
67
75
  return callWithErrorHandling(proxy.target.__injectedRender.bind(proxy.target), proxy, 'render function', [innerCreateElement, getComponent])
68
- }, () => queueJob(update), proxy.scope)
76
+ }, () => { return queueJob(update) }, proxy.scope, debugConfig.debug, debugConfig.name)
69
77
  // render effect允许自触发
70
78
  proxy.toggleRecurse(true)
71
79
  }
@@ -332,7 +340,7 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
332
340
  stateVersion: Symbol(),
333
341
  subscribe: (onStoreChange) => {
334
342
  if (!proxy.effect) {
335
- createEffect(proxy, componentsMap)
343
+ createEffect(proxy, componentsMap, rawOptions)
336
344
  proxy.stateVersion = Symbol()
337
345
  }
338
346
  proxy.onStoreChange = onStoreChange
@@ -348,7 +356,7 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
348
356
  })
349
357
  // react数据响应组件更新管理器
350
358
  if (!proxy.effect) {
351
- createEffect(proxy, componentsMap)
359
+ createEffect(proxy, componentsMap, rawOptions)
352
360
  }
353
361
 
354
362
  return instance
@@ -509,7 +517,17 @@ function getLayoutData (headerHeight) {
509
517
  // 在横屏状态下 screen.height = window.height + bottomVirtualHeight
510
518
  // 在正常状态 screen.height = window.height + bottomVirtualHeight + statusBarHeight
511
519
  const isLandscape = screenDimensions.height < screenDimensions.width
512
- const bottomVirtualHeight = isLandscape ? screenDimensions.height - windowDimensions.height : ((screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight) || 0)
520
+ // const bottomVirtualHeight = isLandscape ? screenDimensions.height - windowDimensions.height : ((screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight) || 0)
521
+ let bottomVirtualHeight = 0
522
+ // 红米手机&魅族16T手机的screen.height = windowHeight + bottomVirtualHeight 导致计算出来的底部虚拟偏少。此部分端引擎同学进行修改中
523
+ // mpx临时兼容 bottomVirtualHeight取 initialWindowMetrics.inset.bottom 和 反算出来的bottomVirtualHeight的更大的值
524
+ if (ReactNative.Platform.OS === 'android') {
525
+ if (isLandscape) {
526
+ bottomVirtualHeight = screenDimensions.height - windowDimensions.height
527
+ } else {
528
+ bottomVirtualHeight = Math.max(screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight, initialWindowMetrics?.insets?.bottom || 0, 0)
529
+ }
530
+ }
513
531
  return {
514
532
  left: 0,
515
533
  top: headerHeight,