@mpxjs/webpack-plugin 2.8.21 → 2.8.23-alpha

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 (39) hide show
  1. package/README.md +1 -1
  2. package/lib/config.js +14 -0
  3. package/lib/dependencies/AddEntryDependency.js +24 -0
  4. package/lib/dependencies/DynamicEntryDependency.js +14 -1
  5. package/lib/dependencies/ResolveDependency.js +4 -0
  6. package/lib/index.js +52 -7
  7. package/lib/loader.js +40 -0
  8. package/lib/platform/template/wx/component-config/button.js +14 -2
  9. package/lib/platform/template/wx/component-config/image.js +4 -0
  10. package/lib/platform/template/wx/component-config/input.js +4 -0
  11. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  12. package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
  13. package/lib/platform/template/wx/component-config/switch.js +4 -0
  14. package/lib/platform/template/wx/component-config/text.js +4 -0
  15. package/lib/platform/template/wx/component-config/textarea.js +5 -0
  16. package/lib/platform/template/wx/component-config/view.js +4 -0
  17. package/lib/platform/template/wx/index.js +121 -1
  18. package/lib/resolve-loader.js +4 -1
  19. package/lib/runtime/components/tenon/getInnerListeners.js +314 -0
  20. package/lib/runtime/components/tenon/tenon-button.vue +305 -0
  21. package/lib/runtime/components/tenon/tenon-image.vue +61 -0
  22. package/lib/runtime/components/tenon/tenon-input.vue +104 -0
  23. package/lib/runtime/components/tenon/tenon-rich-text.vue +21 -0
  24. package/lib/runtime/components/tenon/tenon-scroll-view.vue +124 -0
  25. package/lib/runtime/components/tenon/tenon-switch.vue +91 -0
  26. package/lib/runtime/components/tenon/tenon-text-area.vue +77 -0
  27. package/lib/runtime/components/tenon/tenon-text.vue +64 -0
  28. package/lib/runtime/components/tenon/tenon-view.vue +93 -0
  29. package/lib/runtime/optionProcessor.tenon.js +388 -0
  30. package/lib/style-compiler/index.js +1 -1
  31. package/lib/style-compiler/plugins/hm.js +20 -0
  32. package/lib/template-compiler/compiler.js +11 -2
  33. package/lib/tenon/index.js +104 -0
  34. package/lib/tenon/processJSON.js +356 -0
  35. package/lib/tenon/processScript.js +262 -0
  36. package/lib/tenon/processStyles.js +21 -0
  37. package/lib/tenon/processTemplate.js +133 -0
  38. package/lib/utils/get-relative-path.js +25 -0
  39. package/package.json +5 -2
package/README.md CHANGED
@@ -13,6 +13,6 @@ module.exports = {
13
13
  new mpxWebpackPlugin({
14
14
  mode: 'wx'
15
15
  })
16
- ],
16
+ ]
17
17
  }
18
18
  ```
package/lib/config.js CHANGED
@@ -356,6 +356,20 @@ module.exports = {
356
356
  templatePrefix: 'module.exports = \n'
357
357
  }
358
358
  },
359
+ tenon: {
360
+ directive: {
361
+ if: 'v-if',
362
+ elseif: 'v-else-if',
363
+ else: 'v-else'
364
+ },
365
+ wxs: {
366
+ tag: 'wxs',
367
+ module: 'module',
368
+ src: 'src',
369
+ ext: '.wxs',
370
+ templatePrefix: 'module.exports = \n'
371
+ }
372
+ },
359
373
  qa: {
360
374
  typeExtMap: {
361
375
  json: '.json',
@@ -0,0 +1,24 @@
1
+ const NullDependency = require('webpack/lib/dependencies/NullDependency')
2
+
3
+ class AddEntryDependency extends NullDependency {
4
+ constructor ({ context, dep, name }) {
5
+ super()
6
+ this.__addEntryParams = [context, dep, name]
7
+ }
8
+
9
+ get type () {
10
+ return 'mpx add entry'
11
+ }
12
+
13
+ // updateHash (hash) {
14
+ // super.updateHash(hash)
15
+ // hash.update(this.childCompileEntryModule.identifier())
16
+ // }
17
+ }
18
+
19
+ AddEntryDependency.Template = class AddEntryDependencyTemplate {
20
+ apply () {
21
+ }
22
+ }
23
+
24
+ module.exports = AddEntryDependency
@@ -28,10 +28,23 @@ class DynamicEntryDependency extends NullDependency {
28
28
  return toPosix([request, entryType, outputPath, packageRoot, relativePath, context, ...range].join('|'))
29
29
  }
30
30
 
31
+ collectDynamicRequest (mpx) {
32
+ if (!this.packageRoot) return
33
+ const curValue = mpx.dynamicEntryInfo[this.packageRoot] = mpx.dynamicEntryInfo[this.packageRoot] || {
34
+ hasPage: false,
35
+ entries: []
36
+ }
37
+ if (this.entryType === 'page') {
38
+ curValue.hasPage = true
39
+ } else {
40
+ curValue.entries.push(this.request)
41
+ }
42
+ }
43
+
31
44
  addEntry (compilation, callback) {
32
45
  const mpx = compilation.__mpx__
33
46
  let { request, entryType, outputPath, relativePath, context, originEntryNode, publicPath, resolver } = this
34
-
47
+ this.collectDynamicRequest(mpx)
35
48
  async.waterfall([
36
49
  (callback) => {
37
50
  if (context && resolver) {
@@ -75,6 +75,10 @@ ResolveDependency.Template = class ResolveDependencyTemplate {
75
75
  getContent (dep) {
76
76
  const { resolved = '', compilation } = dep
77
77
  const publicPath = compilation.outputOptions.publicPath || ''
78
+ // for tenon
79
+ if (dep.compilation.__mpx__.mode === 'tenon') {
80
+ return `getRelativePath(currentURL, ${JSON.stringify(resolved)}) + '.js'`
81
+ }
78
82
  return JSON.stringify(publicPath + resolved)
79
83
  }
80
84
  }
package/lib/index.js CHANGED
@@ -317,7 +317,7 @@ class MpxWebpackPlugin {
317
317
  let splitChunksPlugin
318
318
  let splitChunksOptions
319
319
 
320
- if (this.options.mode !== 'web') {
320
+ if (this.options.mode !== 'web' && this.options.mode !== 'tenon') {
321
321
  const optimization = compiler.options.optimization
322
322
  optimization.runtimeChunk = {
323
323
  name: (entrypoint) => {
@@ -453,7 +453,20 @@ class MpxWebpackPlugin {
453
453
  name: 'MpxWebpackPlugin',
454
454
  stage: -1000
455
455
  }, (compilation, callback) => {
456
- processSubpackagesEntriesMap(compilation, callback)
456
+ processSubpackagesEntriesMap(compilation, () => {
457
+ const checkRegisterPack = () => {
458
+ for (const packRoot in mpx.dynamicEntryInfo) {
459
+ const entryMap = mpx.dynamicEntryInfo[packRoot]
460
+ if (!entryMap.hasPage) {
461
+ // 引用未注册分包的所有资源
462
+ const strRequest = entryMap.entries.join(',')
463
+ compilation.errors.push(new Error(`资源${strRequest}目标是打入${packRoot}分包, 但是app.json中并未声明${packRoot}分包`))
464
+ }
465
+ }
466
+ }
467
+ checkRegisterPack()
468
+ callback()
469
+ })
457
470
  })
458
471
 
459
472
  compiler.hooks.compilation.tap('MpxWebpackPlugin ', (compilation, { normalModuleFactory }) => {
@@ -537,6 +550,8 @@ class MpxWebpackPlugin {
537
550
  subpackagesEntriesMap: {},
538
551
  replacePathMap: {},
539
552
  exportModules: new Set(),
553
+ // 动态记录注册的分包与注册页面映射
554
+ dynamicEntryInfo: {},
540
555
  // 记录entryModule与entryNode的对应关系,用于体积分析
541
556
  entryNodeModulesMap: new Map(),
542
557
  // 记录与asset相关联的modules,用于体积分析
@@ -1058,7 +1073,27 @@ class MpxWebpackPlugin {
1058
1073
  }
1059
1074
  })
1060
1075
 
1061
- // 处理跨平台转换
1076
+ // processing for tenon-store
1077
+ if (mpx.mode === 'tenon') {
1078
+ let TENON_STORE_ID = 0
1079
+ parser.hooks.call.for('imported var').tap('MpxWebpackPlugin', (expr) => {
1080
+ if (['createStore', 'createStoreWithThis'].includes(expr.callee.name)) {
1081
+ const current = parser.state.current
1082
+ const storeOptions = expr.arguments.length && expr.arguments[0]
1083
+ if (storeOptions) {
1084
+ current.addDependency(new InjectDependency({
1085
+ content: 'Object.assign(',
1086
+ index: storeOptions.range[0]
1087
+ }))
1088
+ current.addDependency(new InjectDependency({
1089
+ content: `, { __store_id: ${TENON_STORE_ID++} })`,
1090
+ index: storeOptions.range[1]
1091
+ }))
1092
+ }
1093
+ }
1094
+ })
1095
+ }
1096
+
1062
1097
  if (mpx.srcMode !== mpx.mode) {
1063
1098
  // 处理跨平台全局对象转换
1064
1099
  const transGlobalObject = (expr) => {
@@ -1182,7 +1217,7 @@ class MpxWebpackPlugin {
1182
1217
  name: 'MpxWebpackPlugin',
1183
1218
  stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONS
1184
1219
  }, () => {
1185
- if (mpx.mode === 'web') return
1220
+ if (mpx.mode === 'web' || mpx.mode === 'tenon') return
1186
1221
 
1187
1222
  if (this.options.generateBuildMap) {
1188
1223
  const pagesMap = compilation.__mpx__.pagesMap
@@ -1420,21 +1455,31 @@ try {
1420
1455
  if (mpx.mode === 'web') {
1421
1456
  const mpxStyleOptions = queryObj.mpxStyleOptions
1422
1457
  const firstLoader = loaders[0] ? toPosix(loaders[0].loader) : ''
1423
- const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher')
1458
+ const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher') || firstLoader.includes('@hummer/tenon-loader/dist/pitcher.js')
1424
1459
  let cssLoaderIndex = -1
1425
1460
  let vueStyleLoaderIndex = -1
1426
1461
  let mpxStyleLoaderIndex = -1
1462
+ let tenonStyleLoaderIndex = -1
1427
1463
  loaders.forEach((loader, index) => {
1428
1464
  const currentLoader = toPosix(loader.loader)
1429
1465
  if (currentLoader.includes('css-loader') && cssLoaderIndex === -1) {
1430
1466
  cssLoaderIndex = index
1431
1467
  } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader') && vueStyleLoaderIndex === -1) {
1432
1468
  vueStyleLoaderIndex = index
1469
+ } else if (currentLoader.includes('@hummer/tenon-style-loader/dist/index.js') && tenonStyleLoaderIndex === -1) {
1470
+ tenonStyleLoaderIndex = index
1433
1471
  } else if (currentLoader.includes(styleCompilerPath) && mpxStyleLoaderIndex === -1) {
1434
1472
  mpxStyleLoaderIndex = index
1435
1473
  }
1436
1474
  })
1437
- if (mpxStyleLoaderIndex === -1) {
1475
+ if (mpx.mode === 'tenon' && mpxStyleLoaderIndex === -1) {
1476
+ if (tenonStyleLoaderIndex > -1 && !isPitcherRequest) {
1477
+ loaders.splice(tenonStyleLoaderIndex + 1, 0, {
1478
+ loader: normalize.lib('style-compiler/index.js'),
1479
+ options: (mpxStyleOptions && JSON.parse(mpxStyleOptions)) || {}
1480
+ })
1481
+ }
1482
+ } else if (mpxStyleLoaderIndex === -1) {
1438
1483
  let loaderIndex = -1
1439
1484
  if (cssLoaderIndex > -1 && vueStyleLoaderIndex === -1) {
1440
1485
  loaderIndex = cssLoaderIndex
@@ -1497,7 +1542,7 @@ try {
1497
1542
  })
1498
1543
  }
1499
1544
 
1500
- compiler.hooks.done.tapPromise('MpxWebpackPlugin', async () => {
1545
+ compiler.hooks.done.tapPromise('MpxWebpackPlugin', async (stats) => {
1501
1546
  const cache = compiler.getCache('MpxWebpackPlugin')
1502
1547
  const cacheIsValid = await cache.getPromise('cacheIsValid', null)
1503
1548
  if (!cacheIsValid) {
package/lib/loader.js CHANGED
@@ -11,6 +11,7 @@ const processJSON = require('./web/processJSON')
11
11
  const processScript = require('./web/processScript')
12
12
  const processStyles = require('./web/processStyles')
13
13
  const processTemplate = require('./web/processTemplate')
14
+ const processForTenon = require('./tenon/index')
14
15
  const getJSONContent = require('./utils/get-json-content')
15
16
  const normalize = require('./utils/normalize')
16
17
  const getEntryName = require('./utils/get-entry-name')
@@ -127,6 +128,45 @@ module.exports = function (content) {
127
128
  return callback(e)
128
129
  }
129
130
  }
131
+
132
+ if (mode === 'tenon') {
133
+ if (ctorType === 'app' && !queryObj.app) {
134
+ const request = addQuery(this.resource, { app: true })
135
+ output += `
136
+ import App from ${stringifyRequest(request)}
137
+ import * as Tenon from '@hummer/tenon-vue'
138
+
139
+ Tenon.render(App)\n`
140
+ // 直接结束loader进入parse
141
+ this.loaderIndex = -1
142
+ return callback(null, output)
143
+ }
144
+ if (ctorType === 'page' && queryObj.tenon) {
145
+ console.log(resourcePath)
146
+ const request = addQuery(resourcePath, { page: true })
147
+ output += `
148
+ import page from ${stringifyRequest(request)}
149
+ import * as Tenon from '@hummer/tenon-vue'
150
+
151
+ Tenon.render(page)\n`
152
+ this.loaderIndex = -1
153
+ return callback(null, output)
154
+ }
155
+ return processForTenon({
156
+ mpx,
157
+ loaderContext,
158
+ isProduction,
159
+ queryObj,
160
+ filePath,
161
+ parts,
162
+ ctorType,
163
+ autoScope,
164
+ componentsMap,
165
+ moduleId,
166
+ callback
167
+ })
168
+ }
169
+
130
170
  // 处理mode为web时输出vue格式文件
131
171
  if (mode === 'web') {
132
172
  if (ctorType === 'app' && !queryObj.isApp) {
@@ -28,6 +28,8 @@ module.exports = function ({ print }) {
28
28
  const ttEventLog = print({ platform: 'bytedance', tag: TAG_NAME, isError: false, type: 'event' })
29
29
  const webPropLog = print({ platform: 'web', tag: TAG_NAME, isError: false })
30
30
  const webEventLog = print({ platform: 'web', tag: TAG_NAME, isError: false, type: 'event' })
31
+ const tenonPropLog = print({ platform: 'tenon', tag: TAG_NAME, isError: false })
32
+ const tenonEventLog = print({ platform: 'tenon', tag: TAG_NAME, isError: false, type: 'event' })
31
33
  const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
32
34
  const wxPropValueLog = print({ platform: 'wx', tag: TAG_NAME, isError: false, type: 'value' })
33
35
 
@@ -37,6 +39,10 @@ module.exports = function ({ print }) {
37
39
  el.isBuiltIn = true
38
40
  return 'mpx-button'
39
41
  },
42
+ tenon (tag, { el }) {
43
+ el.isBuiltIn = true
44
+ return 'tenon-button'
45
+ },
40
46
  props: [
41
47
  {
42
48
  test: 'open-type',
@@ -131,13 +137,18 @@ module.exports = function ({ print }) {
131
137
  },
132
138
  {
133
139
  test: /^(open-type|lang|session-from|send-message-title|send-message-path|send-message-img|show-message-card|app-parameter)$/,
134
- web: webPropLog
140
+ web: webPropLog,
141
+ tenon: tenonPropLog
135
142
  },
136
143
  {
137
144
  test: /^(size|type|plain|loading|form-type|hover-class|hover-stop-propagation|hover-start-time|hover-stay-time|use-built-in)$/,
138
145
  web (prop, { el }) {
139
146
  // todo 这部分能力基于内部封装实现
140
147
  el.isBuiltIn = true
148
+ },
149
+ tenon (prop, { el }) {
150
+ // todo 这部分能力基于内部封装实现
151
+ el.isBuiltIn = true
141
152
  }
142
153
  },
143
154
  {
@@ -174,7 +185,8 @@ module.exports = function ({ print }) {
174
185
  },
175
186
  {
176
187
  test: /^(getuserinfo|contact|error|launchapp|opensetting|getphonenumber)$/,
177
- web: webEventLog
188
+ web: webEventLog,
189
+ tenon: tenonEventLog
178
190
  }
179
191
  ]
180
192
  }
@@ -13,6 +13,10 @@ module.exports = function ({ print }) {
13
13
  el.isBuiltIn = true
14
14
  return 'mpx-image'
15
15
  },
16
+ tenon (tag, { el }) {
17
+ el.isBuiltIn = true
18
+ return 'tenon-image'
19
+ },
16
20
  props: [
17
21
  {
18
22
  test: /^show-menu-by-longpress$/,
@@ -20,6 +20,10 @@ module.exports = function ({ print }) {
20
20
  el.isBuiltIn = true
21
21
  return 'mpx-input'
22
22
  },
23
+ tenon (tag, { el }) {
24
+ el.isBuiltIn = true
25
+ return 'tenon-input'
26
+ },
23
27
  props: [
24
28
  {
25
29
  test: /^(cursor-spacing|auto-focus|adjust-position|hold-keyboard)$/,
@@ -12,6 +12,10 @@ module.exports = function ({ print }) {
12
12
  el.isBuiltIn = true
13
13
  return 'mpx-rich-text'
14
14
  },
15
+ tenon (tag, { el }) {
16
+ el.isBuiltIn = true
17
+ return 'tenon-rich-text'
18
+ },
15
19
  props: [
16
20
  {
17
21
  test: /^(space)$/,
@@ -19,6 +19,10 @@ module.exports = function ({ print }) {
19
19
  el.isBuiltIn = true
20
20
  return 'mpx-scroll-view'
21
21
  },
22
+ tenon (tag, { el }) {
23
+ el.isBuiltIn = true
24
+ return 'tenon-scroll-view'
25
+ },
22
26
  props: [
23
27
  {
24
28
  test: /^(enable-flex|scroll-anchorin|refresher-enabled|refresher-threshold|refresher-default-style|refresher-background|refresher-triggered|enhanced|bounces|show-scrollbar|paging-enabled|fast-deceleratio)$/,
@@ -10,6 +10,10 @@ module.exports = function ({ print }) {
10
10
  el.isBuiltIn = true
11
11
  return 'mpx-switch'
12
12
  },
13
+ tenon (tag, { el }) {
14
+ el.isBuiltIn = true
15
+ return 'tenon-switch'
16
+ },
13
17
  props: [
14
18
  {
15
19
  test: /^type$/,
@@ -19,6 +19,10 @@ module.exports = function ({ print }) {
19
19
  return 'span'
20
20
  }
21
21
  },
22
+ tenon (tag, { el }) {
23
+ el.isBuiltIn = true
24
+ return 'tenon-text'
25
+ },
22
26
  props: [
23
27
  {
24
28
  test: /^(decode|user-select)$/,
@@ -22,6 +22,11 @@ module.exports = function ({ print }) {
22
22
  el.isBuiltIn = true
23
23
  return 'mpx-textarea'
24
24
  },
25
+ tenon (tag, { el }) {
26
+ // form全量使用内建组件
27
+ el.isBuiltIn = true
28
+ return 'tenon-textarea'
29
+ },
25
30
  props: [
26
31
  {
27
32
  test: /^(auto-focus|fixed|cursor-spacing|cursor|show-confirm-bar|selection-start|selection-end|adjust-position|hold-keyboard|disable-default-padding|confirm-type)$/,
@@ -21,6 +21,10 @@ module.exports = function ({ print }) {
21
21
  return 'div'
22
22
  }
23
23
  },
24
+ tenon (tag, { el }) {
25
+ el.isBuiltIn = true
26
+ return 'tenon-view'
27
+ },
24
28
  qa (tag) {
25
29
  return 'div'
26
30
  },
@@ -10,7 +10,7 @@ const normalize = require('../../../utils/normalize')
10
10
 
11
11
  module.exports = function getSpec ({ warn, error }) {
12
12
  const spec = {
13
- supportedModes: ['ali', 'swan', 'qq', 'tt', 'web', 'qa', 'jd', 'dd'],
13
+ supportedModes: ['ali', 'swan', 'qq', 'tt', 'web', 'qa', 'jd', 'dd', 'tenon'],
14
14
  // props预处理
15
15
  preProps: [],
16
16
  // props后处理
@@ -24,6 +24,15 @@ module.exports = function getSpec ({ warn, error }) {
24
24
  value: parsed.result
25
25
  }
26
26
  }
27
+ },
28
+ tenon ({ name, value }) {
29
+ const parsed = parseMustache(value)
30
+ if (parsed.hasBinding) {
31
+ return {
32
+ name: name === 'animation' ? 'v-' + name : ':' + name,
33
+ value: parsed.result
34
+ }
35
+ }
27
36
  }
28
37
  }
29
38
  ],
@@ -86,6 +95,16 @@ module.exports = function getSpec ({ warn, error }) {
86
95
  name: 'v-for',
87
96
  value: `(${itemName}, ${indexName}) in ${parsed.result}`
88
97
  }
98
+ },
99
+ tenon ({ value }, { el }) {
100
+ const parsed = parseMustache(value)
101
+ const attrsMap = el.attrsMap
102
+ const itemName = attrsMap['wx:for-item'] || 'item'
103
+ const indexName = attrsMap['wx:for-index'] || 'index'
104
+ return {
105
+ name: 'v-for',
106
+ value: `(${itemName}, ${indexName}) in ${parsed.result}`
107
+ }
89
108
  }
90
109
  },
91
110
  {
@@ -111,6 +130,25 @@ module.exports = function getSpec ({ warn, error }) {
111
130
  name: ':key',
112
131
  value
113
132
  }
133
+ },
134
+ tenon ({ value }, { el }) {
135
+ // vue的template中不能包含key,对应于小程序中的block
136
+ if (el.tag === 'block') return false
137
+ const itemName = el.attrsMap['wx:for-item'] || 'item'
138
+ const keyName = value
139
+ if (value === '*this') {
140
+ value = itemName
141
+ } else {
142
+ if (isValidIdentifierStr(keyName)) {
143
+ value = `${itemName}.${keyName}`
144
+ } else {
145
+ value = `${itemName}['${keyName}']`
146
+ }
147
+ }
148
+ return {
149
+ name: ':key',
150
+ value
151
+ }
114
152
  }
115
153
  },
116
154
  {
@@ -121,6 +159,9 @@ module.exports = function getSpec ({ warn, error }) {
121
159
  },
122
160
  web () {
123
161
  return false
162
+ },
163
+ tenon () {
164
+ return false
124
165
  }
125
166
  },
126
167
  {
@@ -163,6 +204,49 @@ module.exports = function getSpec ({ warn, error }) {
163
204
  }
164
205
  ]
165
206
  }
207
+ },
208
+ tenon ({ value }, { el }) {
209
+ el.hasEvent = true
210
+ const attrsMap = el.attrsMap
211
+ const tagRE = /\{\{((?:.|\n|\r)+?)\}\}(?!})/
212
+ const stringify = JSON.stringify
213
+ const match = tagRE.exec(value)
214
+ if (match) {
215
+ const modelProp = attrsMap['wx:model-prop'] || 'value'
216
+ const modelEvent = attrsMap['wx:model-event'] || 'input'
217
+ const modelValuePathRaw = attrsMap['wx:model-value-path']
218
+ const modelValuePath = modelValuePathRaw === undefined ? 'value' : modelValuePathRaw
219
+ const modelFilter = attrsMap['wx:model-filter']
220
+ let modelValuePathArr
221
+ try {
222
+ modelValuePathArr = JSON5.parse(modelValuePath)
223
+ } catch (e) {
224
+ if (modelValuePath === '') {
225
+ modelValuePathArr = []
226
+ } else {
227
+ modelValuePathArr = modelValuePath.split('.')
228
+ }
229
+ }
230
+ const modelValue = match[1].trim()
231
+ return [
232
+ {
233
+ name: ':' + modelProp,
234
+ value: modelValue
235
+ },
236
+ {
237
+ name: 'mpxModelEvent',
238
+ value: modelEvent
239
+ },
240
+ {
241
+ name: 'mpxModelEventId',
242
+ value: Math.random().toString(36).slice(3, 11)
243
+ },
244
+ {
245
+ name: '@mpxModel',
246
+ value: `__model(${stringifyWithResolveComputed(modelValue)}, $event, ${stringify(modelValuePathArr)}, ${stringify(modelFilter)})`
247
+ }
248
+ ]
249
+ }
166
250
  }
167
251
  },
168
252
  {
@@ -217,6 +301,14 @@ module.exports = function getSpec ({ warn, error }) {
217
301
  name: ':class',
218
302
  value: parsed.result
219
303
  }
304
+ },
305
+ tenon ({ name, value }) {
306
+ const dir = this.test.exec(name)[1]
307
+ const parsed = parseMustache(value)
308
+ return {
309
+ name: ':' + dir,
310
+ value: parsed.result
311
+ }
220
312
  }
221
313
  },
222
314
  // 通用指令
@@ -274,6 +366,17 @@ module.exports = function getSpec ({ warn, error }) {
274
366
  name: 'v-' + dir,
275
367
  value: parsed.result
276
368
  }
369
+ },
370
+ tenon ({ name, value }) {
371
+ let dir = this.test.exec(name)[1]
372
+ const parsed = parseMustache(value)
373
+ if (dir === 'elif') {
374
+ dir = 'else-if'
375
+ }
376
+ return {
377
+ name: 'v-' + dir,
378
+ value: parsed.result
379
+ }
277
380
  }
278
381
  },
279
382
  // 事件
@@ -346,6 +449,23 @@ module.exports = function getSpec ({ warn, error }) {
346
449
  name: rPrefix + rEventName + meta.modifierStr,
347
450
  value
348
451
  }
452
+ },
453
+ tenon ({ name, value }, { eventRules, el }) {
454
+ const match = this.test.exec(name)
455
+ const prefix = match[1]
456
+ const eventName = match[2]
457
+ const modifierStr = match[3] || ''
458
+ const meta = {
459
+ modifierStr
460
+ }
461
+ // 记录event监听信息用于后续判断是否需要使用内置基础组件
462
+ el.hasEvent = true
463
+ const rPrefix = runRules(spec.event.prefix, prefix, { mode: 'web', meta })
464
+ const rEventName = runRules(eventRules, eventName, { mode: 'web' })
465
+ return {
466
+ name: rPrefix + rEventName + meta.modifierStr,
467
+ value
468
+ }
349
469
  }
350
470
  },
351
471
  // 无障碍
@@ -1,3 +1,6 @@
1
1
  module.exports = function () {
2
- return `module.exports = __mpx_resolve_path__(${JSON.stringify(this.resource)})`
2
+ return `
3
+ var currentURL = global.currentPagePath
4
+ var getRelativePath = require('@mpxjs/webpack-plugin/lib/utils/get-relative-path').getRelativePath
5
+ module.exports = __mpx_resolve_path__(${JSON.stringify(this.resource)})`
3
6
  }