@mpxjs/webpack-plugin 2.10.6-beta.3 → 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.
@@ -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
@@ -1217,12 +1217,12 @@ class MpxWebpackPlugin {
1217
1217
  // 自动使用分包配置修改splitChunksPlugin配置
1218
1218
  if (splitChunksPlugin) {
1219
1219
  let needInit = false
1220
- if (isWeb(mpx.mode)) {
1220
+ if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1221
1221
  // web独立处理splitChunk
1222
- if (!hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1222
+ if (isWeb(mpx.mode) && !hasOwn(splitChunksOptions.cacheGroups, 'main')) {
1223
1223
  splitChunksOptions.cacheGroups.main = {
1224
1224
  chunks: 'initial',
1225
- name: 'bundle',
1225
+ name: 'bundle/index', // web 输出 chunk 路径和 rn 输出分包格式拉齐
1226
1226
  test: /[\\/]node_modules[\\/]/
1227
1227
  }
1228
1228
  needInit = true
@@ -1230,7 +1230,7 @@ class MpxWebpackPlugin {
1230
1230
  if (!hasOwn(splitChunksOptions.cacheGroups, 'async')) {
1231
1231
  splitChunksOptions.cacheGroups.async = {
1232
1232
  chunks: 'async',
1233
- name: 'async',
1233
+ name: 'async/index',
1234
1234
  minChunks: 2
1235
1235
  }
1236
1236
  needInit = true
@@ -1333,6 +1333,15 @@ class MpxWebpackPlugin {
1333
1333
  compilation.hooks.processAssets.tap({
1334
1334
  name: 'MpxWebpackPlugin'
1335
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
+ }
1336
1345
  try {
1337
1346
  const dynamicAssets = {}
1338
1347
  for (const packageName in mpx.runtimeInfo) {
@@ -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,
@@ -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]
@@ -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,
@@ -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 {
@@ -15,7 +15,7 @@ function getMpxComponentRequest (component) {
15
15
  return JSON.stringify(addQuery(`@mpxjs/webpack-plugin/lib/runtime/components/react/dist/${component}`, { isComponent: true }))
16
16
  }
17
17
 
18
- const mpxAsyncContainer = getMpxComponentRequest('AsyncContainer')
18
+ const mpxAsyncSuspense = getMpxComponentRequest('AsyncSuspense')
19
19
 
20
20
  function getAsyncChunkName (chunkName) {
21
21
  if (chunkName && typeof chunkName !== 'boolean') {
@@ -27,17 +27,14 @@ function getAsyncChunkName (chunkName) {
27
27
  function getAsyncComponent (componentName, componentRequest, chunkName, fallback) {
28
28
  return `getComponent(memo(forwardRef(function(props, ref) {
29
29
  return createElement(
30
- getComponent(require(${mpxAsyncContainer})),
30
+ getComponent(require(${mpxAsyncSuspense})),
31
31
  {
32
32
  type: 'component',
33
33
  props: Object.assign({}, props, { ref }),
34
+ chunkName: ${JSON.stringify(chunkName)},
35
+ request: ${JSON.stringify(componentRequest)},
34
36
  loading: getComponent(require(${fallback})),
35
- children: (props) => createElement(
36
- getComponent(
37
- lazy(function(){ return import(${getAsyncChunkName(chunkName)}${componentRequest}) }), { displayName: ${JSON.stringify(componentName)} }
38
- ),
39
- props
40
- )
37
+ getChildren: () => import(${getAsyncChunkName(chunkName)}${componentRequest})
41
38
  }
42
39
  )
43
40
  })))`
@@ -48,18 +45,15 @@ function getAsyncPage (componentName, componentRequest, chunkName, fallback, loa
48
45
  loading = loading && `getComponent(require('${loading}?isComponent=true'))`
49
46
  return `getComponent(function(props) {
50
47
  return createElement(
51
- getComponent(require(${mpxAsyncContainer})),
48
+ getComponent(require(${mpxAsyncSuspense})),
52
49
  {
53
50
  type: 'page',
54
51
  props: props,
52
+ chunkName: ${JSON.stringify(chunkName)},
53
+ request: ${JSON.stringify(componentRequest)},
55
54
  fallback: ${fallback},
56
55
  loading: ${loading},
57
- children: (props) => createElement(
58
- getComponent(
59
- lazy(function(){ return import(${getAsyncChunkName(chunkName)}${componentRequest}) }), { __mpxPageRoute: ${JSON.stringify(componentName)}, displayName: 'Page' }
60
- ),
61
- props
62
- )
56
+ getChildren: () => import(${getAsyncChunkName(chunkName)}${componentRequest})
63
57
  }
64
58
  )
65
59
  })`
@@ -114,12 +108,13 @@ function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderC
114
108
  const placeholderRequest = JSON.stringify(path.resolve(queryObj.context, rawResourcePath))
115
109
  componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, placeholderRequest)
116
110
  } else {
117
- if (!isBuildInReactTag(placeholder)) {
111
+ const tag = `mpx-${placeholder}`
112
+ if (!isBuildInReactTag(tag)) {
118
113
  loaderContext.emitError(
119
114
  new Error(`[json processor][${loaderContext.resource}]: componentPlaceholder ${placeholder} is not built-in component, please check!`)
120
115
  )
121
116
  }
122
- componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, getMpxComponentRequest(`mpx-${placeholder}`))
117
+ componentsMap[componentName] = getAsyncComponent(componentName, componentRequest, componentCfg.async, getMpxComponentRequest(tag))
123
118
  }
124
119
  } else {
125
120
  loaderContext.emitError(
@@ -1,6 +1,29 @@
1
- import { ComponentType, ReactNode, Component, Fragment, Suspense } from 'react'
1
+ import { ComponentType, ReactNode, Component, Suspense } from 'react'
2
2
  import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native'
3
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
+ }
4
27
 
5
28
  const styles = StyleSheet.create({
6
29
  container: {
@@ -59,7 +82,7 @@ interface PropsType<T extends AsyncType> {
59
82
  props: object
60
83
  loading: ComponentType<unknown>
61
84
  fallback: ComponentType<unknown>
62
- children: (props: unknown) => ReactNode
85
+ children: (props: any) => ReactNode | ReactNode
63
86
  }
64
87
 
65
88
  interface StateType {
@@ -72,7 +95,7 @@ interface ComponentError extends Error {
72
95
  type: 'timeout' | 'fail'
73
96
  }
74
97
 
75
- const DefaultLoading = () => {
98
+ export const DefaultLoading = () => {
76
99
  return (
77
100
  <View style={styles.container}>
78
101
  <FastImage
@@ -83,11 +106,11 @@ const DefaultLoading = () => {
83
106
  )
84
107
  }
85
108
 
86
- interface DefaultFallbackProps {
109
+ export interface DefaultFallbackProps {
87
110
  onReload: () => void
88
111
  }
89
112
 
90
- const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
113
+ export const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
91
114
  return (
92
115
  <View style={styles.container}>
93
116
  <Image
@@ -177,11 +200,16 @@ export default class AsyncContainer extends Component<PropsType<AsyncType>, Stat
177
200
 
178
201
  render () {
179
202
  if (this.state.hasError) {
180
- return this.errorFallback
203
+ if (this.props.type === 'component') {
204
+ return this.errorFallback
205
+ } else {
206
+ return (<PageWrapper>{this.errorFallback}</PageWrapper>)
207
+ }
181
208
  } else {
182
209
  return (
183
210
  <Suspense fallback={this.suspenseFallback} key={this.state.key}>
184
- {this.props.children(this.props.props)}
211
+ {typeof this.props.children === 'function' ? this.props.children(this.props.props) : this.props.children}
212
+ {/* {this.props.children(this.props.props)} */}
185
213
  </Suspense>
186
214
  )
187
215
  }
@@ -0,0 +1,81 @@
1
+ import { useState, ComponentType, useEffect, useCallback, useRef } from 'react'
2
+ import { DefaultFallback, DefaultLoading, PageWrapper } from './AsyncContainer'
3
+ import type { DefaultFallbackProps } from './AsyncContainer'
4
+
5
+ const asyncChunkMap = new Map()
6
+
7
+ interface props {
8
+ type: 'component' | 'page'
9
+ chunkName: string
10
+ request: string
11
+ props: any,
12
+ loading: ComponentType<unknown>
13
+ fallback: ComponentType<unknown>
14
+ getChildren: () => Promise<unknown>
15
+ }
16
+
17
+ const AsyncSuspense: React.FC<props> = ({ type, props, chunkName, request, loading, fallback, getChildren }) => {
18
+ const [status, setStatus] = useState('pending')
19
+ const loaded = asyncChunkMap.has(request)
20
+ const [, setKey] = useState(0)
21
+ const chunkPromise = useRef<null | Promise<unknown>>(null)
22
+
23
+ const reloadPage = useCallback(() => {
24
+ setKey((preV) => preV + 1)
25
+ console.log('[mpxAsyncSuspense]: reload page')
26
+ setStatus('pending')
27
+ }, [])
28
+
29
+ useEffect(() => {
30
+ if (!loaded && status === 'pending') {
31
+ // todo 清楚副作用?
32
+ console.log('the current :', chunkPromise.current)
33
+ chunkPromise.current!
34
+ .then((m: any) => {
35
+ console.log('[mpxAsyncSuspense]: load sucess')
36
+ asyncChunkMap.set(request, m.__esModule ? m.default : m)
37
+ setStatus('loaded')
38
+ })
39
+ .catch((e) => {
40
+ if (type === 'component') {
41
+ console.log(11111, e)
42
+ global.onLazyLoadError({
43
+ type: 'subpackage',
44
+ subpackage: [chunkName],
45
+ errMsg: `loadSubpackage: ${e.type}`
46
+ })
47
+ }
48
+ console.log('[mpxAsyncSuspense]: load eror', e)
49
+ chunkPromise.current = null
50
+ setStatus('error')
51
+ })
52
+ }
53
+ })
54
+
55
+ if (loaded) {
56
+ const Comp = asyncChunkMap.get(request)
57
+ return <Comp {...props}></Comp>
58
+ } else if (status === 'error') {
59
+ console.log('the status is:', status)
60
+ if (type === 'page') {
61
+ const Fallback = fallback as ComponentType<DefaultFallbackProps> || DefaultFallback
62
+ return <><PageWrapper><Fallback onReload={reloadPage}></Fallback></PageWrapper></>
63
+ } else {
64
+ const Fallback = loading
65
+ return <Fallback {...props}></Fallback>
66
+ }
67
+ } else {
68
+ if (!chunkPromise.current) {
69
+ chunkPromise.current = getChildren()
70
+ }
71
+ if (type === 'page') {
72
+ const Fallback = loading || DefaultLoading
73
+ return <PageWrapper><Fallback /></PageWrapper>
74
+ } else {
75
+ const Fallback = loading
76
+ return <Fallback {...props}></Fallback>
77
+ }
78
+ }
79
+ }
80
+
81
+ export default AsyncSuspense