@mpxjs/webpack-plugin 2.10.19 → 2.10.21

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 (137) hide show
  1. package/lib/dependencies/ResolveDependency.js +2 -2
  2. package/lib/index.js +38 -7
  3. package/lib/json-compiler/helper.js +11 -10
  4. package/lib/json-compiler/index.js +7 -4
  5. package/lib/json-compiler/plugin.js +4 -4
  6. package/lib/loader.js +4 -4
  7. package/lib/native-loader.js +4 -4
  8. package/lib/parser.js +1 -1
  9. package/lib/platform/create-diagnostic.js +168 -0
  10. package/lib/platform/index.js +16 -3
  11. package/lib/platform/json/wx/index.js +66 -17
  12. package/lib/platform/run-rules.js +9 -5
  13. package/lib/platform/style/wx/index.js +82 -33
  14. package/lib/platform/template/normalize-component-rules.js +7 -9
  15. package/lib/platform/template/wx/component-config/block.js +2 -1
  16. package/lib/platform/template/wx/component-config/custom-built-in-component.js +34 -0
  17. package/lib/platform/template/wx/component-config/index.js +18 -3
  18. package/lib/platform/template/wx/component-config/input.js +1 -7
  19. package/lib/platform/template/wx/component-config/movable-view.js +1 -7
  20. package/lib/platform/template/wx/component-config/text.js +1 -1
  21. package/lib/platform/template/wx/component-config/textarea.js +1 -25
  22. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  23. package/lib/platform/template/wx/index.js +48 -34
  24. package/lib/react/processJSON.js +7 -4
  25. package/lib/react/processStyles.js +22 -8
  26. package/lib/react/processTemplate.js +98 -41
  27. package/lib/react/style-helper.js +121 -86
  28. package/lib/react/template-loader.js +161 -0
  29. package/lib/runtime/components/react/context.ts +8 -1
  30. package/lib/runtime/components/react/dist/context.d.ts +6 -1
  31. package/lib/runtime/components/react/dist/context.js +1 -0
  32. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -0
  33. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +1 -1
  34. package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -1
  35. package/lib/runtime/components/react/dist/mpx-button.jsx +6 -5
  36. package/lib/runtime/components/react/dist/mpx-camera.jsx +1 -0
  37. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +4 -1
  38. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -1
  39. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +6 -4
  40. package/lib/runtime/components/react/dist/mpx-form.jsx +3 -3
  41. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +5 -1
  42. package/lib/runtime/components/react/dist/mpx-image.d.ts +3 -3
  43. package/lib/runtime/components/react/dist/mpx-image.jsx +45 -12
  44. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +10 -6
  45. package/lib/runtime/components/react/dist/mpx-input.jsx +17 -4
  46. package/lib/runtime/components/react/dist/mpx-label.jsx +6 -4
  47. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +19 -4
  48. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +12 -2
  49. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +1 -1
  50. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +7 -4
  51. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
  52. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +4 -1
  53. package/lib/runtime/components/react/dist/mpx-radio.jsx +5 -4
  54. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -1
  55. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -4
  56. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +52 -6
  57. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +36 -6
  58. package/lib/runtime/components/react/dist/mpx-slider.jsx +2 -1
  59. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +8 -4
  60. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -4
  61. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +7 -4
  62. package/lib/runtime/components/react/dist/mpx-swiper.jsx +15 -4
  63. package/lib/runtime/components/react/dist/mpx-switch.jsx +4 -1
  64. package/lib/runtime/components/react/dist/mpx-text.jsx +57 -12
  65. package/lib/runtime/components/react/dist/mpx-video.d.ts +2 -1
  66. package/lib/runtime/components/react/dist/mpx-video.jsx +10 -4
  67. package/lib/runtime/components/react/dist/mpx-view.jsx +42 -7
  68. package/lib/runtime/components/react/dist/utils.d.ts +21 -11
  69. package/lib/runtime/components/react/dist/utils.jsx +105 -35
  70. package/lib/runtime/components/react/getInnerListeners.ts +1 -0
  71. package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
  72. package/lib/runtime/components/react/mpx-button.tsx +6 -5
  73. package/lib/runtime/components/react/mpx-camera.tsx +1 -0
  74. package/lib/runtime/components/react/mpx-canvas/index.tsx +4 -1
  75. package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -1
  76. package/lib/runtime/components/react/mpx-checkbox.tsx +6 -4
  77. package/lib/runtime/components/react/mpx-form.tsx +3 -3
  78. package/lib/runtime/components/react/mpx-icon/index.tsx +5 -1
  79. package/lib/runtime/components/react/mpx-image.tsx +57 -20
  80. package/lib/runtime/components/react/mpx-inline-text.tsx +12 -7
  81. package/lib/runtime/components/react/mpx-input.tsx +17 -4
  82. package/lib/runtime/components/react/mpx-label.tsx +6 -4
  83. package/lib/runtime/components/react/mpx-movable-view.tsx +20 -4
  84. package/lib/runtime/components/react/mpx-picker/index.tsx +12 -2
  85. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  86. package/lib/runtime/components/react/mpx-picker-view/index.tsx +8 -4
  87. package/lib/runtime/components/react/mpx-portal/index.tsx +5 -1
  88. package/lib/runtime/components/react/mpx-radio-group.tsx +4 -1
  89. package/lib/runtime/components/react/mpx-radio.tsx +5 -4
  90. package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -1
  91. package/lib/runtime/components/react/mpx-scroll-view.tsx +13 -4
  92. package/lib/runtime/components/react/mpx-simple-text.tsx +55 -8
  93. package/lib/runtime/components/react/mpx-simple-view.tsx +30 -6
  94. package/lib/runtime/components/react/mpx-slider.tsx +2 -1
  95. package/lib/runtime/components/react/mpx-sticky-header.tsx +8 -4
  96. package/lib/runtime/components/react/mpx-sticky-section.tsx +6 -4
  97. package/lib/runtime/components/react/mpx-swiper-item.tsx +7 -4
  98. package/lib/runtime/components/react/mpx-swiper.tsx +16 -4
  99. package/lib/runtime/components/react/mpx-switch.tsx +4 -1
  100. package/lib/runtime/components/react/mpx-text.tsx +55 -15
  101. package/lib/runtime/components/react/mpx-video.tsx +11 -5
  102. package/lib/runtime/components/react/mpx-view.tsx +35 -7
  103. package/lib/runtime/components/react/types/global.d.ts +4 -0
  104. package/lib/runtime/components/react/utils.tsx +126 -45
  105. package/lib/runtime/components/wx/default-component.mpx +9 -0
  106. package/lib/runtime/components/wx/default-page.mpx +3 -11
  107. package/lib/runtime/optionProcessor.d.ts +2 -0
  108. package/lib/runtime/optionProcessor.js +77 -1
  109. package/lib/runtime/optionProcessorReact.js +5 -0
  110. package/lib/script-setup-compiler/index.js +1 -1
  111. package/lib/style-compiler/index.js +2 -0
  112. package/lib/style-compiler/plugins/remove-strip-conditional-comments.js +14 -0
  113. package/lib/style-compiler/plugins/trans-special.js +1 -1
  114. package/lib/style-compiler/strip-conditional.js +40 -26
  115. package/lib/template-compiler/compiler.js +306 -125
  116. package/lib/template-compiler/gen-node-react.js +35 -7
  117. package/lib/template-compiler/index.js +9 -7
  118. package/lib/utils/const.js +4 -1
  119. package/lib/utils/gen-component-tag.js +1 -5
  120. package/lib/utils/normalize-perf-options.js +47 -0
  121. package/lib/utils/partial-compile-rules.js +27 -0
  122. package/lib/utils/pre-process-json.js +3 -0
  123. package/lib/utils/source-location.js +96 -0
  124. package/lib/web/compile-wx-template-fragment.js +68 -0
  125. package/lib/web/index.js +3 -0
  126. package/lib/web/processJSON.js +7 -4
  127. package/lib/web/processMainScript.js +3 -7
  128. package/lib/web/processScript.js +43 -8
  129. package/lib/web/processStyles.js +12 -3
  130. package/lib/web/processTemplate.js +61 -19
  131. package/lib/web/template-loader.js +123 -0
  132. package/lib/web/template-shared.js +48 -0
  133. package/lib/wxml/loader.js +4 -3
  134. package/lib/wxss/loader.js +1 -1
  135. package/lib/wxss/utils.js +6 -4
  136. package/package.json +12 -4
  137. package/lib/platform/template/wx/component-config/component.js +0 -41
@@ -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, MPX_TAG_PAGE_SELECTOR } = require('../utils/const')
4
+ const { MPX_ROOT_VIEW, MPX_APP_MODULE_ID, PARENT_MODULE_ID, MPX_TAG_PAGE_SELECTOR, MPX_TEMPLATE_COMPONENT_PREFIX, STYLE_PAD_PLACEHOLDER } = 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')
@@ -17,6 +17,8 @@ const { parseExp } = require('./parse-exps')
17
17
  const shallowStringify = require('../utils/shallow-stringify')
18
18
  const { isReact, isWeb, isNoMode } = require('../utils/env')
19
19
  const { capitalToHyphen } = require('../utils/string')
20
+ const { isNativeMiniTag } = require('../utils/dom-tag-config')
21
+ const { offsetToLoc } = require('../utils/source-location')
20
22
 
21
23
  const no = function () {
22
24
  return false
@@ -105,6 +107,9 @@ let hasVirtualHost
105
107
  let isCustomText
106
108
  let runtimeCompile
107
109
  let rulesRunner
110
+ let customBuiltInComponentsOpt
111
+ let isUrlRequest
112
+ let templateAssetId
108
113
  let currentEl
109
114
  let injectNodes = []
110
115
  let forScopes = []
@@ -180,9 +185,9 @@ const i18nWxsLoaderPath = normalize.lib('wxs/i18n-loader.js')
180
185
  // 添加~前缀避免wxs绝对路径在存在projectRoot时被拼接为错误路径
181
186
  const i18nWxsRequest = '~' + i18nWxsLoaderPath + '!' + i18nWxsPath
182
187
  const i18nModuleName = '_i_'
183
- const stringifyWxsPath = '~' + normalize.lib('runtime/stringify.wxs')
188
+ const stringifyWxsRequest = '~' + normalize.lib('runtime/stringify.wxs')
184
189
  const stringifyModuleName = '_s_'
185
- const optionalChainWxsPath = '~' + normalize.lib('runtime/oc.wxs')
190
+ const optionalChainWxsRequest = '~' + normalize.lib('runtime/oc.wxs')
186
191
  const optionalChainWxsName = '_oc_' // 改成_oc解决web下_o重名问题
187
192
 
188
193
  const tagRES = /(\{\{(?:.|\n|\r)+?\}\})(?!})/
@@ -339,7 +344,10 @@ function parseHTML (html, options) {
339
344
  advance(start[0].length)
340
345
  let end, attr
341
346
  while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
347
+ const attrStart = index
342
348
  advance(attr[0].length)
349
+ attr.start = attrStart
350
+ attr.end = index
343
351
  match.attrs.push(attr)
344
352
  }
345
353
  if (end) {
@@ -391,7 +399,9 @@ function parseHTML (html, options) {
391
399
  }
392
400
  attrs[i] = {
393
401
  name: args[1],
394
- value: decode(value)
402
+ value: decode(value),
403
+ start: args.start,
404
+ end: args.end
395
405
  }
396
406
  }
397
407
 
@@ -584,8 +594,7 @@ function parseComponent (content, options) {
584
594
  let text = content.slice(currentBlock.start, currentBlock.end)
585
595
  // pad content so that linters and pre-processors can output correct
586
596
  // line numbers in errors and warnings
587
- // stylus编译遇到大量空行时会出现栈溢出,故针对stylus不走pad
588
- if (options.pad && !(currentBlock.tag === 'style' && currentBlock.lang === 'stylus')) {
597
+ if (options.pad) {
589
598
  text = padContent(currentBlock, options.pad) + text
590
599
  }
591
600
  currentBlock.content = text
@@ -599,7 +608,7 @@ function parseComponent (content, options) {
599
608
  return content.slice(0, block.start).replace(replaceRE, ' ')
600
609
  } else {
601
610
  const offset = content.slice(0, block.start).split(splitRE).length
602
- const padChar = '\n'
611
+ const padChar = block.tag === 'style' ? `/* ${STYLE_PAD_PLACEHOLDER} */\n` : '\n'
603
612
  return Array(offset).join(padChar)
604
613
  }
605
614
  }
@@ -617,9 +626,9 @@ function parse (template, options) {
617
626
  warn$1 = options.warn || baseWarn
618
627
  error$1 = options.error || baseError
619
628
  mode = options.mode || 'wx'
629
+ srcMode = options.srcMode || mode
620
630
  env = options.env
621
631
  defs = options.defs || {}
622
- srcMode = options.srcMode || mode
623
632
  ctorType = options.ctorType
624
633
  moduleId = options.moduleId
625
634
  isNative = options.isNative
@@ -640,25 +649,28 @@ function parse (template, options) {
640
649
  processingTemplate = false
641
650
  rulesResultMap.clear()
642
651
  componentGenerics = options.componentGenerics || {}
652
+ usingComponentsInfo = options.usingComponentsInfo || {}
653
+ usingComponents = Object.keys(usingComponentsInfo)
654
+ customBuiltInComponentsOpt = options.customBuiltInComponents || null
655
+ isUrlRequest = options.isUrlRequest
656
+ templateAssetId = 0
657
+
643
658
  // 初始化跨平台语法检测配置(每次解析时只初始化一次)
644
659
  crossPlatformConfig = initCrossPlatformConfig()
645
660
 
646
- usingComponents = Object.keys(options.usingComponentsInfo)
647
- usingComponentsInfo = options.usingComponentsInfo
648
-
649
- const _warn = content => {
661
+ const _warn = (content, loc) => {
650
662
  const currentElementRuleResult = rulesResultMap.get(currentEl) || rulesResultMap.set(currentEl, {
651
663
  warnArray: [],
652
664
  errorArray: []
653
665
  }).get(currentEl)
654
- currentElementRuleResult.warnArray.push(content)
666
+ currentElementRuleResult.warnArray.push({ content, loc })
655
667
  }
656
- const _error = content => {
668
+ const _error = (content, loc) => {
657
669
  const currentElementRuleResult = rulesResultMap.get(currentEl) || rulesResultMap.set(currentEl, {
658
670
  warnArray: [],
659
671
  errorArray: []
660
672
  }).get(currentEl)
661
- currentElementRuleResult.errorArray.push(content)
673
+ currentElementRuleResult.errorArray.push({ content, loc })
662
674
  }
663
675
 
664
676
  rulesRunner = getRulesRunner({
@@ -667,10 +679,15 @@ function parse (template, options) {
667
679
  type: 'template',
668
680
  testKey: 'tag',
669
681
  data: {
670
- usingComponents
682
+ usingComponents,
683
+ customBuiltInComponents: customBuiltInComponentsOpt
671
684
  },
672
685
  warn: _warn,
673
- error: _error
686
+ error: _error,
687
+ diagnostic: {
688
+ file: filePath,
689
+ source: template
690
+ }
674
691
  })
675
692
 
676
693
  const stack = []
@@ -700,12 +717,20 @@ function parse (template, options) {
700
717
  isUnaryTag: options.isUnaryTag,
701
718
  canBeLeftOpenTag: options.canBeLeftOpenTag,
702
719
  shouldKeepComment: true,
703
- start: function start (tag, attrs, unary) {
720
+ start: function start (tag, attrs, unary, start, end) {
704
721
  // check namespace.
705
722
  // inherit parent ns if there is one
706
723
  const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag)
707
724
 
708
725
  const element = createASTElement(tag, attrs, currentParent)
726
+ element.start = start
727
+ element.end = end
728
+ element.loc = offsetToLoc(template, start, end)
729
+ element.attrsList.forEach((attr) => {
730
+ if (attr.start != null) {
731
+ attr.loc = offsetToLoc(template, attr.start, attr.end)
732
+ }
733
+ })
709
734
 
710
735
  if (ns) {
711
736
  element.ns = ns
@@ -811,7 +836,7 @@ function parse (template, options) {
811
836
  }
812
837
 
813
838
  if (hasOptionalChaining) {
814
- injectWxs(meta, optionalChainWxsName, optionalChainWxsPath)
839
+ injectWxs(meta, optionalChainWxsName, optionalChainWxsRequest)
815
840
  }
816
841
 
817
842
  injectNodes.forEach((node) => {
@@ -819,8 +844,8 @@ function parse (template, options) {
819
844
  })
820
845
 
821
846
  rulesResultMap.forEach((val) => {
822
- Array.isArray(val.warnArray) && val.warnArray.forEach(item => warn$1(item))
823
- Array.isArray(val.errorArray) && val.errorArray.forEach(item => error$1(item))
847
+ Array.isArray(val.warnArray) && val.warnArray.forEach(item => warn$1(item.content, item.loc))
848
+ Array.isArray(val.errorArray) && val.errorArray.forEach(item => error$1(item.content, item.loc))
824
849
  })
825
850
 
826
851
  if (!tagNames.has('component') && !tagNames.has('template') && options.checkUsingComponents) {
@@ -1703,6 +1728,10 @@ function parseMustacheWithContext (raw = '') {
1703
1728
  const funcNameRE = new RegExp(`(?<![A-Za-z0-9_$.])${i18nFuncName}\\(`)
1704
1729
  const funcNameREG = new RegExp(`(?<![A-Za-z0-9_$.])${i18nFuncName}\\(`, 'g')
1705
1730
  if (funcNameRE.test(exp)) {
1731
+ if (processingTemplate) {
1732
+ warn$1('i18n function is not supported in template!')
1733
+ break
1734
+ }
1706
1735
  if (i18n.useComputed || !i18nFuncName.startsWith('\\$')) {
1707
1736
  const i18nInjectComputedKey = `_i${i18nInjectableComputed.length + 1}`
1708
1737
  i18nInjectableComputed.push(`${i18nInjectComputedKey} () {\nreturn ${exp.trim()}}`)
@@ -1996,17 +2025,23 @@ const spreadREG = /\{\s*\.\.\.\s*([^,{]+?)\s*\}/g
1996
2025
 
1997
2026
  function processAttrs (el, options) {
1998
2027
  el.attrsList.forEach((attr) => {
1999
- const isTemplateData = el.tag === 'template' && attr.name === 'data'
2028
+ const isTemplateData = el.tag === 'template' && attr.name === 'data' && attr.value
2000
2029
  const needWrap = isTemplateData && mode !== 'swan'
2001
2030
  let value = needWrap ? `{${attr.value}}` : attr.value
2002
2031
 
2003
- // 修复React Native环境下属性值中插值表达式带空格的问题
2004
- if (isReact(mode) && typeof value === 'string') {
2005
- // 检查是否为带空格的插值表达式
2006
- const trimmedValue = value.trim()
2007
- if (trimmedValue.startsWith('{{') && trimmedValue.endsWith('}}')) {
2008
- // 如果是纯插值表达式但带有前后空格,则使用去除空格后的值进行解析
2009
- value = trimmedValue
2032
+ if (isReact(mode)) {
2033
+ // 修复React Native环境下属性值中插值表达式带空格的问题
2034
+ if (typeof value === 'string') {
2035
+ // 检查是否为带空格的插值表达式
2036
+ const trimmedValue = value.trim()
2037
+ if (trimmedValue.startsWith('{{') && trimmedValue.endsWith('}}')) {
2038
+ // 如果是纯插值表达式但带有前后空格,则使用去除空格后的值进行解析
2039
+ value = trimmedValue
2040
+ }
2041
+ }
2042
+ if (value === undefined) {
2043
+ value = '{{true}}'
2044
+ modifyAttr(el, attr.name, value)
2010
2045
  }
2011
2046
  }
2012
2047
 
@@ -2381,7 +2416,7 @@ function processClass (el, meta) {
2381
2416
  // swan中externalClass是通过编译时静态实现,因此需要保留原有的staticClass形式避免externalClass失效
2382
2417
  value: mode === 'swan' && staticClass ? `${staticClass} {{${stringifyModuleName}.c('', ${dynamicClassExp})}}` : `{{${stringifyModuleName}.c(${staticClassExp}, ${dynamicClassExp})}}`
2383
2418
  }])
2384
- injectWxs(meta, stringifyModuleName, stringifyWxsPath)
2419
+ injectWxs(meta, stringifyModuleName, stringifyWxsRequest)
2385
2420
  } else if (staticClass) {
2386
2421
  addAttrs(el, [{
2387
2422
  name: targetType,
@@ -2414,7 +2449,7 @@ function processStyle (el, meta) {
2414
2449
  name: targetType,
2415
2450
  value: `{{${stringifyModuleName}.s(${staticStyleExp}, ${dynamicStyleExp})}}`
2416
2451
  }])
2417
- injectWxs(meta, stringifyModuleName, stringifyWxsPath)
2452
+ injectWxs(meta, stringifyModuleName, stringifyWxsRequest)
2418
2453
  } else if (staticStyle) {
2419
2454
  addAttrs(el, [{
2420
2455
  name: targetType,
@@ -2432,6 +2467,10 @@ function isRealNode (el) {
2432
2467
  }
2433
2468
 
2434
2469
  function isComponentNode (el) {
2470
+ if (processingTemplate) {
2471
+ // 处理模版时无法获取真实的usingComponents信息,除了小程序基础组件和框架内建组件外都识别为用户组件
2472
+ return isRealNode(el) && !isNativeMiniTag(el.tag) && !el.isBuiltIn
2473
+ }
2435
2474
  return usingComponents.indexOf(el.tag) !== -1 || el.tag === 'component' || componentGenerics[el.tag]
2436
2475
  }
2437
2476
 
@@ -2443,81 +2482,102 @@ function isReactComponent (el) {
2443
2482
  return !isComponentNode(el) && isRealNode(el) && !el.isBuiltIn
2444
2483
  }
2445
2484
 
2485
+ function processWebClass (classLikeAttrName, classLikeAttrValue, el, options, processingWebTemplate) {
2486
+ let classNames = classLikeAttrValue.split(/\s+/)
2487
+ let hasExternalClass = false
2488
+ const attrsSource = processingWebTemplate ? '(__mpxHost && __mpxHost.$attrs || {})' : '$attrs'
2489
+ classNames = classNames.map((className) => {
2490
+ if (options.externalClasses.includes(className)) {
2491
+ hasExternalClass = true
2492
+ return `(${attrsSource}[${stringify(className)}] || '')`
2493
+ }
2494
+ return stringify(className)
2495
+ })
2496
+ if (hasExternalClass) {
2497
+ classNames.push(`(${attrsSource}[${stringify(PARENT_MODULE_ID)}] || '')`)
2498
+ }
2499
+ if (classLikeAttrName === 'class') {
2500
+ const dynamicClass = getAndRemoveAttr(el, ':class').val
2501
+ if (dynamicClass) classNames.push(dynamicClass)
2502
+ addAttrs(el, [{
2503
+ name: ':class',
2504
+ value: `[${classNames}]`
2505
+ }])
2506
+ } else {
2507
+ addAttrs(el, [{
2508
+ name: ':' + classLikeAttrName,
2509
+ value: `[${classNames}].join(' ')`
2510
+ }])
2511
+ }
2512
+ }
2513
+
2514
+ function processAliClass (classLikeAttrName, classLikeAttrValue, el, options) {
2515
+ let hasExternalClass = false
2516
+ options.externalClasses.forEach((className) => {
2517
+ const reg = new RegExp('\\b' + className + '\\b', 'g')
2518
+ const replacementClassName = dash2hump(className)
2519
+ if (classLikeAttrValue.includes(className)) hasExternalClass = true
2520
+ classLikeAttrValue = classLikeAttrValue.replace(reg, `{{${replacementClassName} || ''}}`)
2521
+ })
2522
+ if (hasExternalClass) {
2523
+ classLikeAttrValue += ` {{${PARENT_MODULE_ID} || ''}}`
2524
+ }
2525
+ addAttrs(el, [{
2526
+ name: classLikeAttrName,
2527
+ value: classLikeAttrValue
2528
+ }])
2529
+ }
2530
+
2446
2531
  function processExternalClasses (el, options) {
2447
2532
  const isComponent = isComponentNode(el)
2448
2533
  const classLikeAttrNames = isComponent ? ['class'].concat(options.externalClasses) : ['class']
2534
+ const processingWebTemplate = isWeb(mode) && processingTemplate
2449
2535
 
2450
2536
  classLikeAttrNames.forEach((classLikeAttrName) => {
2451
2537
  const classLikeAttrValue = getAndRemoveAttr(el, classLikeAttrName).val
2452
2538
  if (classLikeAttrValue) {
2453
2539
  if (mode === 'web') {
2454
- processWebClass(classLikeAttrName, classLikeAttrValue, el, options)
2540
+ processWebClass(classLikeAttrName, classLikeAttrValue, el, options, processingWebTemplate)
2455
2541
  } else {
2456
2542
  processAliClass(classLikeAttrName, classLikeAttrValue, el, options)
2457
2543
  }
2458
2544
  }
2459
2545
  })
2460
2546
 
2461
- if (hasScoped && isComponent) {
2547
+ if ((hasScoped || processingWebTemplate) && isComponent) {
2462
2548
  const needAddModuleId = options.externalClasses.some((className) => {
2463
2549
  return el.attrsMap[className] || (mode === 'web' && el.attrsMap[':' + className])
2464
2550
  })
2465
2551
 
2466
2552
  if (needAddModuleId) {
2467
- addAttrs(el, [{
2468
- name: PARENT_MODULE_ID,
2469
- value: `${moduleId}`
2470
- }])
2471
- }
2472
- }
2473
- function processWebClass (classLikeAttrName, classLikeAttrValue, el, options) {
2474
- let classNames = classLikeAttrValue.split(/\s+/)
2475
- let hasExternalClass = false
2476
- classNames = classNames.map((className) => {
2477
- if (options.externalClasses.includes(className)) {
2478
- hasExternalClass = true
2479
- return `($attrs[${stringify(className)}] || '')`
2553
+ if (processingWebTemplate) {
2554
+ addAttrs(el, [{
2555
+ name: ':' + PARENT_MODULE_ID,
2556
+ value: '(__mpxHost && __mpxHost.$options.__mpxScoped ? (__mpxHost.$options.__mpxModuleId || "") : "")'
2557
+ }])
2558
+ } else {
2559
+ addAttrs(el, [{
2560
+ name: PARENT_MODULE_ID,
2561
+ value: `${moduleId}`
2562
+ }])
2480
2563
  }
2481
- return stringify(className)
2482
- })
2483
- if (hasExternalClass) {
2484
- classNames.push(`($attrs[${stringify(PARENT_MODULE_ID)}] || '')`)
2485
- }
2486
- if (classLikeAttrName === 'class') {
2487
- const dynamicClass = getAndRemoveAttr(el, ':class').val
2488
- if (dynamicClass) classNames.push(dynamicClass)
2489
- addAttrs(el, [{
2490
- name: ':class',
2491
- value: `[${classNames}]`
2492
- }])
2493
- } else {
2494
- addAttrs(el, [{
2495
- name: ':' + classLikeAttrName,
2496
- value: `[${classNames}].join(' ')`
2497
- }])
2498
2564
  }
2499
2565
  }
2500
-
2501
- function processAliClass (classLikeAttrName, classLikeAttrValue, el, options) {
2502
- let hasExternalClass = false
2503
- options.externalClasses.forEach((className) => {
2504
- const reg = new RegExp('\\b' + className + '\\b', 'g')
2505
- const replacementClassName = dash2hump(className)
2506
- if (classLikeAttrValue.includes(className)) hasExternalClass = true
2507
- classLikeAttrValue = classLikeAttrValue.replace(reg, `{{${replacementClassName} || ''}}`)
2508
- })
2509
- if (hasExternalClass) {
2510
- classLikeAttrValue += ` {{${PARENT_MODULE_ID} || ''}}`
2511
- }
2512
- addAttrs(el, [{
2513
- name: classLikeAttrName,
2514
- value: classLikeAttrValue
2515
- }])
2516
- }
2517
2566
  }
2518
2567
 
2519
2568
  function processScoped (el) {
2520
- if (hasScoped && isRealNode(el)) {
2569
+ if (!isRealNode(el)) return
2570
+ // web 模版组件(<template name>)内的节点:scoped 类拼接由运行时 __mpxHost 决定,自成闭环
2571
+ if (isWeb(mode) && processingTemplate) {
2572
+ const parts = []
2573
+ const existingDynamic = getAndRemoveAttr(el, ':class').val
2574
+ if (existingDynamic) parts.push(existingDynamic)
2575
+ const scopedCls = `(__mpxHost && __mpxHost.$options.__mpxScoped ? [__mpxHost.$options.__mpxModuleId || "", __mpxHost.$options.__mpxCtorType !== "component" ? ${stringify(MPX_APP_MODULE_ID)} : ""].filter(Boolean).join(" ") : "")`
2576
+ parts.push(scopedCls)
2577
+ addAttrs(el, [{ name: ':class', value: `[${parts.join(',')}]` }])
2578
+ return
2579
+ }
2580
+ if (hasScoped) {
2521
2581
  const rootModuleId = ctorType === 'component' ? '' : MPX_APP_MODULE_ID // 处理app全局样式对页面的影响
2522
2582
  const staticClass = getAndRemoveAttr(el, 'class').val
2523
2583
  addAttrs(el, [{
@@ -2529,20 +2589,131 @@ function processScoped (el) {
2529
2589
 
2530
2590
  const builtInComponentsPrefix = '@mpxjs/webpack-plugin/lib/runtime/components'
2531
2591
 
2592
+ function resolveCustomBuiltinResource (el) {
2593
+ if (!customBuiltInComponentsOpt || !el.isBuiltIn) return null
2594
+ if (el.originalTag != null && customBuiltInComponentsOpt[el.originalTag]) {
2595
+ return customBuiltInComponentsOpt[el.originalTag]
2596
+ }
2597
+ return null
2598
+ }
2599
+
2532
2600
  function processBuiltInComponents (el, meta) {
2533
2601
  if (el.isBuiltIn) {
2534
2602
  if (!meta.builtInComponentsMap) {
2535
2603
  meta.builtInComponentsMap = {}
2536
2604
  }
2537
2605
  const tag = el.tag
2538
- if (!meta.builtInComponentsMap[tag]) {
2539
- if (isReact(mode)) {
2540
- meta.builtInComponentsMap[tag] = `${builtInComponentsPrefix}/react/dist/${tag}`
2541
- } else {
2542
- meta.builtInComponentsMap[tag] = `${builtInComponentsPrefix}/${mode}/${tag}`
2543
- }
2606
+ const customResource = resolveCustomBuiltinResource(el)
2607
+ const defaultResource = isReact(mode)
2608
+ ? `${builtInComponentsPrefix}/react/dist/${tag}`
2609
+ : `${builtInComponentsPrefix}/${mode}/${tag}`
2610
+ meta.builtInComponentsMap[tag] = customResource != null ? customResource : defaultResource
2611
+ }
2612
+ }
2613
+
2614
+ const reactTemplateAssetTags = makeMap('mpx-image,mpx-video,mpx-audio', true)
2615
+
2616
+ function processTemplateAssetReact (el, meta) {
2617
+ if (!reactTemplateAssetTags(el.tag)) return
2618
+ const src = el.attrsMap.src
2619
+ if (!isUrlRequest(src)) return
2620
+
2621
+ const name = `__mpx_template_asset_${templateAssetId++}__`
2622
+ if (!meta.templateAssets) {
2623
+ meta.templateAssets = {}
2624
+ }
2625
+ meta.templateAssets[name] = src
2626
+ addExp(el, name, false, 'src')
2627
+ }
2628
+
2629
+ /** Web / RN 共用:<import src> 收集并移除 */
2630
+ function processTemplateImport (el, meta) {
2631
+ if (el.tag !== 'import') return false
2632
+ if (el.attrsMap.src) {
2633
+ if (!meta.imports) {
2634
+ meta.imports = []
2635
+ }
2636
+ meta.imports.push(el.attrsMap.src)
2637
+ // RN:存在外部 import 模版时保守关闭 render memo(子文件内 <slot> 不进本轮 AST;见 getDefaultOptions.ios.js __getSlot + useMemo)
2638
+ if (isReact(mode)) {
2639
+ meta.options = Object.assign({}, meta.options, { disableMemo: true })
2544
2640
  }
2545
2641
  }
2642
+ el.shouldRemove = true
2643
+ return true
2644
+ }
2645
+
2646
+ /**
2647
+ * Web / RN 共用:`<template is>` / `<template name>`(Web 下 `is`/`data` 在 platform postProps 中原样保留,与 RN 同一条 parse 路径)
2648
+ * @returns {true|undefined} true 表示进入 template 定义子树
2649
+ */
2650
+ function processTemplateTranspile (el, meta) {
2651
+ if (processTemplateImport(el, meta)) return
2652
+
2653
+ if (el.tag !== 'template' || el.isBlock) return
2654
+
2655
+ const is = getAndRemoveAttr(el, 'is').val
2656
+ if (is) {
2657
+ // template usage, keep processing
2658
+ const data = getAndRemoveAttr(el, 'data').val
2659
+ el.templateInfo = {
2660
+ is: parseMustacheWithContext(is).result,
2661
+ data: data ? parseMustacheWithContext(`{${data}}`).result : ''
2662
+ }
2663
+ return
2664
+ }
2665
+
2666
+ if (el.attrsMap.name) {
2667
+ el.isTemplate = true
2668
+ processingTemplate = true
2669
+ return true
2670
+ }
2671
+ error$1('Invalid template tag, should have valid is or name attr')
2672
+ el.shouldRemove = true
2673
+ }
2674
+
2675
+ // `<template name="...">` 定义:收集 meta.templates 后移除(Web / RN 共用逻辑)
2676
+ function collectTranspileTemplateDefinition (el, meta) {
2677
+ if (!el.isTemplate) return false
2678
+ if (!meta.templates) {
2679
+ meta.templates = {}
2680
+ }
2681
+ if (meta.templates[el.attrsMap.name]) {
2682
+ error$1(`Duplicated template name "${el.attrsMap.name}" in the same file.`)
2683
+ }
2684
+ meta.templates[el.attrsMap.name] = el
2685
+ removeNode(el, true)
2686
+ processingTemplate = false
2687
+ return true
2688
+ }
2689
+
2690
+ function postProcessTemplateReact (el, meta) {
2691
+ collectTranspileTemplateDefinition(el, meta)
2692
+ }
2693
+
2694
+ // Web:template 定义收集 + `<template is="...">` 使用节点替换为 mpx-tpl-* / component
2695
+ function postProcessTemplateWeb (el, meta) {
2696
+ if (collectTranspileTemplateDefinition(el, meta)) return
2697
+ if (el.tag !== 'template' || !el.templateInfo) return
2698
+ const { is, data } = el.templateInfo
2699
+ if (!is) return
2700
+ const literalMatch = /^"([A-Za-z_][\w-]*)"$/.exec(is)
2701
+ const baseAttrs = cloneAttrsList(el.attrsList)
2702
+ let newNode
2703
+ if (literalMatch) {
2704
+ const name = literalMatch[1]
2705
+ const built = data ? [{ name: ':mpx-data', value: data }] : []
2706
+ newNode = createASTElement(`${MPX_TEMPLATE_COMPONENT_PREFIX}${name}`, baseAttrs.concat(built))
2707
+ newNode.unary = true
2708
+ } else {
2709
+ const built = [
2710
+ { name: ':is', value: `'${MPX_TEMPLATE_COMPONENT_PREFIX}' + (${is})` },
2711
+ ...(data ? [{ name: ':mpx-data', value: data }] : [])
2712
+ ]
2713
+ newNode = createASTElement('component', baseAttrs.concat(built))
2714
+ newNode.unary = true
2715
+ }
2716
+ replaceNode(el, newNode, true)
2546
2717
  }
2547
2718
 
2548
2719
  function postProcessAliComponentRootView (el, options, meta) {
@@ -2615,8 +2786,8 @@ function postProcessAliComponentRootView (el, options, meta) {
2615
2786
  // 有virtualHost情况wx组件注入virtualHost。无virtualHost阿里组件注入root-view。其他跳过。
2616
2787
  function getVirtualHostRoot (options, meta) {
2617
2788
  if (srcMode === 'wx') {
2618
- if (ctorType === 'component') {
2619
- if (isWeb(mode) && !hasVirtualHost) {
2789
+ if (ctorType === 'component' && !hasVirtualHost) {
2790
+ if (isWeb(mode)) {
2620
2791
  // ali组件根节点实体化
2621
2792
  const rootView = createASTElement('view', [
2622
2793
  {
@@ -2631,7 +2802,7 @@ function getVirtualHostRoot (options, meta) {
2631
2802
  processElement(rootView, rootView, options, meta)
2632
2803
  return rootView
2633
2804
  }
2634
- if (isReact(mode) && !hasVirtualHost) {
2805
+ if (isReact(mode)) {
2635
2806
  const tagName = isCustomText ? 'text' : 'view'
2636
2807
  const rootView = createASTElement(tagName, [
2637
2808
  {
@@ -2647,18 +2818,20 @@ function getVirtualHostRoot (options, meta) {
2647
2818
  return rootView
2648
2819
  }
2649
2820
  }
2650
- if (isWeb(mode) && ctorType === 'page') {
2651
- return createASTElement('page')
2652
- }
2653
- if (isReact(mode) && ctorType === 'page') {
2654
- const rootView = createASTElement('view', [
2655
- {
2656
- name: 'class',
2657
- value: MPX_TAG_PAGE_SELECTOR
2658
- }
2659
- ])
2660
- processElement(rootView, rootView, options, meta)
2661
- return rootView
2821
+ if (ctorType === 'page') {
2822
+ if (isWeb(mode)) {
2823
+ return createASTElement('page')
2824
+ }
2825
+ if (isReact(mode)) {
2826
+ const rootView = createASTElement('view', [
2827
+ {
2828
+ name: 'class',
2829
+ value: MPX_TAG_PAGE_SELECTOR
2830
+ }
2831
+ ])
2832
+ processElement(rootView, rootView, options, meta)
2833
+ return rootView
2834
+ }
2662
2835
  }
2663
2836
  }
2664
2837
  return getTempNode()
@@ -2713,7 +2886,6 @@ function processTemplate (el) {
2713
2886
  function postProcessTemplate (el) {
2714
2887
  if (el.isTemplate) {
2715
2888
  processingTemplate = false
2716
- return true
2717
2889
  }
2718
2890
  }
2719
2891
 
@@ -2836,11 +3008,11 @@ function processDuplicateAttrsList (el) {
2836
3008
  }
2837
3009
 
2838
3010
  // 处理wxs注入逻辑
2839
- function processInjectWxs (el, meta) {
2840
- if (el.injectWxsProps && el.injectWxsProps.length) {
2841
- el.injectWxsProps.forEach((injectWxsProp) => {
2842
- const { injectWxsPath, injectWxsModuleName } = injectWxsProp
2843
- injectWxs(meta, injectWxsModuleName, injectWxsPath)
3011
+ function processInjectWxsInfos (el, meta) {
3012
+ if (el.injectWxsInfos && el.injectWxsInfos.length) {
3013
+ el.injectWxsInfos.forEach((injectWxsInfo) => {
3014
+ const { injectWxsRequest, injectWxsModuleName } = injectWxsInfo
3015
+ injectWxs(meta, injectWxsModuleName, injectWxsRequest)
2844
3016
  })
2845
3017
  }
2846
3018
  }
@@ -2934,8 +3106,9 @@ function processMpxTagName (el) {
2934
3106
 
2935
3107
  function processElement (el, root, options, meta) {
2936
3108
  processAtMode(el)
2937
- // 如果已经标记了这个元素要被清除,直接return跳过后续处理步骤
2938
3109
  if (el._matchStatus === statusEnum.MISMATCH) {
3110
+ // 如果已经标记了这个元素要被清除,直接return跳过后续处理步骤
3111
+ el.shouldRemove = true
2939
3112
  return
2940
3113
  }
2941
3114
 
@@ -2957,36 +3130,41 @@ function processElement (el, root, options, meta) {
2957
3130
  // 检测跨平台语法使用情况并给出警告
2958
3131
  processCrossPlatformSyntaxWarning(el)
2959
3132
 
2960
- processInjectWxs(el, meta, options)
3133
+ processInjectWxsInfos(el, meta, options)
2961
3134
 
2962
3135
  const transAli = mode === 'ali' && srcMode === 'wx'
2963
3136
 
2964
3137
  if (isWeb(mode)) {
3138
+ const isTemplate = processTemplateTranspile(el, meta) || processingTemplate
3139
+ if (el.shouldRemove) return
2965
3140
  // 收集内建组件
2966
3141
  processBuiltInComponents(el, meta)
2967
3142
  // 预处理代码维度条件编译
2968
3143
  processIfWeb(el)
2969
3144
  processScoped(el)
2970
3145
  processEventWeb(el)
2971
- // processWebExternalClassesHack(el, options)
2972
3146
  processExternalClasses(el, options)
2973
- processComponentGenerics(el, meta)
3147
+ if (!isTemplate) processComponentGenerics(el, meta)
2974
3148
  return
2975
3149
  }
2976
3150
 
2977
3151
  if (isReact(mode)) {
2978
- const pass = isReactComponent(el, options)
3152
+ const isTemplate = processTemplateTranspile(el, meta) || processingTemplate
3153
+ if (el.shouldRemove) return
3154
+ const isReactComponent$1 = isReactComponent(el, options)
2979
3155
  // 收集内建组件
2980
3156
  processBuiltInComponents(el, meta)
3157
+ // 处理模版内资源引用
3158
+ processTemplateAssetReact(el, meta)
2981
3159
  // 预处理代码维度条件编译
2982
3160
  processIf(el)
2983
3161
  processFor(el)
2984
- processRefReact(el, meta)
3162
+ if (!isTemplate) processRefReact(el, meta)
2985
3163
  processStyleReact(el, options)
2986
- if (!pass) {
3164
+ if (!isReactComponent$1) {
2987
3165
  processEventReact(el, options)
2988
- processComponentGenerics(el, meta)
2989
- processComponentIs(el, options)
3166
+ if (!isTemplate) processComponentGenerics(el, meta)
3167
+ if (!isTemplate) processComponentIs(el, options)
2990
3168
  processSlotReact(el, meta)
2991
3169
  }
2992
3170
  processAttrs(el, options)
@@ -3001,7 +3179,6 @@ function processElement (el, root, options, meta) {
3001
3179
  }
3002
3180
 
3003
3181
  if (transAli) {
3004
- // processAliExternalClassesHack(el, options)
3005
3182
  processExternalClasses(el, options)
3006
3183
  }
3007
3184
 
@@ -3026,22 +3203,24 @@ function processElement (el, root, options, meta) {
3026
3203
  }
3027
3204
 
3028
3205
  function closeElement (el, options, meta) {
3029
- postProcessAtMode(el)
3030
3206
  postProcessWxs(el, meta)
3031
3207
 
3032
3208
  if (isWeb(mode)) {
3033
3209
  // 处理代码维度条件编译移除死分支
3034
3210
  postProcessIf(el)
3211
+ postProcessTemplateWeb(el, meta)
3212
+ postProcessRemove(el)
3035
3213
  return
3036
3214
  }
3037
3215
  if (isReact(mode)) {
3038
3216
  postProcessForReact(el)
3039
3217
  postProcessIfReact(el)
3218
+ postProcessTemplateReact(el, meta)
3219
+ postProcessRemove(el)
3040
3220
  return
3041
3221
  }
3042
3222
 
3043
- const isTemplate = postProcessTemplate(el) || processingTemplate
3044
- if (!isTemplate) {
3223
+ if (!processingTemplate) {
3045
3224
  if (!isNative) {
3046
3225
  postProcessComponentIs(el, (child) => {
3047
3226
  if (!getComponentInfo(el).hasVirtualHost && mode === 'ali') {
@@ -3065,6 +3244,8 @@ function closeElement (el, options, meta) {
3065
3244
  postProcessFor(el)
3066
3245
  postProcessIf(el)
3067
3246
  }
3247
+ postProcessTemplate(el)
3248
+ postProcessRemove(el)
3068
3249
  }
3069
3250
 
3070
3251
  // 运行时组件的模版节点收集,最终注入到 mpx-custom-element-*.wxml 中
@@ -3072,8 +3253,8 @@ function collectDynamicInfo (el, options, meta) {
3072
3253
  setBaseWxml(el, { mode, isComponentNode, options }, meta)
3073
3254
  }
3074
3255
 
3075
- function postProcessAtMode (el) {
3076
- if (el._matchStatus === statusEnum.MISMATCH) {
3256
+ function postProcessRemove (el) {
3257
+ if (el.shouldRemove) {
3077
3258
  removeNode(el)
3078
3259
  }
3079
3260
  }
@@ -3307,7 +3488,7 @@ function addIfConditionDynamic (el, condition) {
3307
3488
  el.ifConditions.push(condition)
3308
3489
  }
3309
3490
 
3310
- function processIfConditionsDynamic (el) {
3491
+ function postProcessIfConditionsDynamic (el) {
3311
3492
  const prevNode = findPrevNode(el)
3312
3493
  if (prevNode && prevNode.if) {
3313
3494
  addIfConditionDynamic(prevNode, {
@@ -3389,7 +3570,7 @@ function postProcessIfDynamic (vnode, config) {
3389
3570
  ? config.directive.elseif
3390
3571
  : config.directive.else
3391
3572
  getAndRemoveAttr(vnode, directive)
3392
- processIfConditionsDynamic(vnode)
3573
+ postProcessIfConditionsDynamic(vnode)
3393
3574
  delete vnode.elseif
3394
3575
  delete vnode.else
3395
3576
  }