@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
@@ -31,7 +31,24 @@ function mapAttrName (name) {
31
31
  return name
32
32
  }
33
33
 
34
+ function genTemplate (node) {
35
+ if (!node.children || !node.children.length) return 'function(){}'
36
+ const children = node.children.map(child => genNode(child)).filter(c => c)
37
+ if (!children.length) return 'function(){}'
38
+
39
+ let content
40
+ if (children.length === 1) {
41
+ content = children[0]
42
+ } else {
43
+ // 模版存在多个根节点时,使用 block 包裹
44
+ content = `createElement(getComponent("block"), null, ${children.join(', ')})`
45
+ }
46
+ // data 作为 this 传入,createElement, getComponent 作为参数传入
47
+ return `function(createElement, getComponent){return ${content}}`
48
+ }
49
+
34
50
  function genNode (node, isRoot = false) {
51
+ if (node.isDeleted) return ''
35
52
  let exp = ''
36
53
  if (node) {
37
54
  if (node.type === 3) {
@@ -46,11 +63,20 @@ function genNode (node, isRoot = false) {
46
63
  if (node.type === 1) {
47
64
  if (node.tag !== 'temp-node') {
48
65
  if (node.for && !node.forProcessed) {
49
- exp += genFor(node)
50
- } else if (node.if && !node.ifProcessed) {
51
- exp += genIf(node)
52
- } else {
53
- const attrExpMap = (node.exps || []).reduce((map, { exp, attrName }) => {
66
+ return genFor(node)
67
+ }
68
+ if (node.if && !node.ifProcessed) {
69
+ return genIf(node)
70
+ }
71
+ }
72
+ if (node.tag === 'template') {
73
+ if (node.templateInfo) {
74
+ const data = node.templateInfo.data || '{}'
75
+ // 模版中需要支持宿主组件的事件响应,同时天然支持__iter/__getSlot等帮助函数,故使用Object.create(this)创建作用域
76
+ exp += `(typeof getTemplate === "function" && getTemplate(${node.templateInfo.is}) || function(){}).call(Object.assign(Object.create(this), ${data}), createElement, getComponent)`
77
+ }
78
+ } else if (node.tag !== 'temp-node') {
79
+ const attrExpMap = (node.exps || []).reduce((map, { exp, attrName }) => {
54
80
  if (attrName) {
55
81
  map[attrName] = exp
56
82
  }
@@ -85,7 +111,6 @@ function genNode (node, isRoot = false) {
85
111
  }
86
112
  exp += ')'
87
113
  }
88
- }
89
114
  } else {
90
115
  const nodes = node.children.map((child) => {
91
116
  return genNode(child)
@@ -102,4 +127,7 @@ function genNode (node, isRoot = false) {
102
127
  return exp
103
128
  }
104
129
 
105
- module.exports = genNode
130
+ module.exports = {
131
+ genNode,
132
+ genTemplate
133
+ }
@@ -33,6 +33,7 @@ module.exports = function (raw) {
33
33
  const hasScoped = queryObj.hasScoped
34
34
  const runtimeCompile = queryObj.isDynamic
35
35
  const moduleId = queryObj.moduleId || mpx.getModuleId(resourcePath, false, queryObj.moduleId ? null : this)
36
+ const isStatic = queryObj.isStatic
36
37
 
37
38
  let optimizeRenderLevel = 0
38
39
  for (const rule of optimizeRenderRules) {
@@ -42,15 +43,15 @@ module.exports = function (raw) {
42
43
  }
43
44
  }
44
45
 
45
- const warn = (msg) => {
46
+ const warn = (msg, loc) => {
46
47
  this.emitWarning(
47
- new Error('[Mpx template warning][' + this.resource + ']: ' + msg)
48
+ new Error('[Mpx template warning][' + (loc || this.resourcePath) + ']: ' + msg)
48
49
  )
49
50
  }
50
51
 
51
- const error = (msg) => {
52
+ const error = (msg, loc) => {
52
53
  this.emitError(
53
- new Error('[Mpx template error][' + this.resource + ']: ' + msg)
54
+ new Error('[Mpx template error][' + (loc || this.resourcePath) + ']: ' + msg)
54
55
  )
55
56
  }
56
57
 
@@ -75,10 +76,10 @@ module.exports = function (raw) {
75
76
  // 这里需传递rawResourcePath和wxsContentMap保持一致
76
77
  filePath: rawResourcePath,
77
78
  i18n,
78
- checkUsingComponents: matchCondition(resourcePath, mpx.checkUsingComponentsRules),
79
- globalComponents: Object.keys(mpx.globalComponents),
79
+ globalComponents: Object.keys(mpx.globalComponents || {}),
80
80
  forceProxyEvent: matchCondition(resourcePath, mpx.forceProxyEventRules) || runtimeCompile,
81
81
  hasVirtualHost: matchCondition(resourcePath, mpx.autoVirtualHostRules),
82
+ checkUsingComponents: matchCondition(resourcePath, mpx.checkUsingComponentsRules),
82
83
  dynamicTemplateRuleRunner: mpx.dynamicTemplateRuleRunner
83
84
  })
84
85
 
@@ -89,7 +90,8 @@ module.exports = function (raw) {
89
90
  }
90
91
 
91
92
  let result = runtimeCompile ? '' : compiler.serialize(root)
92
- if (isNative) {
93
+ if (isNative || isStatic) {
94
+ // 对于原生小程序组件和静态模版无需注入运行时信息,直接返回模版编译结果
93
95
  return result
94
96
  }
95
97
 
@@ -7,5 +7,8 @@ module.exports = {
7
7
  MPX_ROOT_VIEW: 'mpx-root-view', // 根节点类名
8
8
  MPX_APP_MODULE_ID: 'mpx-app-scope', // app文件moduleId
9
9
  PARENT_MODULE_ID: '__pid',
10
- MPX_TAG_PAGE_SELECTOR: 'mpx-page'
10
+ MPX_TAG_PAGE_SELECTOR: 'mpx-page',
11
+ // web / template is:具名 wx 模版子组件标签前缀(与 compiler 中 AST 替换一致)
12
+ MPX_TEMPLATE_COMPONENT_PREFIX: 'mpx-tpl-',
13
+ STYLE_PAD_PLACEHOLDER: 'mpx-style-pad-placeholder'
11
14
  }
@@ -20,10 +20,6 @@ function genComponentTag (part, processor = {}) {
20
20
  content: processor
21
21
  }
22
22
  }
23
- if (part.content) {
24
- // unpad
25
- part.content = '\n' + part.content.replace(/^\n*/m, '')
26
- }
27
23
 
28
24
  const tag = processor.tag ? processor.tag(part) : part.tag
29
25
  const attrs = processor.attrs ? processor.attrs(part) : part.attrs
@@ -35,7 +31,7 @@ function genComponentTag (part, processor = {}) {
35
31
  result += stringifyAttrs(attrs)
36
32
  }
37
33
  if (content) {
38
- result += `>${content}</${tag}>`
34
+ result += `>\n${content}\n</${tag}>`
39
35
  } else {
40
36
  result += '/>'
41
37
  }
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ // 当前已知分组列表,未来新增分组扩这个数组 + 同步加 declare 即可。
4
+ // @mpxjs/perf 包零感知分组——分组逻辑只存在于 webpack-plugin 这一侧。
5
+ const PERF_GROUPS = ['framework', 'user']
6
+
7
+ /**
8
+ * 把用户配置 { enable, probes } 归一化成「总开关 + 各分组开关」。
9
+ *
10
+ * 输出形如:
11
+ * { enable: true, framework: true, user: false }
12
+ *
13
+ * - `enable: false` 或不传 perf → 全关。
14
+ * - `enable: true && probes: []` → 等价于 enable: false(没有分组要开就视为关闭)。
15
+ * - probes 中出现未知分组名 → 抛错(避免 typo 静默失效)。
16
+ */
17
+ function normalizePerfOptions (raw) {
18
+ if (!raw || raw.enable !== true) {
19
+ const off = { enable: false }
20
+ for (let i = 0; i < PERF_GROUPS.length; i++) off[PERF_GROUPS[i]] = false
21
+ return off
22
+ }
23
+ const probes = Array.isArray(raw.probes) ? raw.probes : []
24
+ for (let i = 0; i < probes.length; i++) {
25
+ if (PERF_GROUPS.indexOf(probes[i]) === -1) {
26
+ throw new Error(
27
+ `[mpx perf] unknown probe "${probes[i]}"; known probes: ${PERF_GROUPS.join(', ')}`
28
+ )
29
+ }
30
+ }
31
+ const result = {}
32
+ let anyOn = false
33
+ for (let i = 0; i < PERF_GROUPS.length; i++) {
34
+ const k = PERF_GROUPS[i]
35
+ const on = probes.indexOf(k) !== -1
36
+ result[k] = on
37
+ if (on) anyOn = true
38
+ }
39
+ // 派生总开关:任一分组打开 → enable 才真正有效。
40
+ result.enable = anyOn
41
+ return result
42
+ }
43
+
44
+ module.exports = {
45
+ PERF_GROUPS,
46
+ normalizePerfOptions
47
+ }
@@ -0,0 +1,27 @@
1
+ const { matchCondition } = require('./match-condition')
2
+
3
+ const hasTypedRules = rules => !!(rules && (rules.pages || rules.page || rules.components || rules.component))
4
+
5
+ const getPartialCompileRules = (rules, type) => {
6
+ if (!rules) return null
7
+
8
+ if (type === 'page') {
9
+ return rules.pages || rules.page || (hasTypedRules(rules) ? null : rules)
10
+ }
11
+
12
+ if (type === 'component') {
13
+ return rules.components || rules.component || null
14
+ }
15
+
16
+ return null
17
+ }
18
+
19
+ const isPartialCompileExcluded = (resourcePath, rules, type) => {
20
+ const targetRules = getPartialCompileRules(rules, type)
21
+ return !!(targetRules && !matchCondition(resourcePath, targetRules))
22
+ }
23
+
24
+ module.exports = {
25
+ getPartialCompileRules,
26
+ isPartialCompileExcluded
27
+ }
@@ -58,6 +58,9 @@ module.exports = function ({
58
58
  waterfall: true,
59
59
  warn: emitWarning,
60
60
  error: emitError,
61
+ diagnostic: {
62
+ file: resourcePath
63
+ },
61
64
  meta: rulesMeta
62
65
  }
63
66
  if (ctorType !== 'app') {
@@ -0,0 +1,96 @@
1
+ const path = require('path')
2
+ const { codeFrameColumns } = require('@babel/code-frame')
3
+ const { SourceMapConsumer } = require('source-map')
4
+
5
+ function offsetToPosition (source, offset) {
6
+ const before = source.slice(0, offset)
7
+ const lines = before.split(/\r\n|\r|\n/)
8
+ return {
9
+ line: lines.length,
10
+ column: lines[lines.length - 1].length + 1
11
+ }
12
+ }
13
+
14
+ function offsetToLoc (source, start, end) {
15
+ const loc = {
16
+ start: offsetToPosition(source, start)
17
+ }
18
+ if (end != null) {
19
+ loc.end = offsetToPosition(source, end)
20
+ }
21
+ return loc
22
+ }
23
+
24
+ function normalizeLoc (loc) {
25
+ if (!loc) return
26
+ if (loc.start) return loc
27
+ if (loc.line) {
28
+ return {
29
+ start: {
30
+ line: loc.line,
31
+ column: loc.column || 1
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ function createCodeFrame (source, loc) {
38
+ loc = normalizeLoc(loc)
39
+ if (!source || !loc || !loc.start) return ''
40
+ return codeFrameColumns(source, loc, {
41
+ highlightCode: false
42
+ })
43
+ }
44
+
45
+ function originalPositionFor (map, loc) {
46
+ loc = normalizeLoc(loc)
47
+ if (!map || !loc || !loc.start) return
48
+ if (typeof map === 'string') {
49
+ try {
50
+ map = JSON.parse(map)
51
+ } catch (e) {
52
+ return
53
+ }
54
+ }
55
+ let consumer
56
+ try {
57
+ consumer = new SourceMapConsumer(map)
58
+ } catch (e) {
59
+ return
60
+ }
61
+ const original = consumer.originalPositionFor({
62
+ line: loc.start.line,
63
+ column: Math.max((loc.start.column || 1) - 1, 0)
64
+ })
65
+ if (!original || !original.source || !original.line) return
66
+ const sourceIndex = map.sources && map.sources.indexOf(original.source)
67
+ return {
68
+ file: original.source,
69
+ loc: {
70
+ start: {
71
+ line: original.line,
72
+ column: (original.column || 0) + 1
73
+ }
74
+ },
75
+ source: sourceIndex > -1 && map.sourcesContent && map.sourcesContent[sourceIndex],
76
+ generatedLoc: loc
77
+ }
78
+ }
79
+
80
+ function readSource (file, inputFileSystem) {
81
+ if (!file || !inputFileSystem) return ''
82
+ try {
83
+ return inputFileSystem.readFileSync(path.resolve(file), 'utf-8')
84
+ } catch (e) {
85
+ return ''
86
+ }
87
+ }
88
+
89
+ module.exports = {
90
+ offsetToPosition,
91
+ offsetToLoc,
92
+ normalizeLoc,
93
+ createCodeFrame,
94
+ originalPositionFor,
95
+ readSource
96
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * 将 serialize 得到的 **wxml template** 定义片段(单根 HTML)在构建期编译为 Vue 2.7 render / staticRenderFns。
3
+ * 与业务依赖的 `vue` 包对齐:使用 `vue/compiler-sfc` 的 `compileTemplate`(同 vue-loader / @vue/compiler-sfc 与 runtime 配对),运行期仅需 `vue.runtime`。
4
+ */
5
+
6
+ const path = require('path')
7
+
8
+ function tryRequireVueCompilerSfc () {
9
+ try {
10
+ return require('vue/compiler-sfc')
11
+ } catch (e) {
12
+ try {
13
+ const vueRoot = path.dirname(require.resolve('vue/package.json'))
14
+ return require(path.join(vueRoot, 'compiler-sfc'))
15
+ } catch (e2) {
16
+ throw new Error(
17
+ '[Mpx] Failed to load vue/compiler-sfc. Install vue@^2.7 (same version as your app, e.g. 2.7.16) for Web wxml template compilation.'
18
+ )
19
+ }
20
+ }
21
+ }
22
+
23
+ function normalizeCompileErrors (errors) {
24
+ if (!errors || !errors.length) return ''
25
+ return errors.map((e) => (typeof e === 'string' ? e : (e && e.msg) || String(e))).join('\n')
26
+ }
27
+
28
+ /**
29
+ * @param {string} source 单根片段(与 serializeWxTemplateDefinition 输出一致,对应 wxml 侧 `<template name="…">` 体)
30
+ * @param {{ emitError?: (msg: string) => void, definitionName?: string, resourcePath?: string, isProduction?: boolean }} ctx
31
+ * @returns {{ block: string }} `block` 为含 `var render` / `var staticRenderFns` 的脚本片段(与 compileTemplate 的 `code` 一致)
32
+ */
33
+ function compileTemplateFragment (source, ctx) {
34
+ const { compileTemplate } = tryRequireVueCompilerSfc()
35
+ const filename = ctx.resourcePath || `wxml-template-${ctx.definitionName || 'anon'}.html`
36
+ const result = compileTemplate({
37
+ source,
38
+ filename,
39
+ isProduction: ctx.isProduction
40
+ })
41
+ const where = ctx.definitionName
42
+ ? `wxml template "${ctx.definitionName}"`
43
+ : (ctx.resourcePath || 'wxml template fragment')
44
+ if (result.errors && result.errors.length) {
45
+ const msg = normalizeCompileErrors(result.errors)
46
+ const full = `Web ${where} compile error: ${msg}`
47
+ if (ctx.emitError) ctx.emitError(full)
48
+ throw new Error(full)
49
+ }
50
+ return {
51
+ block: result.code
52
+ }
53
+ }
54
+
55
+ /**
56
+ * 用 compileTemplate 产出的 `block` 包一层 IIFE,再调用 createTemplateComponent(block 内已声明 `render` / `staticRenderFns`)。
57
+ * 用于将 wxml template 的 Web 侧子组件选项与宿主 `createTemplateComponent` 对接。
58
+ * @param {string} block compileTemplate 返回的 `code`
59
+ * @param {string} innerOptionProps createTemplateComponent 除 render/staticRenderFns 外的选项片段,例如 `name: "x", components: ...`
60
+ */
61
+ function wrapCreateTemplateComponentWithBlock (block, innerOptionProps) {
62
+ return `(function () {\n${block}\n return createTemplateComponent({ render, staticRenderFns, ${innerOptionProps} })\n})()`
63
+ }
64
+
65
+ module.exports = {
66
+ compileTemplateFragment,
67
+ wrapCreateTemplateComponentWithBlock
68
+ }
package/lib/web/index.js CHANGED
@@ -77,6 +77,7 @@ module.exports = function ({
77
77
  },
78
78
  (callback) => {
79
79
  processStyles(parts.styles, {
80
+ loaderContext,
80
81
  ctorType,
81
82
  autoScope,
82
83
  moduleId
@@ -103,6 +104,7 @@ module.exports = function ({
103
104
  ctorType,
104
105
  srcMode,
105
106
  moduleId,
107
+ hasScoped,
106
108
  isProduction,
107
109
  componentGenerics,
108
110
  jsonConfig: jsonRes.jsonObj,
@@ -110,6 +112,7 @@ module.exports = function ({
110
112
  builtInComponentsMap: templateRes.builtInComponentsMap,
111
113
  genericsInfo: templateRes.genericsInfo,
112
114
  wxsModuleMap: templateRes.wxsModuleMap,
115
+ wxTemplateComponentsInfo: templateRes.wxTemplateComponentsInfo,
113
116
  localComponentsMap: jsonRes.localComponentsMap
114
117
  }, callback)
115
118
  }
@@ -35,15 +35,15 @@ module.exports = function (jsonContent, {
35
35
 
36
36
  const context = loaderContext.context
37
37
 
38
- const emitWarning = (msg) => {
38
+ const emitWarning = (msg, loc) => {
39
39
  loaderContext.emitWarning(
40
- new Error('[Mpx json warning][' + loaderContext.resource + ']: ' + msg)
40
+ new Error('[Mpx json warning][' + (loc || loaderContext.resourcePath) + ']: ' + msg)
41
41
  )
42
42
  }
43
43
 
44
- const emitError = (msg) => {
44
+ const emitError = (msg, loc) => {
45
45
  loaderContext.emitError(
46
- new Error('[Mpx json error][' + loaderContext.resource + ']: ' + msg)
46
+ new Error('[Mpx json error][' + (loc || loaderContext.resourcePath) + ']: ' + msg)
47
47
  )
48
48
  }
49
49
 
@@ -107,6 +107,9 @@ module.exports = function (jsonContent, {
107
107
  waterfall: true,
108
108
  warn: emitWarning,
109
109
  error: emitError,
110
+ diagnostic: {
111
+ file: loaderContext.resourcePath
112
+ },
110
113
  data: {
111
114
  // polyfill global usingComponents
112
115
  globalComponents: mpx.globalComponents
@@ -21,7 +21,7 @@ module.exports = function ({
21
21
  tabBarStr,
22
22
  localPagesMap
23
23
  }, callback) {
24
- const { i18n, webConfig, hasUnoCSS } = loaderContext.getMpx()
24
+ const { i18n, webConfig } = loaderContext.getMpx()
25
25
  const { pagesMap, firstPage, globalTabBar } = buildPagesMap({
26
26
  localPagesMap,
27
27
  loaderContext,
@@ -37,12 +37,8 @@ module.exports = function ({
37
37
  jsonConfig
38
38
  })
39
39
 
40
- let output = 'import \'@mpxjs/webpack-plugin/lib/runtime/base.styl\'\n'
41
- // hasUnoCSS由@mpxjs/unocss-plugin注入
42
- if (hasUnoCSS) {
43
- output += 'import \'uno.css\'\n'
44
- }
45
- output += `import Vue from 'vue'
40
+ let output = `import '@mpxjs/webpack-plugin/lib/runtime/base.styl'
41
+ import Vue from 'vue'
46
42
  import VueRouter from 'vue-router'
47
43
  import Mpx from '@mpxjs/core'
48
44
  import { processAppOption, getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}
@@ -10,12 +10,14 @@ const {
10
10
  stringifyRequest,
11
11
  buildI18n
12
12
  } = require('./script-helper')
13
+ const { compileTemplateFragment, wrapCreateTemplateComponentWithBlock } = require('./compile-wx-template-fragment')
13
14
 
14
15
  module.exports = function (script, {
15
16
  loaderContext,
16
17
  ctorType,
17
18
  srcMode,
18
19
  moduleId,
20
+ hasScoped,
19
21
  isProduction,
20
22
  componentGenerics,
21
23
  jsonConfig,
@@ -23,6 +25,7 @@ module.exports = function (script, {
23
25
  builtInComponentsMap,
24
26
  genericsInfo,
25
27
  wxsModuleMap,
28
+ wxTemplateComponentsInfo,
26
29
  localComponentsMap
27
30
  }, callback) {
28
31
  const { projectRoot, appInfo, webConfig, i18n } = loaderContext.getMpx()
@@ -46,12 +49,15 @@ module.exports = function (script, {
46
49
  delete attrs.setup
47
50
  return attrs
48
51
  },
49
- content (script) {
50
- let content = `\n import { processComponentOption, getComponent, getWxsMixin } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
51
- let hasApp = true
52
- if (!appInfo.name) {
53
- hasApp = false
54
- }
52
+ content (script) {
53
+ const isProduction = loaderContext.mode === 'production'
54
+ const hasWxTemplate = !!(wxTemplateComponentsInfo &&
55
+ ((wxTemplateComponentsInfo.imports && wxTemplateComponentsInfo.imports.length) ||
56
+ (wxTemplateComponentsInfo.locals && wxTemplateComponentsInfo.locals.length)))
57
+ const optionProcessorImports = ['processComponentOption', 'getComponent', 'getWxsMixin']
58
+ if (hasWxTemplate) optionProcessorImports.push('createTemplateComponent')
59
+ let content = ` import { ${optionProcessorImports.join(', ')} } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
60
+ const hasApp = !!appInfo.name
55
61
  // 注入wxs模块
56
62
  content += ' var wxsModules = {}\n'
57
63
  if (wxsModuleMap) {
@@ -65,6 +71,30 @@ module.exports = function (script, {
65
71
  // 获取组件集合
66
72
  const componentsMap = buildComponentsMap({ localComponentsMap, builtInComponentsMap, loaderContext, jsonConfig })
67
73
 
74
+ // 注入 wx template 子组件(<template name> / <import src>)
75
+ let wxTemplateComponentsExpr = ''
76
+ if (hasWxTemplate) {
77
+ const parts = (wxTemplateComponentsInfo.imports || []).slice()
78
+ const localsExprs = (wxTemplateComponentsInfo.locals || []).map((local) => {
79
+ const emitError = (msg) => {
80
+ loaderContext.emitError(new Error('[Mpx template error][' + loaderContext.resource + ']: ' + msg))
81
+ }
82
+ const compiled = compileTemplateFragment(local.template, {
83
+ emitError,
84
+ definitionName: local.name,
85
+ resourcePath: loaderContext.resourcePath,
86
+ isProduction
87
+ })
88
+ const inner = `name: ${JSON.stringify(local.name)}`
89
+ return `${JSON.stringify(local.name)}: ${wrapCreateTemplateComponentWithBlock(compiled.block, inner)}`
90
+ })
91
+ if (localsExprs.length) {
92
+ parts.push(`{${localsExprs.join(',')}}`)
93
+ }
94
+ wxTemplateComponentsExpr = `Object.assign({}, ${parts.join(', ')})`
95
+ content += ` var wxTemplateComponentsMap = ${wxTemplateComponentsExpr}\n`
96
+ }
97
+
68
98
  // 获取pageConfig
69
99
  const pageConfig = {}
70
100
  if (ctorType === 'page') {
@@ -77,20 +107,25 @@ module.exports = function (script, {
77
107
  content += buildI18n({ i18n, loaderContext })
78
108
  }
79
109
  content += getRequireScript({ ctorType, script, loaderContext })
110
+ const componentsMapExpr = hasWxTemplate
111
+ ? `Object.assign({}, ${shallowStringify(componentsMap)}, wxTemplateComponentsMap)`
112
+ : shallowStringify(componentsMap)
80
113
  content += `
81
114
  // @ts-ignore
82
115
  export default processComponentOption({
83
116
  option: global.__mpxOptionsMap[${JSON.stringify(moduleId)}],
84
117
  ctorType: ${JSON.stringify(ctorType)},
118
+ moduleId: ${JSON.stringify(moduleId)},
119
+ hasScoped: ${JSON.stringify(!!hasScoped)},
85
120
  outputPath: ${JSON.stringify(outputPath)},
86
121
  pageConfig: ${JSON.stringify(pageConfig)},
87
- componentsMap: ${shallowStringify(componentsMap)},
122
+ componentsMap: ${componentsMapExpr},
88
123
  componentGenerics: ${JSON.stringify(componentGenerics)},
89
124
  genericsInfo: ${JSON.stringify(genericsInfo)},
90
125
  wxsMixin: getWxsMixin(wxsModules),
91
126
  hasApp: ${hasApp},
92
127
  disablePageTransition: ${JSON.stringify(disablePageTransition)},
93
- })\n`
128
+ })`
94
129
  return content
95
130
  }
96
131
  })
@@ -1,17 +1,19 @@
1
1
  const genComponentTag = require('../utils/gen-component-tag')
2
2
 
3
- module.exports = function (styles, options, callback) {
3
+ module.exports = function (styles, { loaderContext, ctorType, autoScope, moduleId }, callback) {
4
4
  let output = '/* styles */\n'
5
+ const { hasUnoCSS, appInfo } = loaderContext.getMpx()
6
+ const hasApp = !!appInfo.name
5
7
  if (styles.length) {
6
8
  styles.forEach((style) => {
7
9
  output += genComponentTag(style, {
8
10
  attrs (style) {
9
11
  const attrs = Object.assign({}, style.attrs)
10
- if (options.autoScope) attrs.scoped = true
12
+ if (autoScope) attrs.scoped = true
11
13
  attrs.mpxStyleOptions = JSON.stringify({
12
14
  scoped: attrs.scoped,
13
15
  // query中包含module字符串会被新版vue-cli中的默认rules当做css-module处理
14
- mid: options.moduleId
16
+ mid: moduleId
15
17
  })
16
18
  delete attrs.scoped
17
19
  return attrs
@@ -19,6 +21,13 @@ module.exports = function (styles, options, callback) {
19
21
  })
20
22
  output += '\n'
21
23
  })
24
+ }
25
+ if (hasUnoCSS && (ctorType === 'app' || !hasApp)) {
26
+ // 将unocss的引入放到App style之后,拉齐小程序中unocss覆盖全局样式的行为
27
+ output += genComponentTag({
28
+ tag: 'style',
29
+ content: '@import \'uno.css\';'
30
+ })
22
31
  output += '\n'
23
32
  }
24
33
  callback(null, {