Babel自定义插件怎么处理CSS-in-JS里的样式对象?

Mr-红瑞 阅读 69

我最近在写一个Babel插件,想自动给CSS-in-JS的对象加前缀,比如把color: 'red'变成WebkitColor: 'red'。但我发现访问到的AST节点是ObjectExpression,里面的Property值是StringLiteral,但不知道怎么安全地判断这个对象真的是样式对象而不是普通配置对象。

试过检查父节点是不是叫css或者styled,但有些项目用了别名就失效了。有没有更可靠的方式?下面是我想处理的那种样式写法:

.button {
  color: red;
  display: flex;
  transform: rotate(45deg);
}
我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
世梅酱~
这个问题其实挺常见的,光靠父节点名字判断确实不靠谱。

最可靠的办法是结合两种策略:

1. 检查对象是否作为样式函数的参数

CSS-in-JS库无非就是styled-components、emotion、goober这些,调用形式就那几种:

// styled.div... 或 styled(Component)...
// css... 或 css({...})
// styled.div({...})


你可以在遍历ObjectExpression时检查它的父节点是否是CallExpression,并且这个CallExpression的callee是否是已知的样式函数。

2. 检查对象属性是否符合CSS特征

如果上面没匹配到,还可以fallback到属性名检测。看你的示例,样式对象的特点是:属性名是短横线命名(kebab-case)或者常见的CSS属性名,而且基本不会有theme、label、css这种配置属性混在里面。

具体实现大概这样:

const CSS_IN_JS_FUNCTIONS = ['styled', 'css', 'keyframes', 'createGlobalStyle', 'injectGlobal'];

function isStyleObject(path) {
const parent = path.parent;

// 策略1:作为样式函数参数
if (t.isCallExpression(parent)) {
const callee = parent.get('callee');
const fnName = callee.isIdentifier() ? callee.node.name : null;
const memberObject = callee.isMemberExpression() ? callee.node.object.name : null;

if (CSS_IN_JS_FUNCTIONS.includes(fnName) ||
CSS_IN_JS_FUNCTIONS.includes(memberObject)) {
return true;
}
}

// 策略2:属性名看起来像CSS
const props = path.get('properties');
if (props.length === 0) return false;

const cssProps = ['color', 'display', 'flex', 'transform', 'margin', 'padding', 'font', 'background'];
const configProps = ['theme', 'label', 'as', 'css', 'forwardProps'];

const allLookLikeCSS = props.every(prop => {
const key = prop.get('key');
const keyName = key.isIdentifier() ? key.node.name : key.node.value;
return cssProps.includes(keyName) || keyName.includes('-');
});

const hasConfigProp = props.some(prop => {
const key = prop.get('key');
const keyName = key.isIdentifier() ? key.node.name : key.node.value;
return configProps.includes(keyName);
});

return allLookLikeCSS && !hasConfigProp;
}


这样双重判断下来误判概率很低。实际项目中你可以根据具体用的CSS-in-JS库调整函数名列表。
点赞
2026-03-18 04:00