Skip to content

Commit fa3b920

Browse files
authored
Merge pull request #2375 from didi/feat-style-compile-251012-ms
样式相关优化
2 parents 81546b7 + fd8b2b3 commit fa3b920

File tree

7 files changed

+98
-78
lines changed

7 files changed

+98
-78
lines changed

packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isObject, isArray, dash2hump, cached, isEmptyObject, hasOwn, getFocusedNavigation, noop } from '@mpxjs/utils'
1+
import { isObject, isArray, dash2hump, cached, isEmptyObject, hasOwn, getFocusedNavigation } from '@mpxjs/utils'
22
import { StyleSheet, Dimensions } from 'react-native'
33
import { reactive } from '../../observer/reactive'
44
import Mpx from '../../index'
@@ -12,7 +12,7 @@ global.__mpxPageSizeCountMap = reactive({})
1212

1313
global.__GCC = function (className, classMap, classMapValueCache) {
1414
if (!classMapValueCache.has(className)) {
15-
const styleObj = classMap[className]?.()
15+
const styleObj = classMap[className]?.(global.__formatValue)
1616
styleObj && classMapValueCache.set(className, styleObj)
1717
}
1818
return classMapValueCache.get(className)
@@ -266,18 +266,17 @@ export default function styleHelperMixin () {
266266

267267
classString.split(/\s+/).forEach((className) => {
268268
let localStyle, appStyle
269-
const getAppClassStyle = global.__getAppClassStyle || noop
270-
if (localStyle = this.__getClassStyle(className)) {
269+
if (localStyle = this.__getClassStyle?.(className)) {
271270
if (localStyle._media?.length) {
272271
mergeResult(localStyle._default, getMediaStyle(localStyle._media))
273272
} else {
274-
mergeResult(localStyle._default)
273+
mergeResult(localStyle)
275274
}
276-
} else if (appStyle = getAppClassStyle(className)) {
275+
} else if (appStyle = global.__getAppClassStyle?.(className)) {
277276
if (appStyle._media?.length) {
278277
mergeResult(appStyle._default, getMediaStyle(appStyle._media))
279278
} else {
280-
mergeResult(appStyle._default)
279+
mergeResult(appStyle)
281280
}
282281
} else if (isObject(this.__props[className])) {
283282
// externalClasses必定以对象形式传递下来

packages/webpack-plugin/lib/platform/style/wx/index.js

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ module.exports = function getSpec({ warn, error }) {
3333
}
3434
// 值类型
3535
const ValueType = {
36-
number: 'number',
36+
integer: 'integer',
37+
length: 'length',
3738
color: 'color',
3839
enum: 'enum'
3940
}
@@ -63,26 +64,27 @@ module.exports = function getSpec({ warn, error }) {
6364
'align-items': ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
6465
'align-self': ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
6566
'justify-content': ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'],
66-
'background-size': ['contain', 'cover', 'auto', ValueType.number],
67-
'background-position': ['left', 'right', 'top', 'bottom', 'center', ValueType.number],
67+
'background-size': ['contain', 'cover', 'auto', ValueType.length],
68+
'background-position': ['left', 'right', 'top', 'bottom', 'center', ValueType.length],
6869
'background-repeat': ['no-repeat'],
69-
width: ['auto', ValueType.number],
70-
height: ['auto', ValueType.number],
71-
'flex-basis': ['auto', ValueType.number],
72-
margin: ['auto', ValueType.number],
73-
'margin-top': ['auto', ValueType.number],
74-
'margin-left': ['auto', ValueType.number],
75-
'margin-bottom': ['auto', ValueType.number],
76-
'margin-right': ['auto', ValueType.number],
77-
'margin-horizontal': ['auto', ValueType.number],
78-
'margin-vertical': ['auto', ValueType.number]
70+
width: ['auto', ValueType.length],
71+
height: ['auto', ValueType.length],
72+
'flex-basis': ['auto', ValueType.length],
73+
margin: ['auto', ValueType.length],
74+
'margin-top': ['auto', ValueType.length],
75+
'margin-left': ['auto', ValueType.length],
76+
'margin-bottom': ['auto', ValueType.length],
77+
'margin-right': ['auto', ValueType.length],
78+
'margin-horizontal': ['auto', ValueType.length],
79+
'margin-vertical': ['auto', ValueType.length]
7980
}
8081
// 获取值类型
8182
const getValueType = (prop) => {
8283
const propValueTypeRules = [
8384
// 重要!!优先判断是不是枚举类型
8485
[ValueType.enum, new RegExp('^(' + Object.keys(SUPPORTED_PROP_VAL_ARR).join('|') + ')$')],
85-
[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)))$/],
86+
[ValueType.length, /^((gap|left|right|top|bottom)|(.+-(width|height|left|right|top|bottom|radius|spacing|size|gap|offset)))$/],
87+
[ValueType.integer, /^((opacity|flex-grow|flex-shrink|z-index)|(.+-(index|opacity)))$/],
8688
[ValueType.color, /^(color|(.+-color))$/]
8789
]
8890
for (const rule of propValueTypeRules) {
@@ -144,21 +146,29 @@ module.exports = function getSpec({ warn, error }) {
144146
if (calcExp.test(valueForVerify) || envExp.test(valueForVerify)) return true
145147
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']
146148
const valueExp = {
147-
number: /^((-?(\d+(\.\d+)?|\.\d+))(rpx|px|%|vw|vh)?|hairlineWidth)$/,
149+
integer: /^(-?(\d+(\.\d+)?|\.\d+))$/,
150+
length: /^((-?(\d+(\.\d+)?|\.\d+))(rpx|px|%|vw|vh)?|hairlineWidth)$/,
148151
color: new RegExp(('^(' + namedColor.join('|') + ')$') + '|(^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$)|^(rgb|rgba|hsl|hsla|hwb)\\(.+\\)$')
149152
}
150153
const type = getValueType(prop)
151154
const tipsType = (type) => {
152155
const info = {
153-
[ValueType.number]: '2rpx,10%,30rpx',
156+
[ValueType.length]: '2rpx,10%,30rpx',
154157
[ValueType.color]: 'rgb,rgba,hsl,hsla,hwb,named color,#000000',
155158
[ValueType.enum]: `${SUPPORTED_PROP_VAL_ARR[prop]?.join(',')}`
156159
}
157-
tips(`Value of ${prop} in ${selector} should be ${type}, eg ${info[type]}, received [${rawValue}], please check again!`)
160+
tips(`Value of ${prop} in ${selector} should be ${type}${info[type] ? `, eg ${info[type]}` : ''}, received [${rawValue}], please check again!`)
158161
}
159162
switch (type) {
160-
case ValueType.number: {
161-
if (!valueExp.number.test(valueForVerify)) {
163+
case ValueType.length: {
164+
if (!valueExp.length.test(valueForVerify)) {
165+
tipsType(type)
166+
return false
167+
}
168+
return true
169+
}
170+
case ValueType.integer: {
171+
if (!valueExp.integer.test(valueForVerify)) {
162172
tipsType(type)
163173
return false
164174
}

packages/webpack-plugin/lib/react/processStyles.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,26 +48,29 @@ module.exports = function (styles, {
4848
}, (err) => {
4949
if (err) return callback(err)
5050
try {
51+
output += `
52+
global.__classCaches = global.__classCaches || []
53+
var __classCache = new Map()
54+
global.__classCaches.push(__classCache)`
55+
const formatValueName = '_f'
5156
const classMap = getClassMap({
5257
content,
5358
filename: loaderContext.resourcePath,
5459
mode,
5560
srcMode,
5661
ctorType,
5762
warn,
58-
error
63+
error,
64+
formatValueName
5965
})
6066
const classMapCode = Object.entries(classMap).reduce((result, [key, value]) => {
6167
result !== '' && (result += ',')
62-
result += `${isValidIdentifierStr(key) ? `${key}` : `['${key}']`}: () => (${shallowStringify(value)})`
68+
result += `${isValidIdentifierStr(key) ? `${key}` : `['${key}']`}: function(${formatValueName}){return ${shallowStringify(value)};}`
6369
return result
6470
}, '')
6571
if (ctorType === 'app') {
6672
output += `
67-
global.__classCaches = global.__classCaches || []
68-
const __classCache = new Map()
69-
global.__classCaches.push(__classCache)
70-
let __appClassMap
73+
var __appClassMap
7174
global.__getAppClassStyle = function(className) {
7275
if(!__appClassMap) {
7376
__appClassMap = {${classMapCode}};
@@ -76,10 +79,7 @@ module.exports = function (styles, {
7679
};\n`
7780
} else {
7881
output += `
79-
global.__classCaches = global.__classCaches || []
80-
const __classCache = new Map()
81-
global.__classCaches.push(__classCache)
82-
let __classMap
82+
var __classMap
8383
global.currentInject.injectMethods = {
8484
__getClassStyle: function(className) {
8585
if(!__classMap) {

packages/webpack-plugin/lib/react/style-helper.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,9 @@ const unitRegExp = /^\s*(-?\d+(?:\.\d+)?)(rpx|vw|vh|px)?\s*$/
88
const hairlineRegExp = /^\s*hairlineWidth\s*$/
99
const varRegExp = /^--/
1010
const cssPrefixExp = /^-(webkit|moz|ms|o)-/
11-
function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error }) {
11+
function getClassMap ({ content, filename, mode, srcMode, ctorType, formatValueName, warn, error }) {
1212
const classMap = ctorType === 'page'
13-
? {
14-
[MPX_TAG_PAGE_SELECTOR]: {
15-
_media: [],
16-
_default: { flex: 1, height: "'100%'" }
17-
}
18-
}
13+
? { [MPX_TAG_PAGE_SELECTOR]: { flex: 1, height: "'100%'" } }
1914
: {}
2015

2116
const root = postcss.parse(content, {
@@ -30,12 +25,12 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
3025
value = matched[1]
3126
needStringify = false
3227
} else {
33-
value = `global.__formatValue(${+matched[1]}, '${matched[2]}')`
28+
value = `${formatValueName}(${+matched[1]}, '${matched[2]}')`
3429
needStringify = false
3530
}
3631
}
3732
if (hairlineRegExp.test(value)) {
38-
value = `global.__formatValue(${JSON.stringify(value)}, 'hairlineWidth')`
33+
value = `${formatValueName}(${JSON.stringify(value)}, 'hairlineWidth')`
3934
needStringify = false
4035
}
4136
return needStringify ? JSON.stringify(value) : value
@@ -93,7 +88,7 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
9388
root.walkRules(rule => {
9489
const classMapValue = {}
9590
rule.walkDecls(({ prop, value }) => {
96-
if (cssPrefixExp.test(prop) || cssPrefixExp.test(value)) return
91+
if (value === 'undefined' || cssPrefixExp.test(prop) || cssPrefixExp.test(value)) return
9792
let newData = rulesRunner({ prop, value, selector: rule.selector })
9893
if (!newData) return
9994
if (!Array.isArray(newData)) {
@@ -140,19 +135,27 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, warn, error
140135
if (classMapKeys.length) {
141136
classMapKeys.forEach((key) => {
142137
if (Object.keys(classMapValue).length) {
143-
const _default = classMap[key]?._default || {}
144-
const _media = classMap[key]?._media || []
138+
let _default = classMap[key]?._default
139+
let _media = classMap[key]?._media
145140
if (isMedia) {
141+
// 当前是媒体查询
142+
_default = _default || {}
143+
_media = _media || []
146144
_media.push({
147145
options,
148146
value: classMapValue
149147
})
150-
} else {
148+
classMap[key] = {
149+
_media,
150+
_default
151+
}
152+
} else if (_default) {
153+
// 已有媒体查询数据,此次非媒体查询
151154
Object.assign(_default, classMapValue)
152-
}
153-
classMap[key] = {
154-
_media,
155-
_default
155+
} else {
156+
// 无媒体查询
157+
const val = classMap[key] || {}
158+
classMap[key] = Object.assign(val, classMapValue)
156159
}
157160
}
158161
})

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { noop } from '@mpxjs/utils'
2626
import { SvgCssUri } from 'react-native-svg/css'
2727
import useInnerProps, { getCustomEvent } from './getInnerListeners'
2828
import useNodesRef, { HandlerRef } from './useNodesRef'
29-
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils'
29+
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject, isAndroid } from './utils'
3030
import Portal from './mpx-portal'
3131

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

195195
const { layoutRef, layoutStyle, layoutProps } = useLayout({
196196
props,

packages/webpack-plugin/lib/runtime/components/react/utils.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const varUseRegExp = /var\(/
3030
const unoVarDecRegExp = /^--un-/
3131
const unoVarUseRegExp = /var\(--un-/
3232
const calcUseRegExp = /calc\(/
33+
const calcPercentExp = /^calc\(.*-?\d+(\.\d+)?%.*\)$/
3334
const envUseRegExp = /env\(/
3435
const filterRegExp = /(calc|env|%)/
3536

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

44+
export const extendObject = Object.assign
45+
4346
function getSafeAreaInset (name: string, navigation: Record<string, any> | undefined) {
4447
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets)
4548
return insets[safeAreaInsetMap[name]]
@@ -142,16 +145,17 @@ export function splitStyle<T extends Record<string, any>> (styleObj: T): {
142145
innerStyle: Partial<T>
143146
}
144147
}
145-
146-
const selfPercentRule: Record<string, 'height' | 'width'> = {
147-
translateX: 'width',
148-
translateY: 'height',
148+
const radiusPercentRule: Record<string, 'height' | 'width'> = {
149149
borderTopLeftRadius: 'width',
150150
borderBottomLeftRadius: 'width',
151151
borderBottomRightRadius: 'width',
152152
borderTopRightRadius: 'width',
153153
borderRadius: 'width'
154154
}
155+
const selfPercentRule: Record<string, 'height' | 'width'> = extendObject({
156+
translateX: 'width',
157+
translateY: 'height'
158+
}, radiusPercentRule)
155159

156160
const parentHeightPercentRule: Record<string, boolean> = {
157161
height: true,
@@ -401,9 +405,10 @@ interface TransformStyleConfig {
401405
parentFontSize?: number
402406
parentWidth?: number
403407
parentHeight?: number
408+
transformRadiusPercent?: boolean
404409
}
405410

406-
export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
411+
export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, transformRadiusPercent, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
407412
const varStyle: Record<string, any> = {}
408413
const unoVarStyle: Record<string, any> = {}
409414
const normalStyle: Record<string, any> = {}
@@ -451,14 +456,21 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
451456
}
452457
}
453458

454-
function calcVisitor ({ value, keyPath }: VisitorArg) {
459+
function calcVisitor ({ key, value, keyPath }: VisitorArg) {
455460
if (calcUseRegExp.test(value)) {
461+
// calc translate & border-radius 的百分比计算
462+
if (hasOwn(selfPercentRule, key) && calcPercentExp.test(value)) {
463+
hasSelfPercent = true
464+
percentKeyPaths.push(keyPath.slice())
465+
}
456466
calcKeyPaths.push(keyPath.slice())
457467
}
458468
}
459469

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

475487
// traverse var & generate normalStyle
476488
traverseStyle(styleObj, [varVisitor])
477-
478489
hasVarDec = hasVarDec || !!externalVarContext
479490
enableVar = enableVar || hasVarDec || hasVarUse
480491
const enableVarRef = useRef(enableVar)
@@ -538,9 +549,8 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
538549
transformStringify(normalStyle)
539550
// transform rpx to px
540551
transformBoxShadow(normalStyle)
541-
542-
// transform 字符串格式转化数组格式
543-
transformTransform(normalStyle)
552+
// transform 字符串格式转化数组格式(先转数组再处理css var)
553+
transformTransform(styleObj)
544554

545555
return {
546556
hasVarDec,
@@ -737,8 +747,6 @@ export function flatGesture (gestures: Array<GestureHandler> = []) {
737747
})) || []
738748
}
739749

740-
export const extendObject = Object.assign
741-
742750
export function getCurrentPage (pageId: number | null | undefined) {
743751
if (!global.getCurrentPages) return
744752
const pages = global.getCurrentPages()

0 commit comments

Comments
 (0)