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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +1 -1
  2. package/lib/built-in-loader.js +49 -0
  3. package/lib/config.js +0 -14
  4. package/lib/content-loader.js +13 -0
  5. package/lib/dependency/ChildCompileDependency.js +24 -0
  6. package/lib/dependency/InjectDependency.js +26 -0
  7. package/lib/dependency/RemovedModuleDependency.js +23 -0
  8. package/lib/{dependencies → dependency}/ReplaceDependency.js +2 -19
  9. package/lib/dependency/ResolveDependency.js +49 -0
  10. package/lib/extractor.js +178 -82
  11. package/lib/file-loader.js +19 -7
  12. package/lib/helpers.js +334 -39
  13. package/lib/index.js +525 -889
  14. package/lib/json-compiler/index.js +451 -245
  15. package/lib/json-compiler/{theme.js → theme-loader.js} +3 -5
  16. package/lib/loader.js +241 -178
  17. package/lib/native-loader.js +133 -71
  18. package/lib/parser.js +2 -1
  19. package/lib/path-loader.js +3 -0
  20. package/lib/platform/json/wx/index.js +1 -1
  21. package/lib/platform/template/normalize-component-rules.js +3 -2
  22. package/lib/platform/template/wx/component-config/button.js +2 -14
  23. package/lib/platform/template/wx/component-config/image.js +0 -4
  24. package/lib/platform/template/wx/component-config/input.js +0 -4
  25. package/lib/platform/template/wx/component-config/rich-text.js +0 -4
  26. package/lib/platform/template/wx/component-config/scroll-view.js +0 -4
  27. package/lib/platform/template/wx/component-config/switch.js +0 -4
  28. package/lib/platform/template/wx/component-config/text.js +0 -4
  29. package/lib/platform/template/wx/component-config/textarea.js +0 -5
  30. package/lib/platform/template/wx/component-config/view.js +0 -4
  31. package/lib/platform/template/wx/index.js +3 -149
  32. package/lib/plugin-loader.js +287 -0
  33. package/lib/resolver/AddEnvPlugin.js +3 -4
  34. package/lib/resolver/AddModePlugin.js +3 -4
  35. package/lib/resolver/PackageEntryPlugin.js +36 -23
  36. package/lib/runtime/base.styl +0 -5
  37. package/lib/runtime/components/web/getInnerListeners.js +3 -1
  38. package/lib/runtime/components/web/mpx-image.vue +5 -20
  39. package/lib/runtime/components/web/mpx-movable-view.vue +2 -6
  40. package/lib/runtime/components/web/mpx-swiper.vue +3 -18
  41. package/lib/runtime/i18n.wxs +11 -31
  42. package/lib/runtime/optionProcessor.js +3 -48
  43. package/lib/selector.js +10 -29
  44. package/lib/staticConfig.js +4 -0
  45. package/lib/style-compiler/index.js +24 -16
  46. package/lib/style-compiler/load-postcss-config.js +1 -3
  47. package/lib/style-compiler/plugins/conditional-strip.js +65 -68
  48. package/lib/style-compiler/plugins/rpx.js +37 -43
  49. package/lib/style-compiler/plugins/scope-id.js +72 -79
  50. package/lib/style-compiler/plugins/trans-special.js +18 -25
  51. package/lib/style-compiler/plugins/trim.js +7 -13
  52. package/lib/style-compiler/plugins/vw.js +16 -22
  53. package/lib/template-compiler/compiler.js +199 -106
  54. package/lib/template-compiler/index.js +139 -52
  55. package/lib/template-compiler/trans-dynamic-class-expr.js +13 -18
  56. package/lib/url-loader.js +29 -11
  57. package/lib/utils/add-query.js +1 -1
  58. package/lib/utils/get-main-compilation.js +6 -0
  59. package/lib/utils/is-url-request.js +1 -10
  60. package/lib/utils/match-condition.js +1 -4
  61. package/lib/utils/normalize.js +15 -4
  62. package/lib/utils/parse-request.js +3 -3
  63. package/lib/utils/read-json-for-src.js +34 -0
  64. package/lib/utils/stringify-query.js +0 -4
  65. package/lib/utils/try-require.js +16 -0
  66. package/lib/web/processJSON.js +144 -113
  67. package/lib/web/processScript.js +34 -47
  68. package/lib/web/processTemplate.js +40 -57
  69. package/lib/wxml/{loader.js → wxml-loader.js} +62 -21
  70. package/lib/wxs/WxsParserPlugin.js +2 -2
  71. package/lib/wxs/WxsPlugin.js +8 -4
  72. package/lib/wxs/WxsTemplatePlugin.js +92 -46
  73. package/lib/wxs/{i18n-loader.js → wxs-i18n-loader.js} +4 -5
  74. package/lib/wxs/wxs-loader.js +117 -0
  75. package/lib/wxs/{pre-loader.js → wxs-pre-loader.js} +5 -20
  76. package/lib/wxss/getImportPrefix.js +30 -0
  77. package/lib/wxss/loader.js +43 -31
  78. package/lib/wxss/localsLoader.js +5 -1
  79. package/lib/wxss/processCss.js +103 -107
  80. package/package.json +18 -21
  81. package/LICENSE +0 -433
  82. package/lib/dependencies/AddEntryDependency.js +0 -24
  83. package/lib/dependencies/AppEntryDependency.js +0 -58
  84. package/lib/dependencies/CommonJsAsyncDependency.js +0 -51
  85. package/lib/dependencies/CommonJsVariableDependency.js +0 -81
  86. package/lib/dependencies/DynamicEntryDependency.js +0 -171
  87. package/lib/dependencies/FlagPluginDependency.js +0 -24
  88. package/lib/dependencies/InjectDependency.js +0 -43
  89. package/lib/dependencies/RecordGlobalComponentsDependency.js +0 -50
  90. package/lib/dependencies/RecordIndependentDependency.js +0 -44
  91. package/lib/dependencies/RecordResourceMapDependency.js +0 -62
  92. package/lib/dependencies/RemoveEntryDependency.js +0 -40
  93. package/lib/dependencies/ResolveDependency.js +0 -88
  94. package/lib/independent-loader.js +0 -52
  95. package/lib/json-compiler/helper.js +0 -156
  96. package/lib/json-compiler/plugin.js +0 -150
  97. package/lib/partial-compile/index.js +0 -35
  98. package/lib/record-loader.js +0 -11
  99. package/lib/resolve-loader.js +0 -6
  100. package/lib/resolver/FixDescriptionInfoPlugin.js +0 -28
  101. package/lib/runtime/components/tenon/getInnerListeners.js +0 -317
  102. package/lib/runtime/components/tenon/tenon-button.vue +0 -305
  103. package/lib/runtime/components/tenon/tenon-image.vue +0 -61
  104. package/lib/runtime/components/tenon/tenon-input.vue +0 -99
  105. package/lib/runtime/components/tenon/tenon-rich-text.vue +0 -21
  106. package/lib/runtime/components/tenon/tenon-scroll-view.vue +0 -124
  107. package/lib/runtime/components/tenon/tenon-switch.vue +0 -91
  108. package/lib/runtime/components/tenon/tenon-text-area.vue +0 -64
  109. package/lib/runtime/components/tenon/tenon-text.vue +0 -64
  110. package/lib/runtime/components/tenon/tenon-view.vue +0 -93
  111. package/lib/runtime/components/tenon/util.js +0 -44
  112. package/lib/runtime/optionProcessor.tenon.js +0 -386
  113. package/lib/style-compiler/plugins/hm.js +0 -20
  114. package/lib/tenon/index.js +0 -105
  115. package/lib/tenon/processJSON.js +0 -360
  116. package/lib/tenon/processScript.js +0 -260
  117. package/lib/tenon/processStyles.js +0 -21
  118. package/lib/tenon/processTemplate.js +0 -133
  119. package/lib/utils/const.js +0 -10
  120. package/lib/utils/emit-file.js +0 -10
  121. package/lib/utils/eval-json-js.js +0 -31
  122. package/lib/utils/get-entry-name.js +0 -13
  123. package/lib/utils/get-json-content.js +0 -42
  124. package/lib/utils/get-relative-path.js +0 -24
  125. package/lib/utils/resolve.js +0 -13
  126. package/lib/utils/set.js +0 -47
  127. package/lib/utils/stringify-loaders-resource.js +0 -25
  128. package/lib/wxs/WxsModuleIdsPlugin.js +0 -29
  129. package/lib/wxs/loader.js +0 -142
@@ -1,90 +1,88 @@
1
1
  const async = require('async')
2
2
  const JSON5 = require('json5')
3
3
  const path = require('path')
4
+ const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin')
5
+ const loaderUtils = require('loader-utils')
4
6
  const parseComponent = require('../parser')
5
7
  const config = require('../config')
8
+ const normalize = require('../utils/normalize')
9
+ const nativeLoaderPath = normalize.lib('native-loader')
10
+ const themeLoaderPath = normalize.lib('json-compiler/theme-loader')
11
+ const extractorPath = normalize.lib('extractor')
6
12
  const parseRequest = require('../utils/parse-request')
7
- const evalJSONJS = require('../utils/eval-json-js')
13
+ const mpxJSON = require('../utils/mpx-json')
14
+ const toPosix = require('../utils/to-posix')
8
15
  const fixUsingComponent = require('../utils/fix-using-component')
9
16
  const getRulesRunner = require('../platform/index')
17
+ const isUrlRequestRaw = require('../utils/is-url-request')
10
18
  const addQuery = require('../utils/add-query')
11
- const getJSONContent = require('../utils/get-json-content')
12
- const createHelpers = require('../helpers')
13
- const createJSONHelper = require('./helper')
14
- const RecordGlobalComponentsDependency = require('../dependencies/RecordGlobalComponentsDependency')
15
- const RecordIndependentDependency = require('../dependencies/RecordIndependentDependency')
16
- const { MPX_DISABLE_EXTRACTOR_CACHE, RESOLVE_IGNORED_ERR, JSON_JS_EXT } = require('../utils/const')
17
- const resolve = require('../utils/resolve')
18
-
19
- module.exports = function (content) {
19
+ const readJsonForSrc = require('../utils/read-json-for-src')
20
+ const getMainCompilation = require('../utils/get-main-compilation')
21
+
22
+ module.exports = function (raw = '{}') {
23
+ // 该loader中会在每次编译中动态添加entry,不能缓存,否则watch不好使
24
+ this.cacheable(false)
20
25
  const nativeCallback = this.async()
21
- const mpx = this.getMpx()
26
+ const options = loaderUtils.getOptions(this) || {}
27
+ const mainCompilation = getMainCompilation(this._compilation)
28
+ const mpx = mainCompilation.__mpx__
29
+ const getOutputPath = mpx.getOutputPath
30
+
31
+ const emitWarning = (msg) => {
32
+ this.emitWarning(
33
+ new Error('[json compiler][' + this.resource + ']: ' + msg)
34
+ )
35
+ }
36
+
37
+ const emitError = (msg) => {
38
+ this.emitError(
39
+ new Error('[json compiler][' + this.resource + ']: ' + msg)
40
+ )
41
+ }
42
+
43
+ const stringifyRequest = r => loaderUtils.stringifyRequest(this, r)
44
+ const isUrlRequest = r => isUrlRequestRaw(r, options.root)
45
+ const urlToRequest = r => loaderUtils.urlToRequest(r)
22
46
 
23
47
  if (!mpx) {
24
- return nativeCallback(null, content)
48
+ return nativeCallback(null, raw)
25
49
  }
26
- // json模块必须每次都创建(但并不是每次都需要build),用于动态添加编译入口,传递信息以禁用父级extractor的缓存
27
- this.emitFile(MPX_DISABLE_EXTRACTOR_CACHE, '', undefined, { skipEmit: true })
28
50
 
29
51
  // 微信插件下要求组件使用相对路径
30
52
  const useRelativePath = mpx.isPluginMode || mpx.useRelativePath
31
53
  const { resourcePath, queryObj } = parseRequest(this.resource)
32
- const useJSONJS = queryObj.useJSONJS || this.resourcePath.endsWith(JSON_JS_EXT)
33
54
  const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main'
34
55
  const pagesMap = mpx.pagesMap
35
56
  const componentsMap = mpx.componentsMap[packageName]
36
- const appInfo = mpx.appInfo
57
+ const getEntryNode = mpx.getEntryNode
37
58
  const mode = mpx.mode
38
59
  const env = mpx.env
60
+ const defs = mpx.defs
39
61
  const globalSrcMode = mpx.srcMode
40
62
  const localSrcMode = queryObj.mode
41
63
  const srcMode = localSrcMode || globalSrcMode
42
-
64
+ const resolveMode = mpx.resolveMode
65
+ const externals = mpx.externals
66
+ const pathHash = mpx.pathHash
43
67
  const isApp = !(pagesMap[resourcePath] || componentsMap[resourcePath])
44
68
  const publicPath = this._compilation.outputOptions.publicPath || ''
45
69
  const fs = this._compiler.inputFileSystem
70
+ const rootName = mainCompilation._preparedEntrypoints[0].name
71
+ const currentName = componentsMap[resourcePath] || pagesMap[resourcePath] || rootName
72
+ const currentPath = publicPath + currentName
46
73
 
47
- const emitWarning = (msg) => {
48
- this.emitWarning(
49
- new Error('[json compiler][' + this.resource + ']: ' + msg)
50
- )
51
- }
52
-
53
- const emitError = (msg) => {
54
- this.emitError(
55
- new Error('[json compiler][' + this.resource + ']: ' + msg)
56
- )
57
- }
58
-
59
- const {
60
- isUrlRequest,
61
- urlToRequest,
62
- processPage,
63
- processDynamicEntry,
64
- processComponent,
65
- processJsExport
66
- } = createJSONHelper({
67
- loaderContext: this,
68
- emitWarning,
69
- emitError
70
- })
71
-
72
- const { getRequestString } = createHelpers(this)
74
+ // json模块都是由.mpx或.js的入口模块引入,且引入关系为一对一,其issuer必为入口module
75
+ const entryModule = this._module.issuer
76
+ // 通过rawRequest关联entryNode和entryModule
77
+ const entryRequest = entryModule.rawRequest
78
+ const entryType = isApp ? 'App' : pagesMap[resourcePath] ? 'Page' : 'Component'
73
79
 
74
- let currentName
75
-
76
- if (isApp) {
77
- currentName = appInfo.name
78
- } else {
79
- currentName = componentsMap[resourcePath] || pagesMap[resourcePath]
80
- }
81
-
82
- const relativePath = useRelativePath ? publicPath + path.dirname(currentName) : ''
80
+ const currentEntry = getEntryNode(entryRequest, entryType, entryModule)
83
81
 
84
82
  const copydir = (dir, context, callback) => {
85
83
  fs.readdir(dir, (err, files) => {
86
84
  if (err) return callback(err)
87
- async.each(files, (file, callback) => {
85
+ async.forEach(files, (file, callback) => {
88
86
  file = path.join(dir, file)
89
87
  async.waterfall([
90
88
  (callback) => {
@@ -96,7 +94,6 @@ module.exports = function (content) {
96
94
  } else {
97
95
  fs.readFile(file, (err, content) => {
98
96
  if (err) return callback(err)
99
- if (!this._compilation) return callback()
100
97
  let targetPath = path.relative(context, file)
101
98
  this._compilation.assets[targetPath] = {
102
99
  size: function size () {
@@ -115,20 +112,58 @@ module.exports = function (content) {
115
112
  })
116
113
  }
117
114
 
115
+ let entryDeps = new Set()
116
+
117
+ let cacheCallback
118
+
119
+ const checkEntryDeps = (callback) => {
120
+ callback = callback || cacheCallback
121
+ if (callback && entryDeps.size === 0) {
122
+ callback()
123
+ } else {
124
+ cacheCallback = callback
125
+ }
126
+ }
127
+
128
+ const addEntrySafely = (resource, name, callback) => {
129
+ // 如果loader已经回调,就不再添加entry
130
+ if (callbacked) return callback()
131
+ const dep = SingleEntryPlugin.createDependency(resource, name)
132
+ entryDeps.add(dep)
133
+ this._compilation.addEntry(this._compiler.context, dep, name, (err, module) => {
134
+ entryDeps.delete(dep)
135
+ checkEntryDeps()
136
+ callback(err, module)
137
+ })
138
+ }
139
+
140
+ // const deleteEntry = (name) => {
141
+ // const index = this._compilation._preparedEntrypoints.findIndex(slot => slot.name === name)
142
+ // if (index >= 0) {
143
+ // this._compilation._preparedEntrypoints.splice(index, 1)
144
+ // }
145
+ // }
146
+
147
+ let callbacked = false
118
148
  const callback = (err, processOutput) => {
119
- if (err) return nativeCallback(err)
120
- let output = `var json = ${JSON.stringify(json, null, 2)};\n`
121
- if (processOutput) output = processOutput(output)
122
- output += `module.exports = JSON.stringify(json, null, 2);\n`
123
- nativeCallback(null, output)
149
+ checkEntryDeps(() => {
150
+ callbacked = true
151
+ if (err) return nativeCallback(err)
152
+ let output = `var json = ${JSON.stringify(json, null, 2)};\n`
153
+ if (processOutput) output = processOutput(output)
154
+ output += `module.exports = JSON.stringify(json, null, 2);\n`
155
+ nativeCallback(null, output)
156
+ })
124
157
  }
125
158
 
126
- let json
159
+ let json = {}
127
160
  try {
128
- if (useJSONJS) {
129
- json = evalJSONJS(content, this.resourcePath, this)
161
+ // 使用了MPXJSON的话先编译
162
+ // 此处需要使用真实的resourcePath
163
+ if (this.resourcePath.endsWith('.json.js')) {
164
+ json = JSON.parse(mpxJSON.compileMPXJSONText({ source: raw, defs, filePath: this.resourcePath }))
130
165
  } else {
131
- json = JSON5.parse(content || '{}')
166
+ json = JSON5.parse(raw)
132
167
  }
133
168
  } catch (err) {
134
169
  return callback(err)
@@ -141,9 +176,6 @@ module.exports = function (content) {
141
176
  if (!json.usingComponents) {
142
177
  json.usingComponents = {}
143
178
  }
144
- if (!json.component && mode === 'swan') {
145
- json.component = true
146
- }
147
179
  }
148
180
  } else if (componentsMap[resourcePath]) {
149
181
  // component
@@ -189,7 +221,13 @@ module.exports = function (content) {
189
221
  } else {
190
222
  // 保存全局注册组件
191
223
  if (json.usingComponents) {
192
- this._module.addPresentationalDependency(new RecordGlobalComponentsDependency(json.usingComponents, this.context))
224
+ mpx.usingComponents = {}
225
+ Object.keys(json.usingComponents).forEach((key) => {
226
+ const request = json.usingComponents[key]
227
+ mpx.usingComponents[key] = addQuery(request, {
228
+ context: this.context
229
+ })
230
+ })
193
231
  }
194
232
  }
195
233
 
@@ -199,68 +237,141 @@ module.exports = function (content) {
199
237
  rulesRunner(json)
200
238
  }
201
239
 
240
+ const resolve = (context, request, callback) => {
241
+ const { queryObj } = parseRequest(request)
242
+ context = queryObj.context || context
243
+ return this.resolve(context, request, callback)
244
+ }
245
+
202
246
  const processComponents = (components, context, callback) => {
203
247
  if (components) {
204
- async.eachOf(components, (component, name, callback) => {
205
- processComponent(component, context, { relativePath }, (err, entry) => {
206
- if (err === RESOLVE_IGNORED_ERR) {
207
- delete components[name]
208
- return callback()
248
+ async.forEachOf(components, (component, name, callback) => {
249
+ processComponent(component, context, (componentPath) => {
250
+ if (useRelativePath === true) {
251
+ componentPath = toPosix(path.relative(path.dirname(currentPath), componentPath))
209
252
  }
210
- if (err) return callback(err)
211
- components[name] = entry
212
- callback()
213
- })
253
+ components[name] = componentPath
254
+ }, undefined, callback)
214
255
  }, callback)
215
256
  } else {
216
257
  callback()
217
258
  }
218
259
  }
219
260
 
261
+ const processComponent = (component, context, rewritePath, outputPath, callback) => {
262
+ if (!isUrlRequest(component)) return callback()
263
+ if (resolveMode === 'native') {
264
+ component = urlToRequest(component)
265
+ }
266
+
267
+ if (externals.some((external) => {
268
+ if (typeof external === 'string') {
269
+ return external === component
270
+ } else if (external instanceof RegExp) {
271
+ return external.test(component)
272
+ }
273
+ return false
274
+ })) {
275
+ return callback()
276
+ }
277
+
278
+ resolve(context, component, (err, resource, info) => {
279
+ if (err) return callback(err)
280
+ const resourcePath = parseRequest(resource).resourcePath
281
+ const parsed = path.parse(resourcePath)
282
+ const ext = parsed.ext
283
+ const resourceName = path.join(parsed.dir, parsed.name)
284
+
285
+ if (!outputPath) {
286
+ if (ext === '.js' && resourceName.includes('node_modules')) {
287
+ let root = info.descriptionFileRoot
288
+ let name = 'nativeComponent'
289
+ if (info.descriptionFileData) {
290
+ if (info.descriptionFileData.miniprogram) {
291
+ root = path.join(root, info.descriptionFileData.miniprogram)
292
+ }
293
+ if (info.descriptionFileData.name) {
294
+ // 去掉name里面的@符号,因为支付宝不支持文件路径上有@
295
+ name = info.descriptionFileData.name.split('@').join('')
296
+ }
297
+ }
298
+ let relativePath = path.relative(root, resourceName)
299
+ outputPath = path.join('components', name + pathHash(root), relativePath)
300
+ } else {
301
+ outputPath = getOutputPath(resourcePath, 'component')
302
+ }
303
+ }
304
+ const { packageRoot, outputPath: componentPath, alreadyOutputed } = mpx.getPackageInfo({
305
+ resource,
306
+ outputPath,
307
+ resourceType: 'components',
308
+ warn: (err) => {
309
+ this.emitWarning(err)
310
+ }
311
+ })
312
+ if (packageRoot) {
313
+ resource = addQuery(resource, {
314
+ packageRoot
315
+ })
316
+ }
317
+ rewritePath && rewritePath(publicPath + componentPath)
318
+ if (ext === '.js') {
319
+ resource = '!!' + nativeLoaderPath + '!' + resource
320
+ }
321
+ currentEntry.addChild(getEntryNode(resource, 'Component'))
322
+ // 如果之前已经创建了入口,直接return
323
+ if (alreadyOutputed) {
324
+ return callback()
325
+ }
326
+ addEntrySafely(resource, componentPath, callback)
327
+ })
328
+ }
329
+
330
+ // 由于json模块都是由mpx/js文件引入的,需要向上找两层issuer获取真实的引用源
331
+ const getJsonIssuer = (module) => {
332
+ if (module.issuer) {
333
+ return module.issuer.issuer
334
+ }
335
+ }
336
+
220
337
  if (isApp) {
338
+ if (!mpx.hasApp) {
339
+ mpx.hasApp = true
340
+ } else {
341
+ const issuer = getJsonIssuer(this._module)
342
+ if (issuer) {
343
+ emitError(`[json compiler]:Mpx单次构建中只能存在一个App,当前组件/页面[${this.resource}]通过[${issuer.resource}]非法引入,引用的资源将被忽略,请确保组件/页面资源通过usingComponents/pages配置引入!`)
344
+ } else {
345
+ emitError(`[json compiler]:Mpx单次构建中只能存在一个App,请检查当前entry中的资源[${this.resource}]是否为组件/页面,通过添加?component/page查询字符串显式声明该资源是组件/页面!`)
346
+ }
347
+ return callback()
348
+ }
221
349
  // app.json
222
- const localPages = []
223
350
  const subPackagesCfg = {}
224
- const pageKeySet = new Set()
225
-
226
- const processPages = (pages, context, tarRoot = '', callback) => {
227
- if (pages) {
228
- async.each(pages, (page, callback) => {
229
- processPage(page, context, tarRoot, (err, entry, { isFirst, key } = {}) => {
230
- if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err)
231
- if (pageKeySet.has(key)) return callback()
232
- pageKeySet.add(key)
233
- if (tarRoot && subPackagesCfg) {
234
- subPackagesCfg[tarRoot].pages.push(entry)
235
- } else {
236
- // 确保首页
237
- if (isFirst) {
238
- localPages.unshift(entry)
239
- } else {
240
- localPages.push(entry)
241
- }
242
- }
243
- callback()
244
- })
245
- }, callback)
351
+ const localPages = []
352
+ const processSubPackagesQueue = []
353
+ // 添加首页标识
354
+ if (json.pages && json.pages[0]) {
355
+ if (typeof json.pages[0] !== 'string') {
356
+ json.pages[0].src = addQuery(json.pages[0].src, { isFirst: true })
246
357
  } else {
247
- callback()
358
+ json.pages[0] = addQuery(json.pages[0], { isFirst: true })
248
359
  }
249
360
  }
250
361
 
251
362
  const processPackages = (packages, context, callback) => {
252
363
  if (packages) {
253
- async.each(packages, (packagePath, callback) => {
364
+ async.forEach(packages, (packagePath, callback) => {
254
365
  const { queryObj } = parseRequest(packagePath)
255
366
  async.waterfall([
256
367
  (callback) => {
257
- resolve(context, packagePath, this, (err, result) => {
258
- if (err) return callback(err)
368
+ resolve(context, packagePath, (err, result) => {
259
369
  const { rawResourcePath } = parseRequest(result)
260
370
  callback(err, rawResourcePath)
261
371
  })
262
372
  },
263
373
  (result, callback) => {
374
+ this.addDependency(result)
264
375
  fs.readFile(result, (err, content) => {
265
376
  if (err) return callback(err)
266
377
  callback(err, result, content.toString('utf-8'))
@@ -268,21 +379,24 @@ module.exports = function (content) {
268
379
  },
269
380
  (result, content, callback) => {
270
381
  const extName = path.extname(result)
271
- if (extName === '.mpx') {
382
+ if (extName === '.mpx' || extName === '.vue') {
272
383
  const parts = parseComponent(content, {
273
384
  filePath: result,
274
385
  needMap: this.sourceMap,
275
386
  mode,
387
+ defs,
276
388
  env
277
389
  })
278
- // 对于通过.mpx文件声明的独立分包,默认将其自身的script block视为init module
279
- if (queryObj.independent === true) queryObj.independent = result
280
- getJSONContent(parts.json || {}, this, (err, content) => {
281
- callback(err, result, content)
282
- })
283
- } else {
284
- callback(null, result, content)
390
+ const json = parts.json || {}
391
+ if (json.content) {
392
+ content = json.content
393
+ } else if (json.src) {
394
+ return readJsonForSrc(json.src, this, (content) => {
395
+ callback(null, result, content)
396
+ })
397
+ }
285
398
  }
399
+ callback(null, result, content)
286
400
  },
287
401
  (result, content, callback) => {
288
402
  try {
@@ -308,12 +422,12 @@ module.exports = function (content) {
308
422
  subPackage.plugins = content.plugins
309
423
  }
310
424
 
311
- processSelfQueue.push((callback) => {
425
+ processSubPackagesQueue.push((callback) => {
312
426
  processSubPackage(subPackage, context, callback)
313
427
  })
314
428
  } else {
315
429
  processSelfQueue.push((callback) => {
316
- processPages(content.pages, context, '', callback)
430
+ processPages(content.pages, '', '', context, callback)
317
431
  })
318
432
  }
319
433
  }
@@ -328,16 +442,14 @@ module.exports = function (content) {
328
442
  callback()
329
443
  }
330
444
  }
331
- ], (err) => {
332
- callback(err === RESOLVE_IGNORED_ERR ? null : err)
333
- })
445
+ ], callback)
334
446
  }, callback)
335
447
  } else {
336
448
  callback()
337
449
  }
338
450
  }
339
451
 
340
- const getOtherConfig = (config) => {
452
+ const getOtherConfig = (raw) => {
341
453
  let result = {}
342
454
  let blackListMap = {
343
455
  tarRoot: true,
@@ -345,39 +457,14 @@ module.exports = function (content) {
345
457
  root: true,
346
458
  pages: true
347
459
  }
348
- for (let key in config) {
460
+ for (let key in raw) {
349
461
  if (!blackListMap[key]) {
350
- result[key] = config[key]
462
+ result[key] = raw[key]
351
463
  }
352
464
  }
353
465
  return result
354
466
  }
355
467
 
356
- const recordIndependent = (root, request) => {
357
- this._module && this._module.addPresentationalDependency(new RecordIndependentDependency(root, request))
358
- }
359
-
360
- const processIndependent = (otherConfig, context, tarRoot, callback) => {
361
- // 支付宝不支持独立分包,无需处理
362
- const independent = otherConfig.independent
363
- if (!independent || mode === 'ali') {
364
- delete otherConfig.independent
365
- return callback()
366
- }
367
- // independent配置为字符串时视为init module
368
- if (typeof independent === 'string') {
369
- otherConfig.independent = true
370
- resolve(context, independent, this, (err, result) => {
371
- if (err) return callback(err)
372
- recordIndependent(tarRoot, result)
373
- callback()
374
- })
375
- } else {
376
- recordIndependent(tarRoot, true)
377
- callback()
378
- }
379
- }
380
-
381
468
  // 为了获取资源的所属子包,该函数需串行执行
382
469
  const processSubPackage = (subPackage, context, callback) => {
383
470
  if (subPackage) {
@@ -389,27 +476,29 @@ module.exports = function (content) {
389
476
  let srcRoot = subPackage.srcRoot || subPackage.root || ''
390
477
  if (!tarRoot || subPackagesCfg[tarRoot]) return callback()
391
478
 
392
- context = path.join(context, srcRoot)
393
479
  const otherConfig = getOtherConfig(subPackage)
480
+ // 支付宝不支持独立分包,无需处理
481
+ if (otherConfig.independent && mode !== 'ali') {
482
+ mpx.independentSubpackagesMap[tarRoot] = true
483
+ }
484
+
394
485
  subPackagesCfg[tarRoot] = {
395
486
  root: tarRoot,
396
- pages: []
487
+ pages: [],
488
+ ...otherConfig
397
489
  }
490
+ mpx.currentPackageRoot = tarRoot
491
+ mpx.componentsMap[tarRoot] = {}
492
+ mpx.staticResourcesMap[tarRoot] = {}
493
+ mpx.subpackageModulesMap[tarRoot] = {}
398
494
  async.parallel([
399
495
  (callback) => {
400
- processIndependent(otherConfig, context, tarRoot, callback)
401
- },
402
- (callback) => {
403
- processPages(subPackage.pages, context, tarRoot, callback)
496
+ processPages(subPackage.pages, srcRoot, tarRoot, context, callback)
404
497
  },
405
498
  (callback) => {
406
- processPlugins(subPackage.plugins, context, tarRoot, callback)
499
+ processPlugins(subPackage.plugins, srcRoot, tarRoot, context, callback)
407
500
  }
408
- ], (err) => {
409
- if (err) return callback(err)
410
- Object.assign(subPackagesCfg[tarRoot], otherConfig)
411
- callback()
412
- })
501
+ ], callback)
413
502
  } else {
414
503
  callback()
415
504
  }
@@ -417,8 +506,92 @@ module.exports = function (content) {
417
506
 
418
507
  const processSubPackages = (subPackages, context, callback) => {
419
508
  if (subPackages) {
420
- async.each(subPackages, (subPackage, callback) => {
421
- processSubPackage(subPackage, context, callback)
509
+ subPackages.forEach((subPackage) => {
510
+ processSubPackagesQueue.push((callback) => {
511
+ processSubPackage(subPackage, context, callback)
512
+ })
513
+ })
514
+ }
515
+ callback()
516
+ }
517
+
518
+ // const getPageName = (resourcePath, ext) => {
519
+ // const baseName = path.basename(resourcePath, ext)
520
+ // return path.join('pages', baseName + pathHash(resourcePath), baseName)
521
+ // }
522
+
523
+ const processPages = (pages, srcRoot = '', tarRoot = '', context, callback) => {
524
+ if (pages) {
525
+ context = path.join(context, srcRoot)
526
+ async.forEach(pages, (page, callback) => {
527
+ let aliasPath = ''
528
+ if (typeof page !== 'string') {
529
+ aliasPath = page.path
530
+ page = page.src
531
+ }
532
+ if (!isUrlRequest(page)) return callback()
533
+ if (resolveMode === 'native') {
534
+ page = urlToRequest(page)
535
+ }
536
+ resolve(context, page, (err, resource) => {
537
+ if (err) return callback(err)
538
+ const { resourcePath, queryObj } = parseRequest(resource)
539
+ const ext = path.extname(resourcePath)
540
+ // 获取pageName
541
+ let pageName
542
+ if (aliasPath) {
543
+ pageName = toPosix(path.join(tarRoot, aliasPath))
544
+ // 判断 key 存在重复情况直接报错
545
+ for (let key in pagesMap) {
546
+ if (pagesMap[key] === pageName && key !== resourcePath) {
547
+ emitError(`Current page [${resourcePath}] registers a conflict page path [${pageName}] with existed page [${key}], which is not allowed, please rename it!`)
548
+ return callback()
549
+ }
550
+ }
551
+ } else {
552
+ const relative = path.relative(context, resourcePath)
553
+ if (/^\./.test(relative)) {
554
+ // 如果当前page不存在于context中,对其进行重命名
555
+ pageName = getOutputPath(resourcePath, 'page')
556
+ emitWarning(`Current page [${resourcePath}] is not in current pages directory [${context}], the page path will be replaced with [${pageName}], use ?resolve to get the page path and navigate to it!`)
557
+ } else {
558
+ pageName = toPosix(path.join(tarRoot, /^(.*?)(\.[^.]*)?$/.exec(relative)[1]))
559
+ // 如果当前page与已有page存在命名冲突,也进行重命名
560
+ }
561
+ for (let key in pagesMap) {
562
+ if (pagesMap[key] === pageName && key !== resourcePath) {
563
+ const pageNameRaw = pageName
564
+ pageName = getOutputPath(resourcePath, 'page', { conflictPath: pageNameRaw })
565
+ emitWarning(`Current page [${resourcePath}] is registered with a conflict page path [${pageNameRaw}] which is already existed in system, the page path will be replaced with [${pageName}], use ?resolve to get the page path and navigate to it!`)
566
+ break
567
+ }
568
+ }
569
+ }
570
+ if (ext === '.js') {
571
+ resource = '!!' + nativeLoaderPath + '!' + resource
572
+ }
573
+ // 如果之前已经创建了页面入口,直接return,目前暂时不支持多个分包复用同一个页面
574
+ if (pagesMap[resourcePath]) {
575
+ emitWarning(`Current page [${resourcePath}] which is imported from [${this.resourcePath}] has been registered in pagesMap already, it will be ignored, please check it and remove the redundant page declaration!`)
576
+ return callback()
577
+ }
578
+ currentEntry.addChild(getEntryNode(resource, 'Page'))
579
+ pagesMap[resourcePath] = pageName
580
+ if (tarRoot && subPackagesCfg[tarRoot]) {
581
+ resource = addQuery(resource, {
582
+ packageRoot: tarRoot
583
+ })
584
+ subPackagesCfg[tarRoot].pages.push(toPosix(path.relative(tarRoot, pageName)))
585
+ } else {
586
+ // 确保首页
587
+ if (queryObj.isFirst) {
588
+ localPages.unshift(pageName)
589
+ } else {
590
+ localPages.push(pageName)
591
+ }
592
+ }
593
+ addEntrySafely(resource, pageName, callback)
594
+ })
422
595
  }, callback)
423
596
  } else {
424
597
  callback()
@@ -457,11 +630,15 @@ module.exports = function (content) {
457
630
 
458
631
  const processThemeLocation = (output) => {
459
632
  if (json.themeLocation && isUrlRequest(json.themeLocation)) {
460
- const requestString = getRequestString('json', { src: urlToRequest(json.themeLocation) }, {
461
- isTheme: true,
462
- isStatic: true
463
- })
464
- output += `json.themeLocation = require(${requestString});\n`
633
+ const themeRequest = '!!' + extractorPath + '?' +
634
+ JSON.stringify({
635
+ type: 'json',
636
+ index: -1
637
+ }) + '!' +
638
+ themeLoaderPath + '?root = ' + options.root + '!' +
639
+ addQuery(urlToRequest(json.themeLocation), { __component: true, isStatic: true })
640
+
641
+ output += `json.themeLocation = require(${stringifyRequest(themeRequest)});\n`
465
642
  }
466
643
  return output
467
644
  }
@@ -478,114 +655,146 @@ module.exports = function (content) {
478
655
 
479
656
  const processCustomTabBar = (tabBar, context, callback) => {
480
657
  if (tabBar && tabBar.custom) {
481
- processComponent('./custom-tab-bar/index', context, { outputPath: 'custom-tab-bar/index' }, (err, entry) => {
482
- if (err === RESOLVE_IGNORED_ERR) {
483
- delete tabBar.custom
484
- return callback()
485
- }
486
- tabBar.custom = entry // hack for javascript parser call hook.
487
- callback(err)
488
- })
658
+ processComponent('./custom-tab-bar/index', context, undefined, 'custom-tab-bar/index', callback)
489
659
  } else {
490
660
  callback()
491
661
  }
492
662
  }
493
663
 
494
- const processPluginGenericsImplementation = (plugin, context, tarRoot, callback) => {
495
- if (!plugin.genericsImplementation) return callback()
496
- const relativePath = useRelativePath ? publicPath + tarRoot : ''
497
- async.eachOf(plugin.genericsImplementation, (genericComponents, name, callback) => {
498
- async.eachOf(genericComponents, (genericComponentPath, name, callback) => {
499
- processComponent(genericComponentPath, context, {
500
- tarRoot,
501
- relativePath
502
- }, (err, entry) => {
503
- if (err === RESOLVE_IGNORED_ERR) {
504
- delete genericComponents[name]
505
- return callback()
664
+ const addMiniToPluginModules = module => {
665
+ if (mpx.miniToPluginModules) {
666
+ mpx.miniToPluginModules.add(module)
667
+ } else {
668
+ mpx.miniToPluginModules = new Set([module])
669
+ }
670
+ }
671
+
672
+ const processPluginGenericsImplementation = (genericsImplementation, tarRoot, context, callback) => {
673
+ async.forEachOf(genericsImplementation, (genericComponents, name, callback) => {
674
+ async.forEachOf(genericComponents, (genericComponentPath, name, callback) => {
675
+ processComponent(genericComponentPath, context, (componentPath) => {
676
+ if (useRelativePath === true) {
677
+ componentPath = toPosix(path.relative(publicPath + tarRoot, componentPath))
506
678
  }
507
- if (err) return callback(err)
508
- genericComponents[name] = entry
509
- })
679
+ genericComponents[name] = componentPath
680
+ }, undefined, callback)
510
681
  }, callback)
511
682
  }, callback)
512
683
  }
513
684
 
514
- const processPluginExport = (plugin, context, tarRoot, callback) => {
515
- if (!plugin.export) return callback()
516
- processJsExport(plugin.export, context, tarRoot, (err, entry) => {
517
- if (err === RESOLVE_IGNORED_ERR) {
518
- delete plugin.export
519
- return callback()
520
- }
685
+ const processPluginExport = (plugin, tarRoot, context, callback) => {
686
+ if (!plugin.export) {
687
+ return callback()
688
+ }
689
+ let pluginExport = plugin.export
690
+ if (resolveMode === 'native') {
691
+ pluginExport = urlToRequest(pluginExport)
692
+ }
693
+ resolve(context, pluginExport, (err, resource, info) => {
521
694
  if (err) return callback(err)
522
- plugin.export = entry
523
- callback()
695
+ const { resourcePath } = parseRequest(resource)
696
+ // 获取 export 的模块名
697
+ const relative = path.relative(context, resourcePath)
698
+ const name = toPosix(/^(.*?)(\.[^.]*)?$/.exec(relative)[1])
699
+ if (/^\./.test(name)) {
700
+ return callback(new Error(`The miniprogram plugins' export path ${plugin.export} must be in the context ${context}!`))
701
+ }
702
+ plugin.export = name + '.js'
703
+ addEntrySafely(resource, toPosix(tarRoot ? `${tarRoot}/${name}` : name), (err, module) => {
704
+ if (err) return callback(err)
705
+ addMiniToPluginModules(module)
706
+ currentEntry.addChild(getEntryNode(resource, 'PluginExport', module))
707
+ callback(err, module)
708
+ })
524
709
  })
525
710
  }
526
711
 
527
- const processPlugins = (plugins, context, tarRoot = '', callback) => {
528
- if (mode !== 'wx' || !plugins) return callback() // 目前只有微信支持导出到插件
529
- async.eachOf(plugins, (plugin, name, callback) => {
712
+ /* 导出到插件 */
713
+ const processPlugins = (plugins, srcRoot = '', tarRoot = '', context, callback) => {
714
+ if (mpx.mode !== 'wx' || !plugins) return callback() // 目前只有微信支持导出到插件
715
+ context = path.join(context, srcRoot)
716
+ async.forEachOf(plugins, (plugin, name, callback) => {
530
717
  async.parallel([
531
718
  (callback) => {
532
- processPluginGenericsImplementation(plugin, context, tarRoot, callback)
719
+ if (plugin.genericsImplementation) {
720
+ processPluginGenericsImplementation(plugin.genericsImplementation, tarRoot, context, callback)
721
+ } else {
722
+ callback()
723
+ }
533
724
  },
534
725
  (callback) => {
535
- processPluginExport(plugin, context, tarRoot, callback)
726
+ processPluginExport(plugin, tarRoot, context, callback)
536
727
  }
537
- ], callback)
728
+ ], (err) => {
729
+ callback(err)
730
+ })
538
731
  }, callback)
539
732
  }
540
733
 
541
- async.parallel([
734
+ // 串行处理,先处理主包代码,再处理分包代码,为了正确识别出分包中定义的组件属于主包还是分包
735
+ let errors = []
736
+ // 外部收集errors,确保整个series流程能够执行完
737
+ async.series([
542
738
  (callback) => {
543
- // 添加首页标识
544
- if (json.pages && json.pages[0]) {
545
- if (typeof json.pages[0] !== 'string') {
546
- json.pages[0].src = addQuery(json.pages[0].src, { isFirst: true })
547
- } else {
548
- json.pages[0] = addQuery(json.pages[0], { isFirst: true })
739
+ async.parallel([
740
+ (callback) => {
741
+ processPlugins(json.plugins, '', '', this.context, callback)
742
+ },
743
+ (callback) => {
744
+ processPages(json.pages, '', '', this.context, callback)
745
+ },
746
+ (callback) => {
747
+ processComponents(json.usingComponents, this.context, callback)
748
+ },
749
+ (callback) => {
750
+ processWorkers(json.workers, this.context, callback)
751
+ },
752
+ (callback) => {
753
+ processPackages(json.packages, this.context, callback)
754
+ },
755
+ (callback) => {
756
+ processCustomTabBar(json.tabBar, this.context, callback)
757
+ },
758
+ (callback) => {
759
+ processSubPackages(json.subPackages || json.subpackages, this.context, callback)
549
760
  }
550
- }
551
- processPages(json.pages, this.context, '', callback)
552
- },
553
- (callback) => {
554
- processComponents(json.usingComponents, this.context, callback)
555
- },
556
- (callback) => {
557
- processPlugins(json.plugins, this.context, '', callback)
558
- },
559
- (callback) => {
560
- processWorkers(json.workers, this.context, callback)
561
- },
562
- (callback) => {
563
- processPackages(json.packages, this.context, callback)
761
+ ], (err) => {
762
+ if (err) {
763
+ errors.push(err)
764
+ }
765
+ callback()
766
+ })
564
767
  },
565
768
  (callback) => {
566
- processCustomTabBar(json.tabBar, this.context, callback)
769
+ if (mpx.appScriptPromise) {
770
+ mpx.appScriptPromise.then(callback)
771
+ } else {
772
+ callback()
773
+ }
567
774
  },
568
775
  (callback) => {
569
- processSubPackages(json.subPackages || json.subpackages, this.context, callback)
776
+ async.series(processSubPackagesQueue, (err) => {
777
+ if (err) {
778
+ errors.push(err)
779
+ }
780
+ // 处理完分包后重置currentPackageRoot以确保app中的资源输出到主包
781
+ mpx.currentPackageRoot = ''
782
+ callback()
783
+ })
570
784
  }
571
- ], (err) => {
572
- if (err) return callback(err)
785
+ ], () => {
786
+ if (errors.length) return callback(errors[0])
573
787
  delete json.packages
574
788
  delete json.subpackages
575
789
  delete json.subPackages
576
790
  json.pages = localPages
577
791
  for (let root in subPackagesCfg) {
578
- const subPackageCfg = subPackagesCfg[root]
579
- // 分包不存在 pages,输出 subPackages 字段会报错
580
- if (subPackageCfg.pages.length) {
581
- if (!json.subPackages) {
582
- json.subPackages = []
583
- }
584
- json.subPackages.push(subPackageCfg)
792
+ if (!json.subPackages) {
793
+ json.subPackages = []
585
794
  }
795
+ json.subPackages.push(subPackagesCfg[root])
586
796
  }
587
797
  const processOutput = (output) => {
588
- output = processDynamicEntry(output)
589
798
  output = processTabBar(output)
590
799
  output = processOptionMenu(output)
591
800
  output = processThemeLocation(output)
@@ -594,20 +803,16 @@ module.exports = function (content) {
594
803
  callback(null, processOutput)
595
804
  })
596
805
  } else {
597
- // page.json或component.json
598
806
  const processGenerics = (generics, context, callback) => {
599
807
  if (generics) {
600
- async.eachOf(generics, (generic, name, callback) => {
808
+ async.forEachOf(generics, (generic, name, callback) => {
601
809
  if (generic.default) {
602
- processComponent(generic.default, context, { relativePath }, (err, entry) => {
603
- if (err === RESOLVE_IGNORED_ERR) {
604
- delete generic.default
605
- return callback()
810
+ processComponent(generic.default, context, (componentPath) => {
811
+ if (useRelativePath === true) {
812
+ componentPath = toPosix(path.relative(path.dirname(currentPath), componentPath))
606
813
  }
607
- if (err) return callback(err)
608
- generic.default = entry
609
- callback()
610
- })
814
+ generic.default = componentPath
815
+ }, undefined, callback)
611
816
  } else {
612
817
  callback()
613
818
  }
@@ -616,6 +821,7 @@ module.exports = function (content) {
616
821
  callback()
617
822
  }
618
823
  }
824
+ // page.json或component.json
619
825
  async.parallel([
620
826
  (callback) => {
621
827
  processComponents(json.usingComponents, this.context, callback)
@@ -624,7 +830,7 @@ module.exports = function (content) {
624
830
  processGenerics(json.componentGenerics, this.context, callback)
625
831
  }
626
832
  ], (err) => {
627
- callback(err, processDynamicEntry)
833
+ callback(err)
628
834
  })
629
835
  }
630
836
  }