@mpxjs/webpack-plugin 2.6.115 → 2.7.0-alpha

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