@mpxjs/core 2.9.69-beta.3 → 2.9.69-beta.5

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.9.69-beta.3",
3
+ "version": "2.9.69-beta.5",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -1,13 +1,12 @@
1
1
  import transferOptions from '../core/transferOptions'
2
2
  import builtInKeysMap from './patch/builtInKeysMap'
3
- import { makeMap, spreadProp, getFocusedNavigation, hasOwn, extend } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
5
  import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
  import Mpx from '../index'
7
7
  import { createElement, memo, useRef, useEffect } from 'react'
8
8
  import * as ReactNative from 'react-native'
9
9
  import { Image } from 'react-native'
10
- import { ref } from '../observer/ref'
11
10
 
12
11
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
13
12
 
@@ -30,22 +29,24 @@ function filterOptions (options, appData) {
30
29
  return newOptions
31
30
  }
32
31
 
33
- function createAppInstance (appData) {
34
- return extend({}, Mpx.prototype, appData)
35
- }
36
-
37
- export default function createApp (option, config = {}) {
32
+ export default function createApp (options) {
38
33
  const appData = {}
39
34
 
40
35
  const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
41
36
  // app选项目前不需要进行转换
42
- const { rawOptions, currentInject } = transferOptions(option, 'app', false)
37
+ const { rawOptions, currentInject } = transferOptions(options, 'app', false)
43
38
  const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
44
- defaultOptions.onAppInit && defaultOptions.onAppInit()
45
39
  // 在页面script执行前填充getApp()
46
40
  global.getApp = function () {
47
41
  return appData
48
42
  }
43
+
44
+ defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appData))
45
+ defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appData))
46
+ defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appData))
47
+ defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appData))
48
+ defaultOptions.onAppInit && defaultOptions.onAppInit()
49
+
49
50
  const pages = currentInject.getPages() || {}
50
51
  const firstPage = currentInject.firstPage
51
52
  const Stack = createStackNavigator()
@@ -82,55 +83,50 @@ export default function createApp (option, config = {}) {
82
83
  }
83
84
 
84
85
  global.__mpxAppLaunched = false
85
-
86
- global.__mpxAppFocusedState = ref('show')
87
86
  global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
88
- const instanceRef = useRef(null)
89
- if (!instanceRef.current) {
90
- instanceRef.current = createAppInstance(appData)
91
- }
92
- const instance = instanceRef.current
87
+ const firstRef = useRef(true)
93
88
  const initialRouteRef = useRef({
94
89
  initialRouteName: firstPage,
95
90
  initialParams: {}
96
91
  })
97
-
98
- if (!global.__mpxAppLaunched) {
92
+ if (firstRef.current) {
93
+ // 热启动情况下,app会被销毁重建,将__mpxAppHotLaunched重置保障路由等初始化逻辑正确执行
94
+ global.__mpxAppHotLaunched = false
95
+ // 热启动情况下重置__mpxPagesMap避免页面销毁函数未及时执行时错误地引用到之前的navigation
96
+ global.__mpxPagesMap = {}
97
+ firstRef.current = false
98
+ }
99
+ if (!global.__mpxAppHotLaunched) {
99
100
  const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
100
101
  initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
101
102
  initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
102
103
 
103
104
  global.__mpxAppOnLaunch = (navigation) => {
104
- global.__mpxAppLaunched = true
105
105
  const state = navigation.getState()
106
106
  Mpx.config.rnConfig.onStateChange?.(state)
107
107
  const current = state.routes[state.index]
108
- global.__mpxEnterOptions = {
108
+ const options = {
109
109
  path: current.name,
110
110
  query: current.params,
111
111
  scene: 0,
112
112
  shareTicket: '',
113
- referrerInfo: {}
113
+ referrerInfo: {},
114
+ isLaunch: true
115
+ }
116
+ global.__mpxEnterOptions = options
117
+ if (!global.__mpxAppLaunched) {
118
+ global.__mpxLaunchOptions = options
119
+ defaultOptions.onLaunch && defaultOptions.onLaunch.call(appData, options)
114
120
  }
115
- defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, global.__mpxEnterOptions)
116
- defaultOptions.onShow && defaultOptions.onShow.call(instance, global.__mpxEnterOptions)
121
+ global.__mpxAppCbs.show.forEach((cb) => {
122
+ cb(options)
123
+ })
124
+ global.__mpxAppLaunched = true
125
+ global.__mpxAppHotLaunched = true
117
126
  }
118
127
  }
119
128
 
120
129
  useEffect(() => {
121
- if (defaultOptions.onShow) {
122
- global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
123
- }
124
- if (defaultOptions.onHide) {
125
- global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(instance))
126
- }
127
- if (defaultOptions.onError) {
128
- global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
129
- }
130
- if (defaultOptions.onUnhandledRejection) {
131
- global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(instance))
132
- }
133
-
134
130
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
135
131
  if (currentState === 'active') {
136
132
  let options = global.__mpxEnterOptions
@@ -24,19 +24,19 @@ function filterOptions (options, appData) {
24
24
  return newOptions
25
25
  }
26
26
 
27
- export default function createApp (option, config = {}) {
28
- // 在App中挂载mpx对象供周边工具访问,如e2e测试
27
+ export default function createApp (options, config = {}) {
28
+ const appData = {}
29
+ // app选项目前不需要进行转换
30
+ const { rawOptions, currentInject } = transferOptions(options, 'app', false)
29
31
  const builtInMixins = [{
32
+ // 在App中挂载mpx对象供周边工具访问,如e2e测试
30
33
  getMpx () {
31
34
  return Mpx
32
35
  }
33
36
  }]
34
- const appData = {}
35
37
  if (__mpx_mode__ === 'web') {
36
38
  builtInMixins.push({
37
39
  created () {
38
- Object.assign(this, Mpx.prototype)
39
- Object.assign(this, appData)
40
40
  const current = this.$root.$options?.router?.currentRoute || {}
41
41
  const options = {
42
42
  path: current.path && current.path.replace(/^\//, ''),
@@ -45,48 +45,41 @@ export default function createApp (option, config = {}) {
45
45
  shareTicket: '',
46
46
  referrerInfo: {}
47
47
  }
48
+ // web不分冷启动和热启动
48
49
  global.__mpxEnterOptions = options
49
- this.$options.onLaunch && this.$options.onLaunch.call(this, options)
50
- if (isBrowser) {
51
- if (this.$options.onShow) {
52
- this.$options.onShow.call(this, options)
53
- global.__mpxAppCbs.show.push(this.$options.onShow.bind(this))
54
- }
55
- if (this.$options.onHide) {
56
- global.__mpxAppCbs.hide.push(this.$options.onHide.bind(this))
57
- }
58
- if (this.$options.onError) {
59
- global.__mpxAppCbs.error.push(this.$options.onError.bind(this))
60
- }
61
- if (this.$options.onUnhandledRejection) {
62
- global.__mpxAppCbs.rejection.push(this.$options.onUnhandledRejection.bind(this))
63
- }
64
- }
50
+ global.__mpxLaunchOptions = options
51
+ rawOptions.onLaunch && rawOptions.onLaunch.call(appData, options)
52
+ global.__mpxAppCbs.show.forEach((cb) => {
53
+ cb(options)
54
+ })
65
55
  }
66
56
  })
67
57
  } else {
68
58
  builtInMixins.push({
69
59
  onLaunch () {
70
- Object.assign(this, Mpx.prototype)
60
+ initAppProvides(rawOptions.provide, this)
71
61
  }
72
62
  })
73
63
  }
74
- // app选项目前不需要进行转换
75
- const { rawOptions, currentInject } = transferOptions(option, 'app', false)
76
64
  rawOptions.mixins = builtInMixins
77
65
  const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
78
66
 
79
67
  if (__mpx_mode__ === 'web') {
80
- global.__mpxOptionsMap = global.__mpxOptionsMap || {}
81
- global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
82
68
  global.getApp = function () {
83
69
  if (!isBrowser) {
84
70
  console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
85
71
  }
86
72
  return appData
87
73
  }
74
+ if (isBrowser) {
75
+ defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appData))
76
+ defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appData))
77
+ defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appData))
78
+ defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appData))
79
+ }
80
+ global.__mpxOptionsMap = global.__mpxOptionsMap || {}
81
+ global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
88
82
  } else {
89
- initAppProvides(rawOptions)
90
83
  defaultOptions.onAppInit && defaultOptions.onAppInit()
91
84
  const ctor = config.customCtor || global.currentCtor || App
92
85
  ctor(defaultOptions)
@@ -1,3 +1,4 @@
1
+ import { isFunction, isNumber, isString } from '@mpxjs/utils'
1
2
  import { createI18n } from '../builtInMixins/i18nMixin'
2
3
 
3
4
  export function init (Mpx) {
@@ -30,21 +31,30 @@ function initGlobalErrorHandling () {
30
31
  })
31
32
  }
32
33
 
34
+ function onUnhandledRejection (event) {
35
+ if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
36
+ global.__mpxAppCbs.rejection.forEach((cb) => {
37
+ cb(event)
38
+ })
39
+ } else {
40
+ console.warn(`UNHANDLED PROMISE REJECTION ${(isNumber(event.id) || isString(event.id)) ? '(id:' + event.id + ')' : ''}: ${event.reason}\n`)
41
+ }
42
+ }
33
43
  const rejectionTrackingOptions = {
34
44
  allRejections: true,
35
45
  onUnhandled (id, error) {
36
- if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
37
- global.__mpxAppCbs.rejection.forEach((cb) => {
38
- cb(error, id)
39
- })
40
- } else {
41
- console.warn(`UNHANDLED PROMISE REJECTION (id: ${id}): ${error}\n`)
42
- }
46
+ onUnhandledRejection({ id, reason: error, promise: null })
43
47
  }
44
48
  }
45
49
 
46
- if (global?.HermesInternal?.hasPromise?.()) {
47
- global.HermesInternal?.enablePromiseRejectionTracker?.(rejectionTrackingOptions)
50
+ // 支持 core-js promise polyfill
51
+ const oldOnUnhandledRejection = global.onunhandledrejection
52
+ global.onunhandledrejection = function onunhandledrejection (event) {
53
+ onUnhandledRejection(event)
54
+ isFunction(oldOnUnhandledRejection) && oldOnUnhandledRejection.call(this, event)
55
+ }
56
+ if (global.HermesInternal?.hasPromise?.()) {
57
+ global.HermesInternal.enablePromiseRejectionTracker?.(rejectionTrackingOptions)
48
58
  } else {
49
59
  require('promise/setimmediate/rejection-tracking').enable(rejectionTrackingOptions)
50
60
  }
@@ -38,7 +38,7 @@ function initGlobalErrorHandling () {
38
38
  window.addEventListener('unhandledrejection', (event) => {
39
39
  if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
40
40
  global.__mpxAppCbs.rejection.forEach((cb) => {
41
- cb(event.reason, event.promise)
41
+ cb(event)
42
42
  })
43
43
  } else {
44
44
  console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}\n`)
@@ -11,11 +11,10 @@ const providesMap = {
11
11
  global.__mpxProvidesMap = providesMap
12
12
 
13
13
  /** @internal createApp() 初始化应用层 scope provide */
14
- export function initAppProvides (appOptions) {
15
- const provideOpt = appOptions.provide
14
+ export function initAppProvides (provideOpt, instance) {
16
15
  if (provideOpt) {
17
16
  const provided = isFunction(provideOpt)
18
- ? callWithErrorHandling(provideOpt.bind(appOptions), appOptions, 'createApp provide function')
17
+ ? callWithErrorHandling(provideOpt.bind(instance), instance, 'createApp provide function')
19
18
  : provideOpt
20
19
  if (isObject(provided)) {
21
20
  providesMap.__app = provided
@@ -367,21 +367,10 @@ function usePageStatus (navigation, pageId) {
367
367
  const blurSubscription = navigation.addListener('blur', () => {
368
368
  pageStatusMap[pageId] = 'hide'
369
369
  })
370
- const transitionEndSubscription = navigation.addListener('transitionEnd', () => {
371
- if (global.__navigationHelper.transitionEndCallback) {
372
- global.__navigationHelper.transitionEndCallback()
373
- global.__navigationHelper.transitionEndCallback = null
374
- }
375
- })
376
- const unWatchAppFocusedState = watch(global.__mpxAppFocusedState, (value) => {
377
- pageStatusMap[pageId] = value
378
- })
379
370
 
380
371
  return () => {
381
372
  focusSubscription()
382
373
  blurSubscription()
383
- unWatchAppFocusedState()
384
- transitionEndSubscription()
385
374
  del(pageStatusMap, pageId)
386
375
  }
387
376
  }, [navigation])
@@ -452,10 +441,17 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
452
441
 
453
442
  useEffect(() => {
454
443
  if (type === 'page') {
455
- if (!global.__mpxAppLaunched && global.__mpxAppOnLaunch) {
444
+ if (!global.__mpxAppHotLaunched && global.__mpxAppOnLaunch) {
456
445
  global.__mpxAppOnLaunch(props.navigation)
457
446
  }
458
- proxy.callHook(ONLOAD, [props.route.params || {}])
447
+ const loadParams = {}
448
+ // 此处拿到的props.route.params内属性的value被进行过了一次decode, 不符合预期,此处额外进行一次encode来与微信对齐
449
+ if (isObject(props.route.params)) {
450
+ for (const key in props.route.params) {
451
+ loadParams[key] = encodeURIComponent(props.route.params[key])
452
+ }
453
+ }
454
+ proxy.callHook(ONLOAD, [loadParams])
459
455
  }
460
456
  proxy.mounted()
461
457
  return () => {