@mpxjs/webpack-plugin 2.6.103 → 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 (58) 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 -331
  13. package/lib/index.js +475 -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 +78 -177
  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 +8 -7
  24. package/lib/style-compiler/index.js +14 -15
  25. package/lib/template-compiler/compiler.js +16 -153
  26. package/lib/template-compiler/index.js +46 -132
  27. package/lib/url-loader.js +11 -29
  28. package/lib/utils/add-query.js +1 -1
  29. package/lib/utils/const.js +5 -0
  30. package/lib/utils/emit-file.js +10 -0
  31. package/lib/utils/get-entry-name.js +13 -0
  32. package/lib/utils/is-url-request.js +10 -1
  33. package/lib/utils/normalize.js +0 -13
  34. package/lib/utils/parse-request.js +3 -3
  35. package/lib/utils/set.js +47 -0
  36. package/lib/utils/stringify-loaders-resource.js +25 -0
  37. package/lib/utils/stringify-query.js +4 -0
  38. package/lib/web/processScript.js +3 -3
  39. package/lib/web/processTemplate.js +2 -0
  40. package/lib/wxml/{wxml-loader.js → loader.js} +24 -60
  41. package/lib/wxs/WxsModuleIdsPlugin.js +32 -0
  42. package/lib/wxs/WxsParserPlugin.js +2 -2
  43. package/lib/wxs/WxsPlugin.js +4 -8
  44. package/lib/wxs/WxsTemplatePlugin.js +46 -92
  45. package/lib/wxs/{wxs-i18n-loader.js → i18n-loader.js} +0 -0
  46. package/lib/wxs/{wxs-loader.js → loader.js} +33 -38
  47. package/lib/wxs/{wxs-pre-loader.js → pre-loader.js} +0 -0
  48. package/lib/wxss/loader.js +31 -43
  49. package/lib/wxss/localsLoader.js +1 -5
  50. package/package.json +4 -8
  51. package/lib/content-loader.js +0 -13
  52. package/lib/dependency/ChildCompileDependency.js +0 -24
  53. package/lib/dependency/InjectDependency.js +0 -26
  54. package/lib/dependency/RemovedModuleDependency.js +0 -23
  55. package/lib/dependency/ResolveDependency.js +0 -49
  56. package/lib/plugin-loader.js +0 -287
  57. package/lib/utils/try-require.js +0 -16
  58. 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
  }
@@ -102,7 +137,6 @@ class MpxWebpackPlugin {
102
137
  options.writeMode = options.writeMode || 'changed'
103
138
  options.autoScopeRules = options.autoScopeRules || {}
104
139
  options.autoVirtualHostRules = options.autoVirtualHostRules || {}
105
- options.forceDisableInject = options.forceDisableInject || false
106
140
  options.forceDisableProxyCtor = options.forceDisableProxyCtor || false
107
141
  options.transMpxRules = options.transMpxRules || {
108
142
  include: () => true
@@ -146,19 +180,30 @@ class MpxWebpackPlugin {
146
180
  }
147
181
 
148
182
  static loader (options = {}) {
149
- loaderOptions = options
150
- if (loaderOptions.transRpx) {
183
+ if (options.transRpx) {
151
184
  warnings.push('Mpx loader option [transRpx] is deprecated now, please use mpx webpack plugin config [transRpxRules] instead!')
152
185
  }
153
186
  return { loader: normalize.lib('loader'), options }
154
187
  }
155
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
+
156
201
  static pluginLoader (options = {}) {
157
- return { loader: normalize.lib('plugin-loader'), options }
202
+ return { loader: normalize.lib('json-compiler/plugin'), options }
158
203
  }
159
204
 
160
205
  static wxsPreLoader (options = {}) {
161
- return { loader: normalize.lib('wxs/wxs-pre-loader'), options }
206
+ return { loader: normalize.lib('wxs/pre-loader'), options }
162
207
  }
163
208
 
164
209
  static urlLoader (options = {}) {
@@ -207,7 +252,6 @@ class MpxWebpackPlugin {
207
252
  if (!compiler.options.node || !compiler.options.node.global) {
208
253
  compiler.options.node = compiler.options.node || {}
209
254
  compiler.options.node.global = true
210
- warnings.push(`webpack options: MpxWebpackPlugin strongly depends options.node.globel to be true, custom options.node will be ignored!`)
211
255
  }
212
256
 
213
257
  const addModePlugin = new AddModePlugin('before-file', this.options.mode, this.options.fileConditionRules, 'file')
@@ -227,7 +271,8 @@ class MpxWebpackPlugin {
227
271
  let splitChunksOptions
228
272
 
229
273
  if (this.options.mode !== 'web') {
230
- compiler.options.optimization.runtimeChunk = {
274
+ const optimization = compiler.options.optimization
275
+ optimization.runtimeChunk = {
231
276
  name: (entrypoint) => {
232
277
  for (let packageName in mpx.independentSubpackagesMap) {
233
278
  if (mpx.independentSubpackagesMap.hasOwnProperty(packageName) && isChunkInPackage(entrypoint.name, packageName)) {
@@ -237,8 +282,18 @@ class MpxWebpackPlugin {
237
282
  return 'bundle'
238
283
  }
239
284
  }
240
- splitChunksOptions = compiler.options.optimization.splitChunks
241
- 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
242
297
  splitChunksPlugin = new SplitChunksPlugin(splitChunksOptions)
243
298
  splitChunksPlugin.apply(compiler)
244
299
  }
@@ -258,6 +313,8 @@ class MpxWebpackPlugin {
258
313
  }
259
314
  const defs = this.options.defs
260
315
 
316
+ const typeExtMap = config[this.options.mode].typeExtMap
317
+
261
318
  const defsOpt = {
262
319
  '__mpx_wxs__': DefinePlugin.runtimeValue(({ module }) => {
263
320
  return JSON.stringify(!!module.wxs)
@@ -275,12 +332,41 @@ class MpxWebpackPlugin {
275
332
 
276
333
  let mpx
277
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
+
278
360
  compiler.hooks.compilation.tap('MpxWebpackPlugin ', (compilation, { normalModuleFactory }) => {
279
- compilation.hooks.normalModuleLoader.tap('MpxWebpackPlugin', (loaderContext, module) => {
361
+ NormalModule.getCompilationHooks(compilation).loader.tap('MpxWebpackPlugin', (loaderContext, module) => {
280
362
  // 设置loaderContext的minimize
281
363
  if (isProductionLikeMode(compiler.options)) {
282
364
  loaderContext.minimize = true
283
365
  }
366
+
367
+ loaderContext.getMpx = () => {
368
+ return mpx
369
+ }
284
370
  })
285
371
  compilation.dependencyFactories.set(ResolveDependency, new NullFactory())
286
372
  compilation.dependencyTemplates.set(ResolveDependency, new ResolveDependency.Template())
@@ -291,148 +377,72 @@ class MpxWebpackPlugin {
291
377
  compilation.dependencyFactories.set(ReplaceDependency, new NullFactory())
292
378
  compilation.dependencyTemplates.set(ReplaceDependency, new ReplaceDependency.Template())
293
379
 
294
- compilation.dependencyFactories.set(ChildCompileDependency, new NullFactory())
295
- compilation.dependencyTemplates.set(ChildCompileDependency, new ChildCompileDependency.Template())
296
-
297
- compilation.dependencyFactories.set(RemovedModuleDependency, normalModuleFactory)
298
- compilation.dependencyTemplates.set(RemovedModuleDependency, new RemovedModuleDependency.Template())
299
-
300
- // hack cacheGroup参数往addModule中传递当前module的issuer
301
- const rawAddModuleDependencies = compilation.addModuleDependencies
302
- compilation.addModuleDependencies = (
303
- module,
304
- dependencies,
305
- bail,
306
- cacheGroup,
307
- recursive,
308
- callback
309
- ) => {
310
- const hackedCacheGroup = {
311
- module,
312
- cacheGroup
313
- }
314
- return rawAddModuleDependencies.call(
315
- compilation,
316
- module,
317
- dependencies,
318
- bail,
319
- hackedCacheGroup,
320
- recursive,
321
- callback
322
- )
323
- }
380
+ compilation.dependencyFactories.set(AppEntryDependency, new NullFactory())
381
+ compilation.dependencyTemplates.set(AppEntryDependency, new AppEntryDependency.Template())
324
382
 
325
- // 处理watch时缓存模块中的buildInfo
326
- // 在调用addModule前对module添加分包信息,以控制分包输出及消除缓存,该操作由afterResolve钩子迁移至此是由于dependencyCache的存在,watch状态下afterResolve钩子并不会对所有模块执行,而模块的packageName在watch过程中是可能发生变更的,如新增删除一个分包资源的主包引用
327
- const rawAddModule = compilation.addModule
328
- compilation.addModule = (module, cacheGroup) => {
329
- let issuerResource
330
- if (cacheGroup && cacheGroup.module) {
331
- issuerResource = cacheGroup.module.resource
332
- cacheGroup = cacheGroup.cacheGroup
333
- }
334
- // 避免context module报错
335
- if (module.request && module.resource) {
336
- const { queryObj, resourcePath } = parseRequest(module.resource)
337
- let isStatic = queryObj.isStatic
338
- if (module.loaders) {
339
- module.loaders.forEach((loader) => {
340
- if (/(url-loader|file-loader)/.test(loader.loader)) {
341
- isStatic = true
342
- }
343
- })
344
- }
345
- const isIndependent = mpx.independentSubpackagesMap[mpx.currentPackageRoot]
383
+ compilation.dependencyFactories.set(DynamicEntryDependency, new NullFactory())
384
+ compilation.dependencyTemplates.set(DynamicEntryDependency, new DynamicEntryDependency.Template())
346
385
 
347
- let needPackageQuery = isStatic || isIndependent
348
- if (!needPackageQuery && matchCondition(resourcePath, this.options.subpackageModulesRules)) {
349
- needPackageQuery = true
350
- }
386
+ compilation.dependencyFactories.set(FlagPluginDependency, new NullFactory())
387
+ compilation.dependencyTemplates.set(FlagPluginDependency, new FlagPluginDependency.Template())
351
388
 
352
- if (needPackageQuery) {
353
- const { packageRoot } = mpx.getPackageInfo({
354
- resource: module.resource,
355
- resourceType: isStatic ? 'staticResources' : 'subpackageModules',
356
- issuerResource,
357
- warn (e) {
358
- compilation.warnings.push(e)
359
- },
360
- error (e) {
361
- compilation.errors.push(e)
362
- }
363
- })
364
- if (packageRoot) {
365
- module.request = addQuery(module.request, { packageRoot })
366
- module.resource = addQuery(module.resource, { packageRoot })
367
- }
368
- }
369
- }
389
+ compilation.dependencyFactories.set(RecordStaticResourceDependency, new NullFactory())
390
+ compilation.dependencyTemplates.set(RecordStaticResourceDependency, new RecordStaticResourceDependency.Template())
370
391
 
371
- const addModuleResult = rawAddModule.call(compilation, module, cacheGroup)
372
- if (!addModuleResult.build && addModuleResult.issuer) {
373
- const buildInfo = addModuleResult.module.buildInfo
374
- if (buildInfo.pagesMap) {
375
- Object.assign(mpx.pagesMap, buildInfo.pagesMap)
376
- }
377
- if (buildInfo.componentsMap && buildInfo.packageName) {
378
- Object.assign(mpx.componentsMap[buildInfo.packageName], buildInfo.componentsMap)
379
- }
380
- }
381
- return addModuleResult
382
- }
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())
383
397
  })
384
398
 
385
399
  compiler.hooks.thisCompilation.tap('MpxWebpackPlugin', (compilation, { normalModuleFactory }) => {
386
400
  compilation.warnings = compilation.warnings.concat(warnings)
387
401
  compilation.errors = compilation.errors.concat(errors)
388
- // additionalAssets和mpx由于包含缓存机制,必须在每次compilation时重新初始化
389
- const additionalAssets = {}
402
+ const moduleGraph = compilation.moduleGraph
390
403
  if (!compilation.__mpx__) {
391
404
  // init mpx
392
405
  mpx = compilation.__mpx__ = {
406
+ // app信息,便于获取appName
407
+ appInfo: {},
393
408
  // pages全局记录,无需区分主包分包
394
409
  pagesMap: {},
395
- // 记录pages对应的entry,处理多appEntry输出web多页项目时可能出现的pagePath冲突的问题,多appEntry输出目前仅web模式支持
396
- pagesEntryMap: {},
397
- // 组件资源记录,依照所属包进行记录,冗余存储,只要某个包有引用会添加对应记录,不管其会不会在当前包输出,这样设计主要是为了在resolve时能够以较低成本找到特定资源的输出路径
410
+ // 组件资源记录,依照所属包进行记录
398
411
  componentsMap: {
399
412
  main: {}
400
413
  },
401
- // 静态资源(图片,字体,独立样式)等,依照所属包进行记录,冗余存储,同上
414
+ // 静态资源(图片,字体,独立样式)等,依照所属包进行记录
402
415
  staticResourcesMap: {
403
416
  main: {}
404
417
  },
405
- // 用于记录命中subpackageModulesRules的js模块最终输出到了什么分包中
418
+ // 用于记录命中subpackageModulesRules的js模块分包归属,用于js多分包冗余输出
406
419
  subpackageModulesMap: {
407
420
  main: {}
408
421
  },
422
+ // 记录其他资源,如pluginMain、pluginExport,无需区分主包分包
423
+ otherResourcesMap: {},
409
424
  // 记录独立分包
410
425
  independentSubpackagesMap: {},
411
- // 当前机制下分包处理队列在app.json的json-compiler中进行,由于addEntry回调特性,无法保障app.js中引用的模块都被标记为主包,故重写processModuleDependencies获取app.js及其所有依赖处理完成的时机,在这之后再执行分包处理队列
412
- appScriptRawRequest: '',
413
- appScriptPromise: null,
426
+ subpackagesEntriesMap: {},
427
+ replacePathMap: {},
428
+ exportModules: new Set(),
414
429
  // 记录entry依赖关系,用于体积分析
415
430
  entryNodesMap: {},
416
431
  // 记录entryModule与entryNode的对应关系,用于体积分析
417
432
  entryModulesMap: new Map(),
418
- loaderOptions,
419
433
  extractedMap: {},
420
434
  usingComponents: {},
421
- hasApp: false,
422
435
  // todo es6 map读写性能高于object,之后会逐步替换
423
436
  vueContentCache: new Map(),
424
437
  currentPackageRoot: '',
425
438
  wxsMap: {},
426
439
  wxsContentMap: {},
427
440
  assetsInfo: new Map(),
428
- forceDisableInject: this.options.forceDisableInject,
429
441
  forceUsePageCtor: this.options.forceUsePageCtor,
430
442
  resolveMode: this.options.resolveMode,
431
443
  mode: this.options.mode,
432
444
  srcMode: this.options.srcMode,
433
445
  env: this.options.env,
434
- // deprecated option
435
- globalMpxAttrsFilter: this.options.globalMpxAttrsFilter,
436
446
  externalClasses: this.options.externalClasses,
437
447
  projectRoot: this.options.projectRoot,
438
448
  autoScopeRules: this.options.autoScopeRules,
@@ -473,47 +483,71 @@ class MpxWebpackPlugin {
473
483
  return currentEntry
474
484
  },
475
485
  pathHash: (resourcePath) => {
476
- let hashPath = resourcePath
477
- const pathHashMode = this.options.pathHashMode
478
- const projectRoot = this.options.projectRoot || ''
479
- if (pathHashMode === 'relative') {
480
- hashPath = path.relative(projectRoot, resourcePath)
481
- }
482
- if (typeof pathHashMode === 'function') {
483
- hashPath = pathHashMode(resourcePath, projectRoot) || resourcePath
486
+ if (this.options.pathHashMode === 'relative' && this.options.projectRoot) {
487
+ return hash(path.relative(this.options.projectRoot, resourcePath))
484
488
  }
485
- 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
486
495
  },
487
- extract: (content, file, index, sideEffects) => {
488
- index = index === -1 ? 0 : index
489
- additionalAssets[file] = additionalAssets[file] || []
490
- if (!additionalAssets[file][index]) {
491
- 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]
492
522
  }
493
- sideEffects && sideEffects.forEach((sideEffect) => {
494
- sideEffect(additionalAssets)
495
- })
523
+ mpx.extractedFilesCache.set(resource, file)
524
+ return file
496
525
  },
497
526
  // 组件和静态资源的输出规则如下:
498
527
  // 1. 主包引用的资源输出至主包
499
528
  // 2. 分包引用且主包引用过的资源输出至主包,不在当前分包重复输出
500
529
  // 3. 分包引用且无其他包引用的资源输出至当前分包
501
530
  // 4. 分包引用且其他分包也引用过的资源,重复输出至当前分包
502
- getPackageInfo: ({ resource, outputPath, resourceType = 'components', issuerResource, warn }) => {
531
+ getPackageInfo: ({ resource, outputPath, resourceType, issuerResource, warn, error }) => {
503
532
  let packageRoot = ''
504
533
  let packageName = 'main'
505
- const resourceMap = mpx[`${resourceType}Map`]
506
- const { queryObj, resourcePath } = parseRequest(resource)
507
- if (resourceType === 'staticResources' && outputPath) {
508
- packageRoot = queryObj.packageRoot || ''
509
- 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
510
546
  } else {
511
- const currentPackageRoot = mpx.currentPackageRoot
512
- const currentPackageName = currentPackageRoot || 'main'
513
- const isIndependent = mpx.independentSubpackagesMap[currentPackageRoot]
514
547
  // 主包中有引用一律使用主包中资源,不再额外输出
515
548
  // 资源路径匹配到forceMainPackageRules规则时强制输出到主包,降低分包资源冗余
516
549
  // 如果存在issuer且issuerPackageRoot与当前packageRoot不一致,也输出到主包
550
+ // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
517
551
  let isMain = resourceMap.main[resourcePath] || matchCondition(resourcePath, this.options.forceMainPackageRules)
518
552
  if (issuerResource) {
519
553
  const { queryObj } = parseRequest(issuerResource)
@@ -523,36 +557,40 @@ class MpxWebpackPlugin {
523
557
  isMain = true
524
558
  }
525
559
  }
526
- // todo forceMainPackageRules规则目前只能处理当前资源,不能处理资源子树,配置不当有可能会导致资源引用错误
527
560
  if (!isMain || isIndependent) {
528
561
  packageRoot = currentPackageRoot
529
562
  packageName = currentPackageName
530
- if (this.options.auditResource && resourceType !== 'subpackageModules' && !isIndependent) {
531
- if (this.options.auditResource !== 'component' || resourceType === 'components') {
563
+ if (this.options.auditResource && resourceType !== 'subpackageModule' && !isIndependent) {
564
+ if (this.options.auditResource !== 'component' || resourceType === 'component') {
532
565
  Object.keys(resourceMap).filter(key => key !== 'main').forEach((key) => {
533
566
  if (resourceMap[key][resourcePath] && key !== packageName) {
534
- warn && warn(new Error(`当前${resourceType === 'components' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
567
+ warn && warn(new Error(`当前${resourceType === 'component' ? '组件' : '静态'}资源${resourcePath}在分包${key}和分包${packageName}中都有引用,会分别输出到两个分包中,为了总体积最优,可以在主包中建立引用声明以消除资源输出冗余!`))
535
568
  }
536
569
  })
537
570
  }
538
571
  }
539
572
  }
573
+ resourceMap[packageName] = resourceMap[packageName] || {}
574
+ currentResourceMap = resourceMap[packageName]
540
575
  }
541
576
 
542
- resourceMap[packageName] = resourceMap[packageName] || {}
543
- const currentResourceMap = resourceMap[packageName]
544
-
545
- let alreadyOutputed = false
546
- if (outputPath) {
547
- outputPath = toPosix(path.join(packageRoot, outputPath))
548
- // 如果之前已经进行过输出,则不需要重复进行
549
- if (currentResourceMap[resourcePath] === outputPath) {
550
- alreadyOutputed = true
551
- } 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
+ }
552
590
  currentResourceMap[resourcePath] = outputPath
591
+ } else {
592
+ currentResourceMap[resourcePath] = true
553
593
  }
554
- } else if (!currentResourceMap[resourcePath]) {
555
- currentResourceMap[resourcePath] = true
556
594
  }
557
595
 
558
596
  return {
@@ -567,20 +605,95 @@ class MpxWebpackPlugin {
567
605
 
568
606
  const rawProcessModuleDependencies = compilation.processModuleDependencies
569
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
570
620
  let proxyedCallback = callback
571
- if (module.rawRequest === mpx.appScriptRawRequest) {
572
- // 避免模块request重名,只对第一次匹配到的模块进行代理
573
- mpx.appScriptRawRequest = ''
574
- mpx.appScriptPromise = new Promise((resolve) => {
575
- proxyedCallback = (err) => {
576
- resolve()
577
- return callback(err)
621
+ if (originModule) {
622
+ proxyedCallback = (err, module) => {
623
+ // 避免selfModuleFactory的情况
624
+ if (module && module !== originModule) {
625
+ module.issuerResource = originModule.resource
578
626
  }
579
- })
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
+ }
580
667
  }
581
- return rawProcessModuleDependencies.apply(compilation, [module, proxyedCallback])
668
+
669
+ return rawAddModule.call(compilation, module, callback)
582
670
  }
583
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
+
584
697
  compilation.hooks.finishModules.tap('MpxWebpackPlugin', (modules) => {
585
698
  // 自动跟进分包配置修改splitChunksPlugin配置
586
699
  if (splitChunksPlugin) {
@@ -592,45 +705,15 @@ class MpxWebpackPlugin {
592
705
  }
593
706
  })
594
707
  if (needInit) {
595
- splitChunksPlugin.options = SplitChunksPlugin.normalizeOptions(splitChunksOptions)
708
+ splitChunksPlugin.options = new SplitChunksPlugin(splitChunksOptions).options
596
709
  }
597
710
  }
598
711
  })
599
712
 
600
- compilation.hooks.optimizeModules.tap('MpxWebpackPlugin', (modules) => {
601
- modules.forEach((module) => {
602
- if (module.needRemove) {
603
- let removed = false
604
- module.reasons.forEach((reason) => {
605
- if (reason.module) {
606
- if (reason.dependency instanceof HarmonyImportSideEffectDependency) {
607
- reason.module.removeDependency(reason.dependency)
608
- reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module))
609
- removed = true
610
- } else if (reason.dependency instanceof CommonJsRequireDependency && reason.dependency.loc.range) {
611
- let index = reason.module.dependencies.indexOf(reason.dependency)
612
- if (index > -1 && reason.module.dependencies[index + 1] instanceof RequireHeaderDependency) {
613
- reason.module.dependencies.splice(index, 2)
614
- reason.module.addDependency(new RemovedModuleDependency(reason.dependency.request, module, reason.dependency.loc.range))
615
- removed = true
616
- }
617
- }
618
- }
619
- })
620
- if (removed) {
621
- module.chunksIterable.forEach((chunk) => {
622
- module.removeChunk(chunk)
623
- })
624
- module.disconnect()
625
- }
626
- }
627
- })
628
- })
629
-
630
- compilation.moduleTemplates.javascript.hooks.content.tap('MpxWebpackPlugin', (source, module, options) => {
713
+ JavascriptModulesPlugin.getCompilationHooks(compilation).renderModuleContent.tap('MpxWebpackPlugin', (source, module, renderContext) => {
631
714
  // 处理dll产生的external模块
632
715
  if (module.external && module.userRequest.startsWith('dll-reference ') && mpx.mode !== 'web') {
633
- const chunk = options.chunk
716
+ const chunk = renderContext.chunk
634
717
  const request = module.request
635
718
  let relativePath = toPosix(path.relative(path.dirname(chunk.name), request))
636
719
  if (!/^\.\.?\//.test(relativePath)) relativePath = './' + relativePath
@@ -641,77 +724,63 @@ class MpxWebpackPlugin {
641
724
  return source
642
725
  })
643
726
 
644
- compilation.hooks.additionalAssets.tapAsync('MpxWebpackPlugin', (callback) => {
645
- for (let file in additionalAssets) {
646
- let content = new ConcatSource()
647
- if (additionalAssets[file].prefix) {
648
- additionalAssets[file].prefix.forEach((item) => {
649
- if (item) content.add(item)
650
- })
651
- }
652
- additionalAssets[file].forEach((item) => {
653
- if (item) content.add(item)
654
- })
655
- const modules = (additionalAssets[file].modules || []).concat(additionalAssets[file].relativeModules || [])
656
-
657
- if (modules.length > 1) {
658
- // 同步relativeModules和modules之间的依赖
659
- const fileDependencies = new Set()
660
- const contextDependencies = new Set()
661
-
662
- modules.forEach((module) => {
663
- module.buildInfo.fileDependencies.forEach((fileDependency) => {
664
- fileDependencies.add(fileDependency)
665
- })
666
- module.buildInfo.contextDependencies.forEach((contextDependency) => {
667
- contextDependencies.add(contextDependency)
668
- })
669
- module.buildInfo.fileDependencies = fileDependencies
670
- module.buildInfo.contextDependencies = contextDependencies
671
- })
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
+ }
672
742
  }
673
- compilation.emitAsset(file, content, { modules: additionalAssets[file].modules })
674
743
  }
675
- // 所有编译的静态资源assetsInfo合入主编译
676
- mpx.assetsInfo.forEach((assetInfo, name) => {
677
- const oldAssetInfo = compilation.assetsInfo.get(name)
678
- if (oldAssetInfo && oldAssetInfo.modules) {
679
- assetInfo.modules = assetInfo.modules.concat(oldAssetInfo.modules)
680
- }
681
- compilation.assetsInfo.set(name, assetInfo)
682
- })
683
- // 链接主编译模块与子编译入口
684
- Object.values(mpx.wxsMap).concat(Object.values(mpx.extractedMap)).forEach((item) => {
685
- item.modules.forEach((module) => {
686
- module.addDependency(item.dep)
687
- })
688
- })
689
744
 
690
- 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
+ }
691
761
  })
692
762
 
693
763
  normalModuleFactory.hooks.parser.for('javascript/auto').tap('MpxWebpackPlugin', (parser) => {
694
- // hack预处理,将expr.range写入loc中便于在CommonJsRequireDependency中获取,移除无效require
695
- parser.hooks.call.for('require').tap({ name: 'MpxWebpackPlugin', stage: -100 }, (expr) => {
696
- expr.loc.range = expr.range
697
- })
698
-
699
764
  parser.hooks.call.for('__mpx_resolve_path__').tap('MpxWebpackPlugin', (expr) => {
700
765
  if (expr.arguments[0]) {
701
766
  const resource = expr.arguments[0].value
702
- const { queryObj } = parseRequest(resource)
703
- const packageName = queryObj.packageRoot || 'main'
704
- const pagesMap = mpx.pagesMap
705
- const componentsMap = mpx.componentsMap
706
- const staticResourcesMap = mpx.staticResourcesMap
767
+ const packageName = mpx.currentPackageRoot || 'main'
768
+ const issuerResource = moduleGraph.getIssuer(parser.state.module).resource
707
769
  const range = expr.range
708
- const issuerResource = parser.state.module.issuer.resource
709
- const dep = new ResolveDependency(resource, packageName, pagesMap, componentsMap, staticResourcesMap, publicPath, range, issuerResource, compilation)
710
- parser.state.current.addDependency(dep)
770
+ const dep = new ResolveDependency(resource, packageName, issuerResource, range)
771
+ parser.state.current.addPresentationalDependency(dep)
711
772
  return true
712
773
  }
713
774
  })
714
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
+
715
784
  const transHandler = (expr) => {
716
785
  const module = parser.state.module
717
786
  const current = parser.state.current
@@ -735,31 +804,21 @@ class MpxWebpackPlugin {
735
804
  const type = target.name
736
805
 
737
806
  const name = type === 'wx' ? 'mpx' : 'createFactory'
738
- 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)})`
739
808
 
740
809
  const dep = new ReplaceDependency(replaceContent, target.range)
741
- current.addDependency(dep)
810
+ current.addPresentationalDependency(dep)
742
811
 
743
812
  let needInject = true
744
- for (let v of module.variables) {
745
- if (v.name === name) {
813
+ for (let dep of module.dependencies) {
814
+ if (dep instanceof CommonJsVariableDependency && dep.name === name) {
746
815
  needInject = false
747
816
  break
748
817
  }
749
818
  }
750
819
  if (needInject) {
751
- const expression = `require(${JSON.stringify(`@mpxjs/core/src/runtime/${name}`)})`
752
- const deps = []
753
- parser.parse(expression, {
754
- current: {
755
- addDependency: dep => {
756
- dep.userRequest = name
757
- deps.push(dep)
758
- }
759
- },
760
- module
761
- })
762
- module.addVariable(name, expression, deps)
820
+ const dep = new CommonJsVariableDependency(`@mpxjs/core/src/runtime/${name}`, name)
821
+ module.addDependency(dep)
763
822
  }
764
823
  }
765
824
  // hack babel polyfill global
@@ -767,7 +826,7 @@ class MpxWebpackPlugin {
767
826
  if (/core-js.+microtask/.test(parser.state.module.resource)) {
768
827
  if (expr.test.left && (expr.test.left.name === 'Observer' || expr.test.left.name === 'MutationObserver')) {
769
828
  const current = parser.state.current
770
- current.addDependency(new InjectDependency({
829
+ current.addPresentationalDependency(new InjectDependency({
771
830
  content: 'document && ',
772
831
  index: expr.test.range[0]
773
832
  }))
@@ -783,7 +842,7 @@ class MpxWebpackPlugin {
783
842
  // todo 该逻辑在corejs3中不需要,等corejs3比较普及之后可以干掉
784
843
  if (/core-js.+global/.test(parser.state.module.resource)) {
785
844
  if (callee.name === 'Function' && arg0 && arg0.value === 'return this') {
786
- current.addDependency(new InjectDependency({
845
+ current.addPresentationalDependency(new InjectDependency({
787
846
  content: '(function() { return this })() || ',
788
847
  index: expr.range[0]
789
848
  }))
@@ -791,7 +850,7 @@ class MpxWebpackPlugin {
791
850
  }
792
851
  if (/regenerator-runtime/.test(parser.state.module.resource)) {
793
852
  if (callee.name === 'Function' && arg0 && arg0.value === 'r' && arg1 && arg1.value === 'regeneratorRuntime = r') {
794
- current.addDependency(new ReplaceDependency('(function () {})', expr.range))
853
+ current.addPresentationalDependency(new ReplaceDependency('(function () {})', expr.range))
795
854
  }
796
855
  }
797
856
  })
@@ -808,7 +867,7 @@ class MpxWebpackPlugin {
808
867
  // }
809
868
  // })
810
869
  // // Trans for wx.xx, wx['xx'], wx.xx(), wx['xx']()
811
- // parser.hooks.expressionAnyMember.for('wx').tap('MpxWebpackPlugin', transHandler)
870
+ // parser.hooks.expressionMemberChain.for('wx').tap('MpxWebpackPlugin', transHandler)
812
871
  // Proxy ctor for transMode
813
872
  if (!this.options.forceDisableProxyCtor) {
814
873
  parser.hooks.call.for('Page').tap('MpxWebpackPlugin', (expr) => {
@@ -873,20 +932,29 @@ class MpxWebpackPlugin {
873
932
  : JSON.stringify(srcModeString),
874
933
  index: expr.end - 1
875
934
  })
876
- parser.state.current.addDependency(dep)
935
+ parser.state.current.addPresentationalDependency(dep)
877
936
  }
878
937
 
879
938
  if (mpx.srcMode !== mpx.mode) {
880
- parser.hooks.callAnyMember.for('imported var').tap('MpxWebpackPlugin', handler)
881
- parser.hooks.callAnyMember.for('mpx').tap('MpxWebpackPlugin', handler)
882
- 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)
883
942
  }
884
943
  })
885
944
 
886
- // 为了正确生成sourceMap,将该步骤由原来的compile.hooks.emit迁移到compilation.hooks.optimizeChunkAssets中来
887
- compilation.hooks.optimizeChunkAssets.tapAsync('MpxWebpackPlugin', (chunks, callback) => {
888
- if (mpx.mode === 'web') return callback()
889
- 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
890
958
 
891
959
  function getTargetFile (file) {
892
960
  let targetFile = file
@@ -898,21 +966,24 @@ class MpxWebpackPlugin {
898
966
  }
899
967
 
900
968
  const processedChunk = new Set()
901
- const rootName = compilation._preparedEntrypoints[0].name
969
+ // const rootName = compilation.entries.keys().next().value
970
+ const appName = mpx.appInfo.name
902
971
 
903
972
  function processChunk (chunk, isRuntime, relativeChunks) {
904
- if (!chunk.files[0] || processedChunk.has(chunk)) {
973
+ const chunkFile = chunk.files.values().next().value
974
+ if (!chunkFile || processedChunk.has(chunk)) {
905
975
  return
906
976
  }
907
977
 
908
- let originalSource = compilation.assets[chunk.files[0]]
978
+ let originalSource = compilation.assets[chunkFile]
909
979
  const source = new ConcatSource()
910
- source.add('\nvar window = window || {};\n\n')
980
+ source.add(`\nvar ${globalObject} = ${globalObject} || {};\n\n`)
911
981
 
912
982
  relativeChunks.forEach((relativeChunk, index) => {
913
- if (!relativeChunk.files[0]) return
914
- let chunkPath = getTargetFile(chunk.files[0])
915
- 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)
916
987
  relativePath = path.relative(path.dirname(chunkPath), relativePath)
917
988
  relativePath = fixRelative(relativePath, mpx.mode)
918
989
  relativePath = toPosix(relativePath)
@@ -920,19 +991,19 @@ class MpxWebpackPlugin {
920
991
  // 引用runtime
921
992
  // 支付宝分包独立打包,通过全局context获取webpackJSONP
922
993
  if (mpx.mode === 'ali' && !mpx.isPluginMode) {
923
- if (chunk.name === rootName) {
924
- // 在rootChunk中挂载jsonpFunction
994
+ if (chunk.name === appName) {
995
+ // 在rootChunk中挂载jsonpCallback
925
996
  source.add('// process ali subpackages runtime in root chunk\n' +
926
997
  'var context = (function() { return this })() || Function("return this")();\n\n')
927
- 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`)
928
999
  } else {
929
1000
  // 其余chunk中通过context全局传递runtime
930
1001
  source.add('// process ali subpackages runtime in other chunk\n' +
931
1002
  'var context = (function() { return this })() || Function("return this")();\n\n')
932
- source.add(`window[${JSON.stringify(jsonpFunction)}] = context[${JSON.stringify(jsonpFunction)}];\n`)
1003
+ source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = context[${JSON.stringify(chunkLoadingGlobal)}];\n`)
933
1004
  }
934
1005
  } else {
935
- source.add(`window[${JSON.stringify(jsonpFunction)}] = require("${relativePath}");\n`)
1006
+ source.add(`${globalObject}[${JSON.stringify(chunkLoadingGlobal)}] = require("${relativePath}");\n`)
936
1007
  }
937
1008
  } else {
938
1009
  source.add(`require("${relativePath}");\n`)
@@ -968,18 +1039,17 @@ try {
968
1039
  } catch(e){
969
1040
  }\n`)
970
1041
  source.add(originalSource)
971
- source.add(`\nmodule.exports = window[${JSON.stringify(jsonpFunction)}];\n`)
1042
+ source.add(`\nmodule.exports = ${globalObject}[${JSON.stringify(chunkLoadingGlobal)}];\n`)
972
1043
  } else {
973
- if (mpx.pluginMainModule && chunk.entryModule && mpx.pluginMainModule === chunk.entryModule) {
974
- source.add('module.exports =\n')
975
- // mpx.miniToPluginExports is a Set
976
- } 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)) {
977
1047
  source.add('module.exports =\n')
978
1048
  }
979
1049
  source.add(originalSource)
980
1050
  }
981
1051
 
982
- compilation.assets[chunk.files[0]] = source
1052
+ compilation.assets[chunkFile] = source
983
1053
  processedChunk.add(chunk)
984
1054
  }
985
1055
 
@@ -1016,74 +1086,114 @@ try {
1016
1086
  }
1017
1087
  }
1018
1088
  })
1019
-
1020
- callback()
1021
1089
  })
1022
1090
  })
1023
1091
 
1024
1092
  compiler.hooks.normalModuleFactory.tap('MpxWebpackPlugin', (normalModuleFactory) => {
1025
1093
  // resolve前修改原始request
1026
- normalModuleFactory.hooks.beforeResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1094
+ normalModuleFactory.hooks.beforeResolve.tap('MpxWebpackPlugin', (data) => {
1027
1095
  let request = data.request
1028
1096
  let { queryObj, resource } = parseRequest(request)
1029
1097
  if (queryObj.resolve) {
1030
1098
  // 此处的query用于将资源引用的当前包信息传递给resolveDependency
1031
- const pathLoader = normalize.lib('path-loader')
1032
- resource = addQuery(resource, {
1033
- packageRoot: mpx.currentPackageRoot
1034
- })
1035
- data.request = `!!${pathLoader}!${resource}`
1036
- } else if (queryObj.wxsModule) {
1037
- const wxsPreLoader = normalize.lib('wxs/wxs-pre-loader')
1038
- if (!/wxs-loader/.test(request)) {
1039
- data.request = `!!${wxsPreLoader}!${resource}`
1040
- }
1099
+ const resolveLoaderPath = normalize.lib('resolve-loader')
1100
+ data.request = `!!${resolveLoaderPath}!${resource}`
1041
1101
  }
1042
- callback(null, data)
1043
1102
  })
1044
1103
 
1045
- // resolve完成后修改loaders信息并批量添加mode query
1046
- normalModuleFactory.hooks.afterResolve.tapAsync('MpxWebpackPlugin', (data, callback) => {
1047
- if (data.loaders) {
1048
- const { queryObj } = parseRequest(data.request)
1049
- const mpxStyleOptions = queryObj.mpxStyleOptions
1050
- const firstLoader = (data.loaders[0] && data.loaders[0].loader) || ''
1051
- const isPitcherRequest = firstLoader.includes('vue-loader/lib/loaders/pitcher.js')
1052
- let cssLoaderIndex = -1
1053
- let vueStyleLoaderIndex = -1
1054
- let mpxStyleLoaderIndex = -1
1055
- data.loaders.forEach((loader, index) => {
1056
- const currentLoader = loader.loader
1057
- if (currentLoader.includes('ts-loader')) {
1058
- // todo 暂时固定写死options,待后续优化为复用rules后修正
1059
- loader.options = { appendTsSuffixTo: [/\.(mpx|vue)$/] }
1060
- }
1061
- if (currentLoader.includes('css-loader')) {
1062
- cssLoaderIndex = index
1063
- } else if (currentLoader.includes('vue-loader/lib/loaders/stylePostLoader.js')) {
1064
- vueStyleLoaderIndex = index
1065
- } else if (currentLoader.includes('@mpxjs/webpack-plugin/lib/style-compiler/index.js')) {
1066
- mpxStyleLoaderIndex = index
1067
- }
1068
- })
1069
- if (mpxStyleLoaderIndex === -1) {
1070
- let loaderIndex = -1
1071
- if (cssLoaderIndex > -1 && vueStyleLoaderIndex === -1) {
1072
- loaderIndex = cssLoaderIndex
1073
- } else if (cssLoaderIndex > -1 && vueStyleLoaderIndex > -1 && !isPitcherRequest) {
1074
- loaderIndex = vueStyleLoaderIndex
1075
- }
1076
- if (loaderIndex > -1) {
1077
- data.loaders.splice(loaderIndex + 1, 0, {
1078
- loader: normalize.lib('style-compiler/index.js'),
1079
- 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
+ }
1080
1128
  })
1081
- }
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
+ })
1082
1159
  }
1160
+
1161
+ createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
1162
+ createData.request = stringifyLoadersAndResource(loaders, createData.resource)
1083
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
+ // }
1084
1195
  // 根据用户传入的modeRules对特定资源添加mode query
1085
- this.runModeRules(data)
1086
- callback(null, data)
1196
+ this.runModeRules(createData)
1087
1197
  })
1088
1198
  })
1089
1199