@mpxjs/webpack-plugin 2.10.19 → 2.10.20

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 (60) hide show
  1. package/lib/dependencies/ResolveDependency.js +2 -2
  2. package/lib/index.js +25 -6
  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/platform/create-diagnostic.js +168 -0
  9. package/lib/platform/index.js +16 -3
  10. package/lib/platform/json/wx/index.js +66 -17
  11. package/lib/platform/run-rules.js +9 -5
  12. package/lib/platform/style/wx/index.js +4 -3
  13. package/lib/platform/template/normalize-component-rules.js +7 -9
  14. package/lib/platform/template/wx/component-config/custom-built-in-component.js +34 -0
  15. package/lib/platform/template/wx/component-config/index.js +18 -3
  16. package/lib/platform/template/wx/component-config/input.js +1 -7
  17. package/lib/platform/template/wx/component-config/movable-view.js +1 -7
  18. package/lib/platform/template/wx/component-config/text.js +1 -1
  19. package/lib/platform/template/wx/component-config/textarea.js +1 -25
  20. package/lib/platform/template/wx/index.js +48 -34
  21. package/lib/react/processJSON.js +7 -4
  22. package/lib/react/processStyles.js +22 -8
  23. package/lib/react/processTemplate.js +85 -41
  24. package/lib/react/style-helper.js +120 -85
  25. package/lib/react/template-loader.js +148 -0
  26. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +1 -1
  27. package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -1
  28. package/lib/runtime/components/react/dist/mpx-image.jsx +1 -2
  29. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +1 -1
  30. package/lib/runtime/components/react/dist/utils.jsx +3 -2
  31. package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
  32. package/lib/runtime/components/react/mpx-image.tsx +1 -3
  33. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  34. package/lib/runtime/components/react/utils.tsx +3 -2
  35. package/lib/runtime/components/wx/default-component.mpx +9 -0
  36. package/lib/runtime/components/wx/default-page.mpx +3 -11
  37. package/lib/runtime/optionProcessor.d.ts +2 -0
  38. package/lib/runtime/optionProcessor.js +77 -1
  39. package/lib/style-compiler/index.js +2 -0
  40. package/lib/style-compiler/plugins/remove-strip-conditional-comments.js +14 -0
  41. package/lib/style-compiler/strip-conditional.js +40 -26
  42. package/lib/template-compiler/compiler.js +274 -116
  43. package/lib/template-compiler/gen-node-react.js +35 -7
  44. package/lib/template-compiler/index.js +9 -7
  45. package/lib/utils/const.js +4 -1
  46. package/lib/utils/partial-compile-rules.js +27 -0
  47. package/lib/utils/pre-process-json.js +3 -0
  48. package/lib/utils/source-location.js +96 -0
  49. package/lib/web/compile-wx-template-fragment.js +68 -0
  50. package/lib/web/index.js +2 -0
  51. package/lib/web/processJSON.js +7 -4
  52. package/lib/web/processScript.js +41 -3
  53. package/lib/web/processTemplate.js +61 -19
  54. package/lib/web/template-loader.js +123 -0
  55. package/lib/web/template-shared.js +48 -0
  56. package/lib/wxml/loader.js +3 -2
  57. package/lib/wxss/loader.js +1 -1
  58. package/lib/wxss/utils.js +6 -4
  59. package/package.json +11 -4
  60. package/lib/platform/template/wx/component-config/component.js +0 -41
@@ -48,7 +48,6 @@ export type Mode =
48
48
  export interface ImageProps {
49
49
  src?: string
50
50
  mode?: Mode
51
- svg?: boolean
52
51
  style?: ImageStyle & Record<string, any>
53
52
  'enable-offset'?: boolean
54
53
  'enable-var'?: boolean
@@ -456,8 +455,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
456
455
  ),
457
456
  [
458
457
  'src',
459
- 'mode',
460
- 'svg'
458
+ 'mode'
461
459
  ],
462
460
  {
463
461
  layoutRef
@@ -79,7 +79,7 @@ export interface RegionProps extends BasePickerProps {
79
79
  /** 表示选中的省市区,默认选中每一列的第一个值, 默认值 [] */
80
80
  value?: string[]
81
81
  /** 默认值 region */
82
- level?: 'province' | 'city' | 'region' | 'sub-district'
82
+ level?: 'province' | 'city' | 'region'
83
83
  /** 可为每一列的顶部添加一个自定义的项 */
84
84
  'custom-item'?: string
85
85
  /** value 改变时触发 change 事件, event.detail = {value, code, postcode},
@@ -334,8 +334,9 @@ export function parseValues (str: string, char = ' ') {
334
334
  // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
335
335
  function parseTransform (transformStr: string) {
336
336
  const values = parseValues(transformStr)
337
- // Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
338
- values.sort()
337
+ // Todo 2 RN下顺序不一致转换结果不一致,故这里不处理,动画前后transform 排序不一致的问题,由业务调整写法
338
+ // Todo 1 transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
339
+ // values.sort()
339
340
  const transform: { [propName: string]: string | number | number[] }[] = []
340
341
  values.forEach(item => {
341
342
  const match = item.match(/([/\w]+)\((.+)\)/)
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <view></view>
3
+ </template>
4
+
5
+ <script>
6
+ import { createComponent } from '@mpxjs/core'
7
+
8
+ createComponent({})
9
+ </script>
@@ -1,6 +1,5 @@
1
1
  <template>
2
- <view>局部构建兜底页面</view>
3
- <view>当前路由:{{currentRoute}}</view>
2
+ <view>局部构建兜底页面:{{pageRoute}}</view>
4
3
  </template>
5
4
 
6
5
  <script>
@@ -10,18 +9,11 @@ import { createPage } from '@mpxjs/core'
10
9
  createPage({
11
10
  data() {
12
11
  return {
13
- currentRoute: '',
12
+ pageRoute: ''
14
13
  }
15
14
  },
16
15
  onLoad() {
17
- this.getPagePath()
18
- },
19
- methods: {
20
- getPagePath() {
21
- const pages = getCurrentPages() || []
22
- const currPage = pages[pages.length - 1]
23
- this.currentRoute = currPage && currPage.route || ''
24
- },
16
+ this.pageRoute = this.route
25
17
  }
26
18
  })
27
19
  </script>
@@ -17,4 +17,6 @@ export function getComponent (...args: any): object
17
17
 
18
18
  export function getWxsMixin (...args: any): object
19
19
 
20
+ export function createTemplateComponent (...args: any): object
21
+
20
22
  export function processAppOption (...args: any): void
@@ -2,13 +2,15 @@ import { hasOwn, isEmptyObject, extend } from './utils'
2
2
  import { isBrowser } from './env'
3
3
  import transRpxStyle from './transRpxStyle'
4
4
  import animation from './animation'
5
- import { error } from '@mpxjs/utils'
5
+ import { error, proxy } from '@mpxjs/utils'
6
6
  const dash2hump = require('../utils/hump-dash').dash2hump
7
7
 
8
8
  export function processComponentOption (
9
9
  {
10
10
  option,
11
11
  ctorType,
12
+ moduleId,
13
+ hasScoped,
12
14
  outputPath,
13
15
  pageConfig,
14
16
  componentsMap,
@@ -75,6 +77,19 @@ registered in parent context!`)
75
77
  if (outputPath) {
76
78
  option.componentPath = '/' + outputPath
77
79
  }
80
+
81
+ // 宿主组件的 moduleId / scoped / ctorType 信息挂在 option 上,供 mpx-tpl-* 子模版通过 __mpxHost.$options 读取
82
+ option.__mpxModuleId = moduleId || ''
83
+ option.__mpxScoped = !!hasScoped
84
+ option.__mpxCtorType = ctorType
85
+ // 暴露宿主实例引用,供 mpx-tpl-* 子模版组件通过 inject 获取
86
+ const prevProvide = option.provide
87
+ option.provide = function () {
88
+ const base = typeof prevProvide === 'function'
89
+ ? prevProvide.call(this)
90
+ : (prevProvide || {})
91
+ return extend({}, base, { __mpxHost: this })
92
+ }
78
93
  if (ctorType === 'app') {
79
94
  option.data = function () {
80
95
  return {
@@ -134,6 +149,67 @@ export function getWxsMixin (wxsModules) {
134
149
  }
135
150
  }
136
151
 
152
+ /**
153
+ * 将子模版实例的 `$slots` 代理到 `inject` 的宿主 `__mpxHost.$slots`(仅默认 / 具名,与 solutions/web-template-support.md §2.8 一致)。
154
+ * 不使用 `$watch`;若无法 defineProperty(如属性已不可配置),开发环境告警并跳过。
155
+ */
156
+ function installMpxWxTemplateHostSlotsProxy (vm) {
157
+ if (!vm.__mpxHost) return
158
+ try {
159
+ Object.defineProperty(vm, '$slots', {
160
+ configurable: true,
161
+ enumerable: true,
162
+ get () {
163
+ const h = this.__mpxHost
164
+ return (h && h.$slots) || {}
165
+ },
166
+ set () { } // 不支持写入
167
+ })
168
+ } catch (e) {
169
+ if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production') {
170
+ console.warn('[Mpx] mpx-tpl: could not proxy $slots to __mpxHost:', e && e.message)
171
+ }
172
+ }
173
+ }
174
+
175
+ // 创建 wxml template 对应的 Vue 子组件选项(仅接受构建期编译产物,见 web/compile-wx-template-fragment)
176
+ // - props.mpxData:承载模版调用传入的数据,通过 proxy 在 this 上建立访问代理
177
+ // - inject.__mpxHost:从最近的 mpx 宿主获取 this,用于继承 methods/components;其 $slots 经 installMpxWxTemplateHostSlotsProxy 供模版内 <slot> 使用
178
+ // - wxsModules:由模版所在 wxml 自身声明的 wxs 模块(不继承宿主 wxs)
179
+ // - render / staticRenderFns:须由 `vue/compiler-sfc` compileTemplate 等在构建期注入,不支持字符串 template
180
+ export function createTemplateComponent ({ name, render, staticRenderFns, components, wxsModules }) {
181
+ if (typeof render !== 'function') {
182
+ throw new Error('[Mpx] createTemplateComponent requires a build-time `render` function (string template is not supported).')
183
+ }
184
+ const wxsMixin = getWxsMixin(wxsModules)
185
+ const base = {
186
+ name,
187
+ render,
188
+ components: components || {},
189
+ mixins: wxsMixin ? [wxsMixin] : [],
190
+ props: { mpxData: { type: Object, default: () => ({}) } },
191
+ inject: { __mpxHost: { default: null } },
192
+ created () {
193
+ const host = this.__mpxHost
194
+ if (host) {
195
+ const hostMethods = host.$options.methods || {}
196
+ Object.keys(hostMethods).forEach((k) => {
197
+ if (!(k in this)) this[k] = hostMethods[k].bind(host)
198
+ })
199
+ const compBase = this.$options.components || {}
200
+ const merged = Object.create(Object.getPrototypeOf(compBase) || null)
201
+ extend(merged, compBase, host.$options.components || {})
202
+ this.$options.components = merged
203
+ installMpxWxTemplateHostSlotsProxy(this)
204
+ }
205
+ // mpxData 常为宿主每次 render 的新字面量:source 传 getter,proxy 每次读都解析当前 this.mpxData;假定 key 集合在生命周期内不变(不在 updated 中补全新 key)
206
+ proxy(this, () => this.mpxData || {})
207
+ }
208
+ }
209
+ if (staticRenderFns && staticRenderFns.length) base.staticRenderFns = staticRenderFns
210
+ return base
211
+ }
212
+
137
213
  function createApp ({ componentsMap, Vue, pagesMap, firstPage, VueRouter, App, tabBarMap }) {
138
214
  const option = {}
139
215
  // 对于app中的组件需要全局注册
@@ -7,6 +7,7 @@ const vw = require('./plugins/vw')
7
7
  const scopeId = require('./plugins/scope-id')
8
8
  const transSpecial = require('./plugins/trans-special')
9
9
  const cssArrayList = require('./plugins/css-array-list')
10
+ const removeStripConditionalComments = require('./plugins/remove-strip-conditional-comments')
10
11
  const { matchCondition } = require('../utils/match-condition')
11
12
  const parseRequest = require('../utils/parse-request')
12
13
  const isReact = require('../utils/env').isReact
@@ -96,6 +97,7 @@ module.exports = function (css, map) {
96
97
  if (mpx.mode === 'web') {
97
98
  postPlugins.push(vw({ transRpxFn }))
98
99
  }
100
+ postPlugins.push(removeStripConditionalComments())
99
101
 
100
102
  const finalPlugins = config.prePlugins.concat(plugins, config.plugins, postPlugins)
101
103
 
@@ -0,0 +1,14 @@
1
+ const { STYLE_PAD_PLACEHOLDER } = require('../../utils/const')
2
+
3
+ module.exports = () => {
4
+ return {
5
+ postcssPlugin: 'remove-strip-conditional-comments',
6
+ Comment (comment) {
7
+ if (comment.text.trim() === STYLE_PAD_PLACEHOLDER) {
8
+ comment.remove()
9
+ }
10
+ }
11
+ }
12
+ }
13
+
14
+ module.exports.postcss = true
@@ -1,14 +1,23 @@
1
1
  const fs = require('fs')
2
+ const { STYLE_PAD_PLACEHOLDER } = require('../utils/const')
2
3
 
3
4
  class Node {
4
- constructor(type, condition = null) {
5
+ constructor(type, condition = null, value = '') {
5
6
  this.type = type // 'If', 'ElseIf', 'Else' 或 'Text'
6
7
  this.condition = condition // If 或 Elif 的条件
7
8
  this.children = []
8
- this.value = ''
9
+ this.value = value
9
10
  }
10
11
  }
11
12
 
13
+ function keepLines(content) {
14
+ return content.replace(/([^\r\n]*)(\r\n|\r|\n|$)/g, (all, line, lineBreak) => {
15
+ if (!all) return ''
16
+ const indent = (/^[ \t]*/.exec(line) || [''])[0]
17
+ return `${indent}/* ${STYLE_PAD_PLACEHOLDER} */${lineBreak}`
18
+ })
19
+ }
20
+
12
21
  // 提取 css string 为 token
13
22
  function tokenize(cssString) {
14
23
  // Support /* ... */, // ..., and <!-- ... --> styles
@@ -35,7 +44,8 @@ function tokenize(cssString) {
35
44
 
36
45
  tokens.push({
37
46
  type: type,
38
- condition: condition ? condition.trim() : null
47
+ condition: condition ? condition.trim() : null,
48
+ content: match[0]
39
49
  })
40
50
  lastIndex = regex.lastIndex
41
51
  }
@@ -55,11 +65,10 @@ function parse(cssString) {
55
65
  let currentChildren = ast
56
66
  tokens.forEach(token => {
57
67
  if (token.type === 'text') {
58
- const node = new Node('Text')
59
- node.value = token.content
68
+ const node = new Node('Text', null, token.content)
60
69
  currentChildren.push(node)
61
70
  } else if (token.type === 'if') {
62
- const node = new Node('If', token.condition)
71
+ const node = new Node('If', token.condition, token.content)
63
72
  currentChildren.push(node)
64
73
  nodeStack.push(currentChildren)
65
74
  currentChildren = node.children
@@ -68,7 +77,7 @@ function parse(cssString) {
68
77
  throw new Error('[Mpx style error]: elif without a preceding if')
69
78
  }
70
79
  currentChildren = nodeStack[nodeStack.length - 1]
71
- const node = new Node('ElseIf', token.condition)
80
+ const node = new Node('ElseIf', token.condition, token.content)
72
81
  currentChildren.push(node)
73
82
  currentChildren = node.children
74
83
  } else if (token.type === 'else') {
@@ -76,11 +85,12 @@ function parse(cssString) {
76
85
  throw new Error('[Mpx style error]: else without a preceding if')
77
86
  }
78
87
  currentChildren = nodeStack[nodeStack.length - 1]
79
- const node = new Node('Else')
88
+ const node = new Node('Else', null, token.content)
80
89
  currentChildren.push(node)
81
90
  currentChildren = node.children
82
91
  } else if (token.type === 'endif') {
83
92
  if (nodeStack.length > 0) {
93
+ currentChildren.push(new Node('EndIf', null, token.content))
84
94
  currentChildren = nodeStack.pop()
85
95
  }
86
96
  }
@@ -105,31 +115,35 @@ function evaluateCondition(condition, defs) {
105
115
  }
106
116
 
107
117
  function traverseAndEvaluate(ast, defs) {
108
- let output = ''
109
- let batchedIf = false
110
- function traverse(nodes) {
118
+ function traverse(nodes, active) {
119
+ let output = ''
120
+ let batchedIf = false
111
121
  for (const node of nodes) {
112
122
  if (node.type === 'Text') {
113
- output += node.value
123
+ output += active ? node.value : keepLines(node.value)
114
124
  } else if (node.type === 'If') {
115
125
  // 直接判断 If 节点
116
- batchedIf = false
117
- if (evaluateCondition(node.condition, defs)) {
118
- traverse(node.children)
119
- batchedIf = true
120
- }
121
- } else if (node.type === 'ElseIf' && !batchedIf) {
122
- if (evaluateCondition(node.condition, defs)) {
123
- traverse(node.children)
124
- batchedIf = true
125
- }
126
- } else if (node.type === 'Else' && !batchedIf) {
127
- traverse(node.children)
126
+ output += keepLines(node.value)
127
+ const currentMatched = active && evaluateCondition(node.condition, defs)
128
+ output += traverse(node.children, currentMatched)
129
+ batchedIf = currentMatched
130
+ } else if (node.type === 'ElseIf') {
131
+ output += keepLines(node.value)
132
+ const currentMatched = active && !batchedIf && evaluateCondition(node.condition, defs)
133
+ output += traverse(node.children, currentMatched)
134
+ batchedIf = batchedIf || currentMatched
135
+ } else if (node.type === 'Else') {
136
+ output += keepLines(node.value)
137
+ const currentMatched = active && !batchedIf
138
+ output += traverse(node.children, currentMatched)
139
+ batchedIf = true
140
+ } else if (node.type === 'EndIf') {
141
+ output += keepLines(node.value)
128
142
  }
129
143
  }
144
+ return output
130
145
  }
131
- traverse(ast)
132
- return output
146
+ return traverse(ast, true)
133
147
  }
134
148
 
135
149
  /**