@mpxjs/webpack-plugin 2.10.6-beta.2 → 2.10.6-beta.4

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 (46) hide show
  1. package/lib/file-loader.js +1 -1
  2. package/lib/index.js +35 -14
  3. package/lib/platform/index.js +2 -4
  4. package/lib/platform/json/wx/index.js +43 -25
  5. package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
  6. package/lib/platform/template/wx/component-config/index.js +2 -2
  7. package/lib/platform/template/wx/component-config/template.js +1 -26
  8. package/lib/platform/template/wx/index.js +5 -11
  9. package/lib/react/LoadAsyncChunkModule.js +68 -0
  10. package/lib/react/index.js +3 -1
  11. package/lib/react/processJSON.js +72 -17
  12. package/lib/react/processScript.js +4 -3
  13. package/lib/react/script-helper.js +92 -18
  14. package/lib/runtime/components/react/AsyncContainer.tsx +217 -0
  15. package/lib/runtime/components/react/AsyncSuspense.tsx +81 -0
  16. package/lib/runtime/components/react/dist/AsyncContainer.jsx +160 -0
  17. package/lib/runtime/components/react/dist/AsyncSuspense.jsx +68 -0
  18. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
  19. package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
  20. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +2 -2
  21. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +2 -2
  22. package/lib/runtime/components/react/dist/mpx-swiper.jsx +53 -27
  23. package/lib/runtime/components/react/dist/mpx-web-view.jsx +14 -28
  24. package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
  25. package/lib/runtime/components/react/dist/utils.jsx +84 -0
  26. package/lib/runtime/components/react/getInnerListeners.ts +1 -1
  27. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  28. package/lib/runtime/components/react/mpx-movable-view.tsx +2 -2
  29. package/lib/runtime/components/react/mpx-swiper-item.tsx +2 -2
  30. package/lib/runtime/components/react/mpx-swiper.tsx +53 -25
  31. package/lib/runtime/components/react/mpx-web-view.tsx +13 -33
  32. package/lib/runtime/components/react/types/global.d.ts +15 -0
  33. package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
  34. package/lib/runtime/components/react/utils.tsx +83 -1
  35. package/lib/runtime/optionProcessor.js +2 -2
  36. package/lib/template-compiler/compiler.js +11 -61
  37. package/lib/utils/dom-tag-config.js +17 -3
  38. package/lib/web/index.js +0 -2
  39. package/lib/web/processScript.js +7 -29
  40. package/lib/web/processTemplate.js +4 -10
  41. package/lib/web/script-helper.js +1 -1
  42. package/package.json +1 -1
  43. package/lib/dependencies/WriteVfsDependency.js +0 -46
  44. package/lib/utils/get-template-content.js +0 -47
  45. package/lib/web/template2vue.js +0 -280
  46. package/lib/web/wxml-template-loader.js +0 -29
@@ -36,7 +36,7 @@ module.exports = function loader (content, prevOptions) {
36
36
  let publicPath = `__webpack_public_path__ + ${JSON.stringify(url)}`
37
37
 
38
38
  // todo 未来添加分包处理后相对地址不一定是./开头的,需要考虑通过dependency的方式在sourceModule时通过最终的chunkName得到准确的相对路径
39
- if (isRN) publicPath = `__non_webpack_require__(${JSON.stringify(`./${url}`)})`
39
+ if (isRN) publicPath = `__non_webpack_require__(${JSON.stringify(`_mpx_rn_img_relative_path_/${url}`)})`
40
40
 
41
41
  if (options.publicPath) {
42
42
  if (typeof options.publicPath === 'function') {
package/lib/index.js CHANGED
@@ -44,7 +44,6 @@ const FlagPluginDependency = require('./dependencies/FlagPluginDependency')
44
44
  const RemoveEntryDependency = require('./dependencies/RemoveEntryDependency')
45
45
  const RecordLoaderContentDependency = require('./dependencies/RecordLoaderContentDependency')
46
46
  const RecordRuntimeInfoDependency = require('./dependencies/RecordRuntimeInfoDependency')
47
- const WriteVfsDependency = require('./dependencies/WriteVfsDependency')
48
47
  const SplitChunksPlugin = require('webpack/lib/optimize/SplitChunksPlugin')
49
48
  const fixRelative = require('./utils/fix-relative')
50
49
  const parseRequest = require('./utils/parse-request')
@@ -73,6 +72,8 @@ const isEmptyObject = require('./utils/is-empty-object')
73
72
  const DynamicPlugin = require('./resolver/DynamicPlugin')
74
73
  const { isReact, isWeb } = require('./utils/env')
75
74
  const VirtualModulesPlugin = require('webpack-virtual-modules')
75
+ const RuntimeGlobals = require('webpack/lib/RuntimeGlobals')
76
+ const LoadAsyncChunkModule = require('./react/LoadAsyncChunkModule')
76
77
  require('./utils/check-core-version-match')
77
78
 
78
79
  const isProductionLikeMode = options => {
@@ -409,7 +410,7 @@ class MpxWebpackPlugin {
409
410
  let splitChunksOptions = null
410
411
  let splitChunksPlugin = null
411
412
  // 输出web ssr需要将optimization.splitChunks设置为false以关闭splitChunks
412
- if (optimization.splitChunks !== false && !isReact(this.options.mode)) {
413
+ if (optimization.splitChunks !== false) {
413
414
  splitChunksOptions = Object.assign({
414
415
  chunks: 'all',
415
416
  usedExports: optimization.usedExports === true,
@@ -607,6 +608,22 @@ class MpxWebpackPlugin {
607
608
  return mpx
608
609
  }
609
610
  })
611
+
612
+ if (isReact(this.options.mode)) {
613
+ compilation.hooks.runtimeRequirementInTree
614
+ .for(RuntimeGlobals.loadScript)
615
+ .tap({
616
+ stage: -1000,
617
+ name: 'LoadAsyncChunk'
618
+ }, (chunk, set) => {
619
+ compilation.addRuntimeModule(
620
+ chunk,
621
+ new LoadAsyncChunkModule(this.options.rnConfig && this.options.rnConfig.asyncChunk && this.options.rnConfig.asyncChunk.timeout)
622
+ )
623
+ return true
624
+ })
625
+ }
626
+
610
627
  compilation.dependencyFactories.set(ResolveDependency, new NullFactory())
611
628
  compilation.dependencyTemplates.set(ResolveDependency, new ResolveDependency.Template())
612
629
 
@@ -655,9 +672,6 @@ class MpxWebpackPlugin {
655
672
  compilation.dependencyFactories.set(RecordRuntimeInfoDependency, new NullFactory())
656
673
  compilation.dependencyTemplates.set(RecordRuntimeInfoDependency, new RecordRuntimeInfoDependency.Template())
657
674
 
658
- compilation.dependencyFactories.set(WriteVfsDependency, new NullFactory())
659
- compilation.dependencyTemplates.set(WriteVfsDependency, new WriteVfsDependency.Template())
660
-
661
675
  compilation.dependencyTemplates.set(ImportDependency, new ImportDependencyTemplate())
662
676
  })
663
677
 
@@ -681,8 +695,6 @@ class MpxWebpackPlugin {
681
695
  componentsMap: {
682
696
  main: {}
683
697
  },
684
- // 用于template模版获取父组件引用的自定义组件,目前仅输出web时下支持使用
685
- parentLocalComponentsMap: {},
686
698
  // 静态资源(图片,字体,独立样式)等,依照所属包进行记录
687
699
  staticResourcesMap: {
688
700
  main: {}
@@ -746,7 +758,7 @@ class MpxWebpackPlugin {
746
758
  removedChunks: [],
747
759
  forceProxyEventRules: this.options.forceProxyEventRules,
748
760
  // 若配置disableRequireAsync=true, 则全平台构建不支持异步分包
749
- supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode)),
761
+ supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode) || isReact(this.options.mode)),
750
762
  partialCompileRules: this.options.partialCompileRules,
751
763
  collectDynamicEntryInfo: ({ resource, packageName, filename, entryType, hasAsync }) => {
752
764
  const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || {
@@ -1205,12 +1217,12 @@ class MpxWebpackPlugin {
1205
1217
  // 自动使用分包配置修改splitChunksPlugin配置
1206
1218
  if (splitChunksPlugin) {
1207
1219
  let needInit = false
1208
- if (isWeb(mpx.mode)) {
1220
+ if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1209
1221
  // web独立处理splitChunk
1210
- if (!hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1222
+ if (isWeb(mpx.mode) && !hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1211
1223
  splitChunksOptions.cacheGroups.main = {
1212
1224
  chunks: 'initial',
1213
- name: 'bundle',
1225
+ name: 'bundle/index', // web 输出 chunk 路径和 rn 输出分包格式拉齐
1214
1226
  test: /[\\/]node_modules[\\/]/
1215
1227
  }
1216
1228
  needInit = true
@@ -1218,7 +1230,7 @@ class MpxWebpackPlugin {
1218
1230
  if (!hasOwn(splitChunksOptions.cacheGroups, 'async')) {
1219
1231
  splitChunksOptions.cacheGroups.async = {
1220
1232
  chunks: 'async',
1221
- name: 'async',
1233
+ name: 'async/index',
1222
1234
  minChunks: 2
1223
1235
  }
1224
1236
  needInit = true
@@ -1321,6 +1333,15 @@ class MpxWebpackPlugin {
1321
1333
  compilation.hooks.processAssets.tap({
1322
1334
  name: 'MpxWebpackPlugin'
1323
1335
  }, (assets) => {
1336
+ if (isReact(mpx.mode)) {
1337
+ Object.keys(assets).forEach((chunkName) => {
1338
+ if (/\.js$/.test(chunkName)) {
1339
+ let val = assets[chunkName].source()
1340
+ val = val.replace(/_mpx_rn_img_relative_path_/g, chunkName === 'app.js' ? '.' : '..')
1341
+ compilation.assets[chunkName] = new RawSource(val)
1342
+ }
1343
+ })
1344
+ }
1324
1345
  try {
1325
1346
  const dynamicAssets = {}
1326
1347
  for (const packageName in mpx.runtimeInfo) {
@@ -1395,10 +1416,10 @@ class MpxWebpackPlugin {
1395
1416
  if (queryObj.root) request = addQuery(request, {}, false, ['root'])
1396
1417
  // wx、ali和web平台支持require.async,其余平台使用CommonJsAsyncDependency进行模拟抹平
1397
1418
  if (mpx.supportRequireAsync) {
1398
- if (isWeb(mpx.mode)) {
1419
+ if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1399
1420
  const depBlock = new AsyncDependenciesBlock(
1400
1421
  {
1401
- name: tarRoot
1422
+ name: tarRoot + '/index'
1402
1423
  },
1403
1424
  expr.loc,
1404
1425
  request
@@ -9,7 +9,6 @@ module.exports = function getRulesRunner ({
9
9
  testKey,
10
10
  mainKey,
11
11
  waterfall,
12
- moduleId,
13
12
  warn,
14
13
  error
15
14
  }) {
@@ -24,14 +23,13 @@ module.exports = function getRulesRunner ({
24
23
  wx: require('./json/wx')
25
24
  }
26
25
  }
27
- const spec = specMap[type] && specMap[type][srcMode] && specMap[type][srcMode]({ warn, error, moduleId })
26
+ const spec = specMap[type] && specMap[type][srcMode] && specMap[type][srcMode]({ warn, error })
28
27
  if (spec && spec.supportedModes.indexOf(mode) > -1) {
29
28
  const normalizeTest = spec.normalizeTest
30
29
  const mainRules = mainKey ? spec[mainKey] : spec
31
30
  if (mainRules) {
32
31
  return function (input) {
33
- const a = runRules(mainRules, input, { mode, data, meta, testKey, waterfall, normalizeTest })
34
- return a
32
+ return runRules(mainRules, input, { mode, data, meta, testKey, waterfall, normalizeTest })
35
33
  }
36
34
  }
37
35
  }
@@ -3,7 +3,7 @@ const normalizeTest = require('../normalize-test')
3
3
  const changeKey = require('../change-key')
4
4
  const normalize = require('../../../utils/normalize')
5
5
  const { capitalToHyphen } = require('../../../utils/string')
6
- const { isOriginTag, isBuildInTag } = require('../../../utils/dom-tag-config')
6
+ const { isOriginTag, isBuildInWebTag, isBuildInReactTag } = require('../../../utils/dom-tag-config')
7
7
 
8
8
  const mpxViewPath = normalize.lib('runtime/components/ali/mpx-view.mpx')
9
9
  const mpxTextPath = normalize.lib('runtime/components/ali/mpx-text.mpx')
@@ -128,19 +128,41 @@ module.exports = function getSpec ({ warn, error }) {
128
128
  /**
129
129
  * 将小程序代码中使用的与原生 HTML tag 或 内建组件 同名的组件进行转化,以解决与原生tag命名冲突问题。
130
130
  */
131
- function fixComponentName (type) {
132
- return function (input) {
133
- const usingComponents = input[type]
134
- if (usingComponents) {
135
- Object.keys(usingComponents).forEach(tag => {
136
- if (isOriginTag(tag) || isBuildInTag(tag)) {
137
- usingComponents[`mpx-com-${tag}`] = usingComponents[tag]
138
- delete usingComponents[tag]
131
+ function fixComponentName (input, { mode }) {
132
+ const isNeedFixTag = (tag) => {
133
+ switch (mode) {
134
+ case 'web': return isOriginTag(tag) || isBuildInWebTag(tag)
135
+ case 'ios':
136
+ case 'android':
137
+ case 'harmony': return isOriginTag(tag) || isBuildInReactTag(tag)
138
+ }
139
+ }
140
+
141
+ const usingComponents = input.usingComponents
142
+ const componentPlaceholder = input.componentPlaceholder
143
+ if (usingComponents) {
144
+ const transfromKeys = []
145
+ Object.keys(usingComponents).forEach(tag => {
146
+ if (isNeedFixTag(tag)) {
147
+ usingComponents[`mpx-com-${tag}`] = usingComponents[tag]
148
+ delete usingComponents[tag]
149
+ transfromKeys.push(tag)
150
+ }
151
+ })
152
+
153
+ if (transfromKeys.length && componentPlaceholder) {
154
+ Object.keys(componentPlaceholder).forEach(key => {
155
+ if (transfromKeys.includes(componentPlaceholder[key])) {
156
+ componentPlaceholder[key] = `mpx-com-${componentPlaceholder[key]}`
157
+ }
158
+ if (transfromKeys.includes(key)) {
159
+ componentPlaceholder[`mpx-com-${key}`] = componentPlaceholder[key]
160
+ delete componentPlaceholder[key]
139
161
  }
140
162
  })
141
163
  }
142
- return input
143
164
  }
165
+ return input
144
166
  }
145
167
 
146
168
  const componentRules = [
@@ -154,13 +176,6 @@ module.exports = function getSpec ({ warn, error }) {
154
176
  swan: deletePath(),
155
177
  jd: deletePath()
156
178
  },
157
- {
158
- test: 'usingComponents',
159
- web: fixComponentName('usingComponents'),
160
- ios: fixComponentName('usingComponents'),
161
- android: fixComponentName('usingComponents'),
162
- harmony: fixComponentName('usingComponents')
163
- },
164
179
  {
165
180
  test: 'usingComponents',
166
181
  ali: componentNameCapitalToHyphen('usingComponents'),
@@ -170,7 +185,11 @@ module.exports = function getSpec ({ warn, error }) {
170
185
  swan: addGlobalComponents,
171
186
  qq: addGlobalComponents,
172
187
  tt: addGlobalComponents,
173
- jd: addGlobalComponents
188
+ jd: addGlobalComponents,
189
+ web: fixComponentName,
190
+ ios: fixComponentName,
191
+ android: fixComponentName,
192
+ harmony: fixComponentName
174
193
  }
175
194
  ]
176
195
 
@@ -371,13 +390,6 @@ module.exports = function getSpec ({ warn, error }) {
371
390
  tt: deletePath(),
372
391
  jd: deletePath(true)
373
392
  },
374
- {
375
- test: 'usingComponents',
376
- web: fixComponentName('usingComponents'),
377
- ios: fixComponentName('usingComponents'),
378
- android: fixComponentName('usingComponents'),
379
- harmony: fixComponentName('usingComponents')
380
- },
381
393
  {
382
394
  test: 'usingComponents',
383
395
  ali: componentNameCapitalToHyphen('usingComponents'),
@@ -442,6 +454,12 @@ module.exports = function getSpec ({ warn, error }) {
442
454
  swan: getWindowRule(),
443
455
  tt: getWindowRule(),
444
456
  jd: getWindowRule()
457
+ },
458
+ {
459
+ web: fixComponentName,
460
+ ios: fixComponentName,
461
+ android: fixComponentName,
462
+ harmony: fixComponentName
445
463
  }
446
464
  ]
447
465
  }
@@ -1,4 +1,4 @@
1
- const { isOriginTag, isBuildInTag } = require('../../../../utils/dom-tag-config')
1
+ const { isOriginTag, isBuildInWebTag } = require('../../../../utils/dom-tag-config')
2
2
 
3
3
  module.exports = function () {
4
4
  const handleComponentTag = (el, data) => {
@@ -16,7 +16,7 @@ module.exports = function () {
16
16
  waterfall: true,
17
17
  skipNormalize: true,
18
18
  supportedModes: ['web', 'ios', 'android', 'harmony'],
19
- test: (input) => isOriginTag(input) || isBuildInTag(input),
19
+ test: (input) => isOriginTag(input) || isBuildInWebTag(input),
20
20
  web: handleComponentTag,
21
21
  ios: handleComponentTag,
22
22
  android: handleComponentTag,
@@ -45,7 +45,7 @@ const rootPortal = require('./root-portal')
45
45
  const stickyHeader = require('./sticky-header')
46
46
  const stickySection = require('./sticky-section')
47
47
 
48
- module.exports = function getComponentConfigs ({ warn, error, moduleId }) {
48
+ module.exports = function getComponentConfigs ({ warn, error }) {
49
49
  /**
50
50
  * universal print for detail component warn or error
51
51
  * @param {object} config
@@ -116,7 +116,7 @@ module.exports = function getComponentConfigs ({ warn, error, moduleId }) {
116
116
  map({ print }),
117
117
  canvas({ print }),
118
118
  wxs({ print }),
119
- template({ moduleId }),
119
+ template(),
120
120
  block(),
121
121
  icon(),
122
122
  webView({ print }),
@@ -1,13 +1,8 @@
1
1
  const TAG_NAME = 'template'
2
2
 
3
- module.exports = function ({ moduleId }) {
3
+ module.exports = function () {
4
4
  return {
5
5
  test: TAG_NAME,
6
- web (tag, { el }) {
7
- if (el.attrsMap[':is']) {
8
- return 'component'
9
- }
10
- },
11
6
  props: [
12
7
  {
13
8
  test: 'data',
@@ -16,26 +11,6 @@ module.exports = function ({ moduleId }) {
16
11
  name,
17
12
  value: `{${value}}`
18
13
  }
19
- },
20
- web ({ value }) {
21
- let bindValue = value
22
- if (moduleId) {
23
- const lastIndex = value.lastIndexOf('}}')
24
- bindValue = value ? value.slice(0, lastIndex) + `, _data_v_id: '${moduleId}'}}` : `{{ _data_v_id: '${moduleId}' }}`
25
- }
26
- return {
27
- name: 'v-bind',
28
- value: bindValue
29
- }
30
- }
31
- },
32
- {
33
- test: 'is',
34
- web ({ value }) {
35
- return {
36
- name: ':is',
37
- value: `'${value}'`
38
- }
39
14
  }
40
15
  }
41
16
  ]
@@ -3,11 +3,11 @@ const JSON5 = require('json5')
3
3
  const getComponentConfigs = require('./component-config')
4
4
  const normalizeComponentRules = require('../normalize-component-rules')
5
5
  const isValidIdentifierStr = require('../../../utils/is-valid-identifier-str')
6
- const { vbindMustache, parseMustacheWithContext, stringifyWithResolveComputed } = require('../../../template-compiler/compiler')
6
+ const { parseMustacheWithContext, stringifyWithResolveComputed } = require('../../../template-compiler/compiler')
7
7
  const normalize = require('../../../utils/normalize')
8
8
  const { dash2hump } = require('../../../utils/hump-dash')
9
9
 
10
- module.exports = function getSpec ({ warn, error, moduleId }) {
10
+ module.exports = function getSpec ({ warn, error }) {
11
11
  function getRnDirectiveEventHandle (mode) {
12
12
  return function ({ name, value }, { eventRules, el }) {
13
13
  const match = this.test.exec(name)
@@ -34,7 +34,8 @@ module.exports = function getSpec ({ warn, error, moduleId }) {
34
34
  touchstart: 'touchstart',
35
35
  touchmove: 'touchmove',
36
36
  touchend: 'touchend',
37
- touchcancel: 'touchcancel'
37
+ touchcancel: 'touchcancel',
38
+ transitionend: 'transitionend'
38
39
  }
39
40
  if (eventMap[eventName]) {
40
41
  return eventMap[eventName]
@@ -68,13 +69,6 @@ module.exports = function getSpec ({ warn, error, moduleId }) {
68
69
  postProps: [
69
70
  {
70
71
  web ({ name, value }) {
71
- if (name === 'v-bind') {
72
- const vbindValue = vbindMustache(value)
73
- return {
74
- name,
75
- value: vbindValue
76
- }
77
- }
78
72
  const parsed = parseMustacheWithContext(value)
79
73
  if (name.startsWith('data-')) {
80
74
  return {
@@ -574,6 +568,6 @@ module.exports = function getSpec ({ warn, error, moduleId }) {
574
568
  ]
575
569
  }
576
570
  }
577
- spec.rules = normalizeComponentRules(getComponentConfigs({ warn, error, moduleId }).concat({}), spec)
571
+ spec.rules = normalizeComponentRules(getComponentConfigs({ warn, error }).concat({}), spec)
578
572
  return spec
579
573
  }
@@ -0,0 +1,68 @@
1
+ const RuntimeGlobals = require('webpack/lib/RuntimeGlobals')
2
+ const Template = require('webpack/lib/Template')
3
+ const HelperRuntimeModule = require('webpack/lib/runtime/HelperRuntimeModule')
4
+
5
+ class LoadAsyncChunkRuntimeModule extends HelperRuntimeModule {
6
+ constructor (timeout) {
7
+ super('load async chunk')
8
+ this.timeout = timeout || 5000
9
+ }
10
+
11
+ generate () {
12
+ const { compilation } = this
13
+ const { runtimeTemplate } = compilation
14
+ const loadScriptFn = RuntimeGlobals.loadScript
15
+ return Template.asString([
16
+ 'var inProgress = {};',
17
+ `${loadScriptFn} = ${runtimeTemplate.basicFunction(
18
+ 'url, done, key, chunkId',
19
+ [
20
+ `var packageName = ${RuntimeGlobals.getChunkScriptFilename}(chunkId) || ''`,
21
+ 'packageName = packageName.split("/")[0]',
22
+ 'var config = {',
23
+ Template.indent([
24
+ 'url: url,',
25
+ 'package: packageName'
26
+ ]),
27
+ '}',
28
+ 'if(inProgress[url]) { inProgress[url].push(done); return; }',
29
+ 'inProgress[url] = [done];',
30
+ 'var callback = function (type, result) {',
31
+ Template.indent([
32
+ 'var event = {',
33
+ Template.indent([
34
+ 'type: type,',
35
+ 'target: {',
36
+ Template.indent(['src: url']),
37
+ '}'
38
+ ]),
39
+ '}'
40
+ ]),
41
+ Template.indent([
42
+ 'var doneFns = inProgress[url]',
43
+ 'clearTimeout(timeoutCallback)',
44
+ 'delete inProgress[url]',
45
+ `doneFns && doneFns.forEach(${runtimeTemplate.returningFunction(
46
+ 'fn(event)',
47
+ 'fn'
48
+ )})`
49
+ ]),
50
+ '}',
51
+ `var timeoutCallback = setTimeout(callback.bind(null, 'timeout'), ${this.timeout})`,
52
+ "var successCallback = callback.bind(null, 'load');",
53
+ "var failedCallback = callback.bind(null, 'fail')",
54
+ 'var loadChunkAsyncFn = global.__mpx.config.rnConfig && global.__mpx.config.rnConfig.loadChunkAsync',
55
+ 'if (typeof loadChunkAsyncFn !== \'function\') {',
56
+ Template.indent([
57
+ 'console.error("[Mpx runtime error]: please provide correct loadChunkAsync function")',
58
+ 'return'
59
+ ]),
60
+ '}',
61
+ 'loadChunkAsyncFn(config).then(successCallback).catch(failedCallback)'
62
+ ]
63
+ )}`
64
+ ])
65
+ }
66
+ }
67
+
68
+ module.exports = LoadAsyncChunkRuntimeModule
@@ -35,6 +35,7 @@ module.exports = function ({
35
35
  })
36
36
  }
37
37
  const mpx = loaderContext.getMpx()
38
+ const rnConfig = mpx.rnConfig
38
39
  // 通过RecordLoaderContentDependency和loaderContentCache确保子request不再重复生成loaderContent
39
40
  const cacheContent = mpx.loaderContentCache.get(loaderContext.resourcePath)
40
41
  if (cacheContent) return callback(null, cacheContent)
@@ -91,7 +92,8 @@ module.exports = function ({
91
92
  genericsInfo: templateRes.genericsInfo,
92
93
  wxsModuleMap: templateRes.wxsModuleMap,
93
94
  localComponentsMap: jsonRes.localComponentsMap,
94
- localPagesMap: jsonRes.localPagesMap
95
+ localPagesMap: jsonRes.localPagesMap,
96
+ rnConfig
95
97
  }, callback)
96
98
  }
97
99
  ], (err, scriptRes) => {
@@ -11,8 +11,11 @@ const resolve = require('../utils/resolve')
11
11
  const createJSONHelper = require('../json-compiler/helper')
12
12
  const getRulesRunner = require('../platform/index')
13
13
  const { RESOLVE_IGNORED_ERR } = require('../utils/const')
14
+ const normalize = require('../utils/normalize')
14
15
  const RecordResourceMapDependency = require('../dependencies/RecordResourceMapDependency')
15
16
  const RecordPageConfigsMapDependency = require('../dependencies/RecordPageConfigsMapDependency')
17
+ const mpxViewPath = normalize.lib('runtime/components/react/dist/mpx-view.jsx')
18
+ const mpxTextPath = normalize.lib('runtime/components/react/dist/mpx-text.jsx')
16
19
 
17
20
  module.exports = function (jsonContent, {
18
21
  loaderContext,
@@ -113,14 +116,14 @@ module.exports = function (jsonContent, {
113
116
  }
114
117
 
115
118
  if (ctorType === 'page') {
116
- // const keysToExtract = ['navigationStyle']
119
+ const keysToExtract = ['navigationStyle', 'navigationBarTitleText', 'navigationBarTextStyle', 'navigationBarBackgroundColor']
117
120
  const configObj = {}
118
121
  // 暂时先不注入数据,后续如需要使用再用
119
- // keysToExtract.forEach(key => {
120
- // if (jsonObj[key]) {
121
- // configObj[key] = jsonObj[key]
122
- // }
123
- // })
122
+ keysToExtract.forEach(key => {
123
+ if (jsonObj[key]) {
124
+ configObj[key] = jsonObj[key]
125
+ }
126
+ })
124
127
  loaderContext._module.addPresentationalDependency(new RecordPageConfigsMapDependency(parseRequest(loaderContext.resource).resourcePath, configObj))
125
128
  }
126
129
 
@@ -133,6 +136,29 @@ module.exports = function (jsonContent, {
133
136
  isShow: true
134
137
  }
135
138
 
139
+ const fillInComponentPlaceholder = (name, placeholder, placeholderEntry) => {
140
+ const componentPlaceholder = jsonObj.componentPlaceholder || {}
141
+ if (componentPlaceholder[name]) return
142
+ componentPlaceholder[name] = placeholder
143
+ jsonObj.componentPlaceholder = componentPlaceholder
144
+ if (placeholderEntry && !jsonObj.usingComponents[placeholder]) jsonObj.usingComponents[placeholder] = placeholderEntry
145
+ }
146
+ const normalizePlaceholder = (placeholder) => {
147
+ if (typeof placeholder === 'string') {
148
+ const placeholderMap = mode === 'ali'
149
+ ? {
150
+ view: { name: 'mpx-view', resource: mpxViewPath },
151
+ text: { name: 'mpx-text', resource: mpxTextPath }
152
+ }
153
+ : {}
154
+ placeholder = placeholderMap[placeholder] || { name: placeholder }
155
+ }
156
+ if (!placeholder.name) {
157
+ emitError('The asyncSubpackageRules configuration format of @mpxjs/webpack-plugin a is incorrect')
158
+ }
159
+ return placeholder
160
+ }
161
+
136
162
  const processTabBar = (tabBar, callback) => {
137
163
  if (tabBar) {
138
164
  tabBar = Object.assign({}, defaultTabbar, tabBar)
@@ -301,19 +327,48 @@ module.exports = function (jsonContent, {
301
327
  const processComponents = (components, context, callback) => {
302
328
  if (components) {
303
329
  async.eachOf(components, (component, name, callback) => {
304
- processComponent(component, context, {}, (err, { resource, outputPath } = {}, { tarRoot } = {}) => {
330
+ processComponent(component, context, {}, (err, entry = {}, { tarRoot, placeholder } = {}) => {
305
331
  if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err)
306
- const { resourcePath, queryObj } = parseRequest(resource)
307
- componentsMap[resourcePath] = outputPath
308
- loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'component', outputPath))
309
- localComponentsMap[name] = {
310
- resource: addQuery(resource, {
311
- isComponent: true,
312
- outputPath
313
- }),
314
- async: queryObj.async || tarRoot
332
+ const fillComponentsMap = (name, entry, tarRoot) => {
333
+ const { resource, outputPath } = entry
334
+ const { resourcePath, queryObj } = parseRequest(resource)
335
+ componentsMap[resourcePath] = outputPath
336
+ loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'component', outputPath))
337
+ localComponentsMap[name] = {
338
+ resource: addQuery(resource, {
339
+ isComponent: true,
340
+ outputPath
341
+ }),
342
+ async: queryObj.async || tarRoot
343
+ }
344
+ }
345
+ fillComponentsMap(name, entry, tarRoot)
346
+ const { relativePath } = entry
347
+
348
+ if (tarRoot) {
349
+ if (placeholder) {
350
+ placeholder = normalizePlaceholder(placeholder)
351
+ if (placeholder.resource) {
352
+ processComponent(placeholder.resource, projectRoot, { relativePath }, (err, entry) => {
353
+ if (err) return callback(err)
354
+ fillInComponentPlaceholder(name, placeholder.name, entry)
355
+ fillComponentsMap(placeholder.name, entry, '')
356
+ callback()
357
+ })
358
+ } else {
359
+ fillInComponentPlaceholder(name, placeholder.name)
360
+ callback()
361
+ }
362
+ } else {
363
+ if (!jsonObj.componentPlaceholder || !jsonObj.componentPlaceholder[name]) {
364
+ const errMsg = `componentPlaceholder of "${name}" doesn't exist! \n\r`
365
+ emitError(errMsg)
366
+ }
367
+ callback()
368
+ }
369
+ } else {
370
+ callback()
315
371
  }
316
- callback()
317
372
  })
318
373
  }, callback)
319
374
  } else {
@@ -13,6 +13,7 @@ module.exports = function (script, {
13
13
  builtInComponentsMap,
14
14
  localComponentsMap,
15
15
  localPagesMap,
16
+ rnConfig,
16
17
  componentGenerics,
17
18
  genericsInfo
18
19
  }, callback) {
@@ -32,6 +33,7 @@ module.exports = function (script, {
32
33
  }
33
34
 
34
35
  let output = '/* script */\n'
36
+ output += "import { lazy, createElement, memo, forwardRef } from 'react'\n"
35
37
  if (ctorType === 'app') {
36
38
  output += `
37
39
  import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}
@@ -39,7 +41,8 @@ import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPa
39
41
  const { pagesMap, firstPage } = buildPagesMap({
40
42
  localPagesMap,
41
43
  loaderContext,
42
- jsonConfig
44
+ jsonConfig,
45
+ rnConfig
43
46
  })
44
47
  const componentsMap = buildComponentsMap({
45
48
  localComponentsMap,
@@ -50,8 +53,6 @@ import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPa
50
53
  output += getRequireScript({ ctorType, script, loaderContext })
51
54
  output += `export default global.__mpxOptionsMap[${JSON.stringify(moduleId)}]\n`
52
55
  } else {
53
- // RN环境暂不支持异步加载
54
- // output += 'import { lazy } from \'react\'\n'
55
56
  output += `import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
56
57
  // 获取组件集合
57
58
  const componentsMap = buildComponentsMap({