@mpxjs/webpack-plugin 2.6.114-alpha.8 → 2.6.115

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 (129) hide show
  1. package/README.md +1 -1
  2. package/lib/built-in-loader.js +49 -0
  3. package/lib/config.js +0 -14
  4. package/lib/content-loader.js +13 -0
  5. package/lib/dependency/ChildCompileDependency.js +24 -0
  6. package/lib/dependency/InjectDependency.js +26 -0
  7. package/lib/dependency/RemovedModuleDependency.js +23 -0
  8. package/lib/{dependencies → dependency}/ReplaceDependency.js +2 -19
  9. package/lib/dependency/ResolveDependency.js +49 -0
  10. package/lib/extractor.js +178 -82
  11. package/lib/file-loader.js +19 -7
  12. package/lib/helpers.js +334 -39
  13. package/lib/index.js +525 -889
  14. package/lib/json-compiler/index.js +451 -245
  15. package/lib/json-compiler/{theme.js → theme-loader.js} +3 -5
  16. package/lib/loader.js +241 -178
  17. package/lib/native-loader.js +133 -71
  18. package/lib/parser.js +2 -1
  19. package/lib/path-loader.js +3 -0
  20. package/lib/platform/json/wx/index.js +1 -1
  21. package/lib/platform/template/normalize-component-rules.js +3 -2
  22. package/lib/platform/template/wx/component-config/button.js +2 -14
  23. package/lib/platform/template/wx/component-config/image.js +0 -4
  24. package/lib/platform/template/wx/component-config/input.js +0 -4
  25. package/lib/platform/template/wx/component-config/rich-text.js +0 -4
  26. package/lib/platform/template/wx/component-config/scroll-view.js +0 -4
  27. package/lib/platform/template/wx/component-config/switch.js +0 -4
  28. package/lib/platform/template/wx/component-config/text.js +0 -4
  29. package/lib/platform/template/wx/component-config/textarea.js +0 -5
  30. package/lib/platform/template/wx/component-config/view.js +0 -4
  31. package/lib/platform/template/wx/index.js +3 -149
  32. package/lib/plugin-loader.js +287 -0
  33. package/lib/resolver/AddEnvPlugin.js +3 -4
  34. package/lib/resolver/AddModePlugin.js +3 -4
  35. package/lib/resolver/PackageEntryPlugin.js +36 -23
  36. package/lib/runtime/base.styl +0 -5
  37. package/lib/runtime/components/web/getInnerListeners.js +3 -1
  38. package/lib/runtime/components/web/mpx-image.vue +5 -20
  39. package/lib/runtime/components/web/mpx-movable-view.vue +2 -6
  40. package/lib/runtime/components/web/mpx-swiper.vue +3 -18
  41. package/lib/runtime/i18n.wxs +11 -31
  42. package/lib/runtime/optionProcessor.js +3 -48
  43. package/lib/selector.js +10 -29
  44. package/lib/staticConfig.js +4 -0
  45. package/lib/style-compiler/index.js +24 -16
  46. package/lib/style-compiler/load-postcss-config.js +1 -3
  47. package/lib/style-compiler/plugins/conditional-strip.js +65 -68
  48. package/lib/style-compiler/plugins/rpx.js +37 -43
  49. package/lib/style-compiler/plugins/scope-id.js +72 -79
  50. package/lib/style-compiler/plugins/trans-special.js +18 -25
  51. package/lib/style-compiler/plugins/trim.js +7 -13
  52. package/lib/style-compiler/plugins/vw.js +16 -22
  53. package/lib/template-compiler/compiler.js +199 -106
  54. package/lib/template-compiler/index.js +139 -52
  55. package/lib/template-compiler/trans-dynamic-class-expr.js +13 -18
  56. package/lib/url-loader.js +29 -11
  57. package/lib/utils/add-query.js +1 -1
  58. package/lib/utils/get-main-compilation.js +6 -0
  59. package/lib/utils/is-url-request.js +1 -10
  60. package/lib/utils/match-condition.js +1 -4
  61. package/lib/utils/normalize.js +15 -4
  62. package/lib/utils/parse-request.js +3 -3
  63. package/lib/utils/read-json-for-src.js +34 -0
  64. package/lib/utils/stringify-query.js +0 -4
  65. package/lib/utils/try-require.js +16 -0
  66. package/lib/web/processJSON.js +144 -113
  67. package/lib/web/processScript.js +34 -47
  68. package/lib/web/processTemplate.js +40 -57
  69. package/lib/wxml/{loader.js → wxml-loader.js} +62 -21
  70. package/lib/wxs/WxsParserPlugin.js +2 -2
  71. package/lib/wxs/WxsPlugin.js +8 -4
  72. package/lib/wxs/WxsTemplatePlugin.js +92 -46
  73. package/lib/wxs/{i18n-loader.js → wxs-i18n-loader.js} +4 -5
  74. package/lib/wxs/wxs-loader.js +117 -0
  75. package/lib/wxs/{pre-loader.js → wxs-pre-loader.js} +5 -20
  76. package/lib/wxss/getImportPrefix.js +30 -0
  77. package/lib/wxss/loader.js +43 -31
  78. package/lib/wxss/localsLoader.js +5 -1
  79. package/lib/wxss/processCss.js +103 -107
  80. package/package.json +18 -21
  81. package/LICENSE +0 -433
  82. package/lib/dependencies/AddEntryDependency.js +0 -24
  83. package/lib/dependencies/AppEntryDependency.js +0 -58
  84. package/lib/dependencies/CommonJsAsyncDependency.js +0 -51
  85. package/lib/dependencies/CommonJsVariableDependency.js +0 -81
  86. package/lib/dependencies/DynamicEntryDependency.js +0 -171
  87. package/lib/dependencies/FlagPluginDependency.js +0 -24
  88. package/lib/dependencies/InjectDependency.js +0 -43
  89. package/lib/dependencies/RecordGlobalComponentsDependency.js +0 -50
  90. package/lib/dependencies/RecordIndependentDependency.js +0 -44
  91. package/lib/dependencies/RecordResourceMapDependency.js +0 -62
  92. package/lib/dependencies/RemoveEntryDependency.js +0 -40
  93. package/lib/dependencies/ResolveDependency.js +0 -88
  94. package/lib/independent-loader.js +0 -52
  95. package/lib/json-compiler/helper.js +0 -156
  96. package/lib/json-compiler/plugin.js +0 -150
  97. package/lib/partial-compile/index.js +0 -35
  98. package/lib/record-loader.js +0 -11
  99. package/lib/resolve-loader.js +0 -6
  100. package/lib/resolver/FixDescriptionInfoPlugin.js +0 -28
  101. package/lib/runtime/components/tenon/getInnerListeners.js +0 -317
  102. package/lib/runtime/components/tenon/tenon-button.vue +0 -305
  103. package/lib/runtime/components/tenon/tenon-image.vue +0 -61
  104. package/lib/runtime/components/tenon/tenon-input.vue +0 -99
  105. package/lib/runtime/components/tenon/tenon-rich-text.vue +0 -21
  106. package/lib/runtime/components/tenon/tenon-scroll-view.vue +0 -124
  107. package/lib/runtime/components/tenon/tenon-switch.vue +0 -91
  108. package/lib/runtime/components/tenon/tenon-text-area.vue +0 -64
  109. package/lib/runtime/components/tenon/tenon-text.vue +0 -64
  110. package/lib/runtime/components/tenon/tenon-view.vue +0 -93
  111. package/lib/runtime/components/tenon/util.js +0 -44
  112. package/lib/runtime/optionProcessor.tenon.js +0 -386
  113. package/lib/style-compiler/plugins/hm.js +0 -20
  114. package/lib/tenon/index.js +0 -105
  115. package/lib/tenon/processJSON.js +0 -360
  116. package/lib/tenon/processScript.js +0 -260
  117. package/lib/tenon/processStyles.js +0 -21
  118. package/lib/tenon/processTemplate.js +0 -133
  119. package/lib/utils/const.js +0 -10
  120. package/lib/utils/emit-file.js +0 -10
  121. package/lib/utils/eval-json-js.js +0 -31
  122. package/lib/utils/get-entry-name.js +0 -13
  123. package/lib/utils/get-json-content.js +0 -42
  124. package/lib/utils/get-relative-path.js +0 -24
  125. package/lib/utils/resolve.js +0 -13
  126. package/lib/utils/set.js +0 -47
  127. package/lib/utils/stringify-loaders-resource.js +0 -25
  128. package/lib/wxs/WxsModuleIdsPlugin.js +0 -29
  129. package/lib/wxs/loader.js +0 -142
package/lib/index.js CHANGED
@@ -1,89 +1,68 @@
1
1
  'use strict'
2
2
 
3
3
  const path = require('path')
4
- const { ConcatSource, RawSource } = require('webpack').sources
5
- const ResolveDependency = require('./dependencies/ResolveDependency')
6
- const InjectDependency = require('./dependencies/InjectDependency')
7
- const ReplaceDependency = require('./dependencies/ReplaceDependency')
4
+ const ConcatSource = require('webpack-sources').ConcatSource
5
+ const RawSource = require('webpack-sources').RawSource
6
+ const ResolveDependency = require('./dependency/ResolveDependency')
7
+ const InjectDependency = require('./dependency/InjectDependency')
8
+ const ReplaceDependency = require('./dependency/ReplaceDependency')
9
+ const ChildCompileDependency = require('./dependency/ChildCompileDependency')
8
10
  const NullFactory = require('webpack/lib/NullFactory')
9
- const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
10
- const CommonJsAsyncDependency = require('./dependencies/CommonJsAsyncDependency')
11
- const harmonySpecifierTag = require('webpack/lib/dependencies/HarmonyImportDependencyParserPlugin').harmonySpecifierTag
12
- const NormalModule = require('webpack/lib/NormalModule')
13
- const EntryPlugin = require('webpack/lib/EntryPlugin')
14
- const JavascriptModulesPlugin = require('webpack/lib/javascript/JavascriptModulesPlugin')
15
- const FlagEntryExportAsUsedPlugin = require('webpack/lib/FlagEntryExportAsUsedPlugin')
16
- const FileSystemInfo = require('webpack/lib/FileSystemInfo')
17
11
  const normalize = require('./utils/normalize')
18
12
  const toPosix = require('./utils/to-posix')
19
13
  const addQuery = require('./utils/add-query')
20
- const { every } = require('./utils/set')
21
14
  const DefinePlugin = require('webpack/lib/DefinePlugin')
22
15
  const ExternalsPlugin = require('webpack/lib/ExternalsPlugin')
23
16
  const AddModePlugin = require('./resolver/AddModePlugin')
24
17
  const AddEnvPlugin = require('./resolver/AddEnvPlugin')
25
18
  const PackageEntryPlugin = require('./resolver/PackageEntryPlugin')
26
- const FixDescriptionInfoPlugin = require('./resolver/FixDescriptionInfoPlugin')
27
- // const CommonJsRequireDependency = require('webpack/lib/dependencies/CommonJsRequireDependency')
28
- // const HarmonyImportSideEffectDependency = require('webpack/lib/dependencies/HarmonyImportSideEffectDependency')
29
- // const RequireHeaderDependency = require('webpack/lib/dependencies/RequireHeaderDependency')
30
- // const RemovedModuleDependency = require('./dependencies/RemovedModuleDependency')
31
- const AppEntryDependency = require('./dependencies/AppEntryDependency')
32
- const RecordResourceMapDependency = require('./dependencies/RecordResourceMapDependency')
33
- const RecordGlobalComponentsDependency = require('./dependencies/RecordGlobalComponentsDependency')
34
- const RecordIndependentDependency = require('./dependencies/RecordIndependentDependency')
35
- const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
36
- const FlagPluginDependency = require('./dependencies/FlagPluginDependency')
37
- const RemoveEntryDependency = require('./dependencies/RemoveEntryDependency')
19
+ const CommonJsRequireDependency = require('webpack/lib/dependencies/CommonJsRequireDependency')
20
+ const HarmonyImportSideEffectDependency = require('webpack/lib/dependencies/HarmonyImportSideEffectDependency')
21
+ const RequireHeaderDependency = require('webpack/lib/dependencies/RequireHeaderDependency')
22
+ const RemovedModuleDependency = require('./dependency/RemovedModuleDependency')
38
23
  const SplitChunksPlugin = require('webpack/lib/optimize/SplitChunksPlugin')
39
- const PartialCompilePlugin = require('./partial-compile/index')
40
24
  const fixRelative = require('./utils/fix-relative')
41
25
  const parseRequest = require('./utils/parse-request')
42
- const { matchCondition } = require('./utils/match-condition')
26
+ const matchCondition = require('./utils/match-condition')
43
27
  const { preProcessDefs } = require('./utils/index')
44
- const config = require('./config')
45
28
  const hash = require('hash-sum')
46
- const wxssLoaderPath = normalize.lib('wxss/loader')
47
- const wxmlLoaderPath = normalize.lib('wxml/loader')
48
- const wxsLoaderPath = normalize.lib('wxs/loader')
49
- const styleCompilerPath = normalize.lib('style-compiler/index')
50
- const templateCompilerPath = normalize.lib('template-compiler/index')
51
- const jsonCompilerPath = normalize.lib('json-compiler/index')
52
- const jsonThemeCompilerPath = normalize.lib('json-compiler/theme')
53
- const jsonPluginCompilerPath = normalize.lib('json-compiler/plugin')
54
- const extractorPath = normalize.lib('extractor')
55
- const async = require('async')
56
- const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource')
57
- const emitFile = require('./utils/emit-file')
58
- const { MPX_PROCESSED_FLAG, MPX_DISABLE_EXTRACTOR_CACHE, MPX_CURRENT_CHUNK } = require('./utils/const')
59
- const isEmptyObject = require('./utils/is-empty-object')
60
29
 
61
30
  const isProductionLikeMode = options => {
62
31
  return options.mode === 'production' || !options.mode
63
32
  }
64
33
 
65
- const isStaticModule = module => {
66
- if (!module.resource) return false
67
- const { queryObj } = parseRequest(module.resource)
68
- let isStatic = queryObj.isStatic || false
69
- if (module.loaders) {
70
- for (const loader of module.loaders) {
71
- if (/(url-loader|file-loader)/.test(loader.loader)) {
72
- isStatic = true
73
- break
74
- }
75
- }
76
- }
77
- return isStatic
78
- }
79
-
80
34
  const outputFilename = '[name].js'
81
35
  const publicPath = '/'
82
36
 
83
- const isChunkInPackage = (chunkName, packageName) => {
37
+ function isChunkInPackage (chunkName, packageName) {
84
38
  return (new RegExp(`^${packageName}\\/`)).test(chunkName)
85
39
  }
86
40
 
41
+ function getPackageCacheGroup (packageName) {
42
+ if (packageName === 'main') {
43
+ return {
44
+ name: 'bundle',
45
+ minChunks: 2,
46
+ chunks: 'all'
47
+ }
48
+ } else {
49
+ return {
50
+ test: (module, chunks) => {
51
+ return chunks.every((chunk) => {
52
+ return isChunkInPackage(chunk.name, packageName)
53
+ })
54
+ },
55
+ name: `${packageName}/bundle`,
56
+ minChunks: 2,
57
+ minSize: 1000,
58
+ priority: 100,
59
+ chunks: 'all'
60
+ }
61
+ }
62
+ }
63
+
64
+ let loaderOptions
65
+
87
66
  const externalsMap = {
88
67
  weui: /^weui-miniprogram/
89
68
  }
@@ -92,9 +71,10 @@ const warnings = []
92
71
  const errors = []
93
72
 
94
73
  class EntryNode {
95
- constructor (module, type) {
96
- this.module = module
97
- this.type = type
74
+ constructor (options) {
75
+ this.request = options.request
76
+ this.type = options.type
77
+ this.module = null
98
78
  this.parents = new Set()
99
79
  this.children = new Set()
100
80
  }
@@ -122,6 +102,7 @@ class MpxWebpackPlugin {
122
102
  options.writeMode = options.writeMode || 'changed'
123
103
  options.autoScopeRules = options.autoScopeRules || {}
124
104
  options.autoVirtualHostRules = options.autoVirtualHostRules || {}
105
+ options.forceDisableInject = options.forceDisableInject || false
125
106
  options.forceDisableProxyCtor = options.forceDisableProxyCtor || false
126
107
  options.transMpxRules = options.transMpxRules || {
127
108
  include: () => true
@@ -143,8 +124,12 @@ class MpxWebpackPlugin {
143
124
  options.forceUsePageCtor = options.forceUsePageCtor || false
144
125
  options.postcssInlineConfig = options.postcssInlineConfig || {}
145
126
  options.transRpxRules = options.transRpxRules || null
127
+ options.webConfig = options.webConfig || {}
146
128
  options.auditResource = options.auditResource || false
147
129
  options.decodeHTMLText = options.decodeHTMLText || false
130
+ options.nativeOptions = Object.assign({
131
+ cssLangs: ['css', 'less', 'stylus', 'scss', 'sass']
132
+ }, options.nativeOptions)
148
133
  options.i18n = options.i18n || null
149
134
  options.checkUsingComponents = options.checkUsingComponents || false
150
135
  options.reportSize = options.reportSize || null
@@ -159,103 +144,31 @@ class MpxWebpackPlugin {
159
144
  include: () => true
160
145
  }
161
146
  options.customOutputPath = options.customOutputPath || null
162
- options.nativeConfig = Object.assign({
163
- cssLangs: ['css', 'less', 'stylus', 'scss', 'sass']
164
- }, options.nativeConfig)
165
- options.webConfig = options.webConfig || {}
166
- options.partialCompile = options.mode !== 'web' && options.partialCompile
167
- let proxyComponentEventsRules = []
168
- const proxyComponentEventsRulesRaw = options.proxyComponentEventsRules
169
- if (proxyComponentEventsRulesRaw) {
170
- proxyComponentEventsRules = Array.isArray(proxyComponentEventsRulesRaw) ? proxyComponentEventsRulesRaw : [proxyComponentEventsRulesRaw]
171
- }
172
- options.proxyComponentEventsRules = proxyComponentEventsRules
173
147
  this.options = options
174
- // Hack for buildDependencies
175
- const rawResolveBuildDependencies = FileSystemInfo.prototype.resolveBuildDependencies
176
- FileSystemInfo.prototype.resolveBuildDependencies = function (context, deps, rawCallback) {
177
- return rawResolveBuildDependencies.call(this, context, deps, (err, result) => {
178
- if (result && typeof options.hackResolveBuildDependencies === 'function') options.hackResolveBuildDependencies(result)
179
- return rawCallback(err, result)
180
- })
181
- }
182
148
  }
183
149
 
184
150
  static loader (options = {}) {
185
- if (options.transRpx) {
151
+ loaderOptions = options
152
+ if (loaderOptions.transRpx) {
186
153
  warnings.push('Mpx loader option [transRpx] is deprecated now, please use mpx webpack plugin config [transRpxRules] instead!')
187
154
  }
188
- return {
189
- loader: normalize.lib('loader'),
190
- options
191
- }
192
- }
193
-
194
- static nativeLoader (options = {}) {
195
- return {
196
- loader: normalize.lib('native-loader'),
197
- options
198
- }
199
- }
200
-
201
- static wxssLoader (options) {
202
- return {
203
- loader: normalize.lib('wxss/loader'),
204
- options
205
- }
206
- }
207
-
208
- static wxmlLoader (options) {
209
- return {
210
- loader: normalize.lib('wxml/loader'),
211
- options
212
- }
155
+ return { loader: normalize.lib('loader'), options }
213
156
  }
214
157
 
215
158
  static pluginLoader (options = {}) {
216
- return {
217
- loader: normalize.lib('json-compiler/plugin'),
218
- options
219
- }
159
+ return { loader: normalize.lib('plugin-loader'), options }
220
160
  }
221
161
 
222
162
  static wxsPreLoader (options = {}) {
223
- return {
224
- loader: normalize.lib('wxs/pre-loader'),
225
- options
226
- }
163
+ return { loader: normalize.lib('wxs/wxs-pre-loader'), options }
227
164
  }
228
165
 
229
166
  static urlLoader (options = {}) {
230
- return {
231
- loader: normalize.lib('url-loader'),
232
- options
233
- }
167
+ return { loader: normalize.lib('url-loader'), options }
234
168
  }
235
169
 
236
170
  static fileLoader (options = {}) {
237
- return {
238
- loader: normalize.lib('file-loader'),
239
- options
240
- }
241
- }
242
-
243
- static getPageEntry (request) {
244
- return addQuery(request, { isPage: true })
245
- }
246
-
247
- static getComponentEntry (request) {
248
- return addQuery(request, { isComponent: true })
249
- }
250
-
251
- static getPluginEntry (request) {
252
- return addQuery(request, {
253
- mpx: true,
254
- extract: true,
255
- isPlugin: true,
256
- asScript: true,
257
- type: 'json'
258
- })
171
+ return { loader: normalize.lib('file-loader'), options }
259
172
  }
260
173
 
261
174
  runModeRules (data) {
@@ -281,9 +194,6 @@ class MpxWebpackPlugin {
281
194
  errors.push('Multiple MpxWebpackPlugin instances exist in webpack compiler, please check webpack plugins config!')
282
195
  }
283
196
 
284
- // 将entry export标记为used且不可mangle,避免require.async生成的js chunk在生产环境下报错
285
- new FlagEntryExportAsUsedPlugin(true, 'entry').apply(compiler)
286
-
287
197
  if (this.options.mode !== 'web') {
288
198
  // 强制设置publicPath为'/'
289
199
  if (compiler.options.output.publicPath && compiler.options.output.publicPath !== publicPath) {
@@ -299,11 +209,12 @@ class MpxWebpackPlugin {
299
209
  if (!compiler.options.node || !compiler.options.node.global) {
300
210
  compiler.options.node = compiler.options.node || {}
301
211
  compiler.options.node.global = true
212
+ warnings.push(`webpack options: MpxWebpackPlugin strongly depends options.node.globel to be true, custom options.node will be ignored!`)
302
213
  }
303
214
 
304
215
  const addModePlugin = new AddModePlugin('before-file', this.options.mode, this.options.fileConditionRules, 'file')
305
216
  const addEnvPlugin = new AddEnvPlugin('before-file', this.options.env, this.options.fileConditionRules, 'file')
306
- const packageEntryPlugin = new PackageEntryPlugin('before-file', this.options.miniNpmPackages, 'file')
217
+ const packageEntryPlugin = new PackageEntryPlugin('before-described-relative', this.options.miniNpmPackages, 'resolve')
307
218
  if (Array.isArray(compiler.options.resolve.plugins)) {
308
219
  compiler.options.resolve.plugins.push(addModePlugin)
309
220
  } else {
@@ -313,14 +224,12 @@ class MpxWebpackPlugin {
313
224
  compiler.options.resolve.plugins.push(addEnvPlugin)
314
225
  }
315
226
  compiler.options.resolve.plugins.push(packageEntryPlugin)
316
- compiler.options.resolve.plugins.push(new FixDescriptionInfoPlugin())
317
227
 
318
228
  let splitChunksPlugin
319
229
  let splitChunksOptions
320
230
 
321
- if (this.options.mode !== 'web' && this.options.mode !== 'tenon') {
322
- const optimization = compiler.options.optimization
323
- optimization.runtimeChunk = {
231
+ if (this.options.mode !== 'web') {
232
+ compiler.options.optimization.runtimeChunk = {
324
233
  name: (entrypoint) => {
325
234
  for (let packageName in mpx.independentSubpackagesMap) {
326
235
  if (mpx.independentSubpackagesMap.hasOwnProperty(packageName) && isChunkInPackage(entrypoint.name, packageName)) {
@@ -330,18 +239,8 @@ class MpxWebpackPlugin {
330
239
  return 'bundle'
331
240
  }
332
241
  }
333
- splitChunksOptions = Object.assign({
334
- defaultSizeTypes: ['javascript', 'unknown'],
335
- chunks: 'all',
336
- usedExports: optimization.usedExports === true,
337
- minChunks: 1,
338
- minSize: 1000,
339
- enforceSizeThreshold: Infinity,
340
- maxAsyncRequests: 30,
341
- maxInitialRequests: 30,
342
- automaticNameDelimiter: '-'
343
- }, optimization.splitChunks)
344
- delete optimization.splitChunks
242
+ splitChunksOptions = compiler.options.optimization.splitChunks
243
+ delete compiler.options.optimization.splitChunks
345
244
  splitChunksPlugin = new SplitChunksPlugin(splitChunksOptions)
346
245
  splitChunksPlugin.apply(compiler)
347
246
  }
@@ -359,11 +258,8 @@ class MpxWebpackPlugin {
359
258
  originalWriteFile(filePath, content, callback)
360
259
  }
361
260
  }
362
-
363
261
  const defs = this.options.defs
364
262
 
365
- const typeExtMap = config[this.options.mode].typeExtMap
366
-
367
263
  const defsOpt = {
368
264
  '__mpx_wxs__': DefinePlugin.runtimeValue(({ module }) => {
369
265
  return JSON.stringify(!!module.wxs)
@@ -381,92 +277,12 @@ class MpxWebpackPlugin {
381
277
 
382
278
  let mpx
383
279
 
384
- if (this.options.partialCompile) {
385
- new PartialCompilePlugin(this.options.partialCompile).apply(compiler)
386
- }
387
-
388
- const getPackageCacheGroup = packageName => {
389
- if (packageName === 'main') {
390
- return {
391
- // 对于独立分包模块不应用该cacheGroup
392
- test: (module) => {
393
- let isIndependent = false
394
- if (module.resource) {
395
- const { queryObj } = parseRequest(module.resource)
396
- isIndependent = !!queryObj.independent
397
- } else {
398
- const identifier = module.identifier()
399
- isIndependent = /\|independent=/.test(identifier)
400
- }
401
- return !isIndependent
402
- },
403
- name: 'bundle',
404
- minChunks: 2,
405
- chunks: 'all'
406
- }
407
- } else {
408
- return {
409
- test: (module, { chunkGraph }) => {
410
- const chunks = chunkGraph.getModuleChunksIterable(module)
411
- return chunks.size && every(chunks, (chunk) => {
412
- return isChunkInPackage(chunk.name, packageName)
413
- })
414
- },
415
- name: `${packageName}/bundle`,
416
- minChunks: 2,
417
- minSize: 1000,
418
- priority: 100,
419
- chunks: 'all'
420
- }
421
- }
422
- }
423
-
424
- const processSubpackagesEntriesMap = (compilation, callback) => {
425
- const mpx = compilation.__mpx__
426
- if (mpx && !isEmptyObject(mpx.subpackagesEntriesMap)) {
427
- const subpackagesEntriesMap = mpx.subpackagesEntriesMap
428
- // 执行分包队列前清空mpx.subpackagesEntriesMap
429
- mpx.subpackagesEntriesMap = {}
430
- async.eachOfSeries(subpackagesEntriesMap, (deps, packageRoot, callback) => {
431
- mpx.currentPackageRoot = packageRoot
432
- mpx.componentsMap[packageRoot] = mpx.componentsMap[packageRoot] || {}
433
- mpx.staticResourcesMap[packageRoot] = mpx.staticResourcesMap[packageRoot] || {}
434
- mpx.subpackageModulesMap[packageRoot] = mpx.subpackageModulesMap[packageRoot] || {}
435
- async.each(deps, (dep, callback) => {
436
- dep.addEntry(compilation, (err, { resultPath }) => {
437
- if (err) return callback(err)
438
- dep.resultPath = mpx.replacePathMap[dep.key] = resultPath
439
- callback()
440
- })
441
- }, callback)
442
- }, (err) => {
443
- if (err) return callback(err)
444
- // 如果执行完当前队列后产生了新的分包执行队列(一般由异步分包组件造成),则继续执行
445
- processSubpackagesEntriesMap(compilation, callback)
446
- })
447
- } else {
448
- callback()
449
- }
450
- }
451
-
452
- // 构建分包队列,在finishMake钩子当中最先执行,stage传递-1000
453
- compiler.hooks.finishMake.tapAsync({
454
- name: 'MpxWebpackPlugin',
455
- stage: -1000
456
- }, (compilation, callback) => {
457
- processSubpackagesEntriesMap(compilation, callback)
458
- })
459
-
460
280
  compiler.hooks.compilation.tap('MpxWebpackPlugin ', (compilation, { normalModuleFactory }) => {
461
- NormalModule.getCompilationHooks(compilation).loader.tap('MpxWebpackPlugin', (loaderContext) => {
281
+ compilation.hooks.normalModuleLoader.tap('MpxWebpackPlugin', (loaderContext, module) => {
462
282
  // 设置loaderContext的minimize
463
283
  if (isProductionLikeMode(compiler.options)) {
464
284
  loaderContext.minimize = true
465
285
  }
466
-
467
- loaderContext.getMpx = () => {
468
- return mpx
469
- }
470
286
  })
471
287
  compilation.dependencyFactories.set(ResolveDependency, new NullFactory())
472
288
  compilation.dependencyTemplates.set(ResolveDependency, new ResolveDependency.Template())
@@ -477,92 +293,161 @@ class MpxWebpackPlugin {
477
293
  compilation.dependencyFactories.set(ReplaceDependency, new NullFactory())
478
294
  compilation.dependencyTemplates.set(ReplaceDependency, new ReplaceDependency.Template())
479
295
 
480
- compilation.dependencyFactories.set(AppEntryDependency, new NullFactory())
481
- compilation.dependencyTemplates.set(AppEntryDependency, new AppEntryDependency.Template())
482
-
483
- compilation.dependencyFactories.set(DynamicEntryDependency, new NullFactory())
484
- compilation.dependencyTemplates.set(DynamicEntryDependency, new DynamicEntryDependency.Template())
485
-
486
- compilation.dependencyFactories.set(FlagPluginDependency, new NullFactory())
487
- compilation.dependencyTemplates.set(FlagPluginDependency, new FlagPluginDependency.Template())
488
-
489
- compilation.dependencyFactories.set(RemoveEntryDependency, new NullFactory())
490
- compilation.dependencyTemplates.set(RemoveEntryDependency, new RemoveEntryDependency.Template())
491
-
492
- compilation.dependencyFactories.set(RecordResourceMapDependency, new NullFactory())
493
- compilation.dependencyTemplates.set(RecordResourceMapDependency, new RecordResourceMapDependency.Template())
296
+ compilation.dependencyFactories.set(ChildCompileDependency, new NullFactory())
297
+ compilation.dependencyTemplates.set(ChildCompileDependency, new ChildCompileDependency.Template())
298
+
299
+ compilation.dependencyFactories.set(RemovedModuleDependency, normalModuleFactory)
300
+ compilation.dependencyTemplates.set(RemovedModuleDependency, new RemovedModuleDependency.Template())
301
+
302
+ // hack cacheGroup参数往addModule中传递当前module的issuer
303
+ const rawAddModuleDependencies = compilation.addModuleDependencies
304
+ compilation.addModuleDependencies = (
305
+ module,
306
+ dependencies,
307
+ bail,
308
+ cacheGroup,
309
+ recursive,
310
+ callback
311
+ ) => {
312
+ const hackedCacheGroup = {
313
+ module,
314
+ cacheGroup
315
+ }
316
+ return rawAddModuleDependencies.call(
317
+ compilation,
318
+ module,
319
+ dependencies,
320
+ bail,
321
+ hackedCacheGroup,
322
+ recursive,
323
+ callback
324
+ )
325
+ }
494
326
 
495
- compilation.dependencyFactories.set(RecordGlobalComponentsDependency, new NullFactory())
496
- compilation.dependencyTemplates.set(RecordGlobalComponentsDependency, new RecordGlobalComponentsDependency.Template())
327
+ // 处理watch时缓存模块中的buildInfo
328
+ // 在调用addModule前对module添加分包信息,以控制分包输出及消除缓存,该操作由afterResolve钩子迁移至此是由于dependencyCache的存在,watch状态下afterResolve钩子并不会对所有模块执行,而模块的packageName在watch过程中是可能发生变更的,如新增删除一个分包资源的主包引用
329
+ const rawAddModule = compilation.addModule
330
+ compilation.addModule = (module, cacheGroup) => {
331
+ let issuerResource
332
+ if (cacheGroup && cacheGroup.module) {
333
+ issuerResource = cacheGroup.module.resource
334
+ cacheGroup = cacheGroup.cacheGroup
335
+ }
336
+ // 避免context module报错
337
+ if (module.request && module.resource) {
338
+ const { queryObj, resourcePath } = parseRequest(module.resource)
339
+ let isStatic = queryObj.isStatic
340
+ if (module.loaders) {
341
+ module.loaders.forEach((loader) => {
342
+ if (/(url-loader|file-loader)/.test(loader.loader)) {
343
+ isStatic = true
344
+ }
345
+ })
346
+ }
347
+ const isIndependent = mpx.independentSubpackagesMap[mpx.currentPackageRoot]
497
348
 
498
- compilation.dependencyFactories.set(RecordIndependentDependency, new NullFactory())
499
- compilation.dependencyTemplates.set(RecordIndependentDependency, new RecordIndependentDependency.Template())
349
+ let needPackageQuery = isStatic || isIndependent
350
+ if (!needPackageQuery && matchCondition(resourcePath, this.options.subpackageModulesRules)) {
351
+ needPackageQuery = true
352
+ }
500
353
 
501
- compilation.dependencyFactories.set(CommonJsVariableDependency, normalModuleFactory)
502
- compilation.dependencyTemplates.set(CommonJsVariableDependency, new CommonJsVariableDependency.Template())
354
+ if (needPackageQuery) {
355
+ const { packageRoot } = mpx.getPackageInfo({
356
+ resource: module.resource,
357
+ resourceType: isStatic ? 'staticResources' : 'subpackageModules',
358
+ issuerResource,
359
+ warn (e) {
360
+ compilation.warnings.push(e)
361
+ },
362
+ error (e) {
363
+ compilation.errors.push(e)
364
+ }
365
+ })
366
+ const queryObj = {}
367
+ if (packageRoot) queryObj.packageRoot = packageRoot
368
+ // todo 后续可以考虑用module.layer来隔离独立分包的模块
369
+ if (isIndependent) queryObj.isIndependent = true
370
+ module.request = addQuery(module.request, queryObj)
371
+ module.resource = addQuery(module.resource, queryObj)
372
+ }
373
+ }
503
374
 
504
- compilation.dependencyFactories.set(CommonJsAsyncDependency, normalModuleFactory)
505
- compilation.dependencyTemplates.set(CommonJsAsyncDependency, new CommonJsAsyncDependency.Template())
375
+ const addModuleResult = rawAddModule.call(compilation, module, cacheGroup)
376
+ if (!addModuleResult.build && addModuleResult.issuer) {
377
+ const buildInfo = addModuleResult.module.buildInfo
378
+ if (buildInfo.pagesMap) {
379
+ Object.assign(mpx.pagesMap, buildInfo.pagesMap)
380
+ }
381
+ if (buildInfo.componentsMap && buildInfo.packageName) {
382
+ Object.assign(mpx.componentsMap[buildInfo.packageName], buildInfo.componentsMap)
383
+ }
384
+ }
385
+ return addModuleResult
386
+ }
506
387
  })
507
388
 
508
389
  compiler.hooks.thisCompilation.tap('MpxWebpackPlugin', (compilation, { normalModuleFactory }) => {
509
390
  compilation.warnings = compilation.warnings.concat(warnings)
510
391
  compilation.errors = compilation.errors.concat(errors)
511
- const moduleGraph = compilation.moduleGraph
392
+ // additionalAssets和mpx由于包含缓存机制,必须在每次compilation时重新初始化
393
+ const additionalAssets = {}
512
394
  if (!compilation.__mpx__) {
513
395
  // init mpx
514
396
  mpx = compilation.__mpx__ = {
515
- // app信息,便于获取appName
516
- appInfo: {},
517
397
  // pages全局记录,无需区分主包分包
518
398
  pagesMap: {},
519
- // 组件资源记录,依照所属包进行记录
399
+ // 记录pages对应的entry,处理多appEntry输出web多页项目时可能出现的pagePath冲突的问题,多appEntry输出目前仅web模式支持
400
+ pagesEntryMap: {},
401
+ // 组件资源记录,依照所属包进行记录,冗余存储,只要某个包有引用会添加对应记录,不管其会不会在当前包输出,这样设计主要是为了在resolve时能够以较低成本找到特定资源的输出路径
520
402
  componentsMap: {
521
403
  main: {}
522
404
  },
523
- // 静态资源(图片,字体,独立样式)等,依照所属包进行记录
405
+ // 静态资源(图片,字体,独立样式)等,依照所属包进行记录,冗余存储,同上
524
406
  staticResourcesMap: {
525
407
  main: {}
526
408
  },
527
- // 用于记录命中subpackageModulesRules的js模块分包归属,用于js多分包冗余输出
409
+ // 用于记录命中subpackageModulesRules的js模块最终输出到了什么分包中
528
410
  subpackageModulesMap: {
529
411
  main: {}
530
412
  },
531
- // 记录其他资源,如pluginMain、pluginExport,无需区分主包分包
532
- otherResourcesMap: {},
533
413
  // 记录独立分包
534
414
  independentSubpackagesMap: {},
535
- subpackagesEntriesMap: {},
536
- replacePathMap: {},
537
- exportModules: new Set(),
415
+ // 当前机制下分包处理队列在app.json的json-compiler中进行,由于addEntry回调特性,无法保障app.js中引用的模块都被标记为主包,故重写processModuleDependencies获取app.js及其所有依赖处理完成的时机,在这之后再执行分包处理队列
416
+ appScriptRawRequest: '',
417
+ appScriptPromise: null,
418
+ appScriptPromiseResolve: null,
419
+ // 记录entry依赖关系,用于体积分析
420
+ entryNodesMap: {},
538
421
  // 记录entryModule与entryNode的对应关系,用于体积分析
539
- entryNodeModulesMap: new Map(),
540
- // 记录与asset相关联的modules,用于体积分析
541
- assetsModulesMap: new Map(),
542
- // 记录与asset相关联的ast,用于体积分析和esCheck,避免重复parse
543
- assetsASTsMap: new Map(),
422
+ entryModulesMap: new Map(),
423
+ loaderOptions,
424
+ extractedMap: {},
544
425
  usingComponents: {},
426
+ hasApp: false,
545
427
  // todo es6 map读写性能高于object,之后会逐步替换
546
428
  vueContentCache: new Map(),
547
- wxsAssetsCache: new Map(),
548
429
  currentPackageRoot: '',
430
+ wxsMap: {},
549
431
  wxsContentMap: {},
432
+ assetsInfo: new Map(),
433
+ forceDisableInject: this.options.forceDisableInject,
550
434
  forceUsePageCtor: this.options.forceUsePageCtor,
551
435
  resolveMode: this.options.resolveMode,
552
436
  mode: this.options.mode,
553
437
  srcMode: this.options.srcMode,
554
438
  env: this.options.env,
439
+ // deprecated option
440
+ globalMpxAttrsFilter: this.options.globalMpxAttrsFilter,
555
441
  externalClasses: this.options.externalClasses,
556
442
  projectRoot: this.options.projectRoot,
557
443
  autoScopeRules: this.options.autoScopeRules,
558
444
  autoVirtualHostRules: this.options.autoVirtualHostRules,
559
445
  transRpxRules: this.options.transRpxRules,
446
+ webConfig: this.options.webConfig,
560
447
  postcssInlineConfig: this.options.postcssInlineConfig,
561
448
  decodeHTMLText: this.options.decodeHTMLText,
562
- // native文件专用配置
563
- nativeConfig: this.options.nativeConfig,
564
- // 输出web专用配置
565
- webConfig: this.options.webConfig,
449
+ // native文件专用相关配置
450
+ nativeOptions: this.options.nativeOptions,
566
451
  tabBarMap: {},
567
452
  defs: preProcessDefs(this.options.defs),
568
453
  i18n: this.options.i18n,
@@ -574,121 +459,76 @@ class MpxWebpackPlugin {
574
459
  useRelativePath: this.options.useRelativePath,
575
460
  removedChunks: [],
576
461
  forceProxyEventRules: this.options.forceProxyEventRules,
577
- proxyComponentEventsRules: this.options.proxyComponentEventsRules,
578
- pathHash: (resourcePath) => {
579
- if (this.options.pathHashMode === 'relative' && this.options.projectRoot) {
580
- return hash(path.relative(this.options.projectRoot, resourcePath))
462
+ getEntryNode: (request, type, module) => {
463
+ const entryNodesMap = mpx.entryNodesMap
464
+ const entryModulesMap = mpx.entryModulesMap
465
+ if (!entryNodesMap[request]) {
466
+ entryNodesMap[request] = new EntryNode({
467
+ type,
468
+ request
469
+ })
581
470
  }
582
- return hash(resourcePath)
583
- },
584
- addEntry (request, name, callback) {
585
- const dep = EntryPlugin.createDependency(request, { name })
586
- compilation.addEntry(compiler.context, dep, { name }, callback)
587
- return dep
471
+ const currentEntry = entryNodesMap[request]
472
+ if (currentEntry.type !== type) {
473
+ compilation.errors.push(`获取request为${request}的entryNode时类型与已有节点冲突, 当前获取的type为${type}, 已有节点的type为${currentEntry.type}!`)
474
+ }
475
+ if (module) {
476
+ currentEntry.module = module
477
+ entryModulesMap.set(module, currentEntry)
478
+ }
479
+ return currentEntry
588
480
  },
589
- getEntryNode: (module, type) => {
590
- const entryNodeModulesMap = mpx.entryNodeModulesMap
591
- let entryNode = entryNodeModulesMap.get(module)
592
- if (!entryNode) {
593
- entryNode = new EntryNode(module, type)
594
- entryNodeModulesMap.set(module, entryNode)
481
+ pathHash: (resourcePath) => {
482
+ let hashPath = resourcePath
483
+ const pathHashMode = this.options.pathHashMode
484
+ const projectRoot = this.options.projectRoot || ''
485
+ if (pathHashMode === 'relative') {
486
+ hashPath = path.relative(projectRoot, resourcePath)
487
+ }
488
+ if (typeof pathHashMode === 'function') {
489
+ hashPath = pathHashMode(resourcePath, projectRoot) || resourcePath
595
490
  }
596
- return entryNode
491
+ return hash(hashPath)
597
492
  },
598
493
  getOutputPath: (resourcePath, type, { ext = '', conflictPath = '' } = {}) => {
599
494
  const name = path.parse(resourcePath).name
600
495
  const hash = mpx.pathHash(resourcePath)
601
496
  const customOutputPath = this.options.customOutputPath
602
497
  if (conflictPath) return conflictPath.replace(/(\.[^\\/]+)?$/, match => hash + match)
603
- if (typeof customOutputPath === 'function') return customOutputPath(type, name, hash, ext).replace(/^\//, '')
498
+ if (typeof customOutputPath === 'function') return customOutputPath(type, name, hash, ext)
604
499
  if (type === 'component' || type === 'page') return path.join(type + 's', name + hash, 'index' + ext)
605
500
  return path.join(type, name + hash + ext)
606
501
  },
607
- extractedFilesCache: new Map(),
608
- getExtractedFile: (resource, { error } = {}) => {
609
- const cache = mpx.extractedFilesCache.get(resource)
610
- if (cache) return cache
611
- const { resourcePath, queryObj } = parseRequest(resource)
612
- const { type, isStatic, isPlugin } = queryObj
613
- let file
614
- if (isPlugin) {
615
- file = 'plugin.json'
616
- } else if (isStatic) {
617
- const packageRoot = queryObj.packageRoot || ''
618
- file = toPosix(path.join(packageRoot, mpx.getOutputPath(resourcePath, type, { ext: typeExtMap[type] })))
619
- } else {
620
- const appInfo = mpx.appInfo
621
- const pagesMap = mpx.pagesMap
622
- const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
623
- const componentsMap = mpx.componentsMap[packageName]
624
- let filename = resourcePath === appInfo.resourcePath ? appInfo.name : (pagesMap[resourcePath] || componentsMap[resourcePath])
625
- if (!filename) {
626
- error && error(new Error('Get extracted file error: missing filename!'))
627
- filename = 'missing-filename'
628
- }
629
- file = filename + typeExtMap[type]
630
- }
631
- mpx.extractedFilesCache.set(resource, file)
632
- return file
633
- },
634
- recordResourceMap: ({ resourcePath, resourceType, outputPath, packageRoot = '', recordOnly, warn, error }) => {
635
- const packageName = packageRoot || 'main'
636
- const resourceMap = mpx[`${resourceType}sMap`] || mpx.otherResourcesMap
637
- const currentResourceMap = resourceMap.main ? resourceMap[packageName] = resourceMap[packageName] || {} : resourceMap
638
- let alreadyOutputted = false
639
- if (outputPath) {
640
- if (!currentResourceMap[resourcePath] || currentResourceMap[resourcePath] === true) {
641
- if (!recordOnly) {
642
- // 在非recordOnly的模式下,进行输出路径冲突检测,如果存在输出路径冲突,则对输出路径进行重命名
643
- for (let key in currentResourceMap) {
644
- // todo 用outputPathMap来检测输出路径冲突
645
- if (currentResourceMap[key] === outputPath && key !== resourcePath) {
646
- outputPath = mpx.getOutputPath(resourcePath, resourceType, { conflictPath: outputPath })
647
- warn && warn(new Error(`Current ${resourceType} [${resourcePath}] is registered with conflicted outputPath [${currentResourceMap[key]}] which is already existed in system, will be renamed with [${outputPath}], use ?resolve to get the real outputPath!`))
648
- break
649
- }
650
- }
651
- }
652
- currentResourceMap[resourcePath] = outputPath
653
- } else {
654
- if (currentResourceMap[resourcePath] === outputPath) {
655
- alreadyOutputted = true
656
- } else {
657
- error && error(new Error(`Current ${resourceType} [${resourcePath}] is already registered with outputPath [${currentResourceMap[resourcePath]}], you can not register it with another outputPath [${outputPath}]!`))
658
- }
659
- }
660
- } else if (!currentResourceMap[resourcePath]) {
661
- currentResourceMap[resourcePath] = true
662
- }
663
-
664
- return {
665
- outputPath,
666
- alreadyOutputted
502
+ extract: (content, file, index, sideEffects) => {
503
+ index = index === -1 ? 0 : index
504
+ additionalAssets[file] = additionalAssets[file] || []
505
+ if (!additionalAssets[file][index]) {
506
+ additionalAssets[file][index] = content
667
507
  }
508
+ sideEffects && sideEffects.forEach((sideEffect) => {
509
+ sideEffect(additionalAssets)
510
+ })
668
511
  },
669
512
  // 组件和静态资源的输出规则如下:
670
513
  // 1. 主包引用的资源输出至主包
671
514
  // 2. 分包引用且主包引用过的资源输出至主包,不在当前分包重复输出
672
515
  // 3. 分包引用且无其他包引用的资源输出至当前分包
673
516
  // 4. 分包引用且其他分包也引用过的资源,重复输出至当前分包
674
- getPackageInfo: ({ resource, resourceType, outputPath, issuerResource, warn, error }) => {
517
+ getPackageInfo: ({ resource, outputPath, resourceType = 'components', issuerResource, warn }) => {
675
518
  let packageRoot = ''
676
519
  let packageName = 'main'
677
-
678
- const { resourcePath } = parseRequest(resource)
679
- const currentPackageRoot = mpx.currentPackageRoot
680
- const currentPackageName = currentPackageRoot || 'main'
681
- const isIndependent = !!mpx.independentSubpackagesMap[currentPackageRoot]
682
- const resourceMap = mpx[`${resourceType}sMap`] || mpx.otherResourcesMap
683
-
684
- if (!resourceMap.main) {
685
- packageRoot = currentPackageRoot
686
- packageName = currentPackageName
520
+ const resourceMap = mpx[`${resourceType}Map`]
521
+ const { queryObj, resourcePath } = parseRequest(resource)
522
+ if (resourceType === 'staticResources' && outputPath) {
523
+ packageRoot = queryObj.packageRoot || ''
524
+ packageName = packageRoot || 'main'
687
525
  } else {
526
+ const currentPackageRoot = mpx.currentPackageRoot
527
+ const currentPackageName = currentPackageRoot || 'main'
528
+ const isIndependent = mpx.independentSubpackagesMap[currentPackageRoot]
688
529
  // 主包中有引用一律使用主包中资源,不再额外输出
689
530
  // 资源路径匹配到forceMainPackageRules规则时强制输出到主包,降低分包资源冗余
690
531
  // 如果存在issuer且issuerPackageRoot与当前packageRoot不一致,也输出到主包
691
- // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
692
532
  let isMain = resourceMap.main[resourcePath] || matchCondition(resourcePath, this.options.forceMainPackageRules)
693
533
  if (issuerResource) {
694
534
  const { queryObj } = parseRequest(issuerResource)
@@ -698,36 +538,50 @@ class MpxWebpackPlugin {
698
538
  isMain = true
699
539
  }
700
540
  }
541
+ // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
701
542
  if (!isMain || isIndependent) {
702
543
  packageRoot = currentPackageRoot
703
544
  packageName = currentPackageName
704
- if (this.options.auditResource && resourceType !== 'subpackageModule' && !isIndependent) {
705
- if (this.options.auditResource !== 'component' || resourceType === 'component') {
545
+ if (this.options.auditResource && resourceType !== 'subpackageModules' && !isIndependent) {
546
+ if (this.options.auditResource !== 'component' || resourceType === 'components') {
706
547
  Object.keys(resourceMap).filter(key => key !== 'main').forEach((key) => {
707
548
  if (resourceMap[key][resourcePath] && key !== packageName) {
708
- warn && warn(new Error(`当前${resourceType === 'component' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
549
+ warn && warn(new Error(`当前${resourceType === 'components' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
709
550
  }
710
551
  })
711
552
  }
712
553
  }
713
554
  }
714
- resourceMap[packageName] = resourceMap[packageName] || {}
715
555
  }
716
556
 
717
- if (outputPath) outputPath = toPosix(path.join(packageRoot, outputPath))
557
+ resourceMap[packageName] = resourceMap[packageName] || {}
558
+ const currentResourceMap = resourceMap[packageName]
559
+
560
+ let alreadyOutputed = false
561
+ if (outputPath) {
562
+ outputPath = toPosix(path.join(packageRoot, outputPath))
563
+ // 如果之前已经进行过输出,则不需要重复进行
564
+ if (currentResourceMap[resourcePath] === outputPath) {
565
+ alreadyOutputed = true
566
+ } else {
567
+ for (let key in currentResourceMap) {
568
+ if (currentResourceMap[key] === outputPath && key !== resourcePath) {
569
+ outputPath = toPosix(path.join(packageRoot, mpx.getOutputPath(resourcePath, resourceType, { conflictPath: outputPath })))
570
+ warn && warn(new Error(`Current ${resourceType} [${resourcePath}] is registered with a conflict outputPath [${currentResourceMap[key]}] which is already existed in system, will be renamed with [${outputPath}], use ?resolve to get the real outputPath!`))
571
+ break
572
+ }
573
+ }
574
+ currentResourceMap[resourcePath] = outputPath
575
+ }
576
+ } else if (!currentResourceMap[resourcePath]) {
577
+ currentResourceMap[resourcePath] = true
578
+ }
718
579
 
719
580
  return {
720
581
  packageName,
721
582
  packageRoot,
722
- // 返回outputPath及alreadyOutputted
723
- ...mpx.recordResourceMap({
724
- resourcePath,
725
- resourceType,
726
- outputPath,
727
- packageRoot,
728
- warn,
729
- error
730
- })
583
+ outputPath,
584
+ alreadyOutputed
731
585
  }
732
586
  }
733
587
  }
@@ -735,110 +589,18 @@ class MpxWebpackPlugin {
735
589
 
736
590
  const rawProcessModuleDependencies = compilation.processModuleDependencies
737
591
  compilation.processModuleDependencies = (module, callback) => {
738
- const presentationalDependencies = module.presentationalDependencies || []
739
- async.forEach(presentationalDependencies.filter((dep) => dep.mpxAction), (dep, callback) => {
740
- dep.mpxAction(module, compilation, callback)
741
- }, (err) => {
742
- rawProcessModuleDependencies.call(compilation, module, (innerErr) => {
743
- return callback(err || innerErr)
744
- })
745
- })
746
- }
747
-
748
- const rawFactorizeModule = compilation.factorizeModule
749
- compilation.factorizeModule = (options, callback) => {
750
- const originModule = options.originModule
751
592
  let proxyedCallback = callback
752
- if (originModule) {
753
- proxyedCallback = (err, module) => {
754
- // 避免selfModuleFactory的情况
755
- if (module && module !== originModule) {
756
- module.issuerResource = originModule.resource
757
- }
758
- return callback(err, module)
593
+ if (module.rawRequest === mpx.appScriptRawRequest) {
594
+ // 避免模块request重名,只对第一次匹配到的模块进行代理
595
+ mpx.appScriptRawRequest = ''
596
+ proxyedCallback = (err) => {
597
+ mpx.appScriptPromiseResolve()
598
+ return callback(err)
759
599
  }
760
600
  }
761
- return rawFactorizeModule.call(compilation, options, proxyedCallback)
601
+ return rawProcessModuleDependencies.apply(compilation, [module, proxyedCallback])
762
602
  }
763
603
 
764
- // 处理watch时缓存模块中的buildInfo
765
- // 在调用addModule前对module添加分包信息,以控制分包输出及消除缓存,该操作由afterResolve钩子迁移至此是由于dependencyCache的存在,watch状态下afterResolve钩子并不会对所有模块执行,而模块的packageName在watch过程中是可能发生变更的,如新增删除一个分包资源的主包引用
766
- const rawAddModule = compilation.addModule
767
- compilation.addModule = (module, callback) => {
768
- const issuerResource = module.issuerResource
769
- const currentPackageRoot = mpx.currentPackageRoot
770
- const independent = mpx.independentSubpackagesMap[currentPackageRoot]
771
-
772
- if (module.resource) {
773
- // NormalModule
774
- const isStatic = isStaticModule(module)
775
-
776
- let needPackageQuery = isStatic || independent
777
-
778
- if (!needPackageQuery) {
779
- const { resourcePath } = parseRequest(module.resource)
780
- needPackageQuery = matchCondition(resourcePath, this.options.subpackageModulesRules)
781
- }
782
-
783
- if (needPackageQuery) {
784
- const { packageRoot } = mpx.getPackageInfo({
785
- resource: module.resource,
786
- resourceType: isStatic ? 'staticResource' : 'subpackageModule',
787
- issuerResource,
788
- warn (e) {
789
- compilation.warnings.push(e)
790
- },
791
- error (e) {
792
- compilation.errors.push(e)
793
- }
794
- })
795
- if (packageRoot) {
796
- const queryObj = {
797
- packageRoot
798
- }
799
- if (independent) queryObj.independent = independent
800
- module.request = addQuery(module.request, queryObj)
801
- module.resource = addQuery(module.resource, queryObj)
802
- }
803
- }
804
- } else if (independent) {
805
- // ContextModule/RawModule/ExternalModule等只在独立分包的情况下添加分包标记,其余默认不添加
806
- const hackModuleIdentifier = (module) => {
807
- const postfix = `|independent=${independent}|${currentPackageRoot}`
808
- const rawIdentifier = module.identifier
809
- if (rawIdentifier && !rawIdentifier.__mpxHacked) {
810
- module.identifier = () => {
811
- return rawIdentifier.call(module) + postfix
812
- }
813
- module.identifier.__mpxHacked = true
814
- }
815
- }
816
- hackModuleIdentifier(module)
817
- const rawCallback = callback
818
- callback = (err, module) => {
819
- // 因为文件缓存的存在,前面hack identifier的行为对于从文件缓存中创建得到的module并不生效,因此需要在回调中进行二次hack处理
820
- if (err) return rawCallback(err)
821
- hackModuleIdentifier(module)
822
- rawCallback(null, module)
823
- }
824
- }
825
- return rawAddModule.call(compilation, module, callback)
826
- }
827
-
828
- const rawEmitAsset = compilation.emitAsset
829
-
830
- compilation.emitAsset = (file, source, assetInfo) => {
831
- if (assetInfo && assetInfo.skipEmit) return
832
- return rawEmitAsset.call(compilation, file, source, assetInfo)
833
- }
834
-
835
- compilation.hooks.succeedModule.tap('MpxWebpackPlugin', (module) => {
836
- // 静态资源模块由于输出结果的动态性,通过importModule会合并asset的特性,通过emitFile传递信息禁用父级extractor的缓存来保障父级的importModule每次都能被执行
837
- if (isStaticModule(module)) {
838
- emitFile(module, MPX_DISABLE_EXTRACTOR_CACHE, '', undefined, { skipEmit: true })
839
- }
840
- })
841
-
842
604
  compilation.hooks.finishModules.tap('MpxWebpackPlugin', (modules) => {
843
605
  // 自动跟进分包配置修改splitChunksPlugin配置
844
606
  if (splitChunksPlugin) {
@@ -850,15 +612,45 @@ class MpxWebpackPlugin {
850
612
  }
851
613
  })
852
614
  if (needInit) {
853
- splitChunksPlugin.options = new SplitChunksPlugin(splitChunksOptions).options
615
+ splitChunksPlugin.options = SplitChunksPlugin.normalizeOptions(splitChunksOptions)
854
616
  }
855
617
  }
856
618
  })
857
619
 
858
- JavascriptModulesPlugin.getCompilationHooks(compilation).renderModuleContent.tap('MpxWebpackPlugin', (source, module, renderContext) => {
620
+ compilation.hooks.optimizeModules.tap('MpxWebpackPlugin', (modules) => {
621
+ modules.forEach((module) => {
622
+ if (module.needRemove) {
623
+ let removed = false
624
+ module.reasons.forEach((reason) => {
625
+ if (reason.module) {
626
+ if (reason.dependency instanceof HarmonyImportSideEffectDependency) {
627
+ reason.module.removeDependency(reason.dependency)
628
+ reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module))
629
+ removed = true
630
+ } else if (reason.dependency instanceof CommonJsRequireDependency && reason.dependency.loc.range) {
631
+ let index = reason.module.dependencies.indexOf(reason.dependency)
632
+ if (index > -1 && reason.module.dependencies[index + 1] instanceof RequireHeaderDependency) {
633
+ reason.module.dependencies.splice(index, 2)
634
+ reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module, reason.dependency.loc.range))
635
+ removed = true
636
+ }
637
+ }
638
+ }
639
+ })
640
+ if (removed) {
641
+ module.chunksIterable.forEach((chunk) => {
642
+ module.removeChunk(chunk)
643
+ })
644
+ module.disconnect()
645
+ }
646
+ }
647
+ })
648
+ })
649
+
650
+ compilation.moduleTemplates.javascript.hooks.content.tap('MpxWebpackPlugin', (source, module, options) => {
859
651
  // 处理dll产生的external模块
860
652
  if (module.external && module.userRequest.startsWith('dll-reference ') && mpx.mode !== 'web') {
861
- const chunk = renderContext.chunk
653
+ const chunk = options.chunk
862
654
  const request = module.request
863
655
  let relativePath = toPosix(path.relative(path.dirname(chunk.name), request))
864
656
  if (!/^\.\.?\//.test(relativePath)) relativePath = './' + relativePath
@@ -869,141 +661,133 @@ class MpxWebpackPlugin {
869
661
  return source
870
662
  })
871
663
 
872
- JavascriptModulesPlugin.getCompilationHooks(compilation).renderStartup.tap('MpxWebpackPlugin', (source, module) => {
873
- if (module && mpx.exportModules.has(module)) {
874
- source = new ConcatSource(source)
875
- source.add('module.exports = __webpack_exports__;\n')
876
- }
877
- return source
878
- })
879
-
880
- compilation.hooks.moduleAsset.tap('MpxWebpackPlugin', (module, filename) => {
881
- const modules = mpx.assetsModulesMap.get(filename) || new Set()
882
- modules.add(module)
883
- mpx.assetsModulesMap.set(filename, modules)
884
- })
885
-
886
- const fillExtractedAssetsMap = (assetsMap, { index, content }, filename) => {
887
- if (assetsMap.has(index)) {
888
- if (assetsMap.get(index) !== content) {
889
- compilation.errors.push(new Error(`The extracted file [${filename}] is filled with same index [${index}] and different content:
890
- old content: ${assetsMap.get(index)}
891
- new content: ${content}
892
- please check!`))
664
+ compilation.hooks.additionalAssets.tapAsync('MpxWebpackPlugin', (callback) => {
665
+ for (let file in additionalAssets) {
666
+ let content = new ConcatSource()
667
+ if (additionalAssets[file].prefix) {
668
+ additionalAssets[file].prefix.forEach((item) => {
669
+ if (item) content.add(item)
670
+ })
893
671
  }
894
- } else {
895
- assetsMap.set(index, content)
896
- }
897
- }
672
+ additionalAssets[file].forEach((item) => {
673
+ if (item) content.add(item)
674
+ })
675
+ const modules = (additionalAssets[file].modules || []).concat(additionalAssets[file].relativeModules || [])
898
676
 
899
- const sortExtractedAssetsMap = (assetsMap) => {
900
- return [...assetsMap.entries()].sort((a, b) => a[0] - b[0]).map(item => item[1])
901
- }
677
+ if (modules.length > 1) {
678
+ // 同步relativeModules和modules之间的依赖
679
+ const fileDependencies = new Set()
680
+ const contextDependencies = new Set()
902
681
 
903
- compilation.hooks.beforeModuleAssets.tap('MpxWebpackPlugin', () => {
904
- const extractedAssetsMap = new Map()
905
- for (const module of compilation.modules) {
906
- const assetsInfo = module.buildInfo.assetsInfo || new Map()
907
- for (const [filename, { extractedInfo } = {}] of assetsInfo) {
908
- if (extractedInfo) {
909
- let extractedAssets = extractedAssetsMap.get(filename)
910
- if (!extractedAssets) {
911
- extractedAssets = [new Map(), new Map()]
912
- extractedAssetsMap.set(filename, extractedAssets)
913
- }
914
- fillExtractedAssetsMap(extractedInfo.pre ? extractedAssets[0] : extractedAssets[1], extractedInfo, filename)
915
- compilation.hooks.moduleAsset.call(module, filename)
916
- }
682
+ modules.forEach((module) => {
683
+ module.buildInfo.fileDependencies.forEach((fileDependency) => {
684
+ fileDependencies.add(fileDependency)
685
+ })
686
+ module.buildInfo.contextDependencies.forEach((contextDependency) => {
687
+ contextDependencies.add(contextDependency)
688
+ })
689
+ module.buildInfo.fileDependencies = fileDependencies
690
+ module.buildInfo.contextDependencies = contextDependencies
691
+ })
917
692
  }
693
+ compilation.emitAsset(file, content, { modules: additionalAssets[file].modules })
918
694
  }
919
-
920
- for (const [filename, [pre, normal]] of extractedAssetsMap) {
921
- const sortedExtractedAssets = [...sortExtractedAssetsMap(pre), ...sortExtractedAssetsMap(normal)]
922
- const source = new ConcatSource()
923
- sortedExtractedAssets.forEach((content) => {
924
- if (content) {
925
- // 处理replace path
926
- if (/"mpx_replace_path_.*?"/.test(content)) {
927
- content = content.replace(/"mpx_replace_path_(.*?)"/g, (matched, key) => {
928
- return JSON.stringify(mpx.replacePathMap[key] || 'missing replace path')
929
- })
930
- }
931
- source.add(content)
932
- }
695
+ // 所有编译的静态资源assetsInfo合入主编译
696
+ mpx.assetsInfo.forEach((assetInfo, name) => {
697
+ const oldAssetInfo = compilation.assetsInfo.get(name)
698
+ if (oldAssetInfo && oldAssetInfo.modules) {
699
+ assetInfo.modules = assetInfo.modules.concat(oldAssetInfo.modules)
700
+ }
701
+ compilation.assetsInfo.set(name, assetInfo)
702
+ })
703
+ // 链接主编译模块与子编译入口
704
+ Object.values(mpx.wxsMap).concat(Object.values(mpx.extractedMap)).forEach((item) => {
705
+ item.modules.forEach((module) => {
706
+ module.addDependency(item.dep)
933
707
  })
934
- compilation.emitAsset(filename, source)
935
- }
708
+ })
709
+
710
+ callback()
936
711
  })
937
712
 
938
713
  normalModuleFactory.hooks.parser.for('javascript/auto').tap('MpxWebpackPlugin', (parser) => {
714
+ // hack预处理,将expr.range写入loc中便于在CommonJsRequireDependency中获取,移除无效require
715
+ parser.hooks.call.for('require').tap({ name: 'MpxWebpackPlugin', stage: -100 }, (expr) => {
716
+ expr.loc.range = expr.range
717
+ })
718
+
939
719
  parser.hooks.call.for('__mpx_resolve_path__').tap('MpxWebpackPlugin', (expr) => {
940
720
  if (expr.arguments[0]) {
941
721
  const resource = expr.arguments[0].value
942
- const packageName = mpx.currentPackageRoot || 'main'
943
- const issuerResource = moduleGraph.getIssuer(parser.state.module).resource
722
+ const { queryObj } = parseRequest(resource)
723
+ const packageName = queryObj.packageRoot || 'main'
724
+ const pagesMap = mpx.pagesMap
725
+ const componentsMap = mpx.componentsMap
726
+ const staticResourcesMap = mpx.staticResourcesMap
944
727
  const range = expr.range
945
- const dep = new ResolveDependency(resource, packageName, issuerResource, range)
946
- parser.state.current.addPresentationalDependency(dep)
728
+ const issuerResource = parser.state.module.issuer.resource
729
+ const dep = new ResolveDependency(resource, packageName, pagesMap, componentsMap, staticResourcesMap, publicPath, range, issuerResource, compilation)
730
+ parser.state.current.addDependency(dep)
947
731
  return true
948
732
  }
949
733
  })
950
734
 
951
- parser.hooks.call.for('__mpx_dynamic_entry__').tap('MpxWebpackPlugin', (expr) => {
952
- const args = expr.arguments.map((i) => i.value)
953
- args.push(expr.range)
954
- const dep = new DynamicEntryDependency(...args)
955
- parser.state.current.addPresentationalDependency(dep)
956
- return true
957
- })
958
-
959
- const requireAsyncHandler = (expr, members) => {
960
- if (members[0] === 'async') {
961
- let request = expr.arguments[0].value
962
- const range = expr.arguments[0].range
963
- const context = parser.state.module.context
964
- const { queryObj } = parseRequest(request)
965
- if (queryObj.root) {
966
- // 删除root query
967
- request = addQuery(request, {}, false, ['root'])
968
- // 目前仅wx支持require.async,其余平台使用CommonJsAsyncDependency进行模拟抹平
969
- if (mpx.mode === 'wx') {
970
- const dep = new DynamicEntryDependency(request, 'export', '', queryObj.root, MPX_CURRENT_CHUNK, context, range)
971
- parser.state.current.addPresentationalDependency(dep)
972
- // 包含require.async的模块不能被concatenate,避免DynamicEntryDependency中无法获取模块chunk以计算相对路径
973
- parser.state.module.buildInfo.moduleConcatenationBailout = 'require async'
974
- } else {
975
- const range = expr.range
976
- const dep = new CommonJsAsyncDependency(request, range)
977
- parser.state.current.addDependency(dep)
978
- }
979
- return true
980
- } else {
981
- compilation.errors.push(new Error(`The require async JS [${request}] need to declare subpackage name by root`))
982
- return true
983
- }
735
+ const transHandler = (expr) => {
736
+ const module = parser.state.module
737
+ const current = parser.state.current
738
+ const { queryObj, resourcePath } = parseRequest(module.resource)
739
+ const localSrcMode = queryObj.mode
740
+ const globalSrcMode = mpx.srcMode
741
+ const srcMode = localSrcMode || globalSrcMode
742
+ const mode = mpx.mode
743
+
744
+ let target
745
+
746
+ if (expr.type === 'Identifier') {
747
+ target = expr
748
+ } else if (expr.type === 'MemberExpression') {
749
+ target = expr.object
750
+ }
751
+ if (!matchCondition(resourcePath, this.options.transMpxRules) || resourcePath.indexOf('@mpxjs') !== -1 || !target || mode === srcMode) {
752
+ return
984
753
  }
985
- }
986
754
 
987
- parser.hooks.callMemberChain
988
- .for('require')
989
- .tap({
990
- name: 'MpxWebpackPlugin',
991
- stage: -1000
992
- }, (expr, members) => requireAsyncHandler(expr, members))
755
+ const type = target.name
993
756
 
994
- parser.hooks.callMemberChainOfCallMemberChain
995
- .for('require')
996
- .tap({
997
- name: 'MpxWebpackPlugin',
998
- stage: -1000
999
- }, (expr, calleeMembers, callExpr) => requireAsyncHandler(callExpr, calleeMembers))
757
+ const name = type === 'wx' ? 'mpx' : 'createFactory'
758
+ const replaceContent = type === 'wx' ? '__webpack_require__.n(mpx)()' : `__webpack_require__.n(createFactory)()(${JSON.stringify(type)})`
1000
759
 
760
+ const dep = new ReplaceDependency(replaceContent, target.range)
761
+ current.addDependency(dep)
762
+
763
+ let needInject = true
764
+ for (let v of module.variables) {
765
+ if (v.name === name) {
766
+ needInject = false
767
+ break
768
+ }
769
+ }
770
+ if (needInject) {
771
+ const expression = `require(${JSON.stringify(`@mpxjs/core/src/runtime/${name}`)})`
772
+ const deps = []
773
+ parser.parse(expression, {
774
+ current: {
775
+ addDependency: dep => {
776
+ dep.userRequest = name
777
+ deps.push(dep)
778
+ }
779
+ },
780
+ module
781
+ })
782
+ module.addVariable(name, expression, deps)
783
+ }
784
+ }
1001
785
  // hack babel polyfill global
1002
786
  parser.hooks.statementIf.tap('MpxWebpackPlugin', (expr) => {
1003
787
  if (/core-js.+microtask/.test(parser.state.module.resource)) {
1004
788
  if (expr.test.left && (expr.test.left.name === 'Observer' || expr.test.left.name === 'MutationObserver')) {
1005
789
  const current = parser.state.current
1006
- current.addPresentationalDependency(new InjectDependency({
790
+ current.addDependency(new InjectDependency({
1007
791
  content: 'document && ',
1008
792
  index: expr.test.range[0]
1009
793
  }))
@@ -1019,7 +803,7 @@ class MpxWebpackPlugin {
1019
803
  // todo 该逻辑在corejs3中不需要,等corejs3比较普及之后可以干掉
1020
804
  if (/core-js.+global/.test(parser.state.module.resource)) {
1021
805
  if (callee.name === 'Function' && arg0 && arg0.value === 'return this') {
1022
- current.addPresentationalDependency(new InjectDependency({
806
+ current.addDependency(new InjectDependency({
1023
807
  content: '(function() { return this })() || ',
1024
808
  index: expr.range[0]
1025
809
  }))
@@ -1027,169 +811,102 @@ class MpxWebpackPlugin {
1027
811
  }
1028
812
  if (/regenerator-runtime/.test(parser.state.module.resource)) {
1029
813
  if (callee.name === 'Function' && arg0 && arg0.value === 'r' && arg1 && arg1.value === 'regeneratorRuntime = r') {
1030
- current.addPresentationalDependency(new ReplaceDependency('(function () {})', expr.range))
814
+ current.addDependency(new ReplaceDependency('(function () {})', expr.range))
1031
815
  }
1032
816
  }
1033
817
  })
1034
818
 
1035
- // processing for tenon-store
1036
- if (mpx.mode === 'tenon') {
1037
- let TENON_STORE_ID = 0
1038
- parser.hooks.call.for('imported var').tap('MpxWebpackPlugin', (expr) => {
1039
- if (['createStore', 'createStoreWithThis'].includes(expr.callee.name)) {
1040
- const current = parser.state.current
1041
- const storeOptions = expr.arguments.length && expr.arguments[0]
1042
- if (storeOptions) {
1043
- current.addDependency(new InjectDependency({
1044
- content: 'Object.assign(',
1045
- index: storeOptions.range[0]
1046
- }))
1047
- current.addDependency(new InjectDependency({
1048
- content: `, { __store_id: ${TENON_STORE_ID++} })`,
1049
- index: storeOptions.range[1]
1050
- }))
1051
- }
1052
- }
1053
- })
1054
- }
1055
-
1056
819
  if (mpx.srcMode !== mpx.mode) {
1057
- // 处理跨平台全局对象转换
1058
- const transGlobalObject = (expr) => {
1059
- const module = parser.state.module
1060
- const current = parser.state.current
1061
- const { queryObj, resourcePath } = parseRequest(module.resource)
1062
- const localSrcMode = queryObj.mode
1063
- const globalSrcMode = mpx.srcMode
1064
- const srcMode = localSrcMode || globalSrcMode
1065
- const mode = mpx.mode
1066
-
1067
- let target
1068
- if (expr.type === 'Identifier') {
1069
- target = expr
1070
- } else if (expr.type === 'MemberExpression') {
1071
- target = expr.object
1072
- }
1073
-
1074
- if (!matchCondition(resourcePath, this.options.transMpxRules) || resourcePath.indexOf('@mpxjs') !== -1 || !target || mode === srcMode) return
1075
-
1076
- const type = target.name
1077
- const name = type === 'wx' ? 'mpx' : 'createFactory'
1078
- const replaceContent = type === 'wx' ? 'mpx' : `createFactory(${JSON.stringify(type)})`
1079
-
1080
- const dep = new ReplaceDependency(replaceContent, target.range)
1081
- current.addPresentationalDependency(dep)
1082
-
1083
- let needInject = true
1084
- for (let dep of module.dependencies) {
1085
- if (dep instanceof CommonJsVariableDependency && dep.name === name) {
1086
- needInject = false
1087
- break
1088
- }
1089
- }
1090
- if (needInject) {
1091
- const dep = new CommonJsVariableDependency(`@mpxjs/core/src/runtime/${name}`, name)
1092
- module.addDependency(dep)
1093
- }
1094
- }
1095
-
1096
- // 转换wx全局对象
1097
- parser.hooks.expression.for('wx').tap('MpxWebpackPlugin', transGlobalObject)
820
+ // 全量替换未声明的wx identifier
821
+ parser.hooks.expression.for('wx').tap('MpxWebpackPlugin', transHandler)
822
+
823
+ // parser.hooks.evaluate.for('MemberExpression').tap('MpxWebpackPlugin', (expr) => {
824
+ // // Undeclared varible for wx[identifier]()
825
+ // // TODO Unable to handle wx[identifier]
826
+ // if (expr.object.name === 'wx' && !parser.scope.definitions.has('wx')) {
827
+ // transHandler(expr)
828
+ // }
829
+ // })
830
+ // // Trans for wx.xx, wx['xx'], wx.xx(), wx['xx']()
831
+ // parser.hooks.expressionAnyMember.for('wx').tap('MpxWebpackPlugin', transHandler)
1098
832
  // Proxy ctor for transMode
1099
833
  if (!this.options.forceDisableProxyCtor) {
1100
834
  parser.hooks.call.for('Page').tap('MpxWebpackPlugin', (expr) => {
1101
- transGlobalObject(expr.callee)
835
+ transHandler(expr.callee)
1102
836
  })
1103
837
  parser.hooks.call.for('Component').tap('MpxWebpackPlugin', (expr) => {
1104
- transGlobalObject(expr.callee)
838
+ transHandler(expr.callee)
1105
839
  })
1106
840
  parser.hooks.call.for('App').tap('MpxWebpackPlugin', (expr) => {
1107
- transGlobalObject(expr.callee)
841
+ transHandler(expr.callee)
1108
842
  })
1109
843
  if (mpx.mode === 'ali' || mpx.mode === 'web') {
1110
844
  // 支付宝和web不支持Behaviors
1111
845
  parser.hooks.call.for('Behavior').tap('MpxWebpackPlugin', (expr) => {
1112
- transGlobalObject(expr.callee)
846
+ transHandler(expr.callee)
1113
847
  })
1114
848
  }
1115
849
  }
850
+ }
1116
851
 
1117
- // 为跨平台api调用注入srcMode参数指导api运行时转换
1118
- const apiBlackListMap = [
1119
- 'createApp',
1120
- 'createPage',
1121
- 'createComponent',
1122
- 'createStore',
1123
- 'createStoreWithThis',
1124
- 'mixin',
1125
- 'injectMixins',
1126
- 'toPureObject',
1127
- 'observable',
1128
- 'watch',
1129
- 'use',
1130
- 'set',
1131
- 'remove',
1132
- 'delete',
1133
- 'setConvertRule',
1134
- 'getMixin',
1135
- 'getComputed',
1136
- 'implement'
1137
- ].reduce((map, api) => {
1138
- map[api] = true
1139
- return map
1140
- }, {})
1141
-
1142
- const injectSrcModeForTransApi = (expr, members) => {
1143
- // members为空数组时,callee并不是memberExpression
1144
- if (!members.length) return
1145
- const callee = expr.callee
1146
- const args = expr.arguments
1147
- const name = callee.object.name
1148
- const { queryObj, resourcePath } = parseRequest(parser.state.module.resource)
1149
- const localSrcMode = queryObj.mode
1150
- const globalSrcMode = mpx.srcMode
1151
- const srcMode = localSrcMode || globalSrcMode
1152
-
1153
- if (srcMode === globalSrcMode || apiBlackListMap[callee.property.name || callee.property.value] || (name !== 'mpx' && name !== 'wx') || (name === 'wx' && !matchCondition(resourcePath, this.options.transMpxRules))) return
1154
-
1155
- const srcModeString = `__mpx_src_mode_${srcMode}__`
1156
- const dep = new InjectDependency({
1157
- content: args.length
1158
- ? `, ${JSON.stringify(srcModeString)}`
1159
- : JSON.stringify(srcModeString),
1160
- index: expr.end - 1
1161
- })
1162
- parser.state.current.addPresentationalDependency(dep)
852
+ const apiBlackListMap = [
853
+ 'createApp',
854
+ 'createPage',
855
+ 'createComponent',
856
+ 'createStore',
857
+ 'createStoreWithThis',
858
+ 'mixin',
859
+ 'injectMixins',
860
+ 'toPureObject',
861
+ 'observable',
862
+ 'watch',
863
+ 'use',
864
+ 'set',
865
+ 'remove',
866
+ 'delete: del',
867
+ 'setConvertRule',
868
+ 'getMixin',
869
+ 'getComputed',
870
+ 'implement'
871
+ ].reduce((map, api) => {
872
+ map[api] = true
873
+ return map
874
+ }, {})
875
+
876
+ const handler = (expr) => {
877
+ const callee = expr.callee
878
+ const args = expr.arguments
879
+ const name = callee.object.name
880
+ const { queryObj, resourcePath } = parseRequest(parser.state.module.resource)
881
+ const localSrcMode = queryObj.mode
882
+ const globalSrcMode = mpx.srcMode
883
+ const srcMode = localSrcMode || globalSrcMode
884
+
885
+ if (srcMode === globalSrcMode || apiBlackListMap[callee.property.name || callee.property.value] || (name !== 'mpx' && name !== 'wx') || (name === 'wx' && !matchCondition(resourcePath, this.options.transMpxRules))) {
886
+ return
1163
887
  }
1164
888
 
1165
- parser.hooks.callMemberChain.for(harmonySpecifierTag).tap('MpxWebpackPlugin', injectSrcModeForTransApi)
1166
- parser.hooks.callMemberChain.for('mpx').tap('MpxWebpackPlugin', injectSrcModeForTransApi)
1167
- parser.hooks.callMemberChain.for('wx').tap('MpxWebpackPlugin', injectSrcModeForTransApi)
889
+ const srcModeString = `__mpx_src_mode_${srcMode}__`
890
+ const dep = new InjectDependency({
891
+ content: args.length
892
+ ? `, ${JSON.stringify(srcModeString)}`
893
+ : JSON.stringify(srcModeString),
894
+ index: expr.end - 1
895
+ })
896
+ parser.state.current.addDependency(dep)
1168
897
  }
1169
- })
1170
898
 
1171
- // 为了正确生成sourceMap,将该步骤由原来的compile.hooks.emit迁移到compilation.hooks.processAssets
1172
- compilation.hooks.processAssets.tap({
1173
- name: 'MpxWebpackPlugin',
1174
- stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONS
1175
- }, () => {
1176
- if (mpx.mode === 'web') return
1177
-
1178
- if (this.options.generateBuildMap) {
1179
- const pagesMap = compilation.__mpx__.pagesMap
1180
- const componentsPackageMap = compilation.__mpx__.componentsMap
1181
- const componentsMap = Object.keys(componentsPackageMap).map(item => componentsPackageMap[item]).reduce((pre, cur) => {
1182
- return { ...pre, ...cur }
1183
- }, {})
1184
- const outputMap = JSON.stringify({ ...pagesMap, ...componentsMap })
1185
- const filename = this.options.generateBuildMap.filename || 'outputMap.json'
1186
- compilation.assets[filename] = new RawSource(outputMap)
899
+ if (mpx.srcMode !== mpx.mode) {
900
+ parser.hooks.callAnyMember.for('imported var').tap('MpxWebpackPlugin', handler)
901
+ parser.hooks.callAnyMember.for('mpx').tap('MpxWebpackPlugin', handler)
902
+ parser.hooks.callAnyMember.for('wx').tap('MpxWebpackPlugin', handler)
1187
903
  }
904
+ })
1188
905
 
1189
- const {
1190
- globalObject,
1191
- chunkLoadingGlobal
1192
- } = compilation.outputOptions
906
+ // 为了正确生成sourceMap,将该步骤由原来的compile.hooks.emit迁移到compilation.hooks.optimizeChunkAssets中来
907
+ compilation.hooks.optimizeChunkAssets.tapAsync('MpxWebpackPlugin', (chunks, callback) => {
908
+ if (mpx.mode === 'web') return callback()
909
+ const jsonpFunction = compilation.outputOptions.jsonpFunction
1193
910
 
1194
911
  function getTargetFile (file) {
1195
912
  let targetFile = file
@@ -1201,23 +918,21 @@ class MpxWebpackPlugin {
1201
918
  }
1202
919
 
1203
920
  const processedChunk = new Set()
1204
- const appName = mpx.appInfo.name
921
+ const rootName = compilation._preparedEntrypoints[0].name
1205
922
 
1206
923
  function processChunk (chunk, isRuntime, relativeChunks) {
1207
- const chunkFile = chunk.files.values().next().value
1208
- if (!chunkFile || processedChunk.has(chunk)) {
924
+ if (!chunk.files[0] || processedChunk.has(chunk)) {
1209
925
  return
1210
926
  }
1211
927
 
1212
- let originalSource = compilation.assets[chunkFile]
928
+ let originalSource = compilation.assets[chunk.files[0]]
1213
929
  const source = new ConcatSource()
1214
- source.add(`\nvar ${globalObject} = ${globalObject} || {};\n\n`)
930
+ source.add('\nvar window = window || {};\n\n')
1215
931
 
1216
932
  relativeChunks.forEach((relativeChunk, index) => {
1217
- const relativeChunkFile = relativeChunk.files.values().next().value
1218
- if (!relativeChunkFile) return
1219
- let chunkPath = getTargetFile(chunkFile)
1220
- let relativePath = getTargetFile(relativeChunkFile)
933
+ if (!relativeChunk.files[0]) return
934
+ let chunkPath = getTargetFile(chunk.files[0])
935
+ let relativePath = getTargetFile(relativeChunk.files[0])
1221
936
  relativePath = path.relative(path.dirname(chunkPath), relativePath)
1222
937
  relativePath = fixRelative(relativePath, mpx.mode)
1223
938
  relativePath = toPosix(relativePath)
@@ -1225,19 +940,19 @@ class MpxWebpackPlugin {
1225
940
  // 引用runtime
1226
941
  // 支付宝分包独立打包,通过全局context获取webpackJSONP
1227
942
  if (mpx.mode === 'ali' && !mpx.isPluginMode) {
1228
- if (chunk.name === appName) {
1229
- // 在rootChunk中挂载jsonpCallback
943
+ if (chunk.name === rootName) {
944
+ // 在rootChunk中挂载jsonpFunction
1230
945
  source.add('// process ali subpackages runtime in root chunk\n' +
1231
946
  'var context = (function() { return this })() || Function("return this")();\n\n')
1232
- source.add(`context[${JSON.stringify(chunkLoadingGlobal)}] = ${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = require("${relativePath}");\n`)
947
+ source.add(`context[${JSON.stringify(jsonpFunction)}] = window[${JSON.stringify(jsonpFunction)}] = require("${relativePath}");\n`)
1233
948
  } else {
1234
949
  // 其余chunk中通过context全局传递runtime
1235
950
  source.add('// process ali subpackages runtime in other chunk\n' +
1236
951
  'var context = (function() { return this })() || Function("return this")();\n\n')
1237
- source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = context[${JSON.stringify(chunkLoadingGlobal)}];\n`)
952
+ source.add(`window[${JSON.stringify(jsonpFunction)}] = context[${JSON.stringify(jsonpFunction)}];\n`)
1238
953
  }
1239
954
  } else {
1240
- source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = require("${relativePath}");\n`)
955
+ source.add(`window[${JSON.stringify(jsonpFunction)}] = require("${relativePath}");\n`)
1241
956
  }
1242
957
  } else {
1243
958
  source.add(`require("${relativePath}");\n`)
@@ -1290,12 +1005,18 @@ try {
1290
1005
  } catch(e){
1291
1006
  }\n`)
1292
1007
  source.add(originalSource)
1293
- source.add(`\nmodule.exports = ${globalObject}[${JSON.stringify(chunkLoadingGlobal)}];\n`)
1008
+ source.add(`\nmodule.exports = window[${JSON.stringify(jsonpFunction)}];\n`)
1294
1009
  } else {
1010
+ if (mpx.pluginMainModule && chunk.entryModule && mpx.pluginMainModule === chunk.entryModule) {
1011
+ source.add('module.exports =\n')
1012
+ // mpx.miniToPluginExports is a Set
1013
+ } else if (mpx.miniToPluginModules && chunk.entryModule && mpx.miniToPluginModules.has(chunk.entryModule)) {
1014
+ source.add('module.exports =\n')
1015
+ }
1295
1016
  source.add(originalSource)
1296
1017
  }
1297
1018
 
1298
- compilation.assets[chunkFile] = source
1019
+ compilation.assets[chunk.files[0]] = source
1299
1020
  processedChunk.add(chunk)
1300
1021
  }
1301
1022
 
@@ -1332,109 +1053,57 @@ try {
1332
1053
  }
1333
1054
  }
1334
1055
  })
1056
+
1057
+ callback()
1335
1058
  })
1336
1059
  })
1337
1060
 
1338
1061
  compiler.hooks.normalModuleFactory.tap('MpxWebpackPlugin', (normalModuleFactory) => {
1339
1062
  // resolve前修改原始request
1340
- normalModuleFactory.hooks.beforeResolve.tap('MpxWebpackPlugin', (data) => {
1063
+ normalModuleFactory.hooks.beforeResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1341
1064
  let request = data.request
1342
1065
  let { queryObj, resource } = parseRequest(request)
1343
1066
  if (queryObj.resolve) {
1344
1067
  // 此处的query用于将资源引用的当前包信息传递给resolveDependency
1345
- const resolveLoaderPath = normalize.lib('resolve-loader')
1346
- data.request = `!!${resolveLoaderPath}!${resource}`
1347
- }
1348
- })
1349
-
1350
- const typeLoaderProcessInfo = {
1351
- styles: ['css-loader', wxssLoaderPath, styleCompilerPath],
1352
- template: ['html-loader', wxmlLoaderPath, templateCompilerPath]
1353
- }
1354
-
1355
- // 应用过rules后,注入mpx相关资源编译loader
1356
- normalModuleFactory.hooks.afterResolve.tap('MpxWebpackPlugin', ({ createData }) => {
1357
- const { queryObj } = parseRequest(createData.request)
1358
- const loaders = createData.loaders
1359
- if (queryObj.mpx && queryObj.mpx !== MPX_PROCESSED_FLAG) {
1360
- const type = queryObj.type
1361
- const extract = queryObj.extract
1362
- switch (type) {
1363
- case 'styles':
1364
- case 'template':
1365
- let insertBeforeIndex = -1
1366
- const info = typeLoaderProcessInfo[type]
1367
- loaders.forEach((loader, index) => {
1368
- const currentLoader = toPosix(loader.loader)
1369
- if (currentLoader.includes(info[0])) {
1370
- loader.loader = info[1]
1371
- insertBeforeIndex = index
1372
- } else if (currentLoader.includes(info[1])) {
1373
- insertBeforeIndex = index
1374
- }
1375
- })
1376
- if (insertBeforeIndex > -1) {
1377
- loaders.splice(insertBeforeIndex + 1, 0, {
1378
- loader: info[2]
1379
- })
1380
- }
1381
- break
1382
- case 'json':
1383
- if (queryObj.isTheme) {
1384
- loaders.unshift({
1385
- loader: jsonThemeCompilerPath
1386
- })
1387
- } else if (queryObj.isPlugin) {
1388
- loaders.unshift({
1389
- loader: jsonPluginCompilerPath
1390
- })
1391
- } else {
1392
- loaders.unshift({
1393
- loader: jsonCompilerPath
1394
- })
1395
- }
1396
- break
1397
- case 'wxs':
1398
- loaders.unshift({
1399
- loader: wxsLoaderPath
1400
- })
1401
- }
1402
- if (extract) {
1403
- loaders.unshift({
1404
- loader: extractorPath
1405
- })
1068
+ const pathLoader = normalize.lib('path-loader')
1069
+ resource = addQuery(resource, {
1070
+ packageRoot: mpx.currentPackageRoot
1071
+ })
1072
+ data.request = `!!${pathLoader}!${resource}`
1073
+ } else if (queryObj.wxsModule) {
1074
+ const wxsPreLoader = normalize.lib('wxs/wxs-pre-loader')
1075
+ if (!/wxs-loader/.test(request)) {
1076
+ data.request = `!!${wxsPreLoader}!${resource}`
1406
1077
  }
1407
- createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
1408
1078
  }
1079
+ callback(null, data)
1080
+ })
1409
1081
 
1410
- if (mpx.mode === 'web') {
1082
+ // resolve完成后修改loaders信息并批量添加mode query
1083
+ normalModuleFactory.hooks.afterResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1084
+ if (data.loaders) {
1085
+ const { queryObj } = parseRequest(data.request)
1411
1086
  const mpxStyleOptions = queryObj.mpxStyleOptions
1412
- const firstLoader = loaders[0] ? toPosix(loaders[0].loader) : ''
1413
- const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher') || firstLoader.includes('@hummer/tenon-loader/dist/pitcher.js')
1087
+ const firstLoader = (data.loaders[0] && data.loaders[0].loader) || ''
1088
+ const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher.js')
1414
1089
  let cssLoaderIndex = -1
1415
1090
  let vueStyleLoaderIndex = -1
1416
1091
  let mpxStyleLoaderIndex = -1
1417
- let tenonStyleLoaderIndex = -1
1418
- loaders.forEach((loader, index) => {
1419
- const currentLoader = toPosix(loader.loader)
1092
+ data.loaders.forEach((loader, index) => {
1093
+ const currentLoader = loader.loader
1094
+ if (currentLoader.includes('ts-loader')) {
1095
+ // todo 暂时固定写死options,待后续优化为复用rules后修正
1096
+ loader.options = { appendTsSuffixTo: [/\.(mpx|vue)$/] }
1097
+ }
1420
1098
  if (currentLoader.includes('css-loader')) {
1421
1099
  cssLoaderIndex = index
1422
- } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader')) {
1100
+ } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader.js')) {
1423
1101
  vueStyleLoaderIndex = index
1424
- } else if (currentLoader.includes('@hummer/tenon-style-loader/dist/index.js')) {
1425
- tenonStyleLoaderIndex = index
1426
- } else if (currentLoader.includes(styleCompilerPath)) {
1102
+ } else if (currentLoader.includes('@mpxjs/webpack-plugin/lib/style-compiler/index.js')) {
1427
1103
  mpxStyleLoaderIndex = index
1428
1104
  }
1429
1105
  })
1430
- if (mpx.mode === 'tenon' && mpxStyleLoaderIndex === -1) {
1431
- if (tenonStyleLoaderIndex > -1 && !isPitcherRequest) {
1432
- loaders.splice(tenonStyleLoaderIndex + 1, 0, {
1433
- loader: normalize.lib('style-compiler/index.js'),
1434
- options: (mpxStyleOptions && JSON.parse(mpxStyleOptions)) || {}
1435
- })
1436
- }
1437
- } else if (mpxStyleLoaderIndex === -1) {
1106
+ if (mpxStyleLoaderIndex === -1) {
1438
1107
  let loaderIndex = -1
1439
1108
  if (cssLoaderIndex > -1 && vueStyleLoaderIndex === -1) {
1440
1109
  loaderIndex = cssLoaderIndex
@@ -1442,70 +1111,37 @@ try {
1442
1111
  loaderIndex = vueStyleLoaderIndex
1443
1112
  }
1444
1113
  if (loaderIndex > -1) {
1445
- loaders.splice(loaderIndex + 1, 0, {
1446
- loader: styleCompilerPath,
1114
+ data.loaders.splice(loaderIndex + 1, 0, {
1115
+ loader: normalize.lib('style-compiler/index.js'),
1447
1116
  options: (mpxStyleOptions && JSON.parse(mpxStyleOptions)) || {}
1448
1117
  })
1449
1118
  }
1450
1119
  }
1451
1120
  }
1452
-
1453
- createData.request = stringifyLoadersAndResource(loaders, createData.resource)
1454
1121
  // 根据用户传入的modeRules对特定资源添加mode query
1455
- this.runModeRules(createData)
1122
+ this.runModeRules(data)
1123
+ callback(null, data)
1456
1124
  })
1457
1125
  })
1458
1126
 
1459
- const clearFileCache = () => {
1460
- const fs = compiler.intermediateFileSystem
1461
- const cacheLocation = compiler.options.cache.cacheLocation
1462
- return new Promise((resolve) => {
1463
- if (!cacheLocation) return resolve()
1464
- if (typeof fs.rm === 'function') {
1465
- fs.rm(cacheLocation, {
1466
- recursive: true,
1467
- force: true
1468
- }, resolve)
1469
- } else {
1470
- // polyfill fs.rm
1471
- const rm = (file, callback) => {
1472
- async.waterfall([
1473
- (callback) => {
1474
- fs.stat(file, callback)
1475
- },
1476
- (stats, callback) => {
1477
- if (stats.isDirectory()) {
1478
- const dir = file
1479
- fs.readdir(dir, (err, files) => {
1480
- if (err) return callback(err)
1481
- async.each(files, (file, callback) => {
1482
- file = path.join(dir, file)
1483
- rm(file, callback)
1484
- }, (err) => {
1485
- if (err) return callback(err)
1486
- fs.rmdir(dir, callback)
1487
- })
1488
- })
1489
- } else {
1490
- fs.unlink(file, callback)
1491
- }
1492
- }
1493
- ], callback)
1127
+ compiler.hooks.emit.tapAsync('MpxWebpackPlugin', (compilation, callback) => {
1128
+ if (this.options.generateBuildMap) {
1129
+ const pagesMap = compilation.__mpx__.pagesMap
1130
+ const componentsPackageMap = compilation.__mpx__.componentsMap
1131
+ const componentsMap = Object.keys(componentsPackageMap).map(item => componentsPackageMap[item]).reduce((pre, cur) => {
1132
+ return { ...pre, ...cur }
1133
+ }, {})
1134
+ const outputMap = JSON.stringify({ ...pagesMap, ...componentsMap })
1135
+ compilation.assets['../outputMap.json'] = {
1136
+ source: () => {
1137
+ return outputMap
1138
+ },
1139
+ size: () => {
1140
+ return Buffer.byteLength(outputMap, 'utf8')
1494
1141
  }
1495
- rm(cacheLocation, resolve)
1496
1142
  }
1497
- })
1498
- }
1499
-
1500
- compiler.hooks.done.tapPromise('MpxWebpackPlugin', async () => {
1501
- const cache = compiler.getCache('MpxWebpackPlugin')
1502
- const cacheIsValid = await cache.getPromise('cacheIsValid', null)
1503
- if (!cacheIsValid) {
1504
- await Promise.all([
1505
- clearFileCache(),
1506
- cache.storePromise('cacheIsValid', null, true)
1507
- ])
1508
1143
  }
1144
+ callback()
1509
1145
  })
1510
1146
  }
1511
1147
  }