@mpxjs/webpack-plugin 2.9.37 → 2.9.39

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.
@@ -5,6 +5,7 @@ const addQuery = require('../utils/add-query')
5
5
  const toPosix = require('../utils/to-posix')
6
6
  const async = require('async')
7
7
  const parseRequest = require('../utils/parse-request')
8
+ const hasOwn = require('../utils/has-own')
8
9
 
9
10
  class DynamicEntryDependency extends NullDependency {
10
11
  constructor (range, request, entryType, outputPath = '', packageRoot = '', relativePath = '', context = '', extraOptions = {}) {
@@ -131,6 +132,13 @@ class DynamicEntryDependency extends NullDependency {
131
132
  this.publicPath = compilation.outputOptions.publicPath || ''
132
133
  const { packageRoot, context } = this
133
134
  if (context) this.resolver = compilation.resolverFactory.get('normal', module.resolveOptions)
135
+ // post 分包队列在 sub 分包队列构建完毕后进行
136
+ if (this.extraOptions.postSubpackageEntry) {
137
+ mpx.postSubpackageEntriesMap[packageRoot] = mpx.postSubpackageEntriesMap[packageRoot] || []
138
+ mpx.postSubpackageEntriesMap[packageRoot].push(this)
139
+ callback()
140
+ return
141
+ }
134
142
  // 分包构建在需要在主包构建完成后在finishMake中处理,返回的资源路径先用key来占位,在合成extractedAssets时再进行最终替换
135
143
  if (packageRoot && mpx.currentPackageRoot !== packageRoot) {
136
144
  mpx.subpackagesEntriesMap[packageRoot] = mpx.subpackagesEntriesMap[packageRoot] || []
@@ -190,7 +198,7 @@ DynamicEntryDependency.Template = class DynamicEntryDependencyTemplate {
190
198
 
191
199
  let replaceContent = ''
192
200
 
193
- if (extraOptions.replaceContent) {
201
+ if (hasOwn(extraOptions, 'replaceContent')) {
194
202
  replaceContent = extraOptions.replaceContent
195
203
  } else if (resultPath) {
196
204
  if (extraOptions.isRequireAsync) {
@@ -0,0 +1,66 @@
1
+ const NullDependency = require('webpack/lib/dependencies/NullDependency')
2
+ const makeSerializable = require('webpack/lib/util/makeSerializable')
3
+
4
+ class RecordRuntimeInfoDependency extends NullDependency {
5
+ constructor (packageName, resourcePath, { type, info, index } = {}) {
6
+ super()
7
+ this.packageName = packageName
8
+ this.resourcePath = resourcePath
9
+ this.blockType = type
10
+ this.info = info
11
+ this.index = index
12
+ }
13
+
14
+ get type () {
15
+ return 'mpx record runtime component info'
16
+ }
17
+
18
+ mpxAction (module, compilation, callback) {
19
+ const mpx = compilation.__mpx__
20
+
21
+ const runtimeInfoPackage = mpx.runtimeInfo[this.packageName] = mpx.runtimeInfo[this.packageName] || {}
22
+ const componentInfo = runtimeInfoPackage[this.resourcePath] = runtimeInfoPackage[this.resourcePath] || {
23
+ template: {},
24
+ json: {},
25
+ style: [],
26
+ moduleId: '_' + mpx.pathHash(this.resourcePath)
27
+ }
28
+
29
+ const infoConfig = componentInfo[this.blockType]
30
+ if (this.blockType === 'style') { // 多 style block 的场景
31
+ infoConfig[this.index] = this.info
32
+ } else {
33
+ Object.assign(infoConfig, this.info)
34
+ }
35
+
36
+ return callback()
37
+ }
38
+
39
+ serialize (context) {
40
+ const { write } = context
41
+ write(this.packageName)
42
+ write(this.resourcePath)
43
+ write(this.blockType)
44
+ write(this.info)
45
+ write(this.index)
46
+ super.serialize(context)
47
+ }
48
+
49
+ deserialize (context) {
50
+ const { read } = context
51
+ this.packageName = read()
52
+ this.resourcePath = read()
53
+ this.blockType = read()
54
+ this.info = read()
55
+ this.index = read()
56
+ super.deserialize(context)
57
+ }
58
+ }
59
+
60
+ RecordRuntimeInfoDependency.Template = class RecordRuntimeInfoDependencyTemplate {
61
+ apply () {}
62
+ }
63
+
64
+ makeSerializable(RecordRuntimeInfoDependency, '@mpxjs/webpack-plugin/lib/dependencies/RecordRuntimeInfoDependency')
65
+
66
+ module.exports = RecordRuntimeInfoDependency
package/lib/index.js CHANGED
@@ -40,6 +40,7 @@ const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
40
40
  const FlagPluginDependency = require('./dependencies/FlagPluginDependency')
41
41
  const RemoveEntryDependency = require('./dependencies/RemoveEntryDependency')
42
42
  const RecordVueContentDependency = require('./dependencies/RecordVueContentDependency')
43
+ const RecordRuntimeInfoDependency = require('./dependencies/RecordRuntimeInfoDependency')
43
44
  const SplitChunksPlugin = require('webpack/lib/optimize/SplitChunksPlugin')
44
45
  const fixRelative = require('./utils/fix-relative')
45
46
  const parseRequest = require('./utils/parse-request')
@@ -63,6 +64,7 @@ const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource'
63
64
  const emitFile = require('./utils/emit-file')
64
65
  const { MPX_PROCESSED_FLAG, MPX_DISABLE_EXTRACTOR_CACHE } = require('./utils/const')
65
66
  const isEmptyObject = require('./utils/is-empty-object')
67
+ const DynamicPlugin = require('./resolver/DynamicPlugin')
66
68
  require('./utils/check-core-version-match')
67
69
 
68
70
  const isProductionLikeMode = options => {
@@ -123,6 +125,9 @@ class MpxWebpackPlugin {
123
125
  if (options.mode === 'web' && options.srcMode !== 'wx') {
124
126
  errors.push('MpxWebpackPlugin supports mode to be "web" only when srcMode is set to "wx"!')
125
127
  }
128
+ if (options.dynamicComponentRules && !options.dynamicRuntime) {
129
+ errors.push('Please make sure you have set dynamicRuntime true in mpx webpack plugin config because you have use the dynamic runtime feature.')
130
+ }
126
131
  options.externalClasses = options.externalClasses || ['custom-class', 'i-class']
127
132
  options.resolveMode = options.resolveMode || 'webpack'
128
133
  options.writeMode = options.writeMode || 'changed'
@@ -136,7 +141,8 @@ class MpxWebpackPlugin {
136
141
  options.defs = Object.assign({}, options.defs, {
137
142
  __mpx_mode__: options.mode,
138
143
  __mpx_src_mode__: options.srcMode,
139
- __mpx_env__: options.env
144
+ __mpx_env__: options.env,
145
+ __mpx_dynamic_runtime__: options.dynamicRuntime
140
146
  })
141
147
  // 批量指定源码mode
142
148
  options.modeRules = options.modeRules || {}
@@ -174,6 +180,7 @@ class MpxWebpackPlugin {
174
180
  options.optimizeRenderRules = options.optimizeRenderRules ? (Array.isArray(options.optimizeRenderRules) ? options.optimizeRenderRules : [options.optimizeRenderRules]) : []
175
181
  options.retryRequireAsync = options.retryRequireAsync || false
176
182
  options.optimizeSize = options.optimizeSize || false
183
+ options.dynamicComponentRules = options.dynamicComponentRules || {}// 运行时组件配置
177
184
  this.options = options
178
185
  // Hack for buildDependencies
179
186
  const rawResolveBuildDependencies = FileSystemInfo.prototype.resolveBuildDependencies
@@ -320,6 +327,9 @@ class MpxWebpackPlugin {
320
327
  const addModePlugin = new AddModePlugin('before-file', this.options.mode, this.options.fileConditionRules, 'file')
321
328
  const addEnvPlugin = new AddEnvPlugin('before-file', this.options.env, this.options.fileConditionRules, 'file')
322
329
  const packageEntryPlugin = new PackageEntryPlugin('before-file', this.options.miniNpmPackages, 'file')
330
+
331
+ const dynamicPlugin = new DynamicPlugin('result', this.options.dynamicComponentRules)
332
+
323
333
  if (Array.isArray(compiler.options.resolve.plugins)) {
324
334
  compiler.options.resolve.plugins.push(addModePlugin)
325
335
  } else {
@@ -330,6 +340,7 @@ class MpxWebpackPlugin {
330
340
  }
331
341
  compiler.options.resolve.plugins.push(packageEntryPlugin)
332
342
  compiler.options.resolve.plugins.push(new FixDescriptionInfoPlugin())
343
+ compiler.options.resolve.plugins.push(dynamicPlugin)
333
344
 
334
345
  const optimization = compiler.options.optimization
335
346
  if (this.options.mode !== 'web') {
@@ -472,12 +483,12 @@ class MpxWebpackPlugin {
472
483
  }
473
484
  }
474
485
 
475
- const processSubpackagesEntriesMap = (compilation, callback) => {
486
+ const processSubpackagesEntriesMap = (subPackageEntriesType, compilation, callback) => {
476
487
  const mpx = compilation.__mpx__
477
- if (mpx && !isEmptyObject(mpx.subpackagesEntriesMap)) {
478
- const subpackagesEntriesMap = mpx.subpackagesEntriesMap
479
- // 执行分包队列前清空mpx.subpackagesEntriesMap
480
- mpx.subpackagesEntriesMap = {}
488
+ if (mpx && !isEmptyObject(mpx[subPackageEntriesType])) {
489
+ const subpackagesEntriesMap = mpx[subPackageEntriesType]
490
+ // 执行分包队列前清空 mpx[subPackageEntriesType]
491
+ mpx[subPackageEntriesType] = {}
481
492
  async.eachOfSeries(subpackagesEntriesMap, (deps, packageRoot, callback) => {
482
493
  mpx.currentPackageRoot = packageRoot
483
494
  mpx.componentsMap[packageRoot] = mpx.componentsMap[packageRoot] || {}
@@ -493,7 +504,7 @@ class MpxWebpackPlugin {
493
504
  }, (err) => {
494
505
  if (err) return callback(err)
495
506
  // 如果执行完当前队列后产生了新的分包执行队列(一般由异步分包组件造成),则继续执行
496
- processSubpackagesEntriesMap(compilation, callback)
507
+ processSubpackagesEntriesMap(subPackageEntriesType, compilation, callback)
497
508
  })
498
509
  } else {
499
510
  callback()
@@ -505,7 +516,14 @@ class MpxWebpackPlugin {
505
516
  name: 'MpxWebpackPlugin',
506
517
  stage: -1000
507
518
  }, (compilation, callback) => {
508
- processSubpackagesEntriesMap(compilation, (err) => {
519
+ async.series([
520
+ (callback) => {
521
+ processSubpackagesEntriesMap('subpackagesEntriesMap', compilation, callback)
522
+ },
523
+ (callback) => {
524
+ processSubpackagesEntriesMap('postSubpackageEntriesMap', compilation, callback)
525
+ }
526
+ ], (err) => {
509
527
  if (err) return callback(err)
510
528
  const checkDynamicEntryInfo = () => {
511
529
  for (const packageName in mpx.dynamicEntryInfo) {
@@ -578,6 +596,9 @@ class MpxWebpackPlugin {
578
596
  compilation.dependencyFactories.set(RecordVueContentDependency, new NullFactory())
579
597
  compilation.dependencyTemplates.set(RecordVueContentDependency, new RecordVueContentDependency.Template())
580
598
 
599
+ compilation.dependencyFactories.set(RecordRuntimeInfoDependency, new NullFactory())
600
+ compilation.dependencyTemplates.set(RecordRuntimeInfoDependency, new RecordRuntimeInfoDependency.Template())
601
+
581
602
  compilation.dependencyTemplates.set(ImportDependency, new ImportDependencyTemplate())
582
603
  })
583
604
 
@@ -610,6 +631,7 @@ class MpxWebpackPlugin {
610
631
  // 记录独立分包
611
632
  independentSubpackagesMap: {},
612
633
  subpackagesEntriesMap: {},
634
+ postSubpackageEntriesMap: {},
613
635
  replacePathMap: {},
614
636
  exportModules: new Set(),
615
637
  // 记录动态添加入口的分包信息
@@ -837,6 +859,126 @@ class MpxWebpackPlugin {
837
859
  error
838
860
  })
839
861
  }
862
+ },
863
+ // 以包为维度记录不同 package 需要的组件属性等信息,用以最终 mpx-custom-element 相关文件的输出
864
+ runtimeInfo: {},
865
+ // 记录运行时组件依赖的运行时组件当中使用的基础组件 slot,最终依据依赖关系注入到运行时组件的 json 配置当中
866
+ dynamicSlotDependencies: {},
867
+ // 依据 package 注入到 mpx-custom-element-*.json 里面的组件路径
868
+ getPackageInjectedComponentsMap: (packageName = 'main') => {
869
+ const res = {}
870
+ const runtimeInfo = mpx.runtimeInfo[packageName] || {}
871
+ const componentsMap = mpx.componentsMap[packageName] || {}
872
+ const publicPath = compilation.outputOptions.publicPath || ''
873
+ for (const componentPath in runtimeInfo) {
874
+ Object.values(runtimeInfo[componentPath].json).forEach(({ hashName, resourcePath }) => {
875
+ const outputPath = componentsMap[resourcePath]
876
+ if (outputPath) {
877
+ res[hashName] = publicPath + outputPath
878
+ }
879
+ })
880
+ }
881
+ return res
882
+ },
883
+ // 获取生成基础递归渲染模版的节点配置信息
884
+ getPackageInjectedTemplateConfig: (packageName = 'main') => {
885
+ const res = {
886
+ baseComponents: {
887
+ block: {}
888
+ },
889
+ runtimeComponents: {},
890
+ normalComponents: {}
891
+ }
892
+
893
+ const runtimeInfo = mpx.runtimeInfo[packageName] || {}
894
+
895
+ // 包含了某个分包当中所有的运行时组件
896
+ for (const resourcePath in runtimeInfo) {
897
+ const { json, template } = runtimeInfo[resourcePath]
898
+ const customComponents = template.customComponents || {}
899
+ const baseComponents = template.baseComponents || {}
900
+
901
+ // 合并自定义组件的属性
902
+ for (const componentName in customComponents) {
903
+ const extraAttrs = {}
904
+ const attrsMap = customComponents[componentName]
905
+ const { hashName, isDynamic } = json[componentName] || {}
906
+ let componentType = 'normalComponents'
907
+ if (isDynamic) {
908
+ componentType = 'runtimeComponents'
909
+ extraAttrs.slots = ''
910
+ }
911
+ if (!res[componentType][hashName]) {
912
+ res[componentType][hashName] = {}
913
+ }
914
+
915
+ Object.assign(res[componentType][hashName], {
916
+ ...attrsMap,
917
+ ...extraAttrs
918
+ })
919
+ }
920
+
921
+ // 合并基础节点的属性
922
+ for (const componentName in baseComponents) {
923
+ const attrsMap = baseComponents[componentName]
924
+ if (!res.baseComponents[componentName]) {
925
+ res.baseComponents[componentName] = {}
926
+ }
927
+ Object.assign(res.baseComponents[componentName], attrsMap)
928
+ }
929
+ }
930
+
931
+ return res
932
+ },
933
+ injectDynamicSlotDependencies: (usingComponents, resourcePath) => {
934
+ const dynamicSlotReg = /"mpx_dynamic_slot":\s*""*/
935
+ const content = mpx.dynamicSlotDependencies[resourcePath] ? JSON.stringify(mpx.dynamicSlotDependencies[resourcePath]).slice(1, -1) : ''
936
+ const result = usingComponents.replace(dynamicSlotReg, content).replace(/,\s*(\}|\])/g, '$1')
937
+ return result
938
+ },
939
+ changeHashNameForAstNode: (templateAst, componentsMap) => {
940
+ const nameReg = /"tag":\s*"([^"]*)",?/g
941
+
942
+ // 替换 astNode hashName
943
+ const result = templateAst.replace(nameReg, function (match, tag) {
944
+ if (componentsMap[tag]) {
945
+ const { hashName, isDynamic } = componentsMap[tag]
946
+ let content = `"tag": "${hashName}",`
947
+ if (isDynamic) {
948
+ content += '"dynamic": true,'
949
+ }
950
+ return content
951
+ }
952
+ return match
953
+ }).replace(/,\s*(\}|\])/g, '$1')
954
+
955
+ return result
956
+ },
957
+ collectDynamicSlotDependencies: (packageName = 'main') => {
958
+ const componentsMap = mpx.componentsMap[packageName] || {}
959
+ const publicPath = compilation.outputOptions.publicPath || ''
960
+ const runtimeInfo = mpx.runtimeInfo[packageName]
961
+
962
+ for (const resourcePath in runtimeInfo) {
963
+ const { template, json } = runtimeInfo[resourcePath]
964
+ const dynamicSlotDependencies = template.dynamicSlotDependencies || []
965
+
966
+ dynamicSlotDependencies.forEach((slotDependencies) => {
967
+ let lastNeedInjectNode = slotDependencies[0]
968
+ for (let i = 1; i <= slotDependencies.length - 1; i++) {
969
+ const componentName = slotDependencies[i]
970
+ const { resourcePath, isDynamic } = json[componentName] || {}
971
+ if (isDynamic) {
972
+ const { resourcePath: path, hashName } = json[lastNeedInjectNode]
973
+ mpx.dynamicSlotDependencies[resourcePath] = mpx.dynamicSlotDependencies[resourcePath] || {}
974
+ Object.assign(mpx.dynamicSlotDependencies[resourcePath], {
975
+ [hashName]: publicPath + componentsMap[path]
976
+ })
977
+ lastNeedInjectNode = slotDependencies[i]
978
+ }
979
+ }
980
+ })
981
+ }
840
982
  }
841
983
  }
842
984
  }
@@ -1094,6 +1236,37 @@ class MpxWebpackPlugin {
1094
1236
  }
1095
1237
  })
1096
1238
 
1239
+ compilation.hooks.processAssets.tap({
1240
+ name: 'MpxWebpackPlugin'
1241
+ }, (assets) => {
1242
+ const dynamicAssets = {}
1243
+ for (const packageName in mpx.runtimeInfo) {
1244
+ for (const resourcePath in mpx.runtimeInfo[packageName]) {
1245
+ const { moduleId, template, style, json } = mpx.runtimeInfo[packageName][resourcePath]
1246
+ const templateAst = mpx.changeHashNameForAstNode(template.templateAst, json)
1247
+ dynamicAssets[moduleId] = {
1248
+ template: JSON.parse(templateAst),
1249
+ styles: style.reduce((preV, curV) => {
1250
+ preV.push(...curV)
1251
+ return preV
1252
+ }, [])
1253
+ }
1254
+
1255
+ // 注入 dynamic slot dependency
1256
+ const outputPath = mpx.componentsMap[packageName][resourcePath]
1257
+ if (outputPath) {
1258
+ const jsonAsset = outputPath + '.json'
1259
+ const jsonContent = compilation.assets[jsonAsset].source()
1260
+ compilation.assets[jsonAsset] = new RawSource(mpx.injectDynamicSlotDependencies(jsonContent, resourcePath))
1261
+ }
1262
+ }
1263
+ }
1264
+ if (!isEmptyObject(dynamicAssets)) {
1265
+ // 产出 jsonAst 静态产物
1266
+ compilation.assets['dynamic.json'] = new RawSource(JSON.stringify(dynamicAssets))
1267
+ }
1268
+ })
1269
+
1097
1270
  const normalModuleFactoryParserCallback = (parser) => {
1098
1271
  parser.hooks.call.for('__mpx_resolve_path__').tap('MpxWebpackPlugin', (expr) => {
1099
1272
  if (expr.arguments[0]) {
@@ -99,7 +99,9 @@ module.exports = function createJSONHelper ({ loaderContext, emitWarning, custom
99
99
  const entry = getDynamicEntry(resource, 'component', outputPath, tarRoot, relativePath, '', extraOptions)
100
100
  callback(null, entry, {
101
101
  tarRoot,
102
- placeholder
102
+ placeholder,
103
+ resourcePath,
104
+ queryObj
103
105
  })
104
106
  })
105
107
  }
@@ -12,12 +12,14 @@ const createHelpers = require('../helpers')
12
12
  const createJSONHelper = require('./helper')
13
13
  const RecordGlobalComponentsDependency = require('../dependencies/RecordGlobalComponentsDependency')
14
14
  const RecordIndependentDependency = require('../dependencies/RecordIndependentDependency')
15
+ const RecordRuntimeInfoDependency = require('../dependencies/RecordRuntimeInfoDependency')
15
16
  const { MPX_DISABLE_EXTRACTOR_CACHE, RESOLVE_IGNORED_ERR, JSON_JS_EXT } = require('../utils/const')
16
17
  const resolve = require('../utils/resolve')
17
18
  const resolveTabBarPath = require('../utils/resolve-tab-bar-path')
18
19
  const normalize = require('../utils/normalize')
19
20
  const mpxViewPath = normalize.lib('runtime/components/ali/mpx-view.mpx')
20
21
  const mpxTextPath = normalize.lib('runtime/components/ali/mpx-text.mpx')
22
+ const resolveMpxCustomElementPath = require('../utils/resolve-mpx-custom-element-path')
21
23
 
22
24
  module.exports = function (content) {
23
25
  const nativeCallback = this.async()
@@ -47,6 +49,7 @@ module.exports = function (content) {
47
49
  const isApp = !(pagesMap[resourcePath] || componentsMap[resourcePath])
48
50
  const publicPath = this._compilation.outputOptions.publicPath || ''
49
51
  const fs = this._compiler.inputFileSystem
52
+ const runtimeCompile = queryObj.isDynamic
50
53
 
51
54
  const emitWarning = (msg) => {
52
55
  this.emitWarning(
@@ -173,6 +176,17 @@ module.exports = function (content) {
173
176
  }
174
177
  }
175
178
 
179
+ const dependencyComponentsMap = {}
180
+
181
+ if (queryObj.mpxCustomElement) {
182
+ this.cacheable(false)
183
+ mpx.collectDynamicSlotDependencies(packageName)
184
+ }
185
+
186
+ if (runtimeCompile) {
187
+ json.usingComponents = json.usingComponents || {}
188
+ }
189
+
176
190
  // 快应用补全json配置,必填项
177
191
  if (mode === 'qa' && isApp) {
178
192
  const defaultConf = {
@@ -219,13 +233,24 @@ module.exports = function (content) {
219
233
  const processComponents = (components, context, callback) => {
220
234
  if (components) {
221
235
  async.eachOf(components, (component, name, callback) => {
222
- processComponent(component, context, { relativePath }, (err, entry, { tarRoot, placeholder } = {}) => {
236
+ processComponent(component, context, { relativePath }, (err, entry, { tarRoot, placeholder, resourcePath, queryObj = {} } = {}) => {
223
237
  if (err === RESOLVE_IGNORED_ERR) {
224
238
  delete components[name]
225
239
  return callback()
226
240
  }
227
241
  if (err) return callback(err)
228
242
  components[name] = entry
243
+ if (runtimeCompile) {
244
+ // 替换组件的 hashName,并删除原有的组件配置
245
+ const hashName = 'm' + mpx.pathHash(resourcePath)
246
+ components[hashName] = entry
247
+ delete components[name]
248
+ dependencyComponentsMap[name] = {
249
+ hashName,
250
+ resourcePath,
251
+ isDynamic: queryObj.isDynamic
252
+ }
253
+ }
229
254
  if (tarRoot) {
230
255
  if (placeholder) {
231
256
  placeholder = normalizePlaceholder(placeholder)
@@ -250,7 +275,20 @@ module.exports = function (content) {
250
275
  callback()
251
276
  }
252
277
  })
253
- }, callback)
278
+ }, () => {
279
+ const mpxCustomElementPath = resolveMpxCustomElementPath(packageName)
280
+ if (runtimeCompile) {
281
+ components.element = mpxCustomElementPath
282
+ components.mpx_dynamic_slot = '' // 运行时组件打标记,在 processAssets 统一替换
283
+
284
+ this._module.addPresentationalDependency(new RecordRuntimeInfoDependency(packageName, resourcePath, { type: 'json', info: dependencyComponentsMap }))
285
+ }
286
+ if (queryObj.mpxCustomElement) {
287
+ components.element = mpxCustomElementPath
288
+ Object.assign(components, mpx.getPackageInjectedComponentsMap(packageName))
289
+ }
290
+ callback()
291
+ })
254
292
  } else {
255
293
  callback()
256
294
  }
package/lib/loader.js CHANGED
@@ -16,11 +16,13 @@ const AppEntryDependency = require('./dependencies/AppEntryDependency')
16
16
  const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
17
17
  const RecordVueContentDependency = require('./dependencies/RecordVueContentDependency')
18
18
  const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
19
+ const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
19
20
  const tsWatchRunLoaderFilter = require('./utils/ts-loader-watch-run-loader-filter')
20
21
  const { MPX_APP_MODULE_ID } = require('./utils/const')
21
22
  const path = require('path')
22
23
  const processMainScript = require('./web/processMainScript')
23
24
  const getRulesRunner = require('./platform')
25
+ const genMpxCustomElement = require('./runtime-render/gen-mpx-custom-element')
24
26
 
25
27
  module.exports = function (content) {
26
28
  this.cacheable()
@@ -50,6 +52,7 @@ module.exports = function (content) {
50
52
  const localSrcMode = queryObj.mode
51
53
  const srcMode = localSrcMode || globalSrcMode
52
54
  const autoScope = matchCondition(resourcePath, mpx.autoScopeRules)
55
+ const isRuntimeMode = queryObj.isDynamic
53
56
 
54
57
  const emitWarning = (msg) => {
55
58
  this.emitWarning(
@@ -80,6 +83,12 @@ module.exports = function (content) {
80
83
  const appName = getEntryName(this)
81
84
  if (appName) this._module.addPresentationalDependency(new AppEntryDependency(resourcePath, appName))
82
85
  }
86
+
87
+ if (isRuntimeMode) {
88
+ const { request, outputPath } = genMpxCustomElement(packageName)
89
+ this._module.addPresentationalDependency(new DynamicEntryDependency([0, 0], request, 'component', outputPath, packageRoot, '', '', { replaceContent: '', postSubpackageEntry: true }))
90
+ }
91
+
83
92
  const loaderContext = this
84
93
  const isProduction = this.minimize || process.env.NODE_ENV === 'production'
85
94
  const filePath = this.resourcePath
@@ -298,6 +307,7 @@ module.exports = function (content) {
298
307
  hasScoped,
299
308
  hasComment,
300
309
  isNative,
310
+ ctorType,
301
311
  moduleId,
302
312
  usingComponents,
303
313
  componentPlaceholder
@@ -220,6 +220,7 @@ module.exports = function (content) {
220
220
  hasScoped,
221
221
  hasComment,
222
222
  isNative,
223
+ ctorType,
223
224
  moduleId,
224
225
  usingComponents,
225
226
  componentPlaceholder
@@ -16,7 +16,12 @@ module.exports = function getSpec ({ warn, error }) {
16
16
  {
17
17
  web ({ name, value }) {
18
18
  const parsed = parseMustacheWithContext(value)
19
- if (parsed.hasBinding) {
19
+ if (name.startsWith('data-')) {
20
+ return {
21
+ name: ':' + name,
22
+ value: `JSON.stringify(${parsed.result})`
23
+ }
24
+ } else if (parsed.hasBinding) {
20
25
  return {
21
26
  name: name === 'animation' ? 'v-animation' : ':' + name,
22
27
  value: parsed.result
@@ -0,0 +1,18 @@
1
+ const addQuery = require('../utils/add-query')
2
+ const { matchCondition } = require('../utils/match-condition')
3
+
4
+ module.exports = class DynamicPlugin {
5
+ constructor (source, dynamicComponentRules) {
6
+ this.source = source
7
+ this.dynamicComponentRules = dynamicComponentRules
8
+ }
9
+
10
+ apply (resolver) {
11
+ resolver.getHook(this.source).tap('DynamicPlugin', request => {
12
+ const isDynamic = matchCondition(request.path, this.dynamicComponentRules)
13
+ if (isDynamic) {
14
+ request.query = addQuery(request.query, { isDynamic: true })
15
+ }
16
+ })
17
+ }
18
+ }
@@ -0,0 +1,75 @@
1
+ const { getOptimizedComponentInfo } = require('@mpxjs/template-engine/dist/optimizer')
2
+ const mpxConfig = require('../config')
3
+
4
+ function makeAttrsMap (attrKeys = []) {
5
+ return attrKeys.reduce((preVal, curVal) => Object.assign(preVal, { [curVal]: '' }), {})
6
+ }
7
+
8
+ // 部分节点类型不需要被收集
9
+ const RUNTIME_FILTER_NODES = ['import', 'template', 'wxs', 'component', 'slot']
10
+
11
+ function collectParentCustomComponent (el, isComponentNode, options) {
12
+ const res = []
13
+ let parent = el.parent
14
+ while (parent) {
15
+ if (isComponentNode(parent, options)) {
16
+ if (!res.length) res.push(el.tag)
17
+ res.push(parent.tag)
18
+ }
19
+ parent = parent.parent
20
+ }
21
+ return res
22
+ }
23
+
24
+ module.exports = function setBaseWxml (el, config, meta) {
25
+ const { mode, isComponentNode, options } = config
26
+ if (RUNTIME_FILTER_NODES.includes(el.tag)) {
27
+ return
28
+ }
29
+
30
+ if (options.runtimeCompile) {
31
+ const isCustomComponent = isComponentNode(el, options)
32
+
33
+ if (!meta.runtimeInfo) {
34
+ meta.runtimeInfo = {
35
+ baseComponents: {},
36
+ customComponents: {},
37
+ dynamicSlotDependencies: []
38
+ }
39
+ }
40
+
41
+ const tag = el.tag
42
+ // 属性收集
43
+ const modeConfig = mpxConfig[mode]
44
+ const directives = new Set([...Object.values(modeConfig.directive), 'slot'])
45
+ const attrKeys = Object.keys(el.attrsMap).filter(key => !directives.has(key))
46
+ const componentType = isCustomComponent ? 'customComponents' : 'baseComponents'
47
+
48
+ if (!isCustomComponent) {
49
+ const optimizedInfo = getOptimizedComponentInfo(
50
+ {
51
+ nodeType: el.tag,
52
+ attrs: el.attrsMap
53
+ },
54
+ mode
55
+ )
56
+ if (optimizedInfo) {
57
+ el.tag = optimizedInfo.nodeType
58
+ }
59
+ } else {
60
+ // 收集运行时组件模版当中运行时组件使用 slot 的场景,主要因为运行时组件渲染slot时组件上下文发生了变化
61
+ const slotDependencies = collectParentCustomComponent(el, isComponentNode, options)
62
+ if (slotDependencies.length) {
63
+ const dynamicSlotDependencies = meta.runtimeInfo.dynamicSlotDependencies
64
+ dynamicSlotDependencies.push(slotDependencies)
65
+ }
66
+ }
67
+
68
+ const componentsConfig = meta.runtimeInfo[componentType]
69
+
70
+ if (!componentsConfig[tag]) {
71
+ componentsConfig[tag] = {}
72
+ }
73
+ Object.assign(componentsConfig[tag], makeAttrsMap(attrKeys))
74
+ }
75
+ }
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ component: true,
3
+ usingComponents: {}
4
+ }