@mpxjs/webpack-plugin 2.10.15 → 2.10.16-beta.3

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 (89) hide show
  1. package/lib/dependencies/AppEntryDependency.js +2 -2
  2. package/lib/dependencies/DynamicEntryDependency.js +1 -1
  3. package/lib/dependencies/ImportDependency.js +102 -0
  4. package/lib/dependencies/RecordModuleIdMapDependency.js +49 -0
  5. package/lib/dependencies/ResolveDependency.js +1 -1
  6. package/lib/{retry-runtime-module.js → dependencies/RetryRuntimeModule.js} +1 -1
  7. package/lib/helpers.js +2 -0
  8. package/lib/index.js +51 -25
  9. package/lib/json-compiler/helper.js +72 -2
  10. package/lib/json-compiler/index.js +14 -54
  11. package/lib/json-compiler/plugin.js +2 -2
  12. package/lib/loader.js +6 -2
  13. package/lib/native-loader.js +6 -3
  14. package/lib/platform/json/wx/index.js +24 -29
  15. package/lib/platform/style/wx/index.js +8 -1
  16. package/lib/platform/template/wx/component-config/button.js +12 -3
  17. package/lib/platform/template/wx/component-config/camera.js +12 -0
  18. package/lib/platform/template/wx/component-config/component.js +31 -33
  19. package/lib/platform/template/wx/component-config/slider.js +12 -0
  20. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  21. package/lib/react/processJSON.js +39 -71
  22. package/lib/react/processStyles.js +3 -2
  23. package/lib/react/processTemplate.js +6 -6
  24. package/lib/react/script-helper.js +6 -16
  25. package/lib/react/style-helper.js +10 -2
  26. package/lib/resolver/AddEnvPlugin.js +13 -0
  27. package/lib/resolver/AddModePlugin.js +18 -0
  28. package/lib/runtime/components/react/context.ts +2 -0
  29. package/lib/runtime/components/react/dist/context.js +1 -0
  30. package/lib/runtime/components/react/dist/mpx-camera.jsx +102 -0
  31. package/lib/runtime/components/react/dist/mpx-image.jsx +81 -37
  32. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +19 -4
  33. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +3 -2
  34. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +9 -6
  35. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.jsx +8 -11
  36. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +20 -0
  37. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
  38. package/lib/runtime/components/react/dist/mpx-progress.jsx +26 -22
  39. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +6 -14
  40. package/lib/runtime/components/react/dist/mpx-slider.jsx +321 -0
  41. package/lib/runtime/components/react/dist/mpx-text.jsx +33 -5
  42. package/lib/runtime/components/react/dist/mpx-view.jsx +8 -11
  43. package/lib/runtime/components/react/dist/mpx-web-view.jsx +1 -1
  44. package/lib/runtime/components/react/dist/utils.jsx +16 -6
  45. package/lib/runtime/components/react/mpx-camera.tsx +167 -0
  46. package/lib/runtime/components/react/mpx-image.tsx +89 -42
  47. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +31 -4
  48. package/lib/runtime/components/react/mpx-picker-view/index.tsx +4 -1
  49. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +19 -8
  50. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItem.tsx +8 -12
  51. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItemLite.tsx +55 -0
  52. package/lib/runtime/components/react/mpx-portal/index.tsx +8 -2
  53. package/lib/runtime/components/react/mpx-progress.tsx +26 -24
  54. package/lib/runtime/components/react/mpx-scroll-view.tsx +6 -17
  55. package/lib/runtime/components/react/mpx-slider.tsx +444 -0
  56. package/lib/runtime/components/react/mpx-text.tsx +38 -5
  57. package/lib/runtime/components/react/mpx-view.tsx +8 -11
  58. package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
  59. package/lib/runtime/components/react/utils.tsx +15 -6
  60. package/lib/runtime/components/web/mpx-input.vue +1 -1
  61. package/lib/runtime/components/web/mpx-scroll-view.vue +7 -1
  62. package/lib/runtime/components/web/mpx-video.vue +12 -1
  63. package/lib/runtime/optionProcessor.js +3 -1
  64. package/lib/runtime/optionProcessorReact.js +4 -2
  65. package/lib/script-setup-compiler/index.js +2 -2
  66. package/lib/style-compiler/index.js +3 -2
  67. package/lib/style-compiler/load-postcss-config.js +1 -1
  68. package/lib/style-compiler/plugins/trans-special.js +10 -2
  69. package/lib/style-compiler/strip-conditional-loader.js +155 -15
  70. package/lib/template-compiler/compiler.js +262 -61
  71. package/lib/template-compiler/gen-node-react.js +18 -6
  72. package/lib/template-compiler/index.js +6 -4
  73. package/lib/template-compiler/parse-exps.js +1 -1
  74. package/lib/utils/chain-assign.js +47 -0
  75. package/lib/utils/check-core-version-match.js +75 -15
  76. package/lib/utils/const.js +2 -1
  77. package/lib/utils/dom-tag-config.js +1 -1
  78. package/lib/utils/env.js +6 -1
  79. package/lib/utils/get-build-tag-component.js +35 -0
  80. package/lib/utils/pre-process-json.js +5 -0
  81. package/lib/web/processJSON.js +44 -16
  82. package/lib/web/processScript.js +1 -1
  83. package/lib/web/processTemplate.js +4 -4
  84. package/lib/web/script-helper.js +19 -9
  85. package/lib/wxs/pre-loader.js +6 -6
  86. package/lib/wxss/loader.js +1 -9
  87. package/package.json +14 -5
  88. package/LICENSE +0 -433
  89. package/lib/dependencies/ImportDependencyTemplate.js +0 -50
@@ -1,7 +1,7 @@
1
1
  const JSON5 = require('json5')
2
2
  const he = require('he')
3
3
  const config = require('../config')
4
- const { MPX_ROOT_VIEW, MPX_APP_MODULE_ID, PARENT_MODULE_ID } = require('../utils/const')
4
+ const { MPX_ROOT_VIEW, MPX_APP_MODULE_ID, PARENT_MODULE_ID, MPX_TAG_PAGE_SELECTOR } = require('../utils/const')
5
5
  const normalize = require('../utils/normalize')
6
6
  const { normalizeCondition } = require('../utils/match-condition')
7
7
  const isValidIdentifierStr = require('../utils/is-valid-identifier-str')
@@ -15,7 +15,8 @@ const { isNonPhrasingTag } = require('../utils/dom-tag-config')
15
15
  const setBaseWxml = require('../runtime-render/base-wxml')
16
16
  const { parseExp } = require('./parse-exps')
17
17
  const shallowStringify = require('../utils/shallow-stringify')
18
- const { isReact, isWeb } = require('../utils/env')
18
+ const { isReact, isWeb, isNoMode } = require('../utils/env')
19
+ const { capitalToHyphen } = require('../utils/string')
19
20
 
20
21
  const no = function () {
21
22
  return false
@@ -119,6 +120,8 @@ const rulesResultMap = new Map()
119
120
  let usingComponents = []
120
121
  let usingComponentsInfo = {}
121
122
  let componentGenerics = {}
123
+ // 跨平台语法检测的配置,在模块加载时初始化一次
124
+ let crossPlatformConfig = null
122
125
 
123
126
  function updateForScopesMap () {
124
127
  forScopesMap = {}
@@ -147,11 +150,11 @@ const deleteErrorInResultMap = (node) => {
147
150
  }
148
151
 
149
152
  function baseWarn (msg) {
150
- console.warn(('[template compiler]: ' + msg))
153
+ console.warn(('[Mpx template warning]: ' + msg))
151
154
  }
152
155
 
153
156
  function baseError (msg) {
154
- console.error(('[template compiler]: ' + msg))
157
+ console.error(('[Mpx template error]: ' + msg))
155
158
  }
156
159
 
157
160
  const decodeMap = {
@@ -176,11 +179,11 @@ const i18nWxsPath = normalize.lib('runtime/i18n.wxs')
176
179
  const i18nWxsLoaderPath = normalize.lib('wxs/i18n-loader.js')
177
180
  // 添加~前缀避免wxs绝对路径在存在projectRoot时被拼接为错误路径
178
181
  const i18nWxsRequest = '~' + i18nWxsLoaderPath + '!' + i18nWxsPath
179
- const i18nModuleName = '_i'
182
+ const i18nModuleName = '_i_'
180
183
  const stringifyWxsPath = '~' + normalize.lib('runtime/stringify.wxs')
181
- const stringifyModuleName = '_s'
184
+ const stringifyModuleName = '_s_'
182
185
  const optionalChainWxsPath = '~' + normalize.lib('runtime/oc.wxs')
183
- const optionalChainWxsName = '_oc' // 改成_oc解决web下_o重名问题
186
+ const optionalChainWxsName = '_oc_' // 改成_oc解决web下_o重名问题
184
187
 
185
188
  const tagRES = /(\{\{(?:.|\n|\r)+?\}\})(?!})/
186
189
  const tagRE = /\{\{((?:.|\n|\r)+?)\}\}(?!})/
@@ -637,8 +640,9 @@ function parse (template, options) {
637
640
  processingTemplate = false
638
641
  rulesResultMap.clear()
639
642
  componentGenerics = options.componentGenerics || {}
643
+ // 初始化跨平台语法检测配置(每次解析时只初始化一次)
644
+ crossPlatformConfig = initCrossPlatformConfig()
640
645
 
641
- if (typeof options.usingComponentsInfo === 'string') options.usingComponentsInfo = JSON.parse(options.usingComponentsInfo)
642
646
  usingComponents = Object.keys(options.usingComponentsInfo)
643
647
  usingComponentsInfo = options.usingComponentsInfo
644
648
 
@@ -681,7 +685,6 @@ function parse (template, options) {
681
685
  meta.options.virtualHost = true
682
686
  }
683
687
  let currentParent
684
- let multiRootError
685
688
  // 用于记录模板用到的组件,匹配引用组件,看是否有冗余
686
689
  const tagNames = new Set()
687
690
 
@@ -760,7 +763,10 @@ function parse (template, options) {
760
763
  if (!currentParent) genTempRoot()
761
764
 
762
765
  const children = currentParent.children
763
- if (currentParent.tag !== 'text') {
766
+
767
+ const isTextLikeParent = currentParent.tag === 'text' || currentParent.tag === 'mpx-text' || currentParent.tag === 'Text' || currentParent.tag === 'mpx-simple-text'
768
+
769
+ if (!isTextLikeParent) {
764
770
  text = text.trim()
765
771
  } else {
766
772
  text = text.trim() ? text : ''
@@ -793,9 +799,10 @@ function parse (template, options) {
793
799
  }
794
800
  })
795
801
 
796
- if (multiRootError) {
797
- error$1('Template fields should has one single root, considering wrapping your template content with <view> or <text> tag!')
798
- }
802
+ // multiRoot
803
+ // if (root.tag === 'temp-node' && root.children && root.children.filter(node => node.tag !== 'temp-node').length > 1) {
804
+ // error$1('Template fields should has one single root, considering wrapping your template content with <view> or <text> tag!')
805
+ // }
799
806
 
800
807
  if (hasI18n) {
801
808
  if (i18nInjectableComputed.length) {
@@ -1000,12 +1007,34 @@ function processComponentIs (el, options) {
1000
1007
  }
1001
1008
 
1002
1009
  const range = getAndRemoveAttr(el, 'range').val
1003
- const isInRange = makeMap(range || '')
1004
- el.components = (usingComponents).filter(i => {
1005
- if (!range) return true
1006
- return isInRange(i)
1010
+
1011
+ // Map<CurrentName, SourceName>
1012
+ let ranges
1013
+ if (range) {
1014
+ ranges = range.split(',').map(i => i.trim()).filter(i => i)
1015
+ } else {
1016
+ // 根据原始用户写的usingComponents字段生成ranges
1017
+ ranges = options.originalUsingComponents
1018
+ }
1019
+
1020
+ const rangeMap = new Map()
1021
+ ranges.forEach(name => {
1022
+ rangeMap.set(['ali', 'swan'].includes(mode) ? capitalToHyphen(name) : name, name)
1007
1023
  })
1008
- if (!el.components.length) {
1024
+
1025
+ // Map<CurrentName, SourceName>
1026
+ el.componentMap = new Map()
1027
+ usingComponents.forEach((name) => {
1028
+ if (rangeMap.size === 0) {
1029
+ el.componentMap.set(name, name)
1030
+ } else {
1031
+ if (rangeMap.has(name)) {
1032
+ el.componentMap.set(name, rangeMap.get(name))
1033
+ }
1034
+ }
1035
+ })
1036
+
1037
+ if (el.componentMap.size === 0) {
1009
1038
  warn$1('Component in which <component> tag is used must have a non blank usingComponents field')
1010
1039
  }
1011
1040
 
@@ -1383,7 +1412,11 @@ function processEvent (el, options) {
1383
1412
  const targetConfigs = isCapture ? eventConfigMap[type].captureConfigs : eventConfigMap[type].configs
1384
1413
  targetConfigs.push(Object.assign({ name }, parsedFunc))
1385
1414
  if (modifiers.indexOf('proxy') > -1 || options.forceProxyEvent) {
1386
- eventConfigMap[type].proxy = true
1415
+ if (isCapture) {
1416
+ eventConfigMap[type].captureProxy = true
1417
+ } else {
1418
+ eventConfigMap[type].proxy = true
1419
+ }
1387
1420
  }
1388
1421
  }
1389
1422
  }
@@ -1423,10 +1456,10 @@ function processEvent (el, options) {
1423
1456
  }
1424
1457
 
1425
1458
  for (const type in eventConfigMap) {
1426
- const { configs = [], captureConfigs = [], proxy } = eventConfigMap[type]
1459
+ const { configs = [], captureConfigs = [], proxy, captureProxy } = eventConfigMap[type]
1427
1460
 
1428
1461
  let needBubblingBind = isNeedBind(configs, proxy)
1429
- let needCaptureBind = isNeedBind(captureConfigs, proxy)
1462
+ let needCaptureBind = isNeedBind(captureConfigs, captureProxy)
1430
1463
 
1431
1464
  const escapedType = dash2hump(type)
1432
1465
  // 排除特殊情况
@@ -1588,7 +1621,7 @@ function parseOptionalChaining (str) {
1588
1621
  }
1589
1622
  if (grammarMap.checkState() && haveNotGetValue) {
1590
1623
  // 值查找结束但是语法未闭合或者处理到边界还未结束,抛异常
1591
- throw new Error('[optionChain] option value illegal!!!')
1624
+ throw new Error('[Mpx template error]: optionChain option value illegal!!!')
1592
1625
  }
1593
1626
  haveNotGetValue = true
1594
1627
  let keyValue = ''
@@ -1638,7 +1671,7 @@ function parseOptionalChaining (str) {
1638
1671
  }
1639
1672
  if (grammarMap.checkState() && haveNotGetValue) {
1640
1673
  // key值查找结束但是语法未闭合或者处理到边界还未结束,抛异常
1641
- throw new Error('[optionChain] option key illegal!!!')
1674
+ throw new Error('[Mpx template error]: optionChain option key illegal!!!')
1642
1675
  }
1643
1676
  if (keyValue) {
1644
1677
  chainKey += `,'${keyValue}'`
@@ -2080,13 +2113,24 @@ function postProcessIf (el) {
2080
2113
  replaceNode(el, getTempNode())._if = false
2081
2114
  }
2082
2115
  } else {
2116
+ el._if = null
2083
2117
  attrs = [{
2084
2118
  name: config[mode].directive.if,
2085
2119
  value: el.if.raw
2086
2120
  }]
2087
2121
  }
2088
2122
  } else if (el.elseif) {
2123
+ if (el.for) {
2124
+ error$1(`wx:elif (wx:elif="${el.elseif.raw}") invalidly used on the for-list <"${el.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the elif-directive to it`)
2125
+ return
2126
+ }
2127
+
2089
2128
  prevNode = findPrevNode(el)
2129
+ if (!prevNode || prevNode._if === undefined) {
2130
+ error$1(`wx:elif="${el.elseif.raw}" used on element [${el.tag}] without corresponding wx:if or wx:elif.`)
2131
+ return
2132
+ }
2133
+
2090
2134
  if (prevNode._if === true) {
2091
2135
  removeNode(el)
2092
2136
  } else if (prevNode._if === false) {
@@ -2106,6 +2150,7 @@ function postProcessIf (el) {
2106
2150
  removeNode(el)
2107
2151
  }
2108
2152
  } else {
2153
+ el._if = null
2109
2154
  attrs = [{
2110
2155
  name: config[mode].directive.elseif,
2111
2156
  value: el.elseif.raw
@@ -2113,7 +2158,17 @@ function postProcessIf (el) {
2113
2158
  }
2114
2159
  }
2115
2160
  } else if (el.else) {
2161
+ if (el.for) {
2162
+ error$1(`wx:else invalidly used on the for-list <"${el.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the else-directive to it`)
2163
+ return
2164
+ }
2165
+
2116
2166
  prevNode = findPrevNode(el)
2167
+ if (!prevNode || prevNode._if === undefined) {
2168
+ error$1(`wx:else used on element [${el.tag}] without corresponding wx:if or wx:elif.`)
2169
+ return
2170
+ }
2171
+
2117
2172
  if (prevNode._if === true) {
2118
2173
  removeNode(el)
2119
2174
  } else if (prevNode._if === false) {
@@ -2137,23 +2192,100 @@ function addIfCondition (el, condition) {
2137
2192
  el.ifConditions.push(condition)
2138
2193
  }
2139
2194
 
2195
+ function getIfConditions (el) {
2196
+ return el?.ifConditions || []
2197
+ }
2198
+
2140
2199
  function postProcessIfReact (el) {
2141
- let prevNode
2200
+ let prevNode, ifNode, result, ifConditions
2142
2201
  if (el.if) {
2143
- addIfCondition(el, {
2144
- exp: el.if.exp,
2145
- block: el
2146
- })
2147
- } else if (el.elseif || el.else) {
2148
- prevNode = findPrevNode(el)
2149
- if (prevNode && prevNode.if) {
2150
- addIfCondition(prevNode, {
2151
- exp: el.elseif && el.elseif.exp,
2202
+ // 取值
2203
+ // false -> 节点变为temp-node,并添加_if=false
2204
+ // true -> 添加_if=true,移除if
2205
+ // dynamic -> addIfCondition
2206
+ result = evalExp(el.if.exp)
2207
+ if (result.success) {
2208
+ if (result.result) {
2209
+ el._if = true
2210
+ delete el.if
2211
+ } else {
2212
+ replaceNode(el, getTempNode())._if = false
2213
+ }
2214
+ } else {
2215
+ el._if = null
2216
+ addIfCondition(el, {
2217
+ exp: el.if.exp,
2152
2218
  block: el
2153
2219
  })
2154
- removeNode(el, true)
2220
+ }
2221
+ } else if (el.elseif) {
2222
+ if (el.for) {
2223
+ error$1(`wx:elif (wx:elif="${el.elseif.raw}") invalidly used on the for-list <"${el.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the elif-directive to it`)
2224
+ return
2225
+ }
2226
+
2227
+ ifNode = findPrevNode(el)
2228
+ ifConditions = getIfConditions(ifNode)
2229
+ prevNode = ifConditions.length > 0 ? ifConditions[ifConditions.length - 1].block : ifNode
2230
+
2231
+ if (!prevNode || prevNode._if === undefined) {
2232
+ error$1(`wx:elif="${el.elseif.raw}" used on element [${el.tag}] without corresponding wx:if or wx:elif.`)
2233
+ return
2234
+ }
2235
+
2236
+ if (prevNode._if === true) {
2237
+ removeNode(el)
2238
+ } else if (prevNode._if === false) {
2239
+ el.if = el.elseif
2240
+ delete el.elseif
2241
+ postProcessIfReact(el)
2155
2242
  } else {
2156
- warn$1(`wx:${el.elseif ? `elif="${el.elseif.raw}"` : 'else'} used on element [${el.tag}] without corresponding wx:if.`)
2243
+ result = evalExp(el.elseif.exp)
2244
+ if (result.success) {
2245
+ if (result.result) {
2246
+ delete el.elseif
2247
+ el._if = true
2248
+ addIfCondition(ifNode, {
2249
+ exp: el.elseif.exp,
2250
+ block: el
2251
+ })
2252
+ removeNode(el, true)
2253
+ } else {
2254
+ removeNode(el)
2255
+ }
2256
+ } else {
2257
+ el._if = null
2258
+ addIfCondition(ifNode, {
2259
+ exp: el.elseif.exp,
2260
+ block: el
2261
+ })
2262
+ removeNode(el, true)
2263
+ }
2264
+ }
2265
+ } else if (el.else) {
2266
+ if (el.for) {
2267
+ error$1(`wx:else invalidly used on the for-list <"${el.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the else-directive to it`)
2268
+ return
2269
+ }
2270
+
2271
+ ifNode = findPrevNode(el)
2272
+ ifConditions = getIfConditions(ifNode)
2273
+ prevNode = ifConditions.length > 0 ? ifConditions[ifConditions.length - 1].block : ifNode
2274
+
2275
+ if (!prevNode || prevNode._if === undefined) {
2276
+ error$1(`wx:else used on element [${el.tag}] without corresponding wx:if or wx:elif.`)
2277
+ return
2278
+ }
2279
+
2280
+ if (prevNode._if === true) {
2281
+ removeNode(el)
2282
+ } else if (prevNode._if === false) {
2283
+ delete el.else
2284
+ } else {
2285
+ addIfCondition(ifNode, {
2286
+ block: el
2287
+ })
2288
+ removeNode(el, true)
2157
2289
  }
2158
2290
  }
2159
2291
  }
@@ -2520,6 +2652,16 @@ function getVirtualHostRoot (options, meta) {
2520
2652
  if (isWeb(mode) && ctorType === 'page') {
2521
2653
  return createASTElement('page')
2522
2654
  }
2655
+ if (isReact(mode) && ctorType === 'page') {
2656
+ const rootView = createASTElement('view', [
2657
+ {
2658
+ name: 'class',
2659
+ value: MPX_TAG_PAGE_SELECTOR
2660
+ }
2661
+ ])
2662
+ processElement(rootView, rootView, options, meta)
2663
+ return rootView
2664
+ }
2523
2665
  }
2524
2666
  return getTempNode()
2525
2667
  }
@@ -2713,6 +2855,78 @@ function processNoTransAttrs (el) {
2713
2855
  }
2714
2856
  }
2715
2857
 
2858
+ function initCrossPlatformConfig () {
2859
+ // 定义平台与前缀的双向映射关系
2860
+ const platformPrefixMap = {
2861
+ wx: 'wx:',
2862
+ ali: 'a:',
2863
+ swan: 's-',
2864
+ qq: 'qq:',
2865
+ tt: 'tt:',
2866
+ dd: 'dd:',
2867
+ jd: 'jd:',
2868
+ qa: 'qa:',
2869
+ web: 'v-'
2870
+ }
2871
+
2872
+ if (isNoMode(mode)) {
2873
+ return null
2874
+ }
2875
+
2876
+ return {
2877
+ currentPrefix: platformPrefixMap[mode] || 'wx:',
2878
+ platformPrefixMap
2879
+ }
2880
+ }
2881
+
2882
+ // 检测跨平台语法使用情况并给出警告
2883
+ function processCrossPlatformSyntaxWarning (el) {
2884
+ // 使用转换后的属性列表进行检查
2885
+ if (!el.attrsList || el.attrsList.length === 0) {
2886
+ return
2887
+ }
2888
+
2889
+ // 如果配置为空,说明不需要检测
2890
+ if (!crossPlatformConfig) {
2891
+ return
2892
+ }
2893
+
2894
+ const { currentPrefix, platformPrefixMap } = crossPlatformConfig
2895
+
2896
+ // 检查转换后的属性列表
2897
+ el.attrsList.forEach(attr => {
2898
+ const attrName = attr.name
2899
+
2900
+ // 检查是否使用了平台前缀
2901
+ for (const [platformName, prefix] of Object.entries(platformPrefixMap)) {
2902
+ if (attrName.startsWith(prefix)) {
2903
+ if (isReact(mode)) {
2904
+ // React Native 平台:只允许使用 wx: 前缀,其他前缀报错
2905
+ if (prefix !== 'wx:') {
2906
+ error$1(
2907
+ `React Native mode "${mode}" does not support "${prefix}" prefix. ` +
2908
+ `Use "wx:" prefix instead. Found: "${attrName}"`
2909
+ )
2910
+ }
2911
+ } else {
2912
+ // 小程序平台:检测跨平台语法使用
2913
+ if (platformName !== mode) {
2914
+ // 构建建议的正确属性名
2915
+ const suffixPart = attrName.substring(prefix.length)
2916
+ const suggestedAttr = currentPrefix + suffixPart
2917
+
2918
+ warn$1(
2919
+ `Your target mode is "${mode}", but used "${attrName}". ` +
2920
+ `Did you mean "${suggestedAttr}"?`
2921
+ )
2922
+ }
2923
+ }
2924
+ break
2925
+ }
2926
+ }
2927
+ })
2928
+ }
2929
+
2716
2930
  function processMpxTagName (el) {
2717
2931
  const mpxTagName = getAndRemoveAttr(el, 'mpxTagName').val
2718
2932
  if (mpxTagName) {
@@ -2742,6 +2956,9 @@ function processElement (el, root, options, meta) {
2742
2956
 
2743
2957
  processDuplicateAttrsList(el)
2744
2958
 
2959
+ // 检测跨平台语法使用情况并给出警告
2960
+ processCrossPlatformSyntaxWarning(el)
2961
+
2745
2962
  processInjectWxs(el, meta, options)
2746
2963
 
2747
2964
  const transAli = mode === 'ali' && srcMode === 'wx'
@@ -2886,7 +3103,7 @@ function cloneAttrsList (attrsList) {
2886
3103
  }
2887
3104
 
2888
3105
  function postProcessComponentIs (el, postProcessChild) {
2889
- if (el.is && el.components) {
3106
+ if (el.is && el.componentMap && el.componentMap.size > 0) {
2890
3107
  let tempNode
2891
3108
  if (el.for || el.if || el.elseif || el.else) {
2892
3109
  tempNode = createASTElement('block')
@@ -2896,11 +3113,12 @@ function postProcessComponentIs (el, postProcessChild) {
2896
3113
  replaceNode(el, tempNode, true)
2897
3114
  postMoveBaseDirective(tempNode, el)
2898
3115
 
2899
- el.components.forEach(function (component) {
2900
- const newChild = createASTElement(component, cloneAttrsList(el.attrsList), tempNode)
3116
+ // Map<CurrentName, SourceName>
3117
+ el.componentMap.forEach((source, name) => {
3118
+ const newChild = createASTElement(name, cloneAttrsList(el.attrsList), tempNode)
2901
3119
  newChild.if = {
2902
- raw: `{{${el.is} === ${stringify(component)}}}`,
2903
- exp: `${el.is} === ${stringify(component)}`
3120
+ raw: `{{${el.is} === ${stringify(source)}}}`,
3121
+ exp: `${el.is} === ${stringify(source)}`
2904
3122
  }
2905
3123
  el.children.forEach((child) => {
2906
3124
  addChild(newChild, cloneNode(child))
@@ -3025,30 +3243,12 @@ function genIf (node) {
3025
3243
 
3026
3244
  function genElseif (node) {
3027
3245
  node.elseifProcessed = true
3028
- if (node.for) {
3029
- error$1(`wx:elif (wx:elif="${node.elseif.raw}") invalidly used on the for-list <"${node.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the if-directive to it`)
3030
- return
3031
- }
3032
- const preNode = findPrevNode(node)
3033
- if (preNode && (preNode.if || preNode.elseif)) {
3034
- return `else if(${node.elseif.exp}){\n${genNode(node)}}\n`
3035
- } else {
3036
- error$1(`wx:elif (wx:elif="${node.elseif.raw}") invalidly used on the element <"${node.tag}"> without corresponding wx:if or wx:elif.`)
3037
- }
3246
+ return `else if(${node.elseif.exp}){\n${genNode(node)}}\n`
3038
3247
  }
3039
3248
 
3040
3249
  function genElse (node) {
3041
3250
  node.elseProcessed = true
3042
- if (node.for) {
3043
- error$1(`wx:else invalidly used on the for-list <"${node.tag}"> which has a wx:for directive, please create a block element to wrap the for-list and move the if-directive to it`)
3044
- return
3045
- }
3046
- const preNode = findPrevNode(node)
3047
- if (preNode && (preNode.if || preNode.elseif)) {
3048
- return `else{\n${genNode(node)}}\n`
3049
- } else {
3050
- error$1(`wx:else invalidly used on the element <"${node.tag}"> without corresponding wx:if or wx:elif.`)
3051
- }
3251
+ return `else{\n${genNode(node)}}\n`
3052
3252
  }
3053
3253
 
3054
3254
  function genExps (node) {
@@ -3259,5 +3459,6 @@ module.exports = {
3259
3459
  findPrevNode,
3260
3460
  removeNode,
3261
3461
  replaceNode,
3262
- createASTElement
3462
+ createASTElement,
3463
+ evalExp
3263
3464
  }
@@ -9,7 +9,8 @@ function genIfConditions (conditions) {
9
9
  if (!conditions.length) return 'null'
10
10
  const condition = conditions.shift()
11
11
  if (condition.exp) {
12
- return `(${condition.exp})?${genNode(condition.block)}:${genIfConditions(conditions)}`
12
+ // 此处 condition.exp 无需括号包裹,condition.exp本身已经包含括号
13
+ return `${condition.exp}?${genNode(condition.block)}:${genIfConditions(conditions)}`
13
14
  } else {
14
15
  return genNode(condition.block)
15
16
  }
@@ -30,7 +31,7 @@ function mapAttrName (name) {
30
31
  return name
31
32
  }
32
33
 
33
- function genNode (node) {
34
+ function genNode (node, isRoot = false) {
34
35
  let exp = ''
35
36
  if (node) {
36
37
  if (node.type === 3) {
@@ -72,18 +73,29 @@ function genNode (node) {
72
73
  }
73
74
 
74
75
  if (!node.unary && node.children.length) {
75
- exp += ','
76
- exp += node.children.map((child) => {
76
+ const childNode = node.children.map((child) => {
77
77
  return genNode(child)
78
78
  }).filter(fragment => fragment).join(',')
79
+
80
+ // child可能为temp-node等无效节点,所以增加判断确保存在childNode再添加逗号
81
+ if (childNode) {
82
+ exp += ','
83
+ exp += childNode
84
+ }
79
85
  }
80
86
  exp += ')'
81
87
  }
82
88
  }
83
89
  } else {
84
- exp += node.children.map((child) => {
90
+ const nodes = node.children.map((child) => {
85
91
  return genNode(child)
86
- }).filter(fragment => fragment).join(',')
92
+ }).filter(fragment => fragment && fragment !== 'null')
93
+ if (isRoot && nodes.length > 1) {
94
+ // 如果存在多个根节点,使用 block 包裹
95
+ exp = `createElement(getComponent("block"), null, ${nodes.join(',')})`
96
+ } else {
97
+ exp += nodes.join(',')
98
+ }
87
99
  }
88
100
  }
89
101
  }
@@ -24,14 +24,15 @@ module.exports = function (raw) {
24
24
  const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
25
25
  const wxsContentMap = mpx.wxsContentMap
26
26
  const optimizeRenderRules = mpx.optimizeRenderRules
27
- const usingComponentsInfo = queryObj.usingComponentsInfo || {}
27
+ const usingComponentsInfo = queryObj.usingComponentsInfo ? JSON.parse(queryObj.usingComponentsInfo) : {}
28
+ const originalUsingComponents = queryObj.originalUsingComponents ? JSON.parse(queryObj.originalUsingComponents) : []
28
29
  const componentPlaceholder = queryObj.componentPlaceholder || []
29
30
  const hasComment = queryObj.hasComment
30
31
  const isNative = queryObj.isNative
31
32
  const ctorType = queryObj.ctorType
32
33
  const hasScoped = queryObj.hasScoped
33
34
  const runtimeCompile = queryObj.isDynamic
34
- const moduleId = queryObj.moduleId || mpx.getModuleId(resourcePath)
35
+ const moduleId = queryObj.moduleId || mpx.getModuleId(resourcePath, false, queryObj.moduleId ? null : this)
35
36
 
36
37
  let optimizeRenderLevel = 0
37
38
  for (const rule of optimizeRenderRules) {
@@ -43,13 +44,13 @@ module.exports = function (raw) {
43
44
 
44
45
  const warn = (msg) => {
45
46
  this.emitWarning(
46
- new Error('[template compiler][' + this.resource + ']: ' + msg)
47
+ new Error('[Mpx template warning][' + this.resource + ']: ' + msg)
47
48
  )
48
49
  }
49
50
 
50
51
  const error = (msg) => {
51
52
  this.emitError(
52
- new Error('[template compiler][' + this.resource + ']: ' + msg)
53
+ new Error('[Mpx template error][' + this.resource + ']: ' + msg)
53
54
  )
54
55
  }
55
56
 
@@ -70,6 +71,7 @@ module.exports = function (raw) {
70
71
  hasScoped,
71
72
  moduleId,
72
73
  usingComponentsInfo,
74
+ originalUsingComponents,
73
75
  // 这里需传递rawResourcePath和wxsContentMap保持一致
74
76
  filePath: rawResourcePath,
75
77
  i18n,
@@ -23,7 +23,7 @@ const NODE_TYPE = {
23
23
  }
24
24
 
25
25
  const error = function (msg) {
26
- throw new Error(`[Mpx dynamic expression parser error]: ${msg}`)
26
+ throw new Error(`[Mpx template error]: ${msg}`)
27
27
  }
28
28
 
29
29
  walk.full = function full (node, baseVisitor, state, override) {
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 链式合并方法的工具函数
3
+ *
4
+ * 在多条件分支下使用 Object.assign 会导致同名方法被覆盖,
5
+ * 这个函数通过创建组合函数来确保所有方法都能按顺序执行。
6
+ *
7
+ * @param {Object} target - 目标 visitor 对象
8
+ * @param {Object} source - 要链式分配的 visitor 方法对象
9
+ *
10
+ * @example
11
+ * const visitor = {}
12
+ *
13
+ * // 第一次合并
14
+ * chainAssign(visitor, {
15
+ * CallExpression(path) {
16
+ * console.log('第一个处理器')
17
+ * }
18
+ * })
19
+ *
20
+ * // 第二次合并 - 不会覆盖,而是组合执行
21
+ * chainAssign(visitor, {
22
+ * CallExpression(path) {
23
+ * console.log('第二个处理器')
24
+ * }
25
+ * })
26
+ *
27
+ * // 执行时会依次输出:
28
+ * // 第一个处理器
29
+ * // 第二个处理器
30
+ */
31
+ module.exports = function chainAssign (target, source) {
32
+ for (const [key, value] of Object.entries(source)) {
33
+ if (target[key]) {
34
+ // 如果已存在同名方法,创建组合函数依次执行
35
+ const originalMethod = target[key]
36
+ target[key] = function (path) {
37
+ originalMethod.call(this, path)
38
+ // 只有当节点没有停止遍历或被移除时才继续执行
39
+ if (!path.removed && !path.shouldStop) {
40
+ value.call(this, path)
41
+ }
42
+ }
43
+ } else {
44
+ target[key] = value
45
+ }
46
+ }
47
+ }