@mpxjs/webpack-plugin 2.7.0-beta.0 → 2.7.0-beta.12

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 (51) hide show
  1. package/lib/dependencies/AppEntryDependency.js +2 -0
  2. package/lib/dependencies/CommonJsVariableDependency.js +9 -5
  3. package/lib/dependencies/DynamicEntryDependency.js +8 -3
  4. package/lib/dependencies/FlagPluginDependency.js +1 -0
  5. package/lib/dependencies/RecordIndependentDependency.js +41 -0
  6. package/lib/dependencies/{RecordStaticResourceDependency.js → RecordResourceMapDependency.js} +12 -7
  7. package/lib/dependencies/RemoveEntryDependency.js +40 -0
  8. package/lib/dependencies/ResolveDependency.js +8 -7
  9. package/lib/extractor.js +7 -4
  10. package/lib/file-loader.js +2 -2
  11. package/lib/helpers.js +1 -0
  12. package/lib/index.js +227 -151
  13. package/lib/json-compiler/helper.js +21 -25
  14. package/lib/json-compiler/index.js +70 -54
  15. package/lib/json-compiler/plugin.js +21 -5
  16. package/lib/loader.js +59 -77
  17. package/lib/native-loader.js +28 -65
  18. package/lib/parser.js +1 -2
  19. package/lib/platform/json/wx/index.js +7 -2
  20. package/lib/platform/template/wx/component-config/button.js +3 -3
  21. package/lib/platform/template/wx/component-config/navigator.js +1 -1
  22. package/lib/record-loader.js +2 -2
  23. package/lib/resolver/AddEnvPlugin.js +3 -2
  24. package/lib/resolver/AddModePlugin.js +3 -2
  25. package/lib/runtime/base.styl +5 -0
  26. package/lib/runtime/components/web/getInnerListeners.js +51 -45
  27. package/lib/runtime/components/web/mpx-keep-alive.vue +4 -1
  28. package/lib/runtime/components/web/mpx-tab-bar-container.vue +2 -2
  29. package/lib/runtime/optionProcessor.js +5 -20
  30. package/lib/runtime/stringify.wxs +3 -3
  31. package/lib/selector.js +23 -5
  32. package/lib/style-compiler/index.js +4 -5
  33. package/lib/template-compiler/bind-this.js +4 -4
  34. package/lib/template-compiler/compiler.js +105 -45
  35. package/lib/template-compiler/index.js +3 -6
  36. package/lib/template-compiler/trans-dynamic-class-expr.js +3 -3
  37. package/lib/utils/const.js +5 -1
  38. package/lib/utils/eval-json-js.js +31 -0
  39. package/lib/utils/get-json-content.js +41 -0
  40. package/lib/utils/resolve.js +13 -0
  41. package/lib/web/processJSON.js +113 -142
  42. package/lib/web/processScript.js +30 -30
  43. package/lib/web/processTemplate.js +56 -40
  44. package/lib/wxs/i18n-loader.js +1 -3
  45. package/lib/wxs/loader.js +24 -27
  46. package/lib/wxs/pre-loader.js +7 -8
  47. package/lib/wxss/processCss.js +44 -44
  48. package/package.json +8 -8
  49. package/lib/built-in-loader.js +0 -49
  50. package/lib/utils/get-main-compilation.js +0 -6
  51. package/lib/utils/read-json-for-src.js +0 -34
@@ -1,4 +1,5 @@
1
1
  import { isEmptyObject } from './util'
2
+ const isTouchDevice = 'ontouchstart' in document.documentElement
2
3
 
3
4
  function processModel (listeners, context) {
4
5
  // 该函数只有wx:model的情况下才调用,而且默认e.detail.value有值
@@ -54,58 +55,63 @@ function processTap (listeners, context) {
54
55
  })
55
56
  if (isEmptyObject(listenerMap)) return
56
57
  context.__mpxTapInfo = context.__mpxTapInfo || {}
57
- let events = {
58
- touchstart (e) {
59
- context.__mpxTapInfo.detail = {
60
- x: e.changedTouches[0].pageX,
61
- y: e.changedTouches[0].pageY
62
- }
63
- context.__mpxTapInfo.startTimer = null
64
- context.__mpxTapInfo.needTap = true
65
- context.__mpxTapInfo.hadTouch = true
66
- if (listenerMap.longpress || listenerMap.longtap) {
67
- context.__mpxTapInfo.startTimer = setTimeout(() => {
58
+ let events
59
+ if (isTouchDevice) {
60
+ events = {
61
+ touchstart (e) {
62
+ context.__mpxTapInfo.detail = {
63
+ x: e.changedTouches[0].pageX,
64
+ y: e.changedTouches[0].pageY
65
+ }
66
+ context.__mpxTapInfo.startTimer = null
67
+ context.__mpxTapInfo.needTap = true
68
+ if (listenerMap.longpress || listenerMap.longtap) {
69
+ context.__mpxTapInfo.startTimer = setTimeout(() => {
70
+ context.__mpxTapInfo.needTap = false
71
+ if (listenerMap.longpress) {
72
+ const re = inheritEvent('longpress', e, context.__mpxTapInfo.detail)
73
+ context.$emit('longpress', re)
74
+ }
75
+ if (listenerMap.longtap) {
76
+ const re = inheritEvent('longtap', e, context.__mpxTapInfo.detail)
77
+ context.$emit('longtap', re)
78
+ }
79
+ }, 350)
80
+ }
81
+ },
82
+ touchmove (e) {
83
+ const tapDetailInfo = context.__mpxTapInfo.detail || {}
84
+ const currentPageX = e.changedTouches[0].pageX
85
+ const currentPageY = e.changedTouches[0].pageY
86
+ if (Math.abs(currentPageX - tapDetailInfo.x) > 1 || Math.abs(currentPageY - tapDetailInfo.y) > 1) {
68
87
  context.__mpxTapInfo.needTap = false
69
- if (listenerMap.longpress) {
70
- const re = inheritEvent('longpress', e, context.__mpxTapInfo.detail)
71
- context.$emit('longpress', re)
72
- }
73
- if (listenerMap.longtap) {
74
- const re = inheritEvent('longtap', e, context.__mpxTapInfo.detail)
75
- context.$emit('longtap', re)
76
- }
77
- }, 350)
78
- }
79
- },
80
- touchmove (e) {
81
- const tapDetailInfo = context.__mpxTapInfo.detail || {}
82
- const currentPageX = e.changedTouches[0].pageX
83
- const currentPageY = e.changedTouches[0].pageY
84
- if (Math.abs(currentPageX - tapDetailInfo.x) > 1 || Math.abs(currentPageY - tapDetailInfo.y) > 1) {
85
- context.__mpxTapInfo.needTap = false
88
+ context.__mpxTapInfo.startTimer && clearTimeout(context.__mpxTapInfo.startTimer)
89
+ context.__mpxTapInfo.startTimer = null
90
+ }
91
+ },
92
+ touchend (e) {
86
93
  context.__mpxTapInfo.startTimer && clearTimeout(context.__mpxTapInfo.startTimer)
87
- context.__mpxTapInfo.startTimer = null
88
- }
89
- },
90
- touchend (e) {
91
- context.__mpxTapInfo.startTimer && clearTimeout(context.__mpxTapInfo.startTimer)
92
- if (listenerMap.tap && context.__mpxTapInfo.needTap) {
93
- const re = inheritEvent('tap', e, context.__mpxTapInfo.detail)
94
- context.$emit('tap', re)
94
+ if (listenerMap.tap && context.__mpxTapInfo.needTap) {
95
+ const re = inheritEvent('tap', e, context.__mpxTapInfo.detail)
96
+ context.$emit('tap', re)
97
+ }
95
98
  }
96
- },
97
- click (e) {
98
- if (listenerMap.tap && !context.__mpxTapInfo.hadTouch) {
99
- context.__mpxTapInfo.detail = {
100
- x: e.pageX,
101
- y: e.pageY
99
+ }
100
+ } else {
101
+ events = {
102
+ click (e) {
103
+ if (listenerMap.tap) {
104
+ context.__mpxTapInfo.detail = {
105
+ x: e.pageX,
106
+ y: e.pageY
107
+ }
108
+ const re = inheritEvent('tap', e, context.__mpxTapInfo.detail)
109
+ context.$emit('tap', re)
102
110
  }
103
- const re = inheritEvent('tap', e, context.__mpxTapInfo.detail)
104
- context.$emit('tap', re)
105
111
  }
106
- context.__mpxTapInfo.hadTouch = false
107
112
  }
108
113
  }
114
+
109
115
  mergeListeners(listeners, events, {
110
116
  force: true
111
117
  })
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import { inBrowser } from '../../../utils/env'
3
+
3
4
  function isDef (v) {
4
5
  return v !== undefined && v !== null
5
6
  }
@@ -30,7 +31,7 @@
30
31
 
31
32
  function getVnodeKey (vnode) {
32
33
  if (vnode && vnode.componentOptions) {
33
- return vnode.key || vnode.componentOptions.Ctor.cid + (vnode.componentOptions.tag ? ('::' + (vnode.componentOptions.tag)) : '')
34
+ return vnode.componentOptions.Ctor.cid + (vnode.componentOptions.tag ? ('::' + (vnode.componentOptions.tag)) : '')
34
35
  }
35
36
  }
36
37
 
@@ -73,6 +74,8 @@
73
74
  const current = stack[i - 1]
74
75
  if (current.vnode && current.vnodeKey === vnodeKey && current.vnode.componentInstance) {
75
76
  vnode.componentInstance = current.vnode.componentInstance
77
+ // 避免组件实例复用但是vnode.key不一致带来的bad case
78
+ vnode.key = current.vnode.key
76
79
  break
77
80
  }
78
81
  }
@@ -15,7 +15,7 @@
15
15
  'mpx-tab-bar': tabBarPagesMap['mpx-tab-bar']
16
16
  }
17
17
  tabBar.list.forEach(({ pagePath }) => {
18
- const name = pagePath.replace('/', '-')
18
+ const name = pagePath.replace(/\//g, '-')
19
19
  const page = tabBarPagesMap[pagePath]
20
20
  if (page) {
21
21
  components[name] = page
@@ -39,7 +39,7 @@
39
39
  currentComponent () {
40
40
  const index = this.currentIndex
41
41
  const tabItem = tabBar.list[index]
42
- return tabItem.pagePath.replace('/', '-')
42
+ return tabItem.pagePath.replace(/\//g, '-')
43
43
  }
44
44
  },
45
45
  watch: {
@@ -4,7 +4,7 @@ export default function processOption (
4
4
  option,
5
5
  ctorType,
6
6
  firstPage,
7
- componentId,
7
+ outputPath,
8
8
  pageConfig,
9
9
  pagesMap,
10
10
  componentsMap,
@@ -25,23 +25,6 @@ export default function processOption (
25
25
  }
26
26
  }
27
27
 
28
- // 注册v-ex-classes自定义指令处理externalClasses
29
- Vue.directive('ex-classes', (el, binding, vnode) => {
30
- const context = vnode.context
31
- if (context) {
32
- const externalClasses = context.$options.externalClasses || []
33
- const classList = el.classList
34
- binding.value.forEach((className) => {
35
- const actualExternalClassNames = context.$attrs[className]
36
- if (externalClasses.indexOf(className) !== -1 && actualExternalClassNames) {
37
- classList.remove(className)
38
- actualExternalClassNames.split(/\s+/).forEach((actualExternalClassName) => {
39
- if (actualExternalClassName) classList.add(actualExternalClassName)
40
- })
41
- }
42
- })
43
- }
44
- })
45
28
  Vue.directive('animation', (el, binding) => {
46
29
  const newActions = binding && binding.value && binding.value.actions
47
30
  if (el.actions === newActions) {
@@ -121,7 +104,9 @@ export default function processOption (
121
104
  redirect: '/' + firstPage
122
105
  })
123
106
  }
107
+ const webRouteConfig = global.__mpx.config.webRouteConfig
124
108
  global.__mpxRouter = option.router = new VueRouter({
109
+ ...webRouteConfig,
125
110
  routes: routes
126
111
  })
127
112
  global.__mpxRouter.stack = []
@@ -354,8 +339,8 @@ registered in parent context!`)
354
339
  option.mixins = [mixin]
355
340
  }
356
341
 
357
- if (componentId) {
358
- option.componentPath = '/' + componentId
342
+ if (outputPath) {
343
+ option.componentPath = '/' + outputPath
359
344
  }
360
345
 
361
346
  return option
@@ -93,7 +93,7 @@ function isDef (v) {
93
93
  return v !== undefined && v !== null
94
94
  }
95
95
 
96
- function stringifyClass (value) {
96
+ function stringifyDynamicClass (value) {
97
97
  if (!value) return ''
98
98
  if (likeArray(value)) {
99
99
  return stringifyArray(value)
@@ -111,7 +111,7 @@ function stringifyArray (value) {
111
111
  var res = ''
112
112
  var stringified
113
113
  for (var i = 0; i < value.length; i++) {
114
- if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {
114
+ if (isDef(stringified = stringifyDynamicClass(value[i])) && stringified !== '') {
115
115
  if (res) res += ' '
116
116
  res += stringified
117
117
  }
@@ -207,7 +207,7 @@ module.exports = {
207
207
  if (typeof staticClass !== 'string') {
208
208
  return console.log('Template attr class must be a string!')
209
209
  }
210
- return concat(staticClass, stringifyClass(dynamicClass))
210
+ return concat(staticClass, stringifyDynamicClass(dynamicClass))
211
211
  },
212
212
  stringifyStyle: function (staticStyle, dynamicStyle) {
213
213
  var normalizedDynamicStyle = normalizeDynamicStyle(dynamicStyle)
package/lib/selector.js CHANGED
@@ -9,24 +9,42 @@ module.exports = function (content) {
9
9
  return content
10
10
  }
11
11
  const { queryObj } = parseRequest(this.resource)
12
+ const ctorType = queryObj.ctorType
12
13
  const type = queryObj.type
13
14
  const index = queryObj.index || 0
14
15
  const mode = mpx.mode
15
16
  const env = mpx.env
16
- const defs = mpx.defs
17
17
  const filePath = this.resourcePath
18
18
  const parts = parseComponent(content, {
19
19
  filePath,
20
20
  needMap: this.sourceMap,
21
21
  mode,
22
- defs,
23
22
  env
24
23
  })
25
- let part = parts[type] || {}
24
+ let part = parts[type]
26
25
  if (Array.isArray(part)) {
27
- part = part[index] || {
28
- content: ''
26
+ part = part[index]
27
+ }
28
+ if (!part) {
29
+ let content = ''
30
+ // 补全js内容
31
+ if (type === 'script') {
32
+ switch (ctorType) {
33
+ case 'app':
34
+ content += 'import {createApp} from "@mpxjs/core"\n' +
35
+ 'createApp({})\n'
36
+ break
37
+ case 'page':
38
+ content += 'import {createPage} from "@mpxjs/core"\n' +
39
+ 'createPage({})\n'
40
+ break
41
+ case 'component':
42
+ content += 'import {createComponent} from "@mpxjs/core"\n' +
43
+ 'createComponent({})\n'
44
+ }
29
45
  }
46
+ part = { content }
30
47
  }
48
+ part = part || { content: '' }
31
49
  this.callback(null, part.content, part.map)
32
50
  }
@@ -1,5 +1,6 @@
1
1
  const postcss = require('postcss')
2
2
  const loadPostcssConfig = require('./load-postcss-config')
3
+ const { MPX_ROOT_VIEW, MPX_APP_MODULE_ID } = require('../utils/const')
3
4
  const trim = require('./plugins/trim')
4
5
  const rpx = require('./plugins/rpx')
5
6
  const vw = require('./plugins/vw')
@@ -15,12 +16,10 @@ module.exports = function (css, map) {
15
16
  const { resourcePath, queryObj } = parseRequest(this.resource)
16
17
  const id = queryObj.moduleId || queryObj.mid
17
18
  const mpx = this.getMpx()
19
+ const appInfo = mpx.appInfo
18
20
  const defs = mpx.defs
19
21
  const mode = mpx.mode
20
- const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
21
- const componentsMap = mpx.componentsMap[packageName]
22
- const pagesMap = mpx.pagesMap
23
- const isApp = !(pagesMap[resourcePath] || componentsMap[resourcePath])
22
+ const isApp = resourcePath === appInfo.resourcePath
24
23
  const transRpxRulesRaw = mpx.transRpxRules
25
24
  const transRpxRules = transRpxRulesRaw ? (Array.isArray(transRpxRulesRaw) ? transRpxRulesRaw : [transRpxRulesRaw]) : []
26
25
 
@@ -85,7 +84,7 @@ module.exports = function (css, map) {
85
84
  .then(result => {
86
85
  // ali环境添加全局样式抹平root差异
87
86
  if (mode === 'ali' && isApp) {
88
- result.css += '\n.mpx-root-view { display: inline; line-height: normal; }\n'
87
+ result.css += `\n.${MPX_ROOT_VIEW} { display: initial }\n.${MPX_APP_MODULE_ID} { line-height: normal }`
89
88
  }
90
89
  if (result.messages) {
91
90
  result.messages.forEach(({ type, file }) => {
@@ -1,7 +1,7 @@
1
- const babylon = require('babylon')
2
- const traverse = require('babel-traverse').default
3
- const t = require('babel-types')
4
- const generate = require('babel-generator').default
1
+ const babylon = require('@babel/parser')
2
+ const traverse = require('@babel/traverse').default
3
+ const t = require('@babel/types')
4
+ const generate = require('@babel/generator').default
5
5
 
6
6
  let names = 'Infinity,undefined,NaN,isFinite,isNaN,' +
7
7
  'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
@@ -1,10 +1,10 @@
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 } = require('../utils/const')
4
5
  const normalize = require('../utils/normalize')
5
6
  const isValidIdentifierStr = require('../utils/is-valid-identifier-str')
6
7
  const isEmptyObject = require('../utils/is-empty-object')
7
- const mpxJSON = require('../utils/mpx-json')
8
8
  const getRulesRunner = require('../platform/index')
9
9
  const addQuery = require('../utils/add-query')
10
10
  const transDynamicClassExpr = require('./trans-dynamic-class-expr')
@@ -496,7 +496,6 @@ function parseHTML (html, options) {
496
496
 
497
497
  function parseComponent (content, options) {
498
498
  mode = options.mode || 'wx'
499
- defs = options.defs || {}
500
499
  env = options.env
501
500
  filePath = options.filePath
502
501
 
@@ -548,6 +547,9 @@ function parseComponent (content, options) {
548
547
  if (/^application\/json/.test(currentBlock.type) || currentBlock.name === 'json') {
549
548
  tag = 'json'
550
549
  }
550
+ if (currentBlock.name === 'json') {
551
+ currentBlock.useJSONJS = true
552
+ }
551
553
  }
552
554
  if (currentBlock.mode && currentBlock.env) {
553
555
  if (currentBlock.mode === mode && currentBlock.env === env) {
@@ -606,20 +608,15 @@ function parseComponent (content, options) {
606
608
  }
607
609
  }
608
610
 
609
- function end (tag, start, end) {
611
+ function end (tag, start) {
610
612
  if (depth === 1 && currentBlock) {
611
613
  currentBlock.end = start
612
614
  let text = content.slice(currentBlock.start, currentBlock.end)
613
615
  // pad content so that linters and pre-processors can output correct
614
616
  // line numbers in errors and warnings
615
- if (currentBlock.tag !== 'template' && options.pad) {
617
+ if (options.pad) {
616
618
  text = padContent(currentBlock, options.pad) + text
617
619
  }
618
-
619
- // 对于<script name="json">的标签,传参调用函数,其返回结果作为json的内容
620
- if (currentBlock.tag === 'script' && !/^application\/json/.test(currentBlock.type) && currentBlock.name === 'json') {
621
- text = mpxJSON.compileMPXJSONText({ source: text, defs, filePath })
622
- }
623
620
  currentBlock.content = text
624
621
  currentBlock = null
625
622
  }
@@ -1714,31 +1711,71 @@ function processAliExternalClassesHack (el, options) {
1714
1711
  }
1715
1712
  }
1716
1713
 
1714
+ // externalClasses只能模拟静态传递
1717
1715
  function processWebExternalClassesHack (el, options) {
1718
- // todo 处理scoped的情况, 处理组件多层传递externalClass的情况,通过externalClass属性传递实际类名及scopeId信息,可以使用特殊的类名形式代表scopeId,如#idstring
1719
- let staticClass = el.attrsMap['class']
1720
- let dynamicClass = el.attrsMap[':class']
1721
- if (staticClass || dynamicClass) {
1722
- const externalClasses = []
1716
+ const staticClass = getAndRemoveAttr(el, 'class').val
1717
+ if (staticClass) {
1718
+ const classNames = staticClass.split(/\s+/)
1719
+ const replacements = []
1723
1720
  options.externalClasses.forEach((className) => {
1724
- const reg = new RegExp('\\b' + className + '\\b')
1725
- if (reg.test(staticClass) || reg.test(dynamicClass)) {
1726
- externalClasses.push(className)
1721
+ const index = classNames.indexOf(className)
1722
+ if (index > -1) {
1723
+ replacements.push(`$attrs[${JSON.stringify(className)}]`)
1724
+ classNames.splice(index, 1)
1727
1725
  }
1728
1726
  })
1729
- if (externalClasses.length) {
1727
+
1728
+ if (classNames.length) {
1729
+ addAttrs(el, [{
1730
+ name: 'class',
1731
+ value: classNames.join(' ')
1732
+ }])
1733
+ }
1734
+
1735
+ if (replacements.length) {
1736
+ const dynamicClass = getAndRemoveAttr(el, ':class').val
1737
+ if (dynamicClass) replacements.push(dynamicClass)
1738
+
1730
1739
  addAttrs(el, [{
1731
- name: 'v-ex-classes',
1732
- value: JSON.stringify(externalClasses)
1740
+ name: ':class',
1741
+ value: `[${replacements.join(',')}]`
1733
1742
  }])
1734
1743
  }
1735
1744
  }
1745
+
1746
+ // 处理externalClasses多层透传
1747
+ const isComponent = isComponentNode(el, options)
1748
+ if (isComponent) {
1749
+ options.externalClasses.forEach((classLikeAttrName) => {
1750
+ let classLikeAttrValue = getAndRemoveAttr(el, classLikeAttrName).val
1751
+ if (classLikeAttrValue) {
1752
+ const classNames = classLikeAttrValue.split(/\s+/)
1753
+ const replacements = []
1754
+ options.externalClasses.forEach((className) => {
1755
+ const index = classNames.indexOf(className)
1756
+ if (index > -1) {
1757
+ replacements.push(`$attrs[${JSON.stringify(className)}]`)
1758
+ classNames.splice(index, 1)
1759
+ }
1760
+ })
1761
+
1762
+ if (classNames.length) {
1763
+ replacements.unshift(JSON.stringify(classNames.join(' ')))
1764
+ }
1765
+
1766
+ addAttrs(el, [{
1767
+ name: ':' + classLikeAttrName,
1768
+ value: `[${replacements.join(',')}].join(' ')`
1769
+ }])
1770
+ }
1771
+ })
1772
+ }
1736
1773
  }
1737
1774
 
1738
1775
  function processScoped (el, options) {
1739
1776
  if (options.hasScoped && isRealNode(el)) {
1740
1777
  const moduleId = options.moduleId
1741
- const rootModuleId = options.isComponent ? '' : 'mpx-app-scope' // 处理app全局样式对页面的影响
1778
+ const rootModuleId = options.isComponent ? '' : MPX_APP_MODULE_ID // 处理app全局样式对页面的影响
1742
1779
  const staticClass = getAndRemoveAttr(el, 'class').val
1743
1780
  addAttrs(el, [{
1744
1781
  name: 'class',
@@ -1761,17 +1798,33 @@ function processBuiltInComponents (el, meta) {
1761
1798
  }
1762
1799
  }
1763
1800
 
1764
- function processAliStyleClassHack (el, options) {
1765
- if (!isComponentNode(el, options)) return
1801
+ function processAliStyleClassHack (el, options, root) {
1802
+ let processor
1803
+ // 处理组件标签
1804
+ if (isComponentNode(el, options)) processor = ({ value, typeName }) => [typeName, value]
1805
+ // 处理组件根节点
1806
+ if (options.isComponent && el === root && isRealNode(el)) {
1807
+ processor = ({ name, value, typeName }) => {
1808
+ let sep = name === 'style' ? ';' : ' '
1809
+ value = value ? `{{${typeName}||''}}${sep}${value}` : `{{${typeName}||''}}`
1810
+ return [name, value]
1811
+ }
1812
+ }
1813
+ // 非上述两种不处理
1814
+ if (!processor) return
1815
+ // 处理style、class
1766
1816
  ['style', 'class'].forEach((type) => {
1767
1817
  let exp = getAndRemoveAttr(el, type).val
1768
- let typeName = 'mpx' + type.replace(/^./, (matched) => {
1769
- return matched.toUpperCase()
1818
+ let typeName = 'mpx' + type.replace(/^./, (matched) => matched.toUpperCase())
1819
+ let [newName, newValue] = processor({
1820
+ name: type,
1821
+ value: exp,
1822
+ typeName
1770
1823
  })
1771
- if (exp !== undefined) {
1824
+ if (newValue !== undefined) {
1772
1825
  addAttrs(el, [{
1773
- name: typeName,
1774
- value: exp
1826
+ name: newName,
1827
+ value: newValue
1775
1828
  }])
1776
1829
  }
1777
1830
  })
@@ -1779,21 +1832,24 @@ function processAliStyleClassHack (el, options) {
1779
1832
 
1780
1833
  // 有virtualHost情况wx组件注入virtualHost。无virtualHost阿里组件注入root-view。其他跳过。
1781
1834
  function getVirtualHostRoot (options, meta) {
1782
- if (mode === 'wx' && options.hasVirtualHost && options.isComponent) {
1783
- !meta.options && (meta.options = {})
1784
- meta.options.virtualHost = true
1785
- }
1786
- if (mode === 'ali' && !options.hasVirtualHost && options.isComponent) {
1787
- return createASTElement('view', [
1788
- {
1789
- name: 'class',
1790
- value: `mpx-root-view host-${options.moduleId} ${options.hasScoped ? options.moduleId : ''} {{mpxClass||''}}`
1791
- },
1792
- {
1793
- name: 'style',
1794
- value: `{{mpxStyle||''}}`
1795
- }
1796
- ])
1835
+ if (options.isComponent) {
1836
+ // 处理组件时
1837
+ if (mode === 'wx' && options.hasVirtualHost) {
1838
+ // wx组件注入virtualHost配置
1839
+ !meta.options && (meta.options = {})
1840
+ meta.options.virtualHost = true
1841
+ }
1842
+ if (mode === 'ali' && !options.hasVirtualHost) {
1843
+ // ali组件根节点实体化
1844
+ let rootView = createASTElement('view', [
1845
+ {
1846
+ name: 'class',
1847
+ value: `${MPX_ROOT_VIEW} host-${options.moduleId}`
1848
+ }
1849
+ ])
1850
+ processElement(rootView, rootView, options, meta)
1851
+ return rootView
1852
+ }
1797
1853
  }
1798
1854
  return getTempNode()
1799
1855
  }
@@ -1801,7 +1857,10 @@ function getVirtualHostRoot (options, meta) {
1801
1857
  function processShow (el, options, root) {
1802
1858
  let show = getAndRemoveAttr(el, config[mode].directive.show).val
1803
1859
  if (mode === 'swan') show = wrapMustache(show)
1804
- if (options.isComponent && el.parent === root && isRealNode(el)) {
1860
+ let processFlag = el.parent === root
1861
+ // 当ali且未开启virtualHost时,mpxShow打到根节点上
1862
+ if (mode === 'ali' && !options.hasVirtualHost) processFlag = el === root
1863
+ if (options.isComponent && processFlag && isRealNode(el)) {
1805
1864
  if (show !== undefined) {
1806
1865
  show = `{{${parseMustache(show).result}&&mpxShow}}`
1807
1866
  } else {
@@ -2283,5 +2342,6 @@ module.exports = {
2283
2342
  makeAttrsMap,
2284
2343
  stringifyAttr,
2285
2344
  parseMustache,
2286
- stringifyWithResolveComputed
2345
+ stringifyWithResolveComputed,
2346
+ addAttrs
2287
2347
  }
@@ -38,7 +38,7 @@ module.exports = function (raw) {
38
38
  )
39
39
  }
40
40
 
41
- const parsed = compiler.parse(raw, {
41
+ const { root: ast, meta } = compiler.parse(raw, {
42
42
  warn,
43
43
  error,
44
44
  usingComponents,
@@ -57,13 +57,10 @@ module.exports = function (raw) {
57
57
  i18n,
58
58
  checkUsingComponents: mpx.checkUsingComponents,
59
59
  globalComponents: Object.keys(mpx.usingComponents),
60
- forceProxyEvent: matchCondition(this.resourcePath, mpx.forceProxyEventRules),
61
- hasVirtualHost: matchCondition(this.resourcePath, mpx.autoVirtualHostRules)
60
+ forceProxyEvent: matchCondition(resourcePath, mpx.forceProxyEventRules),
61
+ hasVirtualHost: matchCondition(resourcePath, mpx.autoVirtualHostRules)
62
62
  })
63
63
 
64
- let ast = parsed.root
65
- let meta = parsed.meta
66
-
67
64
  if (meta.wxsContentMap) {
68
65
  for (let module in meta.wxsContentMap) {
69
66
  wxsContentMap[`${resourcePath}~${module}`] = meta.wxsContentMap[module]
@@ -1,6 +1,6 @@
1
- const babylon = require('babylon')
2
- const t = require('babel-types')
3
- const generate = require('babel-generator').default
1
+ const babylon = require('@babel/parser')
2
+ const t = require('@babel/types')
3
+ const generate = require('@babel/generator').default
4
4
  const dash2hump = require('../utils/hump-dash').dash2hump
5
5
 
6
6
  module.exports = function transDynamicClassExpr (expr) {
@@ -1,5 +1,9 @@
1
1
  module.exports = {
2
2
  MPX_PROCESSED_FLAG: 'mpx_processed',
3
3
  MPX_DISABLE_EXTRACTOR_CACHE: 'mpx_disable_extractor_cache',
4
- DEFAULT_RESULT_SOURCE: ''
4
+ DEFAULT_RESULT_SOURCE: '',
5
+ RESOLVE_IGNORED_ERR: new Error('Resolve ignored!'),
6
+ JSON_JS_EXT: '.json.js',
7
+ MPX_ROOT_VIEW: 'mpx-root-view', // 根节点类名
8
+ MPX_APP_MODULE_ID: 'mpx-app-scope' // app文件moduleId
5
9
  }
@@ -0,0 +1,31 @@
1
+ const path = require('path')
2
+
3
+ module.exports = function evalJSONJS (source, filename, loaderContext) {
4
+ const fs = loaderContext._compiler.inputFileSystem
5
+ const defs = loaderContext.getMpx().defs
6
+ const defKeys = Object.keys(defs)
7
+ const defValues = defKeys.map((key) => {
8
+ return defs[key]
9
+ })
10
+ // 记录依赖
11
+ loaderContext.addDependency(filename)
12
+ const dirname = path.dirname(filename)
13
+ // eslint-disable-next-line no-new-func
14
+ const func = new Function('module', 'exports', 'require', '__filename', '__dirname', ...defKeys, source)
15
+ const module = {
16
+ exports: {}
17
+ }
18
+ // 此处采用readFileSync+evalJSONJS而不直接使用require获取依赖内容有两个原因:
19
+ // 1. 支持依赖中正常访问defs变量
20
+ // 2. 避免对应的依赖文件被作为buildDependencies
21
+ func(module, module.exports, function (request) {
22
+ if (request.startsWith('.')) {
23
+ request = path.join(dirname, request)
24
+ }
25
+ const filename = require.resolve(request)
26
+ const source = fs.readFileSync(filename).toString('utf-8')
27
+ return evalJSONJS(source, filename, loaderContext)
28
+ }, filename, dirname, ...defValues)
29
+
30
+ return module.exports
31
+ }