@mpxjs/webpack-plugin 2.10.6-beta.7 → 2.10.7-beta.1

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.
@@ -35,9 +35,8 @@ module.exports = function loader (content, prevOptions) {
35
35
 
36
36
  let publicPath = `__webpack_public_path__ + ${JSON.stringify(url)}`
37
37
 
38
- if (isRN) {
39
- publicPath = `__non_webpack_require__(__mpx_rn_resolve_url_path_(${JSON.stringify(url)}))`
40
- }
38
+ // todo 未来添加分包处理后相对地址不一定是./开头的,需要考虑通过dependency的方式在sourceModule时通过最终的chunkName得到准确的相对路径
39
+ if (isRN) publicPath = `__non_webpack_require__(${JSON.stringify(`_mpx_rn_img_relative_path_/${url}`)})`
41
40
 
42
41
  if (options.publicPath) {
43
42
  if (typeof options.publicPath === 'function') {
package/lib/index.js CHANGED
@@ -44,11 +44,9 @@ 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 RecordFileUrlDependency = require('./dependencies/RecordFileUrlDependency')
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')
51
- const { transAsyncSubNameRules, transAsyncSubRules } = require('./utils/trans-async-sub-rules')
52
50
  const { matchCondition } = require('./utils/match-condition')
53
51
  const processDefs = require('./utils/process-defs')
54
52
  const config = require('./config')
@@ -674,9 +672,6 @@ class MpxWebpackPlugin {
674
672
  compilation.dependencyFactories.set(RecordRuntimeInfoDependency, new NullFactory())
675
673
  compilation.dependencyTemplates.set(RecordRuntimeInfoDependency, new RecordRuntimeInfoDependency.Template())
676
674
 
677
- compilation.dependencyFactories.set(RecordFileUrlDependency, new NullFactory())
678
- compilation.dependencyTemplates.set(RecordFileUrlDependency, new RecordFileUrlDependency.Template())
679
-
680
675
  compilation.dependencyTemplates.set(ImportDependency, new ImportDependencyTemplate())
681
676
  })
682
677
 
@@ -779,7 +774,6 @@ class MpxWebpackPlugin {
779
774
  })
780
775
  },
781
776
  asyncSubpackageRules: this.options.asyncSubpackageRules,
782
- asyncSubpackageNameMap: this.options.asyncSubpackageNameMap,
783
777
  optimizeRenderRules: this.options.optimizeRenderRules,
784
778
  pathHash: (resourcePath) => {
785
779
  if (this.options.pathHashMode === 'relative' && this.options.projectRoot) {
@@ -1228,7 +1222,7 @@ class MpxWebpackPlugin {
1228
1222
  if (isWeb(mpx.mode) && !hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1229
1223
  splitChunksOptions.cacheGroups.main = {
1230
1224
  chunks: 'initial',
1231
- name: 'lib/index', // web 输出 chunk 路径和 rn 输出分包格式拉齐
1225
+ name: 'bundle/index', // web 输出 chunk 路径和 rn 输出分包格式拉齐
1232
1226
  test: /[\\/]node_modules[\\/]/
1233
1227
  }
1234
1228
  needInit = true
@@ -1236,7 +1230,7 @@ class MpxWebpackPlugin {
1236
1230
  if (!hasOwn(splitChunksOptions.cacheGroups, 'async')) {
1237
1231
  splitChunksOptions.cacheGroups.async = {
1238
1232
  chunks: 'async',
1239
- name: 'async-common/index',
1233
+ name: 'async/index',
1240
1234
  minChunks: 2
1241
1235
  }
1242
1236
  needInit = true
@@ -1339,6 +1333,15 @@ class MpxWebpackPlugin {
1339
1333
  compilation.hooks.processAssets.tap({
1340
1334
  name: 'MpxWebpackPlugin'
1341
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
+ }
1342
1345
  try {
1343
1346
  const dynamicAssets = {}
1344
1347
  for (const packageName in mpx.runtimeInfo) {
@@ -1384,15 +1387,6 @@ class MpxWebpackPlugin {
1384
1387
  }
1385
1388
  })
1386
1389
 
1387
- parser.hooks.call.for('__mpx_rn_resolve_url_path_').tap('MpxWebpackPlugin', (expr) => {
1388
- const args = expr.arguments.map((i) => i.value)
1389
- args.unshift(expr.range)
1390
-
1391
- const dep = new RecordFileUrlDependency(...args)
1392
- parser.state.current.addPresentationalDependency(dep)
1393
- return true
1394
- })
1395
-
1396
1390
  parser.hooks.call.for('__mpx_dynamic_entry__').tap('MpxWebpackPlugin', (expr) => {
1397
1391
  const args = expr.arguments.map((i) => i.value)
1398
1392
  args.unshift(expr.range)
@@ -1408,16 +1402,20 @@ class MpxWebpackPlugin {
1408
1402
  const range = expr.arguments[0].range
1409
1403
  const context = parser.state.module.context
1410
1404
  const { queryObj, resourcePath } = parseRequest(request)
1411
- let tarRoot = transAsyncSubRules(resourcePath, mpx.asyncSubpackageRules, queryObj.root)
1405
+ let tarRoot = queryObj.root
1406
+ if (!tarRoot && mpx.asyncSubpackageRules) {
1407
+ for (const item of mpx.asyncSubpackageRules) {
1408
+ if (matchCondition(resourcePath, item)) {
1409
+ tarRoot = item.root
1410
+ break
1411
+ }
1412
+ }
1413
+ }
1412
1414
  if (tarRoot) {
1413
1415
  // 删除root query
1414
1416
  if (queryObj.root) request = addQuery(request, {}, false, ['root'])
1415
1417
  // wx、ali和web平台支持require.async,其余平台使用CommonJsAsyncDependency进行模拟抹平
1416
- if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1417
- // web 和 react 平台支持分包名转换,如果转换tarRoot为空,则降级到主包
1418
- tarRoot = transAsyncSubNameRules(mpx.asyncSubpackageNameMap, tarRoot)
1419
- }
1420
- if (mpx.supportRequireAsync && tarRoot) {
1418
+ if (mpx.supportRequireAsync) {
1421
1419
  if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1422
1420
  const depBlock = new AsyncDependenciesBlock(
1423
1421
  {
@@ -8,7 +8,6 @@ const addQuery = require('../utils/add-query')
8
8
  const parseComponent = require('../parser')
9
9
  const getJSONContent = require('../utils/get-json-content')
10
10
  const resolve = require('../utils/resolve')
11
- const { transAsyncSubNameRules } = require('../utils/trans-async-sub-rules')
12
11
  const createJSONHelper = require('../json-compiler/helper')
13
12
  const getRulesRunner = require('../platform/index')
14
13
  const { RESOLVE_IGNORED_ERR } = require('../utils/const')
@@ -286,8 +285,6 @@ module.exports = function (jsonContent, {
286
285
 
287
286
  pagesMap[resourcePath] = outputPath
288
287
  loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'page', outputPath))
289
- // 通过asyncSubPackagesNameRules对tarRoot进行修改,仅修改tarRoot,不修改outputPath页面路径
290
- tarRoot = transAsyncSubNameRules(mpx.asyncSubpackageNameMap, tarRoot)
291
288
  localPagesMap[outputPath] = {
292
289
  resource: addQuery(resource, { isPage: true }),
293
290
  async: queryObj.async || tarRoot,
@@ -335,7 +332,6 @@ module.exports = function (jsonContent, {
335
332
  const fillComponentsMap = (name, entry, tarRoot) => {
336
333
  const { resource, outputPath } = entry
337
334
  const { resourcePath, queryObj } = parseRequest(resource)
338
- tarRoot = transAsyncSubNameRules(mpx.asyncSubpackageNameMap, tarRoot)
339
335
  componentsMap[resourcePath] = outputPath
340
336
  loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'component', outputPath))
341
337
  localComponentsMap[name] = {
@@ -36,7 +36,7 @@ module.exports = function (script, {
36
36
  output += "import { lazy, createElement, memo, forwardRef } from 'react'\n"
37
37
  if (ctorType === 'app') {
38
38
  output += `
39
- import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext, optionProcessorPath)}
39
+ import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}
40
40
  \n`
41
41
  const { pagesMap, firstPage } = buildPagesMap({
42
42
  localPagesMap,
@@ -53,7 +53,7 @@ import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext,
53
53
  output += getRequireScript({ ctorType, script, loaderContext })
54
54
  output += `export default global.__mpxOptionsMap[${JSON.stringify(moduleId)}]\n`
55
55
  } else {
56
- output += `import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
56
+ output += `import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}\n`
57
57
  // 获取组件集合
58
58
  const componentsMap = buildComponentsMap({
59
59
  localComponentsMap,
@@ -4,6 +4,7 @@ const parseRequest = require('../utils/parse-request')
4
4
  const shallowStringify = require('../utils/shallow-stringify')
5
5
  const normalize = require('../utils/normalize')
6
6
  const addQuery = require('../utils/add-query')
7
+ const path = require('path')
7
8
  const { isBuildInReactTag } = require('../utils/dom-tag-config')
8
9
 
9
10
  function stringifyRequest (loaderContext, request) {
@@ -14,6 +15,8 @@ function getMpxComponentRequest (component) {
14
15
  return JSON.stringify(addQuery(`@mpxjs/webpack-plugin/lib/runtime/components/react/dist/${component}`, { isComponent: true }))
15
16
  }
16
17
 
18
+ const mpxAsyncSuspense = getMpxComponentRequest('AsyncSuspense')
19
+
17
20
  function getAsyncChunkName (chunkName) {
18
21
  if (chunkName && typeof chunkName !== 'boolean') {
19
22
  return `/* webpackChunkName: "${chunkName}/index" */`
@@ -21,33 +24,49 @@ function getAsyncChunkName (chunkName) {
21
24
  return ''
22
25
  }
23
26
 
24
- function getAsyncSuspense (type, moduleId, componentRequest, chunkName, fallback, loading) {
25
- fallback = fallback && `getComponent(require(${fallback}))`
26
- loading = loading && `getComponent(require(${loading}))`
27
- return `
28
- getAsyncSuspense({
29
- type: ${JSON.stringify(type)},
30
- moduleId: ${JSON.stringify(moduleId)},
31
- chunkName: ${JSON.stringify(chunkName)},
32
- loading: ${loading},
33
- fallback: ${fallback},
34
- getChildren: () => import(${getAsyncChunkName(chunkName)}${componentRequest})
35
- })
36
- `
27
+ function getAsyncComponent (componentName, componentRequest, chunkName, fallback) {
28
+ return `getComponent(memo(forwardRef(function(props, ref) {
29
+ return createElement(
30
+ getComponent(require(${mpxAsyncSuspense})),
31
+ {
32
+ type: 'component',
33
+ props: Object.assign({}, props, { ref }),
34
+ chunkName: ${JSON.stringify(chunkName)},
35
+ request: ${JSON.stringify(componentRequest)},
36
+ loading: getComponent(require(${fallback})),
37
+ getChildren: () => import(${getAsyncChunkName(chunkName)}${componentRequest})
38
+ }
39
+ )
40
+ })))`
41
+ }
42
+
43
+ function getAsyncPage (componentName, componentRequest, chunkName, fallback, loading) {
44
+ fallback = fallback && `getComponent(require('${fallback}?isComponent=true'))`
45
+ loading = loading && `getComponent(require('${loading}?isComponent=true'))`
46
+ return `getComponent(function(props) {
47
+ return createElement(
48
+ getComponent(require(${mpxAsyncSuspense})),
49
+ {
50
+ type: 'page',
51
+ props: props,
52
+ chunkName: ${JSON.stringify(chunkName)},
53
+ request: ${JSON.stringify(componentRequest)},
54
+ fallback: ${fallback},
55
+ loading: ${loading},
56
+ getChildren: () => import(${getAsyncChunkName(chunkName)}${componentRequest})
57
+ }
58
+ )
59
+ })`
37
60
  }
38
61
 
39
62
  function buildPagesMap ({ localPagesMap, loaderContext, jsonConfig, rnConfig }) {
40
63
  let firstPage = ''
41
64
  const pagesMap = {}
42
- const mpx = loaderContext.getMpx()
43
65
  Object.keys(localPagesMap).forEach((pagePath) => {
44
66
  const pageCfg = localPagesMap[pagePath]
45
67
  const pageRequest = stringifyRequest(loaderContext, pageCfg.resource)
46
68
  if (pageCfg.async) {
47
- const moduleId = mpx.getModuleId(pageCfg.resource)
48
- const fallback = rnConfig.asyncChunk && rnConfig.asyncChunk.fallback && JSON.stringify(addQuery(rnConfig.asyncChunk.fallback, { isComponent: true }))
49
- const loading = rnConfig.asyncChunk && rnConfig.asyncChunk.loading && JSON.stringify(addQuery(rnConfig.asyncChunk.loading, { isComponent: true }))
50
- pagesMap[pagePath] = getAsyncSuspense('page', moduleId, pageRequest, pageCfg.async, fallback, loading)
69
+ pagesMap[pagePath] = getAsyncPage(pagePath, pageRequest, pageCfg.async, rnConfig.asyncChunk && rnConfig.asyncChunk.fallback, rnConfig.asyncChunk && rnConfig.asyncChunk.loading)
51
70
  } else {
52
71
  // 为了保持小程序中app->page->component的js执行顺序,所有的page和component都改为require引入
53
72
  pagesMap[pagePath] = `getComponent(require(${pageRequest}), {__mpxPageRoute: ${JSON.stringify(pagePath)}, displayName: "Page"})`
@@ -73,7 +92,6 @@ function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderC
73
92
  const componentCfg = localComponentsMap[componentName]
74
93
  const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
75
94
  if (componentCfg.async) {
76
- const moduleId = mpx.getModuleId(componentCfg.resource)
77
95
  const placeholder = jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]
78
96
  if (placeholder) {
79
97
  if (localComponentsMap[placeholder]) {
@@ -84,7 +102,11 @@ function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderC
84
102
  new Error(`[json processor][${loaderContext.resource}]: componentPlaceholder ${placeholder} should not be a async component, please check!`)
85
103
  )
86
104
  }
87
- componentsMap[componentName] = getAsyncSuspense('component', moduleId, componentRequest, componentCfg.async, placeholderRequest)
105
+ componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, placeholderRequest)
106
+ } else if (mpx.globalComponents[placeholder]) {
107
+ const { queryObj, rawResourcePath } = parseRequest(mpx.globalComponents[placeholder])
108
+ const placeholderRequest = JSON.stringify(path.resolve(queryObj.context, rawResourcePath))
109
+ componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, placeholderRequest)
88
110
  } else {
89
111
  const tag = `mpx-${placeholder}`
90
112
  if (!isBuildInReactTag(tag)) {
@@ -92,13 +114,13 @@ function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderC
92
114
  new Error(`[json processor][${loaderContext.resource}]: componentPlaceholder ${placeholder} is not built-in component, please check!`)
93
115
  )
94
116
  }
95
- componentsMap[componentName] = getAsyncSuspense('component', moduleId, componentRequest, componentCfg.async, getMpxComponentRequest(tag))
117
+ componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, getMpxComponentRequest(tag))
96
118
  }
97
119
  } else {
98
120
  loaderContext.emitError(
99
121
  new Error(`[json processor][${loaderContext.resource}]: ${componentName} has no componentPlaceholder, please check!`)
100
122
  )
101
- componentsMap[componentName] = getAsyncSuspense('component', moduleId, componentRequest, componentCfg.async)
123
+ componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async)
102
124
  }
103
125
  } else {
104
126
  componentsMap[componentName] = `getComponent(require(${componentRequest}), {displayName: ${JSON.stringify(componentName)}})`
@@ -0,0 +1,217 @@
1
+ import { ComponentType, ReactNode, Component, Suspense } from 'react'
2
+ import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native'
3
+ import FastImage from '@d11/react-native-fast-image'
4
+ import Animated, { useAnimatedStyle } from 'react-native-reanimated'
5
+
6
+ type PageWrapper = {
7
+ children: ReactNode
8
+ }
9
+
10
+ export const PageWrapper = ({ children }: PageWrapper) => {
11
+ const animatedStyle = useAnimatedStyle(() => ({
12
+ transform: [{ translateY: -0 }],
13
+ flexBasis: 'auto',
14
+ flex: 1
15
+ }))
16
+
17
+ return (
18
+ <Animated.View
19
+ style={[
20
+ animatedStyle
21
+ ]}
22
+ >
23
+ {children}
24
+ </Animated.View>
25
+ )
26
+ }
27
+
28
+ const styles = StyleSheet.create({
29
+ container: {
30
+ flex: 1,
31
+ padding: 20,
32
+ backgroundColor: '#fff'
33
+ },
34
+ loadingImage: {
35
+ width: 100,
36
+ height: 100,
37
+ marginTop: 220,
38
+ alignSelf: 'center'
39
+ },
40
+ buttonText: {
41
+ color: '#fff',
42
+ fontSize: 16,
43
+ fontWeight: '500',
44
+ textAlign: 'center'
45
+ },
46
+ errorImage: {
47
+ marginTop: 80,
48
+ width: 220,
49
+ aspectRatio: 1,
50
+ alignSelf: 'center'
51
+ },
52
+ errorText: {
53
+ fontSize: 16,
54
+ textAlign: 'center',
55
+ color: '#333',
56
+ marginBottom: 20
57
+ },
58
+ retryButton: {
59
+ position: 'absolute',
60
+ bottom: 54,
61
+ left: 20,
62
+ right: 20,
63
+ backgroundColor: '#fff',
64
+ paddingVertical: 15,
65
+ borderRadius: 30,
66
+ marginTop: 40,
67
+ borderWidth: 1,
68
+ borderColor: '#FF5F00'
69
+ },
70
+ retryButtonText: {
71
+ color: '#FF5F00',
72
+ fontSize: 16,
73
+ fontWeight: '500',
74
+ textAlign: 'center'
75
+ }
76
+ })
77
+
78
+ type AsyncType = 'page' | 'component'
79
+
80
+ interface PropsType<T extends AsyncType> {
81
+ type: T
82
+ props: object
83
+ loading: ComponentType<unknown>
84
+ fallback: ComponentType<unknown>
85
+ children: (props: any) => ReactNode | ReactNode
86
+ }
87
+
88
+ interface StateType {
89
+ hasError: boolean,
90
+ key: number
91
+ }
92
+
93
+ interface ComponentError extends Error {
94
+ request?: string
95
+ type: 'timeout' | 'fail'
96
+ }
97
+
98
+ export const DefaultLoading = () => {
99
+ return (
100
+ <View style={styles.container}>
101
+ <FastImage
102
+ style={styles.loadingImage}
103
+ source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif' }}
104
+ resizeMode={FastImage.resizeMode.contain}></FastImage>
105
+ </View>
106
+ )
107
+ }
108
+
109
+ export interface DefaultFallbackProps {
110
+ onReload: () => void
111
+ }
112
+
113
+ export const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
114
+ return (
115
+ <View style={styles.container}>
116
+ <Image
117
+ source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png' }}
118
+ style={styles.errorImage}
119
+ resizeMode="contain"
120
+ />
121
+ <Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text>
122
+ <TouchableOpacity
123
+ style={styles.retryButton}
124
+ onPress={onReload}
125
+ activeOpacity={0.7}
126
+ >
127
+ <Text style={styles.retryButtonText}>点击重试</Text>
128
+ </TouchableOpacity>
129
+ </View>
130
+ )
131
+ }
132
+
133
+ export default class AsyncContainer extends Component<PropsType<AsyncType>, StateType> {
134
+ private suspenseFallback: ReactNode
135
+ private errorFallback: ReactNode
136
+
137
+ constructor (props: PropsType<AsyncType>) {
138
+ super(props)
139
+ this.state = {
140
+ hasError: false,
141
+ key: 0
142
+ }
143
+ this.suspenseFallback = this.getSuspenseFallback()
144
+ this.errorFallback = this.getErrorFallback()
145
+ }
146
+
147
+ // render 阶段收集到的错误
148
+ static getDerivedStateFromError (error: ComponentError): StateType | undefined {
149
+ if (error.name === 'ChunkLoadError') {
150
+ return {
151
+ hasError: true,
152
+ key: 0
153
+ }
154
+ } else {
155
+ // 被外层捕获
156
+ throw error
157
+ }
158
+ }
159
+
160
+ componentDidCatch (error: ComponentError): void {
161
+ if (error.name === 'ChunkLoadError' && this.props.type === 'component') {
162
+ const request = error.request || ''
163
+ const subpackage = request.split('/').filter((i: string) => !!i)[0]
164
+ global.onLazyLoadError({
165
+ type: 'subpackage',
166
+ subpackage: [subpackage],
167
+ errMsg: `loadSubpackage: ${error.type}`
168
+ })
169
+ }
170
+ }
171
+
172
+ reloadPage () {
173
+ this.setState((prevState) => {
174
+ return {
175
+ hasError: false,
176
+ key: prevState.key + 1
177
+ }
178
+ })
179
+ }
180
+
181
+ getSuspenseFallback () {
182
+ if (this.props.type === 'page') {
183
+ const Fallback = this.props.loading || DefaultLoading
184
+ return <Fallback />
185
+ } else {
186
+ const Fallback = this.props.loading
187
+ return <Fallback {...this.props.props}></Fallback>
188
+ }
189
+ }
190
+
191
+ getErrorFallback () {
192
+ if (this.props.type === 'page') {
193
+ const Fallback = this.props.fallback as ComponentType<DefaultFallbackProps> || DefaultFallback
194
+ return <Fallback onReload={this.reloadPage.bind(this)}></Fallback>
195
+ } else {
196
+ const Fallback = this.props.loading
197
+ return <Fallback {...this.props.props}></Fallback>
198
+ }
199
+ }
200
+
201
+ render () {
202
+ if (this.state.hasError) {
203
+ if (this.props.type === 'component') {
204
+ return this.errorFallback
205
+ } else {
206
+ return (<PageWrapper>{this.errorFallback}</PageWrapper>)
207
+ }
208
+ } else {
209
+ return (
210
+ <Suspense fallback={this.suspenseFallback} key={this.state.key}>
211
+ {typeof this.props.children === 'function' ? this.props.children(this.props.props) : this.props.children}
212
+ {/* {this.props.children(this.props.props)} */}
213
+ </Suspense>
214
+ )
215
+ }
216
+ }
217
+ }