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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/lib/file-loader.js +1 -1
  2. package/lib/index.js +41 -13
  3. package/lib/platform/json/wx/index.js +43 -26
  4. package/lib/platform/template/wx/component-config/button.js +1 -1
  5. package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
  6. package/lib/platform/template/wx/component-config/index.js +5 -1
  7. package/lib/platform/template/wx/component-config/input.js +1 -1
  8. package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
  9. package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
  10. package/lib/platform/template/wx/index.js +2 -1
  11. package/lib/react/LoadAsyncChunkModule.js +68 -0
  12. package/lib/react/index.js +3 -1
  13. package/lib/react/processJSON.js +68 -12
  14. package/lib/react/processScript.js +4 -3
  15. package/lib/react/script-helper.js +92 -18
  16. package/lib/runtime/components/react/AsyncContainer.tsx +217 -0
  17. package/lib/runtime/components/react/AsyncSuspense.tsx +81 -0
  18. package/lib/runtime/components/react/context.ts +12 -3
  19. package/lib/runtime/components/react/dist/AsyncContainer.jsx +160 -0
  20. package/lib/runtime/components/react/dist/AsyncSuspense.jsx +68 -0
  21. package/lib/runtime/components/react/dist/context.js +4 -1
  22. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
  23. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  24. package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
  25. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +1 -1
  26. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +55 -40
  27. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -0
  28. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +17 -6
  29. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +115 -0
  30. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
  31. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +2 -2
  32. package/lib/runtime/components/react/dist/mpx-swiper.jsx +53 -27
  33. package/lib/runtime/components/react/dist/mpx-view.jsx +21 -7
  34. package/lib/runtime/components/react/dist/mpx-web-view.jsx +16 -30
  35. package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
  36. package/lib/runtime/components/react/dist/utils.jsx +105 -1
  37. package/lib/runtime/components/react/getInnerListeners.ts +1 -1
  38. package/lib/runtime/components/react/mpx-button.tsx +3 -2
  39. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  40. package/lib/runtime/components/react/mpx-movable-area.tsx +1 -1
  41. package/lib/runtime/components/react/mpx-movable-view.tsx +60 -41
  42. package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -0
  43. package/lib/runtime/components/react/mpx-scroll-view.tsx +68 -50
  44. package/lib/runtime/components/react/mpx-sticky-header.tsx +179 -0
  45. package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
  46. package/lib/runtime/components/react/mpx-swiper-item.tsx +2 -2
  47. package/lib/runtime/components/react/mpx-swiper.tsx +53 -25
  48. package/lib/runtime/components/react/mpx-view.tsx +20 -7
  49. package/lib/runtime/components/react/mpx-web-view.tsx +14 -34
  50. package/lib/runtime/components/react/types/global.d.ts +15 -0
  51. package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
  52. package/lib/runtime/components/react/utils.tsx +93 -1
  53. package/lib/runtime/components/web/mpx-scroll-view.vue +21 -4
  54. package/lib/runtime/components/web/mpx-sticky-header.vue +91 -0
  55. package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
  56. package/lib/runtime/optionProcessor.js +0 -2
  57. package/lib/template-compiler/compiler.js +2 -2
  58. package/lib/utils/dom-tag-config.js +17 -3
  59. package/lib/web/script-helper.js +1 -1
  60. package/package.json +4 -4
  61. package/LICENSE +0 -433
@@ -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
@@ -72,6 +72,8 @@ const isEmptyObject = require('./utils/is-empty-object')
72
72
  const DynamicPlugin = require('./resolver/DynamicPlugin')
73
73
  const { isReact, isWeb } = require('./utils/env')
74
74
  const VirtualModulesPlugin = require('webpack-virtual-modules')
75
+ const RuntimeGlobals = require('webpack/lib/RuntimeGlobals')
76
+ const LoadAsyncChunkModule = require('./react/LoadAsyncChunkModule')
75
77
  require('./utils/check-core-version-match')
76
78
 
77
79
  const isProductionLikeMode = options => {
@@ -408,7 +410,7 @@ class MpxWebpackPlugin {
408
410
  let splitChunksOptions = null
409
411
  let splitChunksPlugin = null
410
412
  // 输出web ssr需要将optimization.splitChunks设置为false以关闭splitChunks
411
- if (optimization.splitChunks !== false && !isReact(this.options.mode)) {
413
+ if (optimization.splitChunks !== false) {
412
414
  splitChunksOptions = Object.assign({
413
415
  chunks: 'all',
414
416
  usedExports: optimization.usedExports === true,
@@ -606,6 +608,22 @@ class MpxWebpackPlugin {
606
608
  return mpx
607
609
  }
608
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
+
609
627
  compilation.dependencyFactories.set(ResolveDependency, new NullFactory())
610
628
  compilation.dependencyTemplates.set(ResolveDependency, new ResolveDependency.Template())
611
629
 
@@ -740,7 +758,7 @@ class MpxWebpackPlugin {
740
758
  removedChunks: [],
741
759
  forceProxyEventRules: this.options.forceProxyEventRules,
742
760
  // 若配置disableRequireAsync=true, 则全平台构建不支持异步分包
743
- 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)),
744
762
  partialCompileRules: this.options.partialCompileRules,
745
763
  collectDynamicEntryInfo: ({ resource, packageName, filename, entryType, hasAsync }) => {
746
764
  const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || {
@@ -1199,12 +1217,12 @@ class MpxWebpackPlugin {
1199
1217
  // 自动使用分包配置修改splitChunksPlugin配置
1200
1218
  if (splitChunksPlugin) {
1201
1219
  let needInit = false
1202
- if (isWeb(mpx.mode)) {
1220
+ if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1203
1221
  // web独立处理splitChunk
1204
- if (!hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1222
+ if (isWeb(mpx.mode) && !hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1205
1223
  splitChunksOptions.cacheGroups.main = {
1206
1224
  chunks: 'initial',
1207
- name: 'bundle',
1225
+ name: 'bundle/index', // web 输出 chunk 路径和 rn 输出分包格式拉齐
1208
1226
  test: /[\\/]node_modules[\\/]/
1209
1227
  }
1210
1228
  needInit = true
@@ -1212,7 +1230,7 @@ class MpxWebpackPlugin {
1212
1230
  if (!hasOwn(splitChunksOptions.cacheGroups, 'async')) {
1213
1231
  splitChunksOptions.cacheGroups.async = {
1214
1232
  chunks: 'async',
1215
- name: 'async',
1233
+ name: 'async/index',
1216
1234
  minChunks: 2
1217
1235
  }
1218
1236
  needInit = true
@@ -1315,6 +1333,15 @@ class MpxWebpackPlugin {
1315
1333
  compilation.hooks.processAssets.tap({
1316
1334
  name: 'MpxWebpackPlugin'
1317
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
+ }
1318
1345
  try {
1319
1346
  const dynamicAssets = {}
1320
1347
  for (const packageName in mpx.runtimeInfo) {
@@ -1389,10 +1416,10 @@ class MpxWebpackPlugin {
1389
1416
  if (queryObj.root) request = addQuery(request, {}, false, ['root'])
1390
1417
  // wx、ali和web平台支持require.async,其余平台使用CommonJsAsyncDependency进行模拟抹平
1391
1418
  if (mpx.supportRequireAsync) {
1392
- if (isWeb(mpx.mode)) {
1419
+ if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1393
1420
  const depBlock = new AsyncDependenciesBlock(
1394
1421
  {
1395
- name: tarRoot
1422
+ name: tarRoot + '/index'
1396
1423
  },
1397
1424
  expr.loc,
1398
1425
  request
@@ -1815,11 +1842,9 @@ try {
1815
1842
  normalModuleFactory.hooks.afterResolve.tap('MpxWebpackPlugin', ({ createData }) => {
1816
1843
  const { queryObj } = parseRequest(createData.request)
1817
1844
  const loaders = createData.loaders
1818
- if (queryObj.mpx && queryObj.mpx !== MPX_PROCESSED_FLAG) {
1819
- const type = queryObj.type
1820
- const extract = queryObj.extract
1821
-
1822
- if (type === 'styles') {
1845
+ const type = queryObj.type
1846
+ if ((queryObj.mpx && queryObj.mpx !== MPX_PROCESSED_FLAG) || queryObj.vue) {
1847
+ if (type === 'styles' || type === 'style') {
1823
1848
  let insertBeforeIndex = -1
1824
1849
  // 单次遍历收集所有索引
1825
1850
  loaders.forEach((loader, index) => {
@@ -1834,7 +1859,10 @@ try {
1834
1859
  }
1835
1860
  loaders.push({ loader: styleStripConditionalPath })
1836
1861
  }
1862
+ }
1837
1863
 
1864
+ if (queryObj.mpx && queryObj.mpx !== MPX_PROCESSED_FLAG) {
1865
+ const extract = queryObj.extract
1838
1866
  switch (type) {
1839
1867
  case 'styles':
1840
1868
  case 'template': {
@@ -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
 
@@ -354,7 +373,6 @@ module.exports = function getSpec ({ warn, error }) {
354
373
  },
355
374
  {
356
375
  test: 'preloadRule',
357
- tt: deletePath(),
358
376
  jd: deletePath()
359
377
  },
360
378
  {
@@ -372,13 +390,6 @@ module.exports = function getSpec ({ warn, error }) {
372
390
  tt: deletePath(),
373
391
  jd: deletePath(true)
374
392
  },
375
- {
376
- test: 'usingComponents',
377
- web: fixComponentName('usingComponents'),
378
- ios: fixComponentName('usingComponents'),
379
- android: fixComponentName('usingComponents'),
380
- harmony: fixComponentName('usingComponents')
381
- },
382
393
  {
383
394
  test: 'usingComponents',
384
395
  ali: componentNameCapitalToHyphen('usingComponents'),
@@ -443,6 +454,12 @@ module.exports = function getSpec ({ warn, error }) {
443
454
  swan: getWindowRule(),
444
455
  tt: getWindowRule(),
445
456
  jd: getWindowRule()
457
+ },
458
+ {
459
+ web: fixComponentName,
460
+ ios: fixComponentName,
461
+ android: fixComponentName,
462
+ harmony: fixComponentName
446
463
  }
447
464
  ]
448
465
  }
@@ -124,7 +124,7 @@ module.exports = function ({ print }) {
124
124
  if (isMustache(value)) {
125
125
  ttValueLog({ name, value })
126
126
  } else {
127
- const supportList = ['share', 'getPhoneNumber', 'contact', 'im', 'openSetting']
127
+ const supportList = ['share', 'getPhoneNumber', 'contact', 'im', 'openSetting', 'addShortcut']
128
128
  if (value && supportList.indexOf(value) === -1) {
129
129
  ttValueLogError({ name, value })
130
130
  }
@@ -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,
@@ -42,6 +42,8 @@ const wxs = require('./wxs')
42
42
  const component = require('./component')
43
43
  const fixComponentName = require('./fix-component-name')
44
44
  const rootPortal = require('./root-portal')
45
+ const stickyHeader = require('./sticky-header')
46
+ const stickySection = require('./sticky-section')
45
47
 
46
48
  module.exports = function getComponentConfigs ({ warn, error }) {
47
49
  /**
@@ -125,6 +127,8 @@ module.exports = function getComponentConfigs ({ warn, error }) {
125
127
  hyphenTagName({ print }),
126
128
  label({ print }),
127
129
  component(),
128
- rootPortal({ print })
130
+ rootPortal({ print }),
131
+ stickyHeader({ print }),
132
+ stickySection({ print })
129
133
  ]
130
134
  }
@@ -51,7 +51,7 @@ module.exports = function ({ print }) {
51
51
  swan: baiduPropLog
52
52
  },
53
53
  {
54
- test: /^(placeholder-class|auto-focus|confirm-type|confirm-hold|adjust-position|hold-keyboard)$/,
54
+ test: /^(auto-focus|confirm-type|confirm-hold|adjust-position|hold-keyboard)$/,
55
55
  tt: ttPropLog
56
56
  },
57
57
  {
@@ -0,0 +1,23 @@
1
+ const TAG_NAME = 'sticky-header'
2
+
3
+ module.exports = function ({ print }) {
4
+ return {
5
+ test: TAG_NAME,
6
+ android (tag, { el }) {
7
+ el.isBuiltIn = true
8
+ return 'mpx-sticky-header'
9
+ },
10
+ ios (tag, { el }) {
11
+ el.isBuiltIn = true
12
+ return 'mpx-sticky-header'
13
+ },
14
+ harmony (tag, { el }) {
15
+ el.isBuiltIn = true
16
+ return 'mpx-sticky-header'
17
+ },
18
+ web (tag, { el }) {
19
+ el.isBuiltIn = true
20
+ return 'mpx-sticky-header'
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,23 @@
1
+ const TAG_NAME = 'sticky-section'
2
+
3
+ module.exports = function ({ print }) {
4
+ return {
5
+ test: TAG_NAME,
6
+ android (tag, { el }) {
7
+ el.isBuiltIn = true
8
+ return 'mpx-sticky-section'
9
+ },
10
+ ios (tag, { el }) {
11
+ el.isBuiltIn = true
12
+ return 'mpx-sticky-section'
13
+ },
14
+ harmony (tag, { el }) {
15
+ el.isBuiltIn = true
16
+ return 'mpx-sticky-section'
17
+ },
18
+ web (tag, { el }) {
19
+ el.isBuiltIn = true
20
+ return 'mpx-sticky-section'
21
+ }
22
+ }
23
+ }
@@ -34,7 +34,8 @@ module.exports = function getSpec ({ warn, error }) {
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]
@@ -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,8 +116,9 @@ 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 = {}
121
+ // 暂时先不注入数据,后续如需要使用再用
118
122
  keysToExtract.forEach(key => {
119
123
  if (jsonObj[key]) {
120
124
  configObj[key] = jsonObj[key]
@@ -132,6 +136,29 @@ module.exports = function (jsonContent, {
132
136
  isShow: true
133
137
  }
134
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
+
135
162
  const processTabBar = (tabBar, callback) => {
136
163
  if (tabBar) {
137
164
  tabBar = Object.assign({}, defaultTabbar, tabBar)
@@ -300,19 +327,48 @@ module.exports = function (jsonContent, {
300
327
  const processComponents = (components, context, callback) => {
301
328
  if (components) {
302
329
  async.eachOf(components, (component, name, callback) => {
303
- processComponent(component, context, {}, (err, { resource, outputPath } = {}, { tarRoot } = {}) => {
330
+ processComponent(component, context, {}, (err, entry = {}, { tarRoot, placeholder } = {}) => {
304
331
  if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err)
305
- const { resourcePath, queryObj } = parseRequest(resource)
306
- componentsMap[resourcePath] = outputPath
307
- loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'component', outputPath))
308
- localComponentsMap[name] = {
309
- resource: addQuery(resource, {
310
- isComponent: true,
311
- outputPath
312
- }),
313
- 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()
314
371
  }
315
- callback()
316
372
  })
317
373
  }, callback)
318
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({