@mpxjs/webpack-plugin 2.6.102 → 2.7.0-beta.1

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 (59) hide show
  1. package/lib/dependencies/AppEntryDependency.js +56 -0
  2. package/lib/dependencies/CommonJsVariableDependency.js +74 -0
  3. package/lib/dependencies/DynamicEntryDependency.js +127 -0
  4. package/lib/dependencies/FlagPluginDependency.js +23 -0
  5. package/lib/dependencies/InjectDependency.js +43 -0
  6. package/lib/dependencies/RecordGlobalComponentsDependency.js +50 -0
  7. package/lib/dependencies/RecordStaticResourceDependency.js +47 -0
  8. package/lib/{dependency → dependencies}/ReplaceDependency.js +19 -2
  9. package/lib/dependencies/ResolveDependency.js +83 -0
  10. package/lib/extractor.js +72 -179
  11. package/lib/file-loader.js +7 -19
  12. package/lib/helpers.js +41 -330
  13. package/lib/index.js +472 -356
  14. package/lib/json-compiler/helper.js +152 -0
  15. package/lib/json-compiler/index.js +148 -407
  16. package/lib/json-compiler/plugin.js +134 -0
  17. package/lib/json-compiler/{theme-loader.js → theme.js} +5 -3
  18. package/lib/loader.js +76 -171
  19. package/lib/native-loader.js +40 -70
  20. package/lib/record-loader.js +11 -0
  21. package/lib/{path-loader.js → resolve-loader.js} +0 -0
  22. package/lib/runtime/i18n.wxs +3 -3
  23. package/lib/selector.js +10 -7
  24. package/lib/style-compiler/index.js +20 -12
  25. package/lib/style-compiler/plugins/trans-special.js +21 -0
  26. package/lib/template-compiler/compiler.js +44 -176
  27. package/lib/template-compiler/index.js +47 -128
  28. package/lib/url-loader.js +11 -29
  29. package/lib/utils/add-query.js +1 -1
  30. package/lib/utils/const.js +5 -0
  31. package/lib/utils/emit-file.js +10 -0
  32. package/lib/utils/get-entry-name.js +13 -0
  33. package/lib/utils/is-url-request.js +10 -1
  34. package/lib/utils/normalize.js +0 -13
  35. package/lib/utils/parse-request.js +3 -3
  36. package/lib/utils/set.js +47 -0
  37. package/lib/utils/stringify-loaders-resource.js +25 -0
  38. package/lib/utils/stringify-query.js +4 -0
  39. package/lib/web/processScript.js +3 -3
  40. package/lib/web/processTemplate.js +2 -0
  41. package/lib/wxml/{wxml-loader.js → loader.js} +24 -60
  42. package/lib/wxs/WxsModuleIdsPlugin.js +32 -0
  43. package/lib/wxs/WxsParserPlugin.js +2 -2
  44. package/lib/wxs/WxsPlugin.js +4 -8
  45. package/lib/wxs/WxsTemplatePlugin.js +46 -92
  46. package/lib/wxs/{wxs-i18n-loader.js → i18n-loader.js} +0 -0
  47. package/lib/wxs/{wxs-loader.js → loader.js} +33 -38
  48. package/lib/wxs/{wxs-pre-loader.js → pre-loader.js} +0 -0
  49. package/lib/wxss/loader.js +31 -43
  50. package/lib/wxss/localsLoader.js +1 -5
  51. package/package.json +4 -8
  52. package/lib/content-loader.js +0 -13
  53. package/lib/dependency/ChildCompileDependency.js +0 -24
  54. package/lib/dependency/InjectDependency.js +0 -26
  55. package/lib/dependency/RemovedModuleDependency.js +0 -23
  56. package/lib/dependency/ResolveDependency.js +0 -49
  57. package/lib/plugin-loader.js +0 -287
  58. package/lib/utils/try-require.js +0 -16
  59. package/lib/wxss/getImportPrefix.js +0 -30
package/lib/index.js CHANGED
@@ -1,44 +1,81 @@
1
1
  'use strict'
2
2
 
3
3
  const path = require('path')
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')
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')
10
8
  const NullFactory = require('webpack/lib/NullFactory')
9
+ const CommonJsVariableDependency = require('./dependencies/CommonJsVariableDependency')
10
+ const NormalModule = require('webpack/lib/NormalModule')
11
+ const EntryPlugin = require('webpack/lib/EntryPlugin')
12
+ const JavascriptModulesPlugin = require('webpack/lib/javascript/JavascriptModulesPlugin')
11
13
  const normalize = require('./utils/normalize')
12
14
  const toPosix = require('./utils/to-posix')
13
15
  const addQuery = require('./utils/add-query')
16
+ const { every } = require('./utils/set')
14
17
  const DefinePlugin = require('webpack/lib/DefinePlugin')
15
18
  const ExternalsPlugin = require('webpack/lib/ExternalsPlugin')
16
19
  const AddModePlugin = require('./resolver/AddModePlugin')
17
20
  const AddEnvPlugin = require('./resolver/AddEnvPlugin')
18
21
  const PackageEntryPlugin = require('./resolver/PackageEntryPlugin')
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')
22
+ // const CommonJsRequireDependency = require('webpack/lib/dependencies/CommonJsRequireDependency')
23
+ // const HarmonyImportSideEffectDependency = require('webpack/lib/dependencies/HarmonyImportSideEffectDependency')
24
+ // const RequireHeaderDependency = require('webpack/lib/dependencies/RequireHeaderDependency')
25
+ // const RemovedModuleDependency = require('./dependencies/RemovedModuleDependency')
26
+ const AppEntryDependency = require('./dependencies/AppEntryDependency')
27
+ const RecordStaticResourceDependency = require('./dependencies/RecordStaticResourceDependency')
28
+ const RecordGlobalComponentsDependency = require('./dependencies/RecordGlobalComponentsDependency')
29
+ const DynamicEntryDependency = require('./dependencies/DynamicEntryDependency')
30
+ const FlagPluginDependency = require('./dependencies/FlagPluginDependency')
23
31
  const SplitChunksPlugin = require('webpack/lib/optimize/SplitChunksPlugin')
24
32
  const fixRelative = require('./utils/fix-relative')
25
33
  const parseRequest = require('./utils/parse-request')
26
34
  const matchCondition = require('./utils/match-condition')
27
35
  const { preProcessDefs } = require('./utils/index')
36
+ const config = require('./config')
28
37
  const hash = require('hash-sum')
38
+ const wxssLoaderPath = normalize.lib('wxss/loader')
39
+ const wxmlLoaderPath = normalize.lib('wxml/loader')
40
+ const wxsLoaderPath = normalize.lib('wxs/loader')
41
+ const styleCompilerPath = normalize.lib('style-compiler/index')
42
+ const templateCompilerPath = normalize.lib('template-compiler/index')
43
+ const jsonCompilerPath = normalize.lib('json-compiler/index')
44
+ const jsonThemeCompilerPath = normalize.lib('json-compiler/theme')
45
+ const jsonPluginCompilerPath = normalize.lib('json-compiler/plugin')
46
+ const extractorPath = normalize.lib('extractor')
47
+ const async = require('async')
48
+ const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource')
49
+ const emitFile = require('./utils/emit-file')
50
+ const { MPX_PROCESSED_FLAG, MPX_DISABLE_EXTRACTOR_CACHE } = require('./utils/const')
29
51
 
30
52
  const isProductionLikeMode = options => {
31
53
  return options.mode === 'production' || !options.mode
32
54
  }
33
55
 
56
+ const isStaticModule = module => {
57
+ if (!module.resource) return false
58
+ const { queryObj } = parseRequest(module.resource)
59
+ let isStatic = queryObj.isStatic || false
60
+ if (module.loaders) {
61
+ for (const loader of module.loaders) {
62
+ if (/(url-loader|file-loader)/.test(loader.loader)) {
63
+ isStatic = true
64
+ break
65
+ }
66
+ }
67
+ }
68
+ return isStatic
69
+ }
70
+
34
71
  const outputFilename = '[name].js'
35
72
  const publicPath = '/'
36
73
 
37
- function isChunkInPackage (chunkName, packageName) {
74
+ const isChunkInPackage = (chunkName, packageName) => {
38
75
  return (new RegExp(`^${packageName}\\/`)).test(chunkName)
39
76
  }
40
77
 
41
- function getPackageCacheGroup (packageName) {
78
+ const getPackageCacheGroup = packageName => {
42
79
  if (packageName === 'main') {
43
80
  return {
44
81
  name: 'bundle',
@@ -47,8 +84,9 @@ function getPackageCacheGroup (packageName) {
47
84
  }
48
85
  } else {
49
86
  return {
50
- test: (module, chunks) => {
51
- return chunks.every((chunk) => {
87
+ test: (module, { chunkGraph }) => {
88
+ const chunks = chunkGraph.getModuleChunksIterable(module)
89
+ return chunks.size && every(chunks, (chunk) => {
52
90
  return isChunkInPackage(chunk.name, packageName)
53
91
  })
54
92
  },
@@ -61,8 +99,6 @@ function getPackageCacheGroup (packageName) {
61
99
  }
62
100
  }
63
101
 
64
- let loaderOptions
65
-
66
102
  const externalsMap = {
67
103
  weui: /^weui-miniprogram/
68
104
  }
@@ -101,7 +137,7 @@ class MpxWebpackPlugin {
101
137
  options.resolveMode = options.resolveMode || 'webpack'
102
138
  options.writeMode = options.writeMode || 'changed'
103
139
  options.autoScopeRules = options.autoScopeRules || {}
104
- options.forceDisableInject = options.forceDisableInject || false
140
+ options.autoVirtualHostRules = options.autoVirtualHostRules || {}
105
141
  options.forceDisableProxyCtor = options.forceDisableProxyCtor || false
106
142
  options.transMpxRules = options.transMpxRules || {
107
143
  include: () => true
@@ -145,19 +181,30 @@ class MpxWebpackPlugin {
145
181
  }
146
182
 
147
183
  static loader (options = {}) {
148
- loaderOptions = options
149
- if (loaderOptions.transRpx) {
184
+ if (options.transRpx) {
150
185
  warnings.push('Mpx loader option [transRpx] is deprecated now, please use mpx webpack plugin config [transRpxRules] instead!')
151
186
  }
152
187
  return { loader: normalize.lib('loader'), options }
153
188
  }
154
189
 
190
+ static nativeLoader (options = {}) {
191
+ return { loader: normalize.lib('native-loader'), options }
192
+ }
193
+
194
+ static wxssLoader (options) {
195
+ return { loader: normalize.lib('wxss/loader'), options }
196
+ }
197
+
198
+ static wxmlLoader (options) {
199
+ return { loader: normalize.lib('wxml/loader'), options }
200
+ }
201
+
155
202
  static pluginLoader (options = {}) {
156
- return { loader: normalize.lib('plugin-loader'), options }
203
+ return { loader: normalize.lib('json-compiler/plugin'), options }
157
204
  }
158
205
 
159
206
  static wxsPreLoader (options = {}) {
160
- return { loader: normalize.lib('wxs/wxs-pre-loader'), options }
207
+ return { loader: normalize.lib('wxs/pre-loader'), options }
161
208
  }
162
209
 
163
210
  static urlLoader (options = {}) {
@@ -206,7 +253,6 @@ class MpxWebpackPlugin {
206
253
  if (!compiler.options.node || !compiler.options.node.global) {
207
254
  compiler.options.node = compiler.options.node || {}
208
255
  compiler.options.node.global = true
209
- warnings.push(`webpack options: MpxWebpackPlugin strongly depends options.node.globel to be true, custom options.node will be ignored!`)
210
256
  }
211
257
 
212
258
  const addModePlugin = new AddModePlugin('before-file', this.options.mode, this.options.fileConditionRules, 'file')
@@ -226,7 +272,8 @@ class MpxWebpackPlugin {
226
272
  let splitChunksOptions
227
273
 
228
274
  if (this.options.mode !== 'web') {
229
- compiler.options.optimization.runtimeChunk = {
275
+ const optimization = compiler.options.optimization
276
+ optimization.runtimeChunk = {
230
277
  name: (entrypoint) => {
231
278
  for (let packageName in mpx.independentSubpackagesMap) {
232
279
  if (mpx.independentSubpackagesMap.hasOwnProperty(packageName) && isChunkInPackage(entrypoint.name, packageName)) {
@@ -236,8 +283,18 @@ class MpxWebpackPlugin {
236
283
  return 'bundle'
237
284
  }
238
285
  }
239
- splitChunksOptions = compiler.options.optimization.splitChunks
240
- delete compiler.options.optimization.splitChunks
286
+ splitChunksOptions = Object.assign({
287
+ defaultSizeTypes: ['javascript', 'unknown'],
288
+ chunks: 'all',
289
+ usedExports: optimization.usedExports === true,
290
+ minChunks: 1,
291
+ minSize: 1000,
292
+ enforceSizeThreshold: Infinity,
293
+ maxAsyncRequests: 30,
294
+ maxInitialRequests: 30,
295
+ automaticNameDelimiter: '-'
296
+ }, optimization.splitChunks)
297
+ delete optimization.splitChunks
241
298
  splitChunksPlugin = new SplitChunksPlugin(splitChunksOptions)
242
299
  splitChunksPlugin.apply(compiler)
243
300
  }
@@ -257,6 +314,8 @@ class MpxWebpackPlugin {
257
314
  }
258
315
  const defs = this.options.defs
259
316
 
317
+ const typeExtMap = config[this.options.mode].typeExtMap
318
+
260
319
  const defsOpt = {
261
320
  '__mpx_wxs__': DefinePlugin.runtimeValue(({ module }) => {
262
321
  return JSON.stringify(!!module.wxs)
@@ -274,12 +333,41 @@ class MpxWebpackPlugin {
274
333
 
275
334
  let mpx
276
335
 
336
+ // 构建分包队列,在finishMake钩子当中最先执行,stage传递-1000
337
+ compiler.hooks.finishMake.tapAsync({
338
+ name: 'MpxWebpackPlugin',
339
+ stage: -1000
340
+ }, (compilation, callback) => {
341
+ const mpx = compilation.__mpx__
342
+ if (mpx && mpx.subpackagesEntriesMap) {
343
+ async.eachOfSeries(mpx.subpackagesEntriesMap, (deps, packageRoot, callback) => {
344
+ mpx.currentPackageRoot = packageRoot
345
+ mpx.componentsMap[packageRoot] = {}
346
+ mpx.staticResourcesMap[packageRoot] = {}
347
+ mpx.subpackageModulesMap[packageRoot] = {}
348
+ async.each(deps, (dep, callback) => {
349
+ dep.addEntry(compilation, (err, { resultPath }) => {
350
+ if (err) return callback(err)
351
+ mpx.replacePathMap[dep.key] = resultPath
352
+ callback()
353
+ })
354
+ }, callback)
355
+ }, callback)
356
+ } else {
357
+ callback()
358
+ }
359
+ })
360
+
277
361
  compiler.hooks.compilation.tap('MpxWebpackPlugin ', (compilation, { normalModuleFactory }) => {
278
- compilation.hooks.normalModuleLoader.tap('MpxWebpackPlugin', (loaderContext, module) => {
362
+ NormalModule.getCompilationHooks(compilation).loader.tap('MpxWebpackPlugin', (loaderContext, module) => {
279
363
  // 设置loaderContext的minimize
280
364
  if (isProductionLikeMode(compiler.options)) {
281
365
  loaderContext.minimize = true
282
366
  }
367
+
368
+ loaderContext.getMpx = () => {
369
+ return mpx
370
+ }
283
371
  })
284
372
  compilation.dependencyFactories.set(ResolveDependency, new NullFactory())
285
373
  compilation.dependencyTemplates.set(ResolveDependency, new ResolveDependency.Template())
@@ -290,151 +378,76 @@ class MpxWebpackPlugin {
290
378
  compilation.dependencyFactories.set(ReplaceDependency, new NullFactory())
291
379
  compilation.dependencyTemplates.set(ReplaceDependency, new ReplaceDependency.Template())
292
380
 
293
- compilation.dependencyFactories.set(ChildCompileDependency, new NullFactory())
294
- compilation.dependencyTemplates.set(ChildCompileDependency, new ChildCompileDependency.Template())
295
-
296
- compilation.dependencyFactories.set(RemovedModuleDependency, normalModuleFactory)
297
- compilation.dependencyTemplates.set(RemovedModuleDependency, new RemovedModuleDependency.Template())
298
-
299
- // hack cacheGroup参数往addModule中传递当前module的issuer
300
- const rawAddModuleDependencies = compilation.addModuleDependencies
301
- compilation.addModuleDependencies = (
302
- module,
303
- dependencies,
304
- bail,
305
- cacheGroup,
306
- recursive,
307
- callback
308
- ) => {
309
- const hackedCacheGroup = {
310
- module,
311
- cacheGroup
312
- }
313
- return rawAddModuleDependencies.call(
314
- compilation,
315
- module,
316
- dependencies,
317
- bail,
318
- hackedCacheGroup,
319
- recursive,
320
- callback
321
- )
322
- }
381
+ compilation.dependencyFactories.set(AppEntryDependency, new NullFactory())
382
+ compilation.dependencyTemplates.set(AppEntryDependency, new AppEntryDependency.Template())
323
383
 
324
- // 处理watch时缓存模块中的buildInfo
325
- // 在调用addModule前对module添加分包信息,以控制分包输出及消除缓存,该操作由afterResolve钩子迁移至此是由于dependencyCache的存在,watch状态下afterResolve钩子并不会对所有模块执行,而模块的packageName在watch过程中是可能发生变更的,如新增删除一个分包资源的主包引用
326
- const rawAddModule = compilation.addModule
327
- compilation.addModule = (module, cacheGroup) => {
328
- let issuerResource
329
- if (cacheGroup && cacheGroup.module) {
330
- issuerResource = cacheGroup.module.resource
331
- cacheGroup = cacheGroup.cacheGroup
332
- }
333
- // 避免context module报错
334
- if (module.request && module.resource) {
335
- const { queryObj, resourcePath } = parseRequest(module.resource)
336
- let isStatic = queryObj.isStatic
337
- if (module.loaders) {
338
- module.loaders.forEach((loader) => {
339
- if (/(url-loader|file-loader)/.test(loader.loader)) {
340
- isStatic = true
341
- }
342
- })
343
- }
344
- const isIndependent = mpx.independentSubpackagesMap[mpx.currentPackageRoot]
384
+ compilation.dependencyFactories.set(DynamicEntryDependency, new NullFactory())
385
+ compilation.dependencyTemplates.set(DynamicEntryDependency, new DynamicEntryDependency.Template())
345
386
 
346
- let needPackageQuery = isStatic || isIndependent
347
- if (!needPackageQuery && matchCondition(resourcePath, this.options.subpackageModulesRules)) {
348
- needPackageQuery = true
349
- }
387
+ compilation.dependencyFactories.set(FlagPluginDependency, new NullFactory())
388
+ compilation.dependencyTemplates.set(FlagPluginDependency, new FlagPluginDependency.Template())
350
389
 
351
- if (needPackageQuery) {
352
- const { packageRoot } = mpx.getPackageInfo({
353
- resource: module.resource,
354
- resourceType: isStatic ? 'staticResources' : 'subpackageModules',
355
- issuerResource,
356
- warn (e) {
357
- compilation.warnings.push(e)
358
- },
359
- error (e) {
360
- compilation.errors.push(e)
361
- }
362
- })
363
- if (packageRoot) {
364
- module.request = addQuery(module.request, { packageRoot })
365
- module.resource = addQuery(module.resource, { packageRoot })
366
- }
367
- }
368
- }
390
+ compilation.dependencyFactories.set(RecordStaticResourceDependency, new NullFactory())
391
+ compilation.dependencyTemplates.set(RecordStaticResourceDependency, new RecordStaticResourceDependency.Template())
369
392
 
370
- const addModuleResult = rawAddModule.call(compilation, module, cacheGroup)
371
- if (!addModuleResult.build && addModuleResult.issuer) {
372
- const buildInfo = addModuleResult.module.buildInfo
373
- if (buildInfo.pagesMap) {
374
- Object.assign(mpx.pagesMap, buildInfo.pagesMap)
375
- }
376
- if (buildInfo.componentsMap && buildInfo.packageName) {
377
- Object.assign(mpx.componentsMap[buildInfo.packageName], buildInfo.componentsMap)
378
- }
379
- }
380
- return addModuleResult
381
- }
393
+ compilation.dependencyFactories.set(RecordGlobalComponentsDependency, new NullFactory())
394
+ compilation.dependencyTemplates.set(RecordGlobalComponentsDependency, new RecordGlobalComponentsDependency.Template())
395
+
396
+ compilation.dependencyFactories.set(CommonJsVariableDependency, normalModuleFactory)
397
+ compilation.dependencyTemplates.set(CommonJsVariableDependency, new CommonJsVariableDependency.Template())
382
398
  })
383
399
 
384
400
  compiler.hooks.thisCompilation.tap('MpxWebpackPlugin', (compilation, { normalModuleFactory }) => {
385
401
  compilation.warnings = compilation.warnings.concat(warnings)
386
402
  compilation.errors = compilation.errors.concat(errors)
387
- // additionalAssets和mpx由于包含缓存机制,必须在每次compilation时重新初始化
388
- const additionalAssets = {}
403
+ const moduleGraph = compilation.moduleGraph
389
404
  if (!compilation.__mpx__) {
390
405
  // init mpx
391
406
  mpx = compilation.__mpx__ = {
407
+ // app信息,便于获取appName
408
+ appInfo: {},
392
409
  // pages全局记录,无需区分主包分包
393
410
  pagesMap: {},
394
- // 记录pages对应的entry,处理多appEntry输出web多页项目时可能出现的pagePath冲突的问题,多appEntry输出目前仅web模式支持
395
- pagesEntryMap: {},
396
- // 组件资源记录,依照所属包进行记录,冗余存储,只要某个包有引用会添加对应记录,不管其会不会在当前包输出,这样设计主要是为了在resolve时能够以较低成本找到特定资源的输出路径
411
+ // 组件资源记录,依照所属包进行记录
397
412
  componentsMap: {
398
413
  main: {}
399
414
  },
400
- // 静态资源(图片,字体,独立样式)等,依照所属包进行记录,冗余存储,同上
415
+ // 静态资源(图片,字体,独立样式)等,依照所属包进行记录
401
416
  staticResourcesMap: {
402
417
  main: {}
403
418
  },
404
- // 用于记录命中subpackageModulesRules的js模块最终输出到了什么分包中
419
+ // 用于记录命中subpackageModulesRules的js模块分包归属,用于js多分包冗余输出
405
420
  subpackageModulesMap: {
406
421
  main: {}
407
422
  },
423
+ // 记录其他资源,如pluginMain、pluginExport,无需区分主包分包
424
+ otherResourcesMap: {},
408
425
  // 记录独立分包
409
426
  independentSubpackagesMap: {},
410
- // 当前机制下分包处理队列在app.json的json-compiler中进行,由于addEntry回调特性,无法保障app.js中引用的模块都被标记为主包,故重写processModuleDependencies获取app.js及其所有依赖处理完成的时机,在这之后再执行分包处理队列
411
- appScriptRawRequest: '',
412
- appScriptPromise: null,
427
+ subpackagesEntriesMap: {},
428
+ replacePathMap: {},
429
+ exportModules: new Set(),
413
430
  // 记录entry依赖关系,用于体积分析
414
431
  entryNodesMap: {},
415
432
  // 记录entryModule与entryNode的对应关系,用于体积分析
416
433
  entryModulesMap: new Map(),
417
- loaderOptions,
418
434
  extractedMap: {},
419
435
  usingComponents: {},
420
- hasApp: false,
421
436
  // todo es6 map读写性能高于object,之后会逐步替换
422
437
  vueContentCache: new Map(),
423
438
  currentPackageRoot: '',
424
439
  wxsMap: {},
425
440
  wxsContentMap: {},
426
441
  assetsInfo: new Map(),
427
- forceDisableInject: this.options.forceDisableInject,
428
442
  forceUsePageCtor: this.options.forceUsePageCtor,
429
443
  resolveMode: this.options.resolveMode,
430
444
  mode: this.options.mode,
431
445
  srcMode: this.options.srcMode,
432
446
  env: this.options.env,
433
- // deprecated option
434
- globalMpxAttrsFilter: this.options.globalMpxAttrsFilter,
435
447
  externalClasses: this.options.externalClasses,
436
448
  projectRoot: this.options.projectRoot,
437
449
  autoScopeRules: this.options.autoScopeRules,
450
+ autoVirtualHostRules: this.options.autoVirtualHostRules,
438
451
  transRpxRules: this.options.transRpxRules,
439
452
  postcssInlineConfig: this.options.postcssInlineConfig,
440
453
  decodeHTMLText: this.options.decodeHTMLText,
@@ -471,47 +484,71 @@ class MpxWebpackPlugin {
471
484
  return currentEntry
472
485
  },
473
486
  pathHash: (resourcePath) => {
474
- let hashPath = resourcePath
475
- const pathHashMode = this.options.pathHashMode
476
- const projectRoot = this.options.projectRoot || ''
477
- if (pathHashMode === 'relative') {
478
- hashPath = path.relative(projectRoot, resourcePath)
479
- }
480
- if (typeof pathHashMode === 'function') {
481
- hashPath = pathHashMode(resourcePath, projectRoot) || resourcePath
487
+ if (this.options.pathHashMode === 'relative' && this.options.projectRoot) {
488
+ return hash(path.relative(this.options.projectRoot, resourcePath))
482
489
  }
483
- return hash(hashPath)
490
+ return hash(resourcePath)
484
491
  },
485
- extract: (content, file, index, sideEffects) => {
486
- index = index === -1 ? 0 : index
487
- additionalAssets[file] = additionalAssets[file] || []
488
- if (!additionalAssets[file][index]) {
489
- additionalAssets[file][index] = content
492
+ addEntry (request, name, callback) {
493
+ const dep = EntryPlugin.createDependency(request, { name })
494
+ compilation.addEntry(compiler.context, dep, { name }, callback)
495
+ return dep
496
+ },
497
+ extractedFilesCache: new Map(),
498
+ getExtractedFile: (resource, { error } = {}) => {
499
+ const cache = mpx.extractedFilesCache.get(resource)
500
+ if (cache) return cache
501
+ const { resourcePath, queryObj } = parseRequest(resource)
502
+ const type = queryObj.type
503
+ const isStatic = queryObj.isStatic
504
+ const isPlugin = queryObj.isPlugin
505
+ let file
506
+ if (isPlugin) {
507
+ file = 'plugin.json'
508
+ } else if (isStatic) {
509
+ const packageRoot = queryObj.packageRoot || ''
510
+ const resourceName = path.parse(resourcePath).name
511
+ file = toPosix(path.join(packageRoot, type, resourceName + mpx.pathHash(resourcePath) + typeExtMap[type]))
512
+ } else {
513
+ const appInfo = mpx.appInfo
514
+ const pagesMap = mpx.pagesMap
515
+ const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
516
+ const componentsMap = mpx.componentsMap[packageName]
517
+ let filename = resourcePath === appInfo.resourcePath ? appInfo.name : (pagesMap[resourcePath] || componentsMap[resourcePath])
518
+ if (!filename) {
519
+ error && error(new Error('Get extracted file error: missing filename!'))
520
+ filename = 'missing-filename'
521
+ }
522
+ file = filename + typeExtMap[type]
490
523
  }
491
- sideEffects && sideEffects.forEach((sideEffect) => {
492
- sideEffect(additionalAssets)
493
- })
524
+ mpx.extractedFilesCache.set(resource, file)
525
+ return file
494
526
  },
495
527
  // 组件和静态资源的输出规则如下:
496
528
  // 1. 主包引用的资源输出至主包
497
529
  // 2. 分包引用且主包引用过的资源输出至主包,不在当前分包重复输出
498
530
  // 3. 分包引用且无其他包引用的资源输出至当前分包
499
531
  // 4. 分包引用且其他分包也引用过的资源,重复输出至当前分包
500
- getPackageInfo: ({ resource, outputPath, resourceType = 'components', issuerResource, warn }) => {
532
+ getPackageInfo: ({ resource, outputPath, resourceType, issuerResource, warn, error }) => {
501
533
  let packageRoot = ''
502
534
  let packageName = 'main'
503
- const resourceMap = mpx[`${resourceType}Map`]
504
- const { queryObj, resourcePath } = parseRequest(resource)
505
- if (resourceType === 'staticResources' && outputPath) {
506
- packageRoot = queryObj.packageRoot || ''
507
- packageName = packageRoot || 'main'
535
+ let currentResourceMap = {}
536
+
537
+ const { resourcePath } = parseRequest(resource)
538
+ const currentPackageRoot = mpx.currentPackageRoot
539
+ const currentPackageName = currentPackageRoot || 'main'
540
+ const isIndependent = mpx.independentSubpackagesMap[currentPackageRoot]
541
+ const resourceMap = mpx[`${resourceType}sMap`] || mpx.otherResourcesMap
542
+
543
+ if (!resourceMap.main) {
544
+ currentResourceMap = resourceMap
545
+ packageRoot = currentPackageRoot
546
+ packageName = currentPackageName
508
547
  } else {
509
- const currentPackageRoot = mpx.currentPackageRoot
510
- const currentPackageName = currentPackageRoot || 'main'
511
- const isIndependent = mpx.independentSubpackagesMap[currentPackageRoot]
512
548
  // 主包中有引用一律使用主包中资源,不再额外输出
513
549
  // 资源路径匹配到forceMainPackageRules规则时强制输出到主包,降低分包资源冗余
514
550
  // 如果存在issuer且issuerPackageRoot与当前packageRoot不一致,也输出到主包
551
+ // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
515
552
  let isMain = resourceMap.main[resourcePath] || matchCondition(resourcePath, this.options.forceMainPackageRules)
516
553
  if (issuerResource) {
517
554
  const { queryObj } = parseRequest(issuerResource)
@@ -521,25 +558,23 @@ class MpxWebpackPlugin {
521
558
  isMain = true
522
559
  }
523
560
  }
524
- // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
525
561
  if (!isMain || isIndependent) {
526
562
  packageRoot = currentPackageRoot
527
563
  packageName = currentPackageName
528
- if (this.options.auditResource && resourceType !== 'subpackageModules' && !isIndependent) {
529
- if (this.options.auditResource !== 'component' || resourceType === 'components') {
564
+ if (this.options.auditResource && resourceType !== 'subpackageModule' && !isIndependent) {
565
+ if (this.options.auditResource !== 'component' || resourceType === 'component') {
530
566
  Object.keys(resourceMap).filter(key => key !== 'main').forEach((key) => {
531
567
  if (resourceMap[key][resourcePath] && key !== packageName) {
532
- warn && warn(new Error(`当前${resourceType === 'components' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
568
+ warn && warn(new Error(`当前${resourceType === 'component' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
533
569
  }
534
570
  })
535
571
  }
536
572
  }
537
573
  }
574
+ resourceMap[packageName] = resourceMap[packageName] || {}
575
+ currentResourceMap = resourceMap[packageName]
538
576
  }
539
577
 
540
- resourceMap[packageName] = resourceMap[packageName] || {}
541
- const currentResourceMap = resourceMap[packageName]
542
-
543
578
  let alreadyOutputed = false
544
579
  if (outputPath) {
545
580
  outputPath = toPosix(path.join(packageRoot, outputPath))
@@ -548,6 +583,15 @@ class MpxWebpackPlugin {
548
583
  alreadyOutputed = true
549
584
  } else {
550
585
  currentResourceMap[resourcePath] = outputPath
586
+ // 输出冲突检测只有page需要
587
+ if (resourceType === 'page') {
588
+ for (let key in currentResourceMap) {
589
+ if (currentResourceMap[key] === outputPath && key !== resourcePath) {
590
+ error && error(new Error(`Current ${resourceType} [${resourcePath}] registers a same output path [${outputPath}] with existed ${resourceType} [${key}], which is not allowed!`))
591
+ break
592
+ }
593
+ }
594
+ }
551
595
  }
552
596
  } else if (!currentResourceMap[resourcePath]) {
553
597
  currentResourceMap[resourcePath] = true
@@ -565,20 +609,95 @@ class MpxWebpackPlugin {
565
609
 
566
610
  const rawProcessModuleDependencies = compilation.processModuleDependencies
567
611
  compilation.processModuleDependencies = (module, callback) => {
612
+ const presentationalDependencies = module.presentationalDependencies || []
613
+ async.forEach(presentationalDependencies.filter((dep) => dep.mpxAction), (dep, callback) => {
614
+ dep.mpxAction(module, compilation, callback)
615
+ }, (err) => {
616
+ if (err) return callback(err)
617
+ rawProcessModuleDependencies.call(compilation, module, callback)
618
+ })
619
+ }
620
+
621
+ const rawFactorizeModule = compilation.factorizeModule
622
+ compilation.factorizeModule = (options, callback) => {
623
+ const originModule = options.originModule
568
624
  let proxyedCallback = callback
569
- if (module.rawRequest === mpx.appScriptRawRequest) {
570
- // 避免模块request重名,只对第一次匹配到的模块进行代理
571
- mpx.appScriptRawRequest = ''
572
- mpx.appScriptPromise = new Promise((resolve) => {
573
- proxyedCallback = (err) => {
574
- resolve()
575
- return callback(err)
625
+ if (originModule) {
626
+ proxyedCallback = (err, module) => {
627
+ // 避免selfModuleFactory的情况
628
+ if (module && module !== originModule) {
629
+ module.issuerResource = originModule.resource
576
630
  }
577
- })
631
+ return callback(err, module)
632
+ }
633
+ }
634
+ return rawFactorizeModule.call(compilation, options, proxyedCallback)
635
+ }
636
+
637
+ // 处理watch时缓存模块中的buildInfo
638
+ // 在调用addModule前对module添加分包信息,以控制分包输出及消除缓存,该操作由afterResolve钩子迁移至此是由于dependencyCache的存在,watch状态下afterResolve钩子并不会对所有模块执行,而模块的packageName在watch过程中是可能发生变更的,如新增删除一个分包资源的主包引用
639
+ const rawAddModule = compilation.addModule
640
+ compilation.addModule = (module, callback) => {
641
+ const issuerResource = module.issuerResource
642
+ // 避免context module报错
643
+ if (module.request && module.resource) {
644
+ const isStatic = isStaticModule(module)
645
+ const isIndependent = mpx.independentSubpackagesMap[mpx.currentPackageRoot]
646
+
647
+ let needPackageQuery = isStatic || isIndependent
648
+
649
+ if (!needPackageQuery) {
650
+ const { resourcePath } = parseRequest(module.resource)
651
+ needPackageQuery = matchCondition(resourcePath, this.options.subpackageModulesRules)
652
+ }
653
+
654
+ if (needPackageQuery) {
655
+ const { packageRoot } = mpx.getPackageInfo({
656
+ resource: module.resource,
657
+ resourceType: isStatic ? 'staticResource' : 'subpackageModule',
658
+ issuerResource,
659
+ warn (e) {
660
+ compilation.warnings.push(e)
661
+ },
662
+ error (e) {
663
+ compilation.errors.push(e)
664
+ }
665
+ })
666
+ if (packageRoot) {
667
+ module.request = addQuery(module.request, { packageRoot })
668
+ module.resource = addQuery(module.resource, { packageRoot })
669
+ }
670
+ }
578
671
  }
579
- return rawProcessModuleDependencies.apply(compilation, [module, proxyedCallback])
672
+
673
+ return rawAddModule.call(compilation, module, callback)
580
674
  }
581
675
 
676
+ const rawEmitAsset = compilation.emitAsset
677
+
678
+ compilation.emitAsset = (file, source, assetInfo) => {
679
+ if (assetInfo && assetInfo.skipEmit) return
680
+ return rawEmitAsset.call(compilation, file, source, assetInfo)
681
+ }
682
+
683
+ compilation.hooks.succeedModule.tap('MpxWebpackPlugin', (module) => {
684
+ // 静态资源模块由于输出结果的动态性,通过importModule会合并asset的特性,通过emitFile传递信息禁用父级extractor的缓存来保障父级的importModule每次都能被执行
685
+ if (isStaticModule(module)) {
686
+ emitFile(module, MPX_DISABLE_EXTRACTOR_CACHE, '', undefined, { skipEmit: true })
687
+ }
688
+ })
689
+
690
+ // todo 统一通过dep+mpx actions处理
691
+ compilation.hooks.stillValidModule.tap('MpxWebpackPlugin', (module) => {
692
+ const buildInfo = module.buildInfo
693
+ if (buildInfo.pagesMap) {
694
+ Object.assign(mpx.pagesMap, buildInfo.pagesMap)
695
+ }
696
+ if (buildInfo.componentsMap && buildInfo.packageName) {
697
+ Object.assign(mpx.componentsMap[buildInfo.packageName], buildInfo.componentsMap)
698
+ }
699
+ })
700
+
582
701
  compilation.hooks.finishModules.tap('MpxWebpackPlugin', (modules) => {
583
702
  // 自动跟进分包配置修改splitChunksPlugin配置
584
703
  if (splitChunksPlugin) {
@@ -590,45 +709,15 @@ class MpxWebpackPlugin {
590
709
  }
591
710
  })
592
711
  if (needInit) {
593
- splitChunksPlugin.options = SplitChunksPlugin.normalizeOptions(splitChunksOptions)
712
+ splitChunksPlugin.options = new SplitChunksPlugin(splitChunksOptions).options
594
713
  }
595
714
  }
596
715
  })
597
716
 
598
- compilation.hooks.optimizeModules.tap('MpxWebpackPlugin', (modules) => {
599
- modules.forEach((module) => {
600
- if (module.needRemove) {
601
- let removed = false
602
- module.reasons.forEach((reason) => {
603
- if (reason.module) {
604
- if (reason.dependency instanceof HarmonyImportSideEffectDependency) {
605
- reason.module.removeDependency(reason.dependency)
606
- reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module))
607
- removed = true
608
- } else if (reason.dependency instanceof CommonJsRequireDependency && reason.dependency.loc.range) {
609
- let index = reason.module.dependencies.indexOf(reason.dependency)
610
- if (index > -1 && reason.module.dependencies[index + 1] instanceof RequireHeaderDependency) {
611
- reason.module.dependencies.splice(index, 2)
612
- reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module, reason.dependency.loc.range))
613
- removed = true
614
- }
615
- }
616
- }
617
- })
618
- if (removed) {
619
- module.chunksIterable.forEach((chunk) => {
620
- module.removeChunk(chunk)
621
- })
622
- module.disconnect()
623
- }
624
- }
625
- })
626
- })
627
-
628
- compilation.moduleTemplates.javascript.hooks.content.tap('MpxWebpackPlugin', (source, module, options) => {
717
+ JavascriptModulesPlugin.getCompilationHooks(compilation).renderModuleContent.tap('MpxWebpackPlugin', (source, module, renderContext) => {
629
718
  // 处理dll产生的external模块
630
719
  if (module.external && module.userRequest.startsWith('dll-reference ') && mpx.mode !== 'web') {
631
- const chunk = options.chunk
720
+ const chunk = renderContext.chunk
632
721
  const request = module.request
633
722
  let relativePath = toPosix(path.relative(path.dirname(chunk.name), request))
634
723
  if (!/^\.\.?\//.test(relativePath)) relativePath = './' + relativePath
@@ -639,77 +728,63 @@ class MpxWebpackPlugin {
639
728
  return source
640
729
  })
641
730
 
642
- compilation.hooks.additionalAssets.tapAsync('MpxWebpackPlugin', (callback) => {
643
- for (let file in additionalAssets) {
644
- let content = new ConcatSource()
645
- if (additionalAssets[file].prefix) {
646
- additionalAssets[file].prefix.forEach((item) => {
647
- if (item) content.add(item)
648
- })
649
- }
650
- additionalAssets[file].forEach((item) => {
651
- if (item) content.add(item)
652
- })
653
- const modules = (additionalAssets[file].modules || []).concat(additionalAssets[file].relativeModules || [])
654
-
655
- if (modules.length > 1) {
656
- // 同步relativeModules和modules之间的依赖
657
- const fileDependencies = new Set()
658
- const contextDependencies = new Set()
659
-
660
- modules.forEach((module) => {
661
- module.buildInfo.fileDependencies.forEach((fileDependency) => {
662
- fileDependencies.add(fileDependency)
663
- })
664
- module.buildInfo.contextDependencies.forEach((contextDependency) => {
665
- contextDependencies.add(contextDependency)
666
- })
667
- module.buildInfo.fileDependencies = fileDependencies
668
- module.buildInfo.contextDependencies = contextDependencies
669
- })
731
+ compilation.hooks.beforeModuleAssets.tap('MpxWebpackPlugin', () => {
732
+ const extractedAssetsMap = new Map()
733
+ for (const module of compilation.modules) {
734
+ const assetsInfo = module.buildInfo.assetsInfo || new Map()
735
+ for (const [filename, { extractedInfo } = {}] of assetsInfo) {
736
+ if (extractedInfo) {
737
+ let extractedAssets = extractedAssetsMap.get(filename)
738
+ if (!extractedAssets) {
739
+ extractedAssets = []
740
+ extractedAssetsMap.set(filename, extractedAssets)
741
+ }
742
+ extractedAssets.push(extractedInfo)
743
+ // todo 后续计算体积时可以通过这个钩子关联静态assets和module
744
+ // compilation.hooks.moduleAsset.call(module, filename)
745
+ }
670
746
  }
671
- compilation.emitAsset(file, content, { modules: additionalAssets[file].modules })
672
747
  }
673
- // 所有编译的静态资源assetsInfo合入主编译
674
- mpx.assetsInfo.forEach((assetInfo, name) => {
675
- const oldAssetInfo = compilation.assetsInfo.get(name)
676
- if (oldAssetInfo && oldAssetInfo.modules) {
677
- assetInfo.modules = assetInfo.modules.concat(oldAssetInfo.modules)
678
- }
679
- compilation.assetsInfo.set(name, assetInfo)
680
- })
681
- // 链接主编译模块与子编译入口
682
- Object.values(mpx.wxsMap).concat(Object.values(mpx.extractedMap)).forEach((item) => {
683
- item.modules.forEach((module) => {
684
- module.addDependency(item.dep)
685
- })
686
- })
687
748
 
688
- callback()
749
+ for (const [filename, extractedAssets] of extractedAssetsMap) {
750
+ const sortedExtractedAssets = extractedAssets.sort((a, b) => a.index - b.index)
751
+ const source = new ConcatSource()
752
+ sortedExtractedAssets.forEach(({ content }) => {
753
+ if (content) {
754
+ // 处理replace path
755
+ if (/"mpx_replace_path_.*?"/.test(content)) {
756
+ content = content.replace(/"mpx_replace_path_(.*?)"/g, (matched, key) => {
757
+ return JSON.stringify(mpx.replacePathMap[key] || 'missing replace path')
758
+ })
759
+ }
760
+ source.add(content)
761
+ }
762
+ })
763
+ compilation.emitAsset(filename, source)
764
+ }
689
765
  })
690
766
 
691
767
  normalModuleFactory.hooks.parser.for('javascript/auto').tap('MpxWebpackPlugin', (parser) => {
692
- // hack预处理,将expr.range写入loc中便于在CommonJsRequireDependency中获取,移除无效require
693
- parser.hooks.call.for('require').tap({ name: 'MpxWebpackPlugin', stage: -100 }, (expr) => {
694
- expr.loc.range = expr.range
695
- })
696
-
697
768
  parser.hooks.call.for('__mpx_resolve_path__').tap('MpxWebpackPlugin', (expr) => {
698
769
  if (expr.arguments[0]) {
699
770
  const resource = expr.arguments[0].value
700
- const { queryObj } = parseRequest(resource)
701
- const packageName = queryObj.packageRoot || 'main'
702
- const pagesMap = mpx.pagesMap
703
- const componentsMap = mpx.componentsMap
704
- const staticResourcesMap = mpx.staticResourcesMap
771
+ const packageName = mpx.currentPackageRoot || 'main'
772
+ const issuerResource = moduleGraph.getIssuer(parser.state.module).resource
705
773
  const range = expr.range
706
- const issuerResource = parser.state.module.issuer.resource
707
- const dep = new ResolveDependency(resource, packageName, pagesMap, componentsMap, staticResourcesMap, publicPath, range, issuerResource, compilation)
708
- parser.state.current.addDependency(dep)
774
+ const dep = new ResolveDependency(resource, packageName, issuerResource, range)
775
+ parser.state.current.addPresentationalDependency(dep)
709
776
  return true
710
777
  }
711
778
  })
712
779
 
780
+ parser.hooks.call.for('__mpx_dynamic_entry__').tap('MpxWebpackPlugin', (expr) => {
781
+ const args = expr.arguments.map((i) => i.value)
782
+ args.push(expr.range)
783
+ const dep = new DynamicEntryDependency(...args)
784
+ parser.state.current.addPresentationalDependency(dep)
785
+ return true
786
+ })
787
+
713
788
  const transHandler = (expr) => {
714
789
  const module = parser.state.module
715
790
  const current = parser.state.current
@@ -733,31 +808,21 @@ class MpxWebpackPlugin {
733
808
  const type = target.name
734
809
 
735
810
  const name = type === 'wx' ? 'mpx' : 'createFactory'
736
- const replaceContent = type === 'wx' ? '__webpack_require__.n(mpx)()' : `__webpack_require__.n(createFactory)()(${JSON.stringify(type)})`
811
+ const replaceContent = type === 'wx' ? 'mpx' : `createFactory(${JSON.stringify(type)})`
737
812
 
738
813
  const dep = new ReplaceDependency(replaceContent, target.range)
739
- current.addDependency(dep)
814
+ current.addPresentationalDependency(dep)
740
815
 
741
816
  let needInject = true
742
- for (let v of module.variables) {
743
- if (v.name === name) {
817
+ for (let dep of module.dependencies) {
818
+ if (dep instanceof CommonJsVariableDependency && dep.name === name) {
744
819
  needInject = false
745
820
  break
746
821
  }
747
822
  }
748
823
  if (needInject) {
749
- const expression = `require(${JSON.stringify(`@mpxjs/core/src/runtime/${name}`)})`
750
- const deps = []
751
- parser.parse(expression, {
752
- current: {
753
- addDependency: dep => {
754
- dep.userRequest = name
755
- deps.push(dep)
756
- }
757
- },
758
- module
759
- })
760
- module.addVariable(name, expression, deps)
824
+ const dep = new CommonJsVariableDependency(`@mpxjs/core/src/runtime/${name}`, name)
825
+ module.addDependency(dep)
761
826
  }
762
827
  }
763
828
  // hack babel polyfill global
@@ -765,7 +830,7 @@ class MpxWebpackPlugin {
765
830
  if (/core-js.+microtask/.test(parser.state.module.resource)) {
766
831
  if (expr.test.left && (expr.test.left.name === 'Observer' || expr.test.left.name === 'MutationObserver')) {
767
832
  const current = parser.state.current
768
- current.addDependency(new InjectDependency({
833
+ current.addPresentationalDependency(new InjectDependency({
769
834
  content: 'document && ',
770
835
  index: expr.test.range[0]
771
836
  }))
@@ -781,7 +846,7 @@ class MpxWebpackPlugin {
781
846
  // todo 该逻辑在corejs3中不需要,等corejs3比较普及之后可以干掉
782
847
  if (/core-js.+global/.test(parser.state.module.resource)) {
783
848
  if (callee.name === 'Function' && arg0 && arg0.value === 'return this') {
784
- current.addDependency(new InjectDependency({
849
+ current.addPresentationalDependency(new InjectDependency({
785
850
  content: '(function() { return this })() || ',
786
851
  index: expr.range[0]
787
852
  }))
@@ -789,7 +854,7 @@ class MpxWebpackPlugin {
789
854
  }
790
855
  if (/regenerator-runtime/.test(parser.state.module.resource)) {
791
856
  if (callee.name === 'Function' && arg0 && arg0.value === 'r' && arg1 && arg1.value === 'regeneratorRuntime = r') {
792
- current.addDependency(new ReplaceDependency('(function () {})', expr.range))
857
+ current.addPresentationalDependency(new ReplaceDependency('(function () {})', expr.range))
793
858
  }
794
859
  }
795
860
  })
@@ -806,7 +871,7 @@ class MpxWebpackPlugin {
806
871
  // }
807
872
  // })
808
873
  // // Trans for wx.xx, wx['xx'], wx.xx(), wx['xx']()
809
- // parser.hooks.expressionAnyMember.for('wx').tap('MpxWebpackPlugin', transHandler)
874
+ // parser.hooks.expressionMemberChain.for('wx').tap('MpxWebpackPlugin', transHandler)
810
875
  // Proxy ctor for transMode
811
876
  if (!this.options.forceDisableProxyCtor) {
812
877
  parser.hooks.call.for('Page').tap('MpxWebpackPlugin', (expr) => {
@@ -871,20 +936,29 @@ class MpxWebpackPlugin {
871
936
  : JSON.stringify(srcModeString),
872
937
  index: expr.end - 1
873
938
  })
874
- parser.state.current.addDependency(dep)
939
+ parser.state.current.addPresentationalDependency(dep)
875
940
  }
876
941
 
877
942
  if (mpx.srcMode !== mpx.mode) {
878
- parser.hooks.callAnyMember.for('imported var').tap('MpxWebpackPlugin', handler)
879
- parser.hooks.callAnyMember.for('mpx').tap('MpxWebpackPlugin', handler)
880
- parser.hooks.callAnyMember.for('wx').tap('MpxWebpackPlugin', handler)
943
+ parser.hooks.callMemberChain.for('imported var').tap('MpxWebpackPlugin', handler)
944
+ parser.hooks.callMemberChain.for('mpx').tap('MpxWebpackPlugin', handler)
945
+ parser.hooks.callMemberChain.for('wx').tap('MpxWebpackPlugin', handler)
881
946
  }
882
947
  })
883
948
 
884
- // 为了正确生成sourceMap,将该步骤由原来的compile.hooks.emit迁移到compilation.hooks.optimizeChunkAssets中来
885
- compilation.hooks.optimizeChunkAssets.tapAsync('MpxWebpackPlugin', (chunks, callback) => {
886
- if (mpx.mode === 'web') return callback()
887
- const jsonpFunction = compilation.outputOptions.jsonpFunction
949
+ // 为了正确生成sourceMap,将该步骤由原来的compile.hooks.emit迁移到compilation.hooks.processAssets
950
+ compilation.hooks.processAssets.tap({
951
+ name: 'MpxWebpackPlugin',
952
+ stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONS
953
+ }, () => {
954
+ if (mpx.mode === 'web') return
955
+
956
+ const {
957
+ globalObject,
958
+ chunkLoadingGlobal
959
+ } = compilation.outputOptions
960
+
961
+ const { chunkGraph } = compilation
888
962
 
889
963
  function getTargetFile (file) {
890
964
  let targetFile = file
@@ -896,21 +970,24 @@ class MpxWebpackPlugin {
896
970
  }
897
971
 
898
972
  const processedChunk = new Set()
899
- const rootName = compilation._preparedEntrypoints[0].name
973
+ // const rootName = compilation.entries.keys().next().value
974
+ const appName = mpx.appInfo.name
900
975
 
901
976
  function processChunk (chunk, isRuntime, relativeChunks) {
902
- if (!chunk.files[0] || processedChunk.has(chunk)) {
977
+ const chunkFile = chunk.files.values().next().value
978
+ if (!chunkFile || processedChunk.has(chunk)) {
903
979
  return
904
980
  }
905
981
 
906
- let originalSource = compilation.assets[chunk.files[0]]
982
+ let originalSource = compilation.assets[chunkFile]
907
983
  const source = new ConcatSource()
908
- source.add('\nvar window = window || {};\n\n')
984
+ source.add(`\nvar ${globalObject} = ${globalObject} || {};\n\n`)
909
985
 
910
986
  relativeChunks.forEach((relativeChunk, index) => {
911
- if (!relativeChunk.files[0]) return
912
- let chunkPath = getTargetFile(chunk.files[0])
913
- let relativePath = getTargetFile(relativeChunk.files[0])
987
+ const relativeChunkFile = relativeChunk.files.values().next().value
988
+ if (!relativeChunkFile) return
989
+ let chunkPath = getTargetFile(chunkFile)
990
+ let relativePath = getTargetFile(relativeChunkFile)
914
991
  relativePath = path.relative(path.dirname(chunkPath), relativePath)
915
992
  relativePath = fixRelative(relativePath, mpx.mode)
916
993
  relativePath = toPosix(relativePath)
@@ -918,19 +995,19 @@ class MpxWebpackPlugin {
918
995
  // 引用runtime
919
996
  // 支付宝分包独立打包,通过全局context获取webpackJSONP
920
997
  if (mpx.mode === 'ali' && !mpx.isPluginMode) {
921
- if (chunk.name === rootName) {
922
- // 在rootChunk中挂载jsonpFunction
998
+ if (chunk.name === appName) {
999
+ // 在rootChunk中挂载jsonpCallback
923
1000
  source.add('// process ali subpackages runtime in root chunk\n' +
924
1001
  'var context = (function() { return this })() || Function("return this")();\n\n')
925
- source.add(`context[${JSON.stringify(jsonpFunction)}] = window[${JSON.stringify(jsonpFunction)}] = require("${relativePath}");\n`)
1002
+ source.add(`context[${JSON.stringify(chunkLoadingGlobal)}] = ${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = require("${relativePath}");\n`)
926
1003
  } else {
927
1004
  // 其余chunk中通过context全局传递runtime
928
1005
  source.add('// process ali subpackages runtime in other chunk\n' +
929
1006
  'var context = (function() { return this })() || Function("return this")();\n\n')
930
- source.add(`window[${JSON.stringify(jsonpFunction)}] = context[${JSON.stringify(jsonpFunction)}];\n`)
1007
+ source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = context[${JSON.stringify(chunkLoadingGlobal)}];\n`)
931
1008
  }
932
1009
  } else {
933
- source.add(`window[${JSON.stringify(jsonpFunction)}] = require("${relativePath}");\n`)
1010
+ source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = require("${relativePath}");\n`)
934
1011
  }
935
1012
  } else {
936
1013
  source.add(`require("${relativePath}");\n`)
@@ -966,18 +1043,17 @@ try {
966
1043
  } catch(e){
967
1044
  }\n`)
968
1045
  source.add(originalSource)
969
- source.add(`\nmodule.exports = window[${JSON.stringify(jsonpFunction)}];\n`)
1046
+ source.add(`\nmodule.exports = ${globalObject}[${JSON.stringify(chunkLoadingGlobal)}];\n`)
970
1047
  } else {
971
- if (mpx.pluginMainModule && chunk.entryModule && mpx.pluginMainModule === chunk.entryModule) {
972
- source.add('module.exports =\n')
973
- // mpx.miniToPluginExports is a Set
974
- } else if (mpx.miniToPluginModules && chunk.entryModule && mpx.miniToPluginModules.has(chunk.entryModule)) {
1048
+ const entryModules = chunkGraph.getChunkEntryModulesIterable(chunk)
1049
+ const entryModule = entryModules && entryModules[0]
1050
+ if (entryModule && mpx.exportModules.has(entryModule)) {
975
1051
  source.add('module.exports =\n')
976
1052
  }
977
1053
  source.add(originalSource)
978
1054
  }
979
1055
 
980
- compilation.assets[chunk.files[0]] = source
1056
+ compilation.assets[chunkFile] = source
981
1057
  processedChunk.add(chunk)
982
1058
  }
983
1059
 
@@ -1014,74 +1090,114 @@ try {
1014
1090
  }
1015
1091
  }
1016
1092
  })
1017
-
1018
- callback()
1019
1093
  })
1020
1094
  })
1021
1095
 
1022
1096
  compiler.hooks.normalModuleFactory.tap('MpxWebpackPlugin', (normalModuleFactory) => {
1023
1097
  // resolve前修改原始request
1024
- normalModuleFactory.hooks.beforeResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1098
+ normalModuleFactory.hooks.beforeResolve.tap('MpxWebpackPlugin', (data) => {
1025
1099
  let request = data.request
1026
1100
  let { queryObj, resource } = parseRequest(request)
1027
1101
  if (queryObj.resolve) {
1028
1102
  // 此处的query用于将资源引用的当前包信息传递给resolveDependency
1029
- const pathLoader = normalize.lib('path-loader')
1030
- resource = addQuery(resource, {
1031
- packageRoot: mpx.currentPackageRoot
1032
- })
1033
- data.request = `!!${pathLoader}!${resource}`
1034
- } else if (queryObj.wxsModule) {
1035
- const wxsPreLoader = normalize.lib('wxs/wxs-pre-loader')
1036
- if (!/wxs-loader/.test(request)) {
1037
- data.request = `!!${wxsPreLoader}!${resource}`
1038
- }
1103
+ const resolveLoaderPath = normalize.lib('resolve-loader')
1104
+ data.request = `!!${resolveLoaderPath}!${resource}`
1039
1105
  }
1040
- callback(null, data)
1041
1106
  })
1042
1107
 
1043
- // resolve完成后修改loaders信息并批量添加mode query
1044
- normalModuleFactory.hooks.afterResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1045
- if (data.loaders) {
1046
- const { queryObj } = parseRequest(data.request)
1047
- const mpxStyleOptions = queryObj.mpxStyleOptions
1048
- const firstLoader = (data.loaders[0] && data.loaders[0].loader) || ''
1049
- const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher.js')
1050
- let cssLoaderIndex = -1
1051
- let vueStyleLoaderIndex = -1
1052
- let mpxStyleLoaderIndex = -1
1053
- data.loaders.forEach((loader, index) => {
1054
- const currentLoader = loader.loader
1055
- if (currentLoader.includes('ts-loader')) {
1056
- // todo 暂时固定写死options,待后续优化为复用rules后修正
1057
- loader.options = { appendTsSuffixTo: [/\.(mpx|vue)$/] }
1058
- }
1059
- if (currentLoader.includes('css-loader')) {
1060
- cssLoaderIndex = index
1061
- } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader.js')) {
1062
- vueStyleLoaderIndex = index
1063
- } else if (currentLoader.includes('@mpxjs/webpack-plugin/lib/style-compiler/index.js')) {
1064
- mpxStyleLoaderIndex = index
1065
- }
1066
- })
1067
- if (mpxStyleLoaderIndex === -1) {
1068
- let loaderIndex = -1
1069
- if (cssLoaderIndex > -1 && vueStyleLoaderIndex === -1) {
1070
- loaderIndex = cssLoaderIndex
1071
- } else if (cssLoaderIndex > -1 && vueStyleLoaderIndex > -1 && !isPitcherRequest) {
1072
- loaderIndex = vueStyleLoaderIndex
1073
- }
1074
- if (loaderIndex > -1) {
1075
- data.loaders.splice(loaderIndex + 1, 0, {
1076
- loader: normalize.lib('style-compiler/index.js'),
1077
- options: (mpxStyleOptions && JSON.parse(mpxStyleOptions)) || {}
1108
+ const typeLoaderProcessInfo = {
1109
+ styles: ['css-loader', wxssLoaderPath, styleCompilerPath],
1110
+ template: ['html-loader', wxmlLoaderPath, templateCompilerPath]
1111
+ }
1112
+
1113
+ // 应用过rules后,注入mpx相关资源编译loader
1114
+ normalModuleFactory.hooks.afterResolve.tap('MpxWebpackPlugin', ({ createData }) => {
1115
+ const { queryObj } = parseRequest(createData.request)
1116
+ const loaders = createData.loaders
1117
+ if (queryObj.mpx && queryObj.mpx !== MPX_PROCESSED_FLAG) {
1118
+ const type = queryObj.type
1119
+ const extract = queryObj.extract
1120
+ switch (type) {
1121
+ case 'styles':
1122
+ case 'template':
1123
+ let insertBeforeIndex = -1
1124
+ const info = typeLoaderProcessInfo[type]
1125
+ loaders.forEach((loader, index) => {
1126
+ if (loader.loader.includes(info[0])) {
1127
+ loader.loader = info[1]
1128
+ }
1129
+ if (loader.loader === info[1]) {
1130
+ insertBeforeIndex = index
1131
+ }
1078
1132
  })
1079
- }
1133
+ if (insertBeforeIndex > -1) {
1134
+ loaders.splice(insertBeforeIndex + 1, 0, {
1135
+ loader: info[2]
1136
+ })
1137
+ }
1138
+ break
1139
+ case 'json':
1140
+ if (queryObj.isTheme) {
1141
+ loaders.unshift({
1142
+ loader: jsonThemeCompilerPath
1143
+ })
1144
+ } else if (queryObj.isPlugin) {
1145
+ loaders.unshift({
1146
+ loader: jsonPluginCompilerPath
1147
+ })
1148
+ } else {
1149
+ loaders.unshift({
1150
+ loader: jsonCompilerPath
1151
+ })
1152
+ }
1153
+ break
1154
+ case 'wxs':
1155
+ loaders.unshift({
1156
+ loader: wxsLoaderPath
1157
+ })
1158
+ }
1159
+ if (extract) {
1160
+ loaders.unshift({
1161
+ loader: extractorPath
1162
+ })
1080
1163
  }
1164
+
1165
+ createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
1166
+ createData.request = stringifyLoadersAndResource(loaders, createData.resource)
1081
1167
  }
1168
+
1169
+ // const mpxStyleOptions = queryObj.mpxStyleOptions
1170
+ // const firstLoader = (data.loaders[0] && data.loaders[0].loader) || ''
1171
+ // const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher.js')
1172
+ // let cssLoaderIndex = -1
1173
+ // let vueStyleLoaderIndex = -1
1174
+ // let mpxStyleLoaderIndex = -1
1175
+ // data.loaders.forEach((loader, index) => {
1176
+ // const currentLoader = loader.loader
1177
+ // if (currentLoader.includes('css-loader')) {
1178
+ // cssLoaderIndex = index
1179
+ // } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader.js')) {
1180
+ // vueStyleLoaderIndex = index
1181
+ // } else if (currentLoader.includes('@mpxjs/webpack-plugin/lib/style-compiler/index.js')) {
1182
+ // mpxStyleLoaderIndex = index
1183
+ // }
1184
+ // })
1185
+ // if (mpxStyleLoaderIndex === -1) {
1186
+ // let loaderIndex = -1
1187
+ // if (cssLoaderIndex > -1 && vueStyleLoaderIndex === -1) {
1188
+ // loaderIndex = cssLoaderIndex
1189
+ // } else if (cssLoaderIndex > -1 && vueStyleLoaderIndex > -1 && !isPitcherRequest) {
1190
+ // loaderIndex = vueStyleLoaderIndex
1191
+ // }
1192
+ // if (loaderIndex > -1) {
1193
+ // data.loaders.splice(loaderIndex + 1, 0, {
1194
+ // loader: normalize.lib('style-compiler/index.js'),
1195
+ // options: (mpxStyleOptions && JSON.parse(mpxStyleOptions)) || {}
1196
+ // })
1197
+ // }
1198
+ // }
1082
1199
  // 根据用户传入的modeRules对特定资源添加mode query
1083
- this.runModeRules(data)
1084
- callback(null, data)
1200
+ this.runModeRules(createData)
1085
1201
  })
1086
1202
  })
1087
1203