@mpxjs/webpack-plugin 2.6.100 → 2.7.0-alpha.0

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