Skip to content

Commit ddf569a

Browse files
committed
Merge branch 'master' of https://github.com/didi/mpx
2 parents f14e5df + de85d37 commit ddf569a

File tree

10 files changed

+188
-94
lines changed

10 files changed

+188
-94
lines changed

docs-vitepress/api/compile.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,39 @@ module.exports = defineConfig({
11231123
* 本功能只会对使用require.async异步引用的js模块生效,若引用路径中已配置?root,则以路径中?root优先
11241124
:::
11251125

1126+
### transSubpackageRules
1127+
1128+
`Array`
1129+
1130+
仅在输出 RN (ios/android/harmony) 时生效。
1131+
1132+
用于配置分包资源转移规则,可将指定分包中的页面或组件资源转移到其他分包或主包中。
1133+
1134+
- **from**: `Array<string>` 源分包名称列表
1135+
- **to**: `string` 目标分包名称。当为 `''` (空字符串) 时,表示输出到主包
1136+
1137+
#### 示例
1138+
1139+
```js
1140+
// mpx.config.js
1141+
module.exports = {
1142+
pluginOptions: {
1143+
mpx: {
1144+
transSubpackageRules: [
1145+
{
1146+
from: ['comp-pages'],
1147+
to: 'common'
1148+
},
1149+
{
1150+
from: ['sub1'],
1151+
to: ''
1152+
}
1153+
]
1154+
}
1155+
}
1156+
}
1157+
```
1158+
11261159
### retryRequireAsync
11271160

11281161
`boolean = false`

packages/webpack-plugin/lib/index.js

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,7 @@ class MpxWebpackPlugin {
14551455
const context = parser.state.module.context
14561456
const { queryObj, resourcePath } = parseRequest(request)
14571457
let tarRoot = queryObj.root
1458+
14581459
if (!tarRoot && mpx.asyncSubpackageRules) {
14591460
for (const item of mpx.asyncSubpackageRules) {
14601461
if (matchCondition(resourcePath, item)) {
@@ -1463,49 +1464,49 @@ class MpxWebpackPlugin {
14631464
}
14641465
}
14651466
}
1466-
if (tarRoot) {
1467+
// TODO 后续考虑和 asyncSubpackageRules 配置合并
1468+
if (isReact(mpx.mode)) tarRoot = transSubpackage(mpx.transSubpackageRules, tarRoot)
1469+
1470+
if (tarRoot && mpx.supportRequireAsync) {
14671471
// 删除root query
14681472
if (queryObj.root) request = addQuery(request, {}, false, ['root'])
14691473
// wx、ali和web平台支持require.async,其余平台使用CommonJsAsyncDependency进行模拟抹平
1470-
if (mpx.supportRequireAsync) {
1471-
if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1472-
if (isReact(mpx.mode)) tarRoot = transSubpackage(mpx.transSubpackageRules, tarRoot)
1473-
const depBlock = new AsyncDependenciesBlock(
1474-
{
1475-
name: tarRoot + '/index'
1476-
},
1477-
expr.loc,
1478-
request
1479-
)
1480-
const dep = new ImportDependency(request, expr.range, undefined, {
1481-
isRequireAsync: true,
1482-
retryRequireAsync: this.options.retryRequireAsync
1483-
})
1484-
dep.loc = expr.loc
1485-
depBlock.addDependency(dep)
1486-
parser.state.current.addBlock(depBlock)
1487-
} else {
1488-
const dep = new DynamicEntryDependency(range, request, 'export', '', tarRoot, '', context, {
1489-
isAsync: true,
1490-
isRequireAsync: true,
1491-
retryRequireAsync: this.options.retryRequireAsync,
1492-
requireAsyncRange: expr.range
1493-
})
1494-
1495-
parser.state.current.addPresentationalDependency(dep)
1496-
// 包含require.async的模块不能被concatenate,避免DynamicEntryDependency中无法获取模块chunk以计算相对路径
1497-
parser.state.module.buildInfo.moduleConcatenationBailout = 'require async'
1498-
}
1474+
if (isWeb(mpx.mode) || isReact(mpx.mode)) {
1475+
const depBlock = new AsyncDependenciesBlock(
1476+
{
1477+
name: tarRoot + '/index'
1478+
},
1479+
expr.loc,
1480+
request
1481+
)
1482+
const dep = new ImportDependency(request, expr.range, undefined, {
1483+
isRequireAsync: true,
1484+
retryRequireAsync: this.options.retryRequireAsync
1485+
})
1486+
dep.loc = expr.loc
1487+
depBlock.addDependency(dep)
1488+
parser.state.current.addBlock(depBlock)
14991489
} else {
1500-
const range = expr.range
1501-
const dep = new CommonJsAsyncDependency(request, range)
1502-
parser.state.current.addDependency(dep)
1490+
const dep = new DynamicEntryDependency(range, request, 'export', '', tarRoot, '', context, {
1491+
isAsync: true,
1492+
isRequireAsync: true,
1493+
retryRequireAsync: this.options.retryRequireAsync,
1494+
requireAsyncRange: expr.range
1495+
})
1496+
1497+
parser.state.current.addPresentationalDependency(dep)
1498+
// 包含require.async的模块不能被concatenate,避免DynamicEntryDependency中无法获取模块chunk以计算相对路径
1499+
parser.state.module.buildInfo.moduleConcatenationBailout = 'require async'
15031500
}
1504-
if (args) parser.walkExpressions(args)
1505-
return true
15061501
} else {
1507-
compilation.errors.push(new Error(`The require async JS [${request}] need to declare subpackage name by root`))
1502+
const dep = new CommonJsAsyncDependency(request, expr.range)
1503+
parser.state.current.addDependency(dep)
1504+
if (!tarRoot) {
1505+
compilation.warnings.push(new Error(`The require async JS [${request}] need to declare subpackage name by root`))
1506+
}
15081507
}
1508+
if (args) parser.walkExpressions(args)
1509+
return true
15091510
}
15101511
}
15111512

packages/webpack-plugin/lib/runtime/components/react/mpx-async-suspense.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
8282

8383
const DefaultLoading = () => {
8484
// eslint-disable-next-line @typescript-eslint/no-var-requires
85-
const FastImage = require('@d11/react-native-fast-image')
85+
const FastImageModule = require('@d11/react-native-fast-image')
86+
const FastImage = FastImageModule.default || FastImageModule
8687
return (
8788
<View style={styles.container}>
8889
<FastImage

packages/webpack-plugin/lib/runtime/components/react/mpx-input.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import {
5454
NativeTouchEvent
5555
} from 'react-native'
5656
import { warn } from '@mpxjs/utils'
57-
import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isIOS } from './utils'
57+
import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isAndroid } from './utils'
5858
import useInnerProps, { getCustomEvent } from './getInnerListeners'
5959
import useNodesRef, { HandlerRef } from './useNodesRef'
6060
import { FormContext, FormFieldValue, KeyboardAvoidContext } from './context'
@@ -188,6 +188,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
188188
}
189189

190190
const defaultValue = parseValue(value)
191+
// 微信小程序的 input 永远是单行,textAlignVertical 固定为 auto
192+
// multiline 为 true 时表示是 textarea 组件复用此逻辑
191193
const textAlignVertical = multiline ? 'top' : 'auto'
192194
const isAutoFocus = !!autoFocus || !!focus
193195

@@ -467,6 +469,12 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
467469
: (nodeRef.current as TextInput)?.blur()
468470
}, [isAutoFocus])
469471

472+
// 使用 multiline 来修复光标位置问题
473+
// React Native 的 TextInput 在 textAlign center + placeholder 时光标会跑到右边
474+
// 这个问题只在 Android 上出现
475+
// 参考:https://github.com/facebook/react-native/issues/28794 (Android only)
476+
const needMultilineFix = isAndroid && !multiline
477+
470478
const innerProps = useInnerProps(
471479
extendObject(
472480
{},
@@ -490,7 +498,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
490498
underlineColorAndroid: 'rgba(0,0,0,0)',
491499
textAlignVertical: textAlignVertical,
492500
placeholderTextColor: placeholderStyle?.color,
493-
multiline: !!multiline,
501+
multiline: multiline || needMultilineFix,
494502
onTouchStart,
495503
onTouchEnd,
496504
onFocus,
@@ -500,6 +508,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
500508
onContentSizeChange,
501509
onSubmitEditing: bindconfirm && onSubmitEditing
502510
},
511+
needMultilineFix ? { numberOfLines: 1 } : {},
503512
!!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }
504513
),
505514
[

packages/webpack-plugin/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
2323
// 比如机型 iPhone 11 Pro,可能会导致显隐动画冲突
2424
// 因此增加状态标记 + cancelAnimation 来优化
2525
const isShow = useRef<boolean>(false)
26+
const keybaordHandleTimerRef = useRef<NodeJS.Timeout | null>(null)
2627

2728
const animatedStyle = useAnimatedStyle(() => ({
2829
// translate/position top+ overflow hidden 在 android 上时因为键盘顶起让页面高度变小,同时元素位置上移
@@ -79,7 +80,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
7980
// 重置标记位
8081
keyboardAvoid.current.readyToShow = false
8182
}
82-
if (!keyboardAvoid?.current || isShow.current) {
83+
if (!keyboardAvoid?.current) {
8384
return
8485
}
8586

@@ -124,13 +125,23 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
124125
}
125126

126127
if (isIOS) {
127-
subscriptions = [Keyboard.addListener('keyboardWillShow', keybaordAvoding), Keyboard.addListener('keyboardWillHide', resetKeyboard)]
128+
subscriptions = [
129+
Keyboard.addListener('keyboardWillShow', (evt: any) => {
130+
if (keybaordHandleTimerRef.current) {
131+
clearTimeout(keybaordHandleTimerRef.current)
132+
}
133+
// iphone 在input聚焦时长按滑动后会导致 show 事件先于 focus 事件发生,因此等一下,等 focus 先触发拿到 input,避免键盘出现但input没顶上去
134+
keybaordHandleTimerRef.current = setTimeout(() => keybaordAvoding(evt), 32)
135+
}),
136+
Keyboard.addListener('keyboardWillHide', resetKeyboard)
137+
]
128138
} else {
129139
subscriptions = [Keyboard.addListener('keyboardDidShow', keybaordAvoding), Keyboard.addListener('keyboardDidHide', resetKeyboard)]
130140
}
131141

132142
return () => {
133143
subscriptions.forEach(subscription => subscription.remove())
144+
keybaordHandleTimerRef.current && clearTimeout(keybaordHandleTimerRef.current)
134145
}
135146
}, [keyboardAvoid])
136147

0 commit comments

Comments
 (0)