Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
88fe2dd
1.z-index auto 报错;2.样式编译优化:es6语法+__formatValue简化
wenwenhua Dec 10, 2025
9f754c5
del percentVisitor
wenwenhua Dec 11, 2025
c06680f
z-index auto
wenwenhua Dec 11, 2025
224617c
fix eslint
wenwenhua Dec 11, 2025
6177871
支持 transform translateX(var(--un-translate-x, -50%)) translateY(var(-…
wenwenhua Dec 23, 2025
6d4cfdc
add calc translate percent
wenwenhua Dec 24, 2025
01dce81
Merge branch 'master' into feat-style-compile-251012
wenwenhua Dec 24, 2025
8c5413b
优化非媒体查询的_default&_media
wenwenhua Dec 24, 2025
661131f
优化非媒体查询的_default&_media
wenwenhua Dec 24, 2025
a061fa2
fix js error __getClassStyle is not function
wenwenhua Dec 24, 2025
b71205d
fix __formatValue to _f
wenwenhua Dec 24, 2025
0597ac7
del space
wenwenhua Dec 24, 2025
2b8b302
fix eslint
wenwenhua Dec 24, 2025
ef01c4d
fix 单测
wenwenhua Dec 24, 2025
9e49ee2
Merge branch 'master' into feat-style-compile-251012
wenwenhua Jan 4, 2026
dabdba6
feat: fix mr
wenwenhua Jan 4, 2026
cc1e3c2
fix image borderRadius + cr
wenwenhua Jan 7, 2026
67330d9
fix image borderRadius + cr
wenwenhua Jan 7, 2026
2fbba82
del hasown
wenwenhua Jan 7, 2026
d1d9f77
仅base image 计算
wenwenhua Jan 7, 2026
5de271e
del transform var
wenwenhua Jan 7, 2026
2e21b17
回滚transform
wenwenhua Jan 7, 2026
849c678
del unused
wenwenhua Jan 7, 2026
6a7d250
format
wenwenhua Jan 7, 2026
d1b48da
Merge branch 'master' into feat-style-compile-251012-ms
wenwenhua Jan 13, 2026
d73f18d
fix cr
wenwenhua Jan 16, 2026
8c31a78
Merge branch 'master' into feat-style-compile-251012-ms
hiyuki Jan 22, 2026
6d50090
Merge branch 'master' into feat-style-compile-251012-ms
hiyuki Jan 22, 2026
a27ee7c
merge master
wenwenhua Jan 22, 2026
cfcdc94
Merge branch 'feat-style-compile-251012-ms' of github.com:didi/mpx in…
wenwenhua Jan 22, 2026
fd8b2b3
fix 单测
wenwenhua Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isObject, isArray, dash2hump, cached, isEmptyObject, hasOwn, getFocusedNavigation, noop } from '@mpxjs/utils'
import { isObject, isArray, dash2hump, cached, isEmptyObject, hasOwn, getFocusedNavigation } from '@mpxjs/utils'
import { StyleSheet, Dimensions } from 'react-native'
import { reactive } from '../../observer/reactive'
import Mpx from '../../index'
Expand All @@ -12,7 +12,7 @@ global.__mpxPageSizeCountMap = reactive({})

global.__GCC = function (className, classMap, classMapValueCache) {
if (!classMapValueCache.has(className)) {
const styleObj = classMap[className]?.()
const styleObj = classMap[className]?.(global.__formatValue)
styleObj && classMapValueCache.set(className, styleObj)
}
return classMapValueCache.get(className)
Expand Down Expand Up @@ -266,18 +266,17 @@ export default function styleHelperMixin () {

classString.split(/\s+/).forEach((className) => {
let localStyle, appStyle
const getAppClassStyle = global.__getAppClassStyle || noop
if (localStyle = this.__getClassStyle(className)) {
if (localStyle = this.__getClassStyle?.(className)) {
if (localStyle._media?.length) {
mergeResult(localStyle._default, getMediaStyle(localStyle._media))
} else {
mergeResult(localStyle._default)
mergeResult(localStyle)
}
} else if (appStyle = getAppClassStyle(className)) {
} else if (appStyle = global.__getAppClassStyle?.(className)) {
if (appStyle._media?.length) {
mergeResult(appStyle._default, getMediaStyle(appStyle._media))
} else {
mergeResult(appStyle._default)
mergeResult(appStyle)
}
} else if (isObject(this.__props[className])) {
// externalClasses必定以对象形式传递下来
Expand Down
48 changes: 29 additions & 19 deletions packages/webpack-plugin/lib/platform/style/wx/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = function getSpec({ warn, error }) {
}
// 值类型
const ValueType = {
number: 'number',
integer: 'integer',
length: 'length',
color: 'color',
enum: 'enum'
}
Expand Down Expand Up @@ -63,26 +64,27 @@ module.exports = function getSpec({ warn, error }) {
'align-items': ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
'align-self': ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
'justify-content': ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'],
'background-size': ['contain', 'cover', 'auto', ValueType.number],
'background-position': ['left', 'right', 'top', 'bottom', 'center', ValueType.number],
'background-size': ['contain', 'cover', 'auto', ValueType.length],
'background-position': ['left', 'right', 'top', 'bottom', 'center', ValueType.length],
'background-repeat': ['no-repeat'],
width: ['auto', ValueType.number],
height: ['auto', ValueType.number],
'flex-basis': ['auto', ValueType.number],
margin: ['auto', ValueType.number],
'margin-top': ['auto', ValueType.number],
'margin-left': ['auto', ValueType.number],
'margin-bottom': ['auto', ValueType.number],
'margin-right': ['auto', ValueType.number],
'margin-horizontal': ['auto', ValueType.number],
'margin-vertical': ['auto', ValueType.number]
width: ['auto', ValueType.length],
height: ['auto', ValueType.length],
'flex-basis': ['auto', ValueType.length],
margin: ['auto', ValueType.length],
'margin-top': ['auto', ValueType.length],
'margin-left': ['auto', ValueType.length],
'margin-bottom': ['auto', ValueType.length],
'margin-right': ['auto', ValueType.length],
'margin-horizontal': ['auto', ValueType.length],
'margin-vertical': ['auto', ValueType.length]
}
// 获取值类型
const getValueType = (prop) => {
const propValueTypeRules = [
// 重要!!优先判断是不是枚举类型
[ValueType.enum, new RegExp('^(' + Object.keys(SUPPORTED_PROP_VAL_ARR).join('|') + ')$')],
[ValueType.number, /^((opacity|flex-grow|flex-shrink|gap|left|right|top|bottom)|(.+-(width|height|left|right|top|bottom|radius|spacing|size|gap|index|offset|opacity)))$/],
[ValueType.length, /^((gap|left|right|top|bottom)|(.+-(width|height|left|right|top|bottom|radius|spacing|size|gap|offset)))$/],
[ValueType.integer, /^((opacity|flex-grow|flex-shrink|z-index)|(.+-(index|opacity)))$/],
[ValueType.color, /^(color|(.+-color))$/]
]
for (const rule of propValueTypeRules) {
Expand Down Expand Up @@ -144,21 +146,29 @@ module.exports = function getSpec({ warn, error }) {
if (calcExp.test(valueForVerify) || envExp.test(valueForVerify)) return true
const namedColor = ['transparent', 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen']
const valueExp = {
number: /^((-?(\d+(\.\d+)?|\.\d+))(rpx|px|%|vw|vh)?|hairlineWidth)$/,
integer: /^(-?(\d+(\.\d+)?|\.\d+))$/,
length: /^((-?(\d+(\.\d+)?|\.\d+))(rpx|px|%|vw|vh)?|hairlineWidth)$/,
color: new RegExp(('^(' + namedColor.join('|') + ')$') + '|(^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$)|^(rgb|rgba|hsl|hsla|hwb)\\(.+\\)$')
}
const type = getValueType(prop)
const tipsType = (type) => {
const info = {
[ValueType.number]: '2rpx,10%,30rpx',
[ValueType.length]: '2rpx,10%,30rpx',
[ValueType.color]: 'rgb,rgba,hsl,hsla,hwb,named color,#000000',
[ValueType.enum]: `${SUPPORTED_PROP_VAL_ARR[prop]?.join(',')}`
}
tips(`Value of ${prop} in ${selector} should be ${type}, eg ${info[type]}, received [${rawValue}], please check again!`)
tips(`Value of ${prop} in ${selector} should be ${type}${info[type] ? `, eg ${info[type]}` : ''}, received [${rawValue}], please check again!`)
}
switch (type) {
case ValueType.number: {
if (!valueExp.number.test(valueForVerify)) {
case ValueType.length: {
if (!valueExp.length.test(valueForVerify)) {
tipsType(type)
return false
}
return true
}
case ValueType.integer: {
if (!valueExp.integer.test(valueForVerify)) {
tipsType(type)
return false
}
Expand Down
20 changes: 10 additions & 10 deletions packages/webpack-plugin/lib/react/processStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,29 @@ module.exports = function (styles, {
}, (err) => {
if (err) return callback(err)
try {
output += `
global.__classCaches = global.__classCaches || []
var __classCache = new Map()
global.__classCaches.push(__classCache)`
const formatValueName = '_f'
const classMap = getClassMap({
content,
filename: loaderContext.resourcePath,
mode,
srcMode,
ctorType,
warn,
error
error,
formatValueName
})
const classMapCode = Object.entries(classMap).reduce((result, [key, value]) => {
result !== '' && (result += ',')
result += `${isValidIdentifierStr(key) ? `${key}` : `['${key}']`}: () => (${shallowStringify(value)})`
result += `${isValidIdentifierStr(key) ? `${key}` : `['${key}']`}: function(${formatValueName}){return ${shallowStringify(value)};}`
return result
}, '')
if (ctorType === 'app') {
output += `
global.__classCaches = global.__classCaches || []
const __classCache = new Map()
global.__classCaches.push(__classCache)
let __appClassMap
var __appClassMap
global.__getAppClassStyle = function(className) {
if(!__appClassMap) {
__appClassMap = {${classMapCode}};
Expand All @@ -76,10 +79,7 @@ module.exports = function (styles, {
};\n`
} else {
output += `
global.__classCaches = global.__classCaches || []
const __classCache = new Map()
global.__classCaches.push(__classCache)
let __classMap
var __classMap
global.currentInject.injectMethods = {
__getClassStyle: function(className) {
if(!__classMap) {
Expand Down
37 changes: 20 additions & 17 deletions packages/webpack-plugin/lib/react/style-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ const unitRegExp = /^\s*(-?\d+(?:\.\d+)?)(rpx|vw|vh|px)?\s*$/
const hairlineRegExp = /^\s*hairlineWidth\s*$/
const varRegExp = /^--/
const cssPrefixExp = /^-(webkit|moz|ms|o)-/
function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error }) {
function getClassMap ({ content, filename, mode, srcMode, ctorType, formatValueName, warn, error }) {
const classMap = ctorType === 'page'
? {
[MPX_TAG_PAGE_SELECTOR]: {
_media: [],
_default: { flex: 1, height: "'100%'" }
}
}
? { [MPX_TAG_PAGE_SELECTOR]: { flex: 1, height: "'100%'" } }
: {}

const root = postcss.parse(content, {
Expand All @@ -30,12 +25,12 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
value = matched[1]
needStringify = false
} else {
value = `global.__formatValue(${+matched[1]}, '${matched[2]}')`
value = `${formatValueName}(${+matched[1]}, '${matched[2]}')`
needStringify = false
}
}
if (hairlineRegExp.test(value)) {
value = `global.__formatValue(${JSON.stringify(value)}, 'hairlineWidth')`
value = `${formatValueName}(${JSON.stringify(value)}, 'hairlineWidth')`
needStringify = false
}
return needStringify ? JSON.stringify(value) : value
Expand Down Expand Up @@ -93,7 +88,7 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
root.walkRules(rule => {
const classMapValue = {}
rule.walkDecls(({ prop, value }) => {
if (cssPrefixExp.test(prop) || cssPrefixExp.test(value)) return
if (value === 'undefined' || cssPrefixExp.test(prop) || cssPrefixExp.test(value)) return
let newData = rulesRunner({ prop, value, selector: rule.selector })
if (!newData) return
if (!Array.isArray(newData)) {
Expand Down Expand Up @@ -140,19 +135,27 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
if (classMapKeys.length) {
classMapKeys.forEach((key) => {
if (Object.keys(classMapValue).length) {
const _default = classMap[key]?._default || {}
const _media = classMap[key]?._media || []
let _default = classMap[key]?._default
let _media = classMap[key]?._media
if (isMedia) {
// 当前是媒体查询
_default = _default || {}
_media = _media || []
_media.push({
options,
value: classMapValue
})
} else {
classMap[key] = {
_media,
_default
}
} else if (_default) {
// 已有媒体查询数据,此次非媒体查询
Object.assign(_default, classMapValue)
}
classMap[key] = {
_media,
_default
} else {
// 无媒体查询
const val = classMap[key] || {}
classMap[key] = Object.assign(val, classMapValue)
}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { noop } from '@mpxjs/utils'
import { SvgCssUri } from 'react-native-svg/css'
import useInnerProps, { getCustomEvent } from './getInnerListeners'
import useNodesRef, { HandlerRef } from './useNodesRef'
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils'
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject, isAndroid } from './utils'
import Portal from './mpx-portal'

export type Mode =
Expand Down Expand Up @@ -190,7 +190,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
normalStyle,
setWidth,
setHeight
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
} = useTransformStyle(styleObj, { enableVar, transformRadiusPercent: isAndroid && !isSvg && !isLayoutMode, externalVarContext, parentFontSize, parentWidth, parentHeight })

const { layoutRef, layoutStyle, layoutProps } = useLayout({
props,
Expand Down
34 changes: 21 additions & 13 deletions packages/webpack-plugin/lib/runtime/components/react/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const varUseRegExp = /var\(/
const unoVarDecRegExp = /^--un-/
const unoVarUseRegExp = /var\(--un-/
const calcUseRegExp = /calc\(/
const calcPercentExp = /^calc\(.*-?\d+(\.\d+)?%.*\)$/
const envUseRegExp = /env\(/
const filterRegExp = /(calc|env|%)/

Expand All @@ -40,6 +41,8 @@ const safeAreaInsetMap: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {
'safe-area-inset-left': 'left'
}

export const extendObject = Object.assign

function getSafeAreaInset (name: string, navigation: Record<string, any> | undefined) {
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets)
return insets[safeAreaInsetMap[name]]
Expand Down Expand Up @@ -142,16 +145,17 @@ export function splitStyle<T extends Record<string, any>> (styleObj: T): {
innerStyle: Partial<T>
}
}

const selfPercentRule: Record<string, 'height' | 'width'> = {
translateX: 'width',
translateY: 'height',
const radiusPercentRule: Record<string, 'height' | 'width'> = {
borderTopLeftRadius: 'width',
borderBottomLeftRadius: 'width',
borderBottomRightRadius: 'width',
borderTopRightRadius: 'width',
borderRadius: 'width'
}
const selfPercentRule: Record<string, 'height' | 'width'> = extendObject({
translateX: 'width',
translateY: 'height'
}, radiusPercentRule)

const parentHeightPercentRule: Record<string, boolean> = {
height: true,
Expand Down Expand Up @@ -401,9 +405,10 @@ interface TransformStyleConfig {
parentFontSize?: number
parentWidth?: number
parentHeight?: number
transformRadiusPercent?: boolean
}

export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, transformRadiusPercent, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
const varStyle: Record<string, any> = {}
const unoVarStyle: Record<string, any> = {}
const normalStyle: Record<string, any> = {}
Expand Down Expand Up @@ -451,14 +456,21 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
}
}

function calcVisitor ({ value, keyPath }: VisitorArg) {
function calcVisitor ({ key, value, keyPath }: VisitorArg) {
if (calcUseRegExp.test(value)) {
// calc translate & border-radius 的百分比计算
if (hasOwn(selfPercentRule, key) && calcPercentExp.test(value)) {
hasSelfPercent = true
percentKeyPaths.push(keyPath.slice())
}
calcKeyPaths.push(keyPath.slice())
}
}

function percentVisitor ({ key, value, keyPath }: VisitorArg) {
if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
// fixme 去掉 translate & border-radius 的百分比计算
// fixme Image 组件 borderRadius 仅支持 number
if (transformRadiusPercent && hasOwn(radiusPercentRule, key) && PERCENT_REGEX.test(value)) {
hasSelfPercent = true
percentKeyPaths.push(keyPath.slice())
} else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) {
Expand All @@ -474,7 +486,6 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV

// traverse var & generate normalStyle
traverseStyle(styleObj, [varVisitor])

hasVarDec = hasVarDec || !!externalVarContext
enableVar = enableVar || hasVarDec || hasVarUse
const enableVarRef = useRef(enableVar)
Expand Down Expand Up @@ -538,9 +549,8 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
transformStringify(normalStyle)
// transform rpx to px
transformBoxShadow(normalStyle)

// transform 字符串格式转化数组格式
transformTransform(normalStyle)
// transform 字符串格式转化数组格式(先转数组再处理css var)
transformTransform(styleObj)

return {
hasVarDec,
Expand Down Expand Up @@ -737,8 +747,6 @@ export function flatGesture (gestures: Array<GestureHandler> = []) {
})) || []
}

export const extendObject = Object.assign

export function getCurrentPage (pageId: number | null | undefined) {
if (!global.getCurrentPages) return
const pages = global.getCurrentPages()
Expand Down
Loading