@mpxjs/webpack-plugin 2.9.38 → 2.9.40
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.
- package/lib/dependencies/DynamicEntryDependency.js +9 -1
- package/lib/dependencies/RecordRuntimeInfoDependency.js +66 -0
- package/lib/index.js +181 -8
- package/lib/json-compiler/helper.js +3 -1
- package/lib/json-compiler/index.js +40 -2
- package/lib/loader.js +10 -0
- package/lib/native-loader.js +1 -0
- package/lib/resolver/DynamicPlugin.js +18 -0
- package/lib/runtime-render/base-wxml.js +75 -0
- package/lib/runtime-render/custom-element-json.js +4 -0
- package/lib/runtime-render/custom-element-script.js +32 -0
- package/lib/runtime-render/gen-dynamic-template.js +6 -0
- package/lib/runtime-render/gen-mpx-custom-element.js +13 -0
- package/lib/runtime-render/mpx-custom-element-main.mpx +18 -0
- package/lib/runtime-render/mpx-custom-element.mpx +18 -0
- package/lib/style-compiler/index.js +18 -1
- package/lib/style-compiler/plugins/css-array-list.js +26 -0
- package/lib/template-compiler/compiler.js +516 -324
- package/lib/template-compiler/dynamic.js +13 -0
- package/lib/template-compiler/index.js +36 -7
- package/lib/template-compiler/parse-exps.js +148 -0
- package/lib/utils/resolve-mpx-custom-element-path.js +7 -0
- package/lib/utils/shallow-stringify.js +17 -0
- package/lib/web/processTemplate.js +1 -2
- package/lib/wxml/loader.js +9 -2
- package/package.json +4 -2
|
@@ -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
|
|
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
|
|
478
|
-
const subpackagesEntriesMap = mpx
|
|
479
|
-
// 执行分包队列前清空mpx
|
|
480
|
-
mpx
|
|
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
|
-
|
|
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
|
-
},
|
|
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
|
package/lib/native-loader.js
CHANGED
|
@@ -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,32 @@
|
|
|
1
|
+
import { createComponent } from '@mpxjs/core'
|
|
2
|
+
|
|
3
|
+
createComponent({
|
|
4
|
+
options: {
|
|
5
|
+
addGlobalClass: true,
|
|
6
|
+
styleIsolation: 'shared',
|
|
7
|
+
// 超过基础模板的层数,virtualHost 置为 true,避免样式规则失效
|
|
8
|
+
virtualHost: true
|
|
9
|
+
},
|
|
10
|
+
properties: {
|
|
11
|
+
r: { // vdom 数据
|
|
12
|
+
type: Object,
|
|
13
|
+
value: {
|
|
14
|
+
nt: 'block'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
data: {
|
|
19
|
+
// 运行时组件的标识
|
|
20
|
+
mpxCustomElement: true
|
|
21
|
+
},
|
|
22
|
+
computed: {
|
|
23
|
+
vnodeData () {
|
|
24
|
+
const data = this.r.d || {}
|
|
25
|
+
return data
|
|
26
|
+
},
|
|
27
|
+
// 真实的组件上下文 uid
|
|
28
|
+
uid () {
|
|
29
|
+
return this.vnodeData.uid
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
const { createSetupTemplate } = require('@mpxjs/template-engine')
|
|
2
|
+
|
|
3
|
+
module.exports = function (packageName) {
|
|
4
|
+
const basePath = packageName === 'main' ? '' : `/${packageName}`
|
|
5
|
+
return `<import src="${basePath}/mpx-custom-element-${packageName}"/>${createSetupTemplate()}`
|
|
6
|
+
}
|