@mpxjs/core 2.9.38 → 2.9.41-react.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.
Files changed (44) hide show
  1. package/package.json +37 -3
  2. package/src/convertor/convertor.js +4 -1
  3. package/src/convertor/getConvertMode.js +3 -1
  4. package/src/convertor/wxToReact.js +31 -0
  5. package/src/core/proxy.js +75 -7
  6. package/src/core/transferOptions.js +9 -1
  7. package/src/dynamic/astCache.js +25 -0
  8. package/src/dynamic/dynamicRenderMixin.js +77 -0
  9. package/src/dynamic/vnode/context.js +17 -0
  10. package/src/dynamic/vnode/css-select/cssauron.js +445 -0
  11. package/src/dynamic/vnode/css-select/index.js +116 -0
  12. package/src/dynamic/vnode/css-select/through.js +19 -0
  13. package/src/dynamic/vnode/css-select/tokenizer.js +371 -0
  14. package/src/dynamic/vnode/interpreter.js +449 -0
  15. package/src/dynamic/vnode/render.js +289 -0
  16. package/src/{vuePlugin.js → external/vuePlugin.js} +1 -1
  17. package/src/index.js +8 -2
  18. package/src/platform/builtInMixins/directiveHelperMixin.android.js +2 -0
  19. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +15 -0
  20. package/src/platform/builtInMixins/directiveHelperMixin.js +3 -0
  21. package/src/platform/builtInMixins/index.js +20 -2
  22. package/src/platform/builtInMixins/proxyEventMixin.android.js +2 -0
  23. package/src/platform/builtInMixins/proxyEventMixin.ios.js +49 -0
  24. package/src/platform/builtInMixins/proxyEventMixin.js +12 -14
  25. package/src/platform/builtInMixins/refsMixin.android.js +2 -0
  26. package/src/platform/builtInMixins/refsMixin.ios.js +311 -0
  27. package/src/platform/builtInMixins/renderHelperMixin.js +2 -2
  28. package/src/platform/builtInMixins/styleHelperMixin.android.js +2 -0
  29. package/src/platform/builtInMixins/styleHelperMixin.ios.js +141 -0
  30. package/src/platform/builtInMixins/styleHelperMixin.js +3 -0
  31. package/src/platform/createApp.android.js +2 -0
  32. package/src/platform/createApp.ios.js +103 -0
  33. package/src/platform/createApp.js +3 -5
  34. package/src/platform/export/api.web.js +1 -1
  35. package/src/platform/patch/ali/getDefaultOptions.js +24 -4
  36. package/src/platform/patch/index.js +9 -6
  37. package/src/platform/patch/react/getDefaultOptions.android.js +1 -0
  38. package/src/platform/patch/react/getDefaultOptions.ios.js +270 -0
  39. package/src/platform/patch/react/getDefaultOptions.js +1 -0
  40. package/src/platform/patch/swan/getDefaultOptions.js +1 -1
  41. package/src/platform/patch/web/getDefaultOptions.js +13 -3
  42. package/src/platform/patch/wx/getDefaultOptions.js +21 -1
  43. /package/src/{vue.js → external/vue.js} +0 -0
  44. /package/src/{vue.web.js → external/vue.web.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.9.38",
3
+ "version": "2.9.41-react.0",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,18 +19,52 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.9.38",
22
+ "@mpxjs/utils": "^2.9.41-react.0",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@mpxjs/api-proxy": "^2.9.0",
28
28
  "@mpxjs/store": "^2.9.0",
29
+ "@react-navigation/native": "^6.1.17",
30
+ "@react-navigation/native-stack": "^6.9.26",
31
+ "react": "^18.3.1",
32
+ "react-native": "^0.74.3",
33
+ "react-native-root-siblings": "^5.0.1",
29
34
  "vue": "^2.7.10",
30
35
  "vue-demi": "^0.14.6",
31
36
  "vue-i18n": "^8.27.2",
32
37
  "vue-i18n-bridge": "^9.2.2"
33
38
  },
39
+ "peerDependenciesMeta": {
40
+ "vue": {
41
+ "optional": true
42
+ },
43
+ "vue-demi": {
44
+ "optional": true
45
+ },
46
+ "vue-i18n": {
47
+ "optional": true
48
+ },
49
+ "vue-i18n-bridge": {
50
+ "optional": true
51
+ },
52
+ "react": {
53
+ "optional": true
54
+ },
55
+ "react-native": {
56
+ "optional": true
57
+ },
58
+ "@react-navigation/native": {
59
+ "optional": true
60
+ },
61
+ "@react-navigation/native-stack": {
62
+ "optional": true
63
+ },
64
+ "react-native-root-siblings": {
65
+ "optional": true
66
+ }
67
+ },
34
68
  "publishConfig": {
35
69
  "registry": "https://registry.npmjs.org",
36
70
  "access": "public"
@@ -47,5 +81,5 @@
47
81
  "url": "https://github.com/didi/mpx/issues"
48
82
  },
49
83
  "sideEffects": false,
50
- "gitHead": "5e2740e2091edda91eda9ffe775989c7fd9838df"
84
+ "gitHead": "1c9ae7527a257fad98f5536114e63415cea54271"
51
85
  }
@@ -11,6 +11,7 @@ import wxToQqRule from './wxToQq'
11
11
  import wxToTtRule from './wxToTt'
12
12
  import wxToDdRule from './wxToDd'
13
13
  import wxToJdRule from './wxToJd'
14
+ import wxToReactRule from './wxToReact'
14
15
 
15
16
  // 根据当前环境获取的默认生命周期信息
16
17
  let lifecycleInfo
@@ -55,7 +56,9 @@ const rulesMap = {
55
56
  wxToQq: { ...defaultConvertRule, ...wxToQqRule },
56
57
  wxToTt: { ...defaultConvertRule, ...wxToTtRule },
57
58
  wxToDd: { ...defaultConvertRule, ...wxToDdRule },
58
- wxToJd: { ...defaultConvertRule, ...wxToJdRule }
59
+ wxToJd: { ...defaultConvertRule, ...wxToJdRule },
60
+ wxToIos: { ...defaultConvertRule, ...wxToReactRule },
61
+ wxToAndroid: { ...defaultConvertRule, ...wxToReactRule }
59
62
  }
60
63
 
61
64
  export function getConvertRule (convertMode) {
@@ -5,7 +5,9 @@ const convertModes = {
5
5
  'wx-qq': 'wxToQq',
6
6
  'wx-tt': 'wxToTt',
7
7
  'wx-jd': 'wxToJd',
8
- 'wx-dd': 'wxToDd'
8
+ 'wx-dd': 'wxToDd',
9
+ 'wx-ios': 'wxToIos',
10
+ 'wx-android': 'wxToAndroid'
9
11
  }
10
12
 
11
13
  export function getConvertMode (srcMode) {
@@ -0,0 +1,31 @@
1
+ import {
2
+ error,
3
+ isDev
4
+ } from '@mpxjs/utils'
5
+ import { implemented } from '../core/implement'
6
+
7
+ // 暂不支持的wx选项,后期需要各种花式支持
8
+ const unsupported = ['relations', 'moved', 'definitionFilter', 'onShareAppMessage', 'options', 'behaviors', 'externalClasses']
9
+
10
+ function convertErrorDesc (key) {
11
+ error(`Options.${key} is not supported in runtime conversion from wx to react native.`, global.currentResource)
12
+ }
13
+
14
+ function notSupportTip (options) {
15
+ unsupported.forEach(key => {
16
+ if (options[key]) {
17
+ if (!implemented[key]) {
18
+ isDev && convertErrorDesc(key)
19
+ delete options[key]
20
+ } else if (implemented[key].remove) {
21
+ delete options[key]
22
+ }
23
+ }
24
+ })
25
+ }
26
+
27
+ export default {
28
+ convert (options) {
29
+ notSupportTip(options)
30
+ }
31
+ }
package/src/core/proxy.js CHANGED
@@ -27,7 +27,8 @@ import {
27
27
  callWithErrorHandling,
28
28
  warn,
29
29
  error,
30
- getEnvObj
30
+ getEnvObj,
31
+ isReact
31
32
  } from '@mpxjs/utils'
32
33
  import {
33
34
  BEFORECREATE,
@@ -44,6 +45,8 @@ import {
44
45
  ONHIDE,
45
46
  ONRESIZE
46
47
  } from './innerLifecycle'
48
+ import contextMap from '../dynamic/vnode/context'
49
+ import { getAst } from '../dynamic/astCache'
47
50
 
48
51
  let uid = 0
49
52
 
@@ -126,11 +129,15 @@ export default class MpxProxy {
126
129
  this.forceUpdateAll = false
127
130
  this.currentRenderTask = null
128
131
  this.propsUpdatedFlag = false
132
+ // react专用,正确触发updated钩子
133
+ this.pendingUpdatedFlag = false
129
134
  }
130
135
  this.initApi()
131
136
  }
132
137
 
133
138
  created () {
139
+ // 缓存上下文,在 destoryed 阶段删除
140
+ contextMap.set(this.uid, this.target)
134
141
  if (__mpx_mode__ !== 'web') {
135
142
  // web中BEFORECREATE钩子通过vue的beforeCreate钩子单独驱动
136
143
  this.callHook(BEFORECREATE)
@@ -146,7 +153,7 @@ export default class MpxProxy {
146
153
  this.state = CREATED
147
154
  this.callHook(CREATED)
148
155
 
149
- if (__mpx_mode__ !== 'web') {
156
+ if (__mpx_mode__ !== 'web' && !isReact) {
150
157
  this.initRender()
151
158
  }
152
159
 
@@ -168,9 +175,9 @@ export default class MpxProxy {
168
175
 
169
176
  mounted () {
170
177
  if (this.state === CREATED) {
171
- this.state = MOUNTED
172
178
  // 用于处理refs等前置工作
173
179
  this.callHook(BEFOREMOUNT)
180
+ this.state = MOUNTED
174
181
  this.callHook(MOUNTED)
175
182
  this.currentRenderTask && this.currentRenderTask.resolve()
176
183
  }
@@ -190,11 +197,13 @@ export default class MpxProxy {
190
197
  }
191
198
 
192
199
  unmounted () {
200
+ // 页面/组件销毁清除上下文的缓存
201
+ contextMap.remove(this.uid)
193
202
  this.callHook(BEFOREUNMOUNT)
194
203
  this.scope?.stop()
195
204
  if (this.update) this.update.active = false
196
- this.callHook(UNMOUNTED)
197
205
  this.state = UNMOUNTED
206
+ this.callHook(UNMOUNTED)
198
207
  }
199
208
 
200
209
  isUnmounted () {
@@ -230,7 +239,12 @@ export default class MpxProxy {
230
239
  }
231
240
 
232
241
  initProps () {
233
- this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
242
+ if (isReact) {
243
+ // react模式下props内部对象透传无需深clone,依赖对象深层的数据响应触发子组件更新
244
+ this.props = this.target.__getProps()
245
+ } else {
246
+ this.props = diffAndCloneA(this.target.__getProps(this.options)).clone
247
+ }
234
248
  reactive(this.props)
235
249
  proxy(this.target, this.props, undefined, false, this.createProxyConflictHandler('props'))
236
250
  }
@@ -379,7 +393,10 @@ export default class MpxProxy {
379
393
  this.doRender(this.processRenderDataWithStrictDiff(renderData))
380
394
  }
381
395
 
382
- renderWithData (skipPre) {
396
+ renderWithData (skipPre, vnode) {
397
+ if (vnode) {
398
+ return this.doRenderWithVNode(vnode)
399
+ }
383
400
  const renderData = skipPre ? this.renderData : preProcessRenderData(this.renderData)
384
401
  this.doRender(this.processRenderDataWithStrictDiff(renderData))
385
402
  // 重置renderData准备下次收集
@@ -478,6 +495,25 @@ export default class MpxProxy {
478
495
  return result
479
496
  }
480
497
 
498
+ doRenderWithVNode (vnode) {
499
+ if (!this._vnode) {
500
+ this.target.__render({ r: vnode })
501
+ } else {
502
+ let diffPath = diffAndCloneA(vnode, this._vnode).diffData
503
+ if (!isEmptyObject(diffPath)) {
504
+ // 构造 diffPath 数据
505
+ diffPath = Object.keys(diffPath).reduce((preVal, curVal) => {
506
+ const key = 'r' + curVal
507
+ preVal[key] = diffPath[curVal]
508
+ return preVal
509
+ }, {})
510
+ this.target.__render(diffPath)
511
+ }
512
+ }
513
+ // 缓存本地的 vnode 用以下一次 diff
514
+ this._vnode = diffAndCloneA(vnode).clone
515
+ }
516
+
481
517
  doRender (data, cb) {
482
518
  if (typeof this.target.__render !== 'function') {
483
519
  error('Please specify a [__render] function to render view.', this.options.mpxFileResource)
@@ -545,12 +581,30 @@ export default class MpxProxy {
545
581
  const _c = this.target._c.bind(this.target)
546
582
  const _r = this.target._r.bind(this.target)
547
583
  const _sc = this.target._sc.bind(this.target)
584
+ const _g = this.target._g?.bind(this.target)
585
+ const __getAst = this.target.__getAst?.bind(this.target)
586
+ const moduleId = this.target.__moduleId
587
+ const dynamicTarget = this.target.__dynamic
588
+
548
589
  const effect = this.effect = new ReactiveEffect(() => {
549
590
  // pre render for props update
550
591
  if (this.propsUpdatedFlag) {
551
592
  this.updatePreRender()
552
593
  }
553
-
594
+ if (dynamicTarget || __getAst) {
595
+ try {
596
+ const ast = getAst(__getAst, moduleId)
597
+ return _r(false, _g(ast, moduleId))
598
+ } catch (e) {
599
+ e.errType = 'mpx-dynamic-render'
600
+ e.errmsg = e.message
601
+ if (!__mpx_dynamic_runtime__) {
602
+ return error('Please make sure you have set dynamicRuntime true in mpx webpack plugin config because you have use the dynamic runtime feature.', this.options.mpxFileResource, e)
603
+ } else {
604
+ return error('Dynamic rendering error', this.options.mpxFileResource, e)
605
+ }
606
+ }
607
+ }
554
608
  if (this.target.__injectedRender) {
555
609
  try {
556
610
  return this.target.__injectedRender(_i, _c, _r, _sc)
@@ -596,6 +650,20 @@ export default class MpxProxy {
596
650
  this.forceUpdateAll = true
597
651
  }
598
652
 
653
+ if (isReact) {
654
+ // rn中不需要setdata
655
+ this.forceUpdateData = {}
656
+ this.forceUpdateAll = false
657
+ if (this.update) {
658
+ options.sync ? this.update() : queueJob(this.update)
659
+ }
660
+ if (callback) {
661
+ callback = callback.bind(this.target)
662
+ options.sync ? callback() : nextTick(callback)
663
+ }
664
+ return
665
+ }
666
+
599
667
  if (this.effect) {
600
668
  options.sync ? this.effect.run() : this.effect.update()
601
669
  } else {
@@ -7,6 +7,10 @@ export default function transferOptions (options, type, needConvert = true) {
7
7
  let currentInject
8
8
  if (global.currentInject && global.currentInject.moduleId === global.currentModuleId) {
9
9
  currentInject = global.currentInject
10
+ } else {
11
+ currentInject = {
12
+ moduleId: global.currentModuleId
13
+ }
10
14
  }
11
15
  // 文件编译路径
12
16
  options.mpxFileResource = global.currentResource
@@ -18,8 +22,12 @@ export default function transferOptions (options, type, needConvert = true) {
18
22
  // 编译计算属性注入
19
23
  options.computed = Object.assign({}, currentInject.injectComputed, options.computed)
20
24
  }
25
+ if (currentInject && currentInject.injectMethods) {
26
+ // 编译methods注入
27
+ options.methods = Object.assign({}, currentInject.injectMethods, options.methods)
28
+ }
21
29
  if (currentInject && currentInject.injectOptions) {
22
- // 编译option注入,优先微信中的单独配置
30
+ // 编译options注入,优先微信中的单独配置
23
31
  options.options = Object.assign({}, currentInject.injectOptions, options.options)
24
32
  }
25
33
  if (currentInject && currentInject.pageEvents) {
@@ -0,0 +1,25 @@
1
+ import { isFunction, isObject, error } from '@mpxjs/utils'
2
+
3
+ class DynamicAstCache {
4
+ #astCache = {}
5
+
6
+ getAst (id) {
7
+ return this.#astCache[id]
8
+ }
9
+
10
+ setAst (id, ast) {
11
+ this.#astCache[id] = ast
12
+ }
13
+ }
14
+
15
+ export const dynamic = new DynamicAstCache()
16
+
17
+ export const getAst = (__getAst, moduleId) => {
18
+ if ((__getAst && isFunction(__getAst))) {
19
+ const ast = __getAst()
20
+ if (!isObject(ast)) return error('__getAst returned data is not of type object')
21
+ return Object.values(ast)[0]
22
+ } else {
23
+ return dynamic.getAst(moduleId)
24
+ }
25
+ }
@@ -0,0 +1,77 @@
1
+ import { hasOwn, isObject, error } from '@mpxjs/utils'
2
+ import genVnodeTree from './vnode/render'
3
+ import contextMap from './vnode/context'
4
+ import { CREATED } from '../core/innerLifecycle'
5
+
6
+ function dynamicRefsMixin () {
7
+ return {
8
+ [CREATED] () {
9
+ // 处理ref场景,如果是在容器组件的上下文渲染
10
+ if (this.mpxCustomElement) {
11
+ this._getRuntimeRefs()
12
+ }
13
+ },
14
+ methods: {
15
+ _getRuntimeRefs () {
16
+ const vnodeContext = contextMap.get(this.uid)
17
+ if (vnodeContext) {
18
+ const refsArr = vnodeContext.__getRefsData && vnodeContext.__getRefsData()
19
+ if (Array.isArray(refsArr)) {
20
+ refsArr.forEach((ref) => {
21
+ const all = ref.all
22
+ if (!vnodeContext.$refs[ref.key] || (all && !vnodeContext.$refs[ref.key].length)) {
23
+ const refNode = this.__getRefNode(ref)
24
+ if ((all && refNode.length) || refNode) {
25
+ Object.defineProperty(vnodeContext.$refs, ref.key, {
26
+ enumerable: true,
27
+ configurable: true,
28
+ get: () => {
29
+ return refNode
30
+ }
31
+ })
32
+ }
33
+ }
34
+ })
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ function dynamicSlotMixin () {
43
+ if (__mpx_mode__ === 'ali') {
44
+ return {
45
+ props: { slots: {} }
46
+ }
47
+ } else {
48
+ return {
49
+ properties: { slots: { type: Object } }
50
+ }
51
+ }
52
+ }
53
+
54
+ function dynamicRenderHelperMixin () {
55
+ return {
56
+ methods: {
57
+ _g (astData, moduleId) {
58
+ const location = this.__mpxProxy && this.__mpxProxy.options.mpxFileResource
59
+ if (astData && isObject(astData) && hasOwn(astData, 'template')) {
60
+ const vnodeTree = genVnodeTree(astData, [this], { moduleId, location })
61
+ return vnodeTree
62
+ } else {
63
+ error('Dynamic component get the wrong json ast data, please check.', location, {
64
+ errType: 'mpx-dynamic-render',
65
+ errmsg: 'invalid json ast data'
66
+ })
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ export {
74
+ dynamicRefsMixin,
75
+ dynamicSlotMixin,
76
+ dynamicRenderHelperMixin
77
+ }
@@ -0,0 +1,17 @@
1
+ const cache = {}
2
+
3
+ const contextMap = {
4
+ set (id, context) {
5
+ cache[id] = context
6
+ },
7
+ get (id) {
8
+ return cache[id]
9
+ },
10
+ remove (id) {
11
+ if (cache[id]) {
12
+ delete cache[id]
13
+ }
14
+ }
15
+ }
16
+
17
+ export default contextMap