Style Dictionary配置求助:如何导出关联式设计令牌?
Style Dictionary 保留令牌层级关联引用的配置方案
我有三层设计令牌(原始层、语义层、特定层),使用Style Dictionary编译到不同平台时,所有令牌都被替换成了原始值,无法保留JSON源文件中的关联引用关系。之前尝试用GPT建议的build.js定义转换规则,但构建时出现报错。以下是我的相关文件和编译结果:
参考JSON文件
{ "token": { "spacer": { "value": "12px", "type": "dimension" }, "gap": { "value": "{token.spacer}", "type": "dimension" }, "button-gap": { "value": "{token.gap}", "type": "dimension" } } }
原配置文件
{ "source": ["tokens/**/*.json"], "platforms": { "web": { "transformGroup": "scss", "buildPath": "build/web/", "files": [ { "destination": "variables.scss", "format": "scss/variables" } ] }, "ios": { "transformGroup": "ios", "buildPath": "build/ios/", "files": [ { "destination": "tokens.h", "format": "ios/macros" } ] }, "android": { "transformGroup": "android", "buildPath": "build/android/", "files": [ { "destination": "tokens.xml", "format": "android/resources" } ] } } }
当前编译结果
Web(variables.scss)
$token-spacer: 12px; $token-gap: 12px; $token-button-gap: 12px;
Android(tokens.xml)
<resources> <dimen name="token_spacer">192.00dp</dimen> <dimen name="token_gap">192.00dp</dimen> <dimen name="token_button_gap">192.00dp</dimen> </resources>
iOS(tokens.h)
#define TokenSpacer 192.00f #define TokenGap 192.00f #define TokenButtonGap 192.00f
解决方案:保留关联引用的配置与自定义格式器
核心思路是禁用Style Dictionary默认的令牌值解析替换,同时编写自定义格式器,将令牌引用转换为对应平台支持的变量/宏引用语法。
1. 修改配置文件,禁用默认值解析
在每个平台的配置中添加"resolveReferences": false,阻止Style Dictionary自动替换引用的令牌值;同时指定自定义格式器:
{ "source": ["tokens/**/*.json"], "platforms": { "web": { "transformGroup": "scss", "resolveReferences": false, "buildPath": "build/web/", "files": [ { "destination": "variables.scss", "format": "custom/scss-references" } ] }, "ios": { "transformGroup": "ios", "resolveReferences": false, "buildPath": "build/ios/", "files": [ { "destination": "tokens.h", "format": "custom/ios-macros-references" } ] }, "android": { "transformGroup": "android", "resolveReferences": false, "buildPath": "build/android/", "files": [ { "destination": "tokens.xml", "format": "custom/android-resources-references" } ] } } }
2. 创建自定义格式器脚本(build.js)
编写build.js注册自定义格式器,处理令牌引用转换与单位转换逻辑:
const StyleDictionary = require('style-dictionary'); // 自定义SCSS格式:将令牌引用转为SCSS变量 StyleDictionary.registerFormat({ name: 'custom/scss-references', formatter: function({ dictionary }) { return dictionary.allTokens.map(token => { let value = token.value; // 替换{token.spacer}为$token-spacer if (value.startsWith('{') && value.endsWith('}')) { const refTokenName = value.slice(1, -1).replace(/\./g, '-'); value = `$${refTokenName}`; } return `$${token.name}: ${value};`; }).join('\n'); } }); // 自定义iOS宏格式:将令牌引用转为宏名称 StyleDictionary.registerFormat({ name: 'custom/ios-macros-references', formatter: function({ dictionary }) { return dictionary.allTokens.map(token => { let value = token.value; // 替换{token.spacer}为TokenSpacer if (value.startsWith('{') && value.endsWith('}')) { const refTokenPath = value.slice(1, -1).split('.'); const refTokenName = refTokenPath.map(part => part.charAt(0).toUpperCase() + part.slice(1) ).join(''); value = refTokenName; } // 处理px转iOS pt单位(1px=16pt) if (typeof value === 'string' && value.endsWith('px')) { value = `${parseFloat(value) * 16}.00f`; } return `#define ${token.name} ${value}`; }).join('\n'); } }); // 自定义Android资源格式:将令牌引用转为@dimen/xxx StyleDictionary.registerFormat({ name: 'custom/android-resources-references', formatter: function({ dictionary }) { const tokens = dictionary.allTokens.map(token => { let value = token.value; // 替换{token.spacer}为@dimen/token_spacer if (value.startsWith('{') && value.endsWith('}')) { const refTokenName = value.slice(1, -1).replace(/\./g, '_'); value = `@dimen/${refTokenName}`; } // 处理px转Android dp单位(1px=16dp) if (typeof value === 'string' && value.endsWith('px')) { value = `${parseFloat(value) * 16}.00dp`; } return ` <dimen name="${token.name}">${value}</dimen>`; }).join('\n'); return `<resources>\n${tokens}\n</resources>`; } }); // 执行构建 StyleDictionary.extend('config.json').buildAllPlatforms();
3. 运行构建命令
替换原有的Style Dictionary构建命令,执行自定义脚本:
node build.js
预期编译结果
Web(variables.scss)
$token-spacer: 12px; $token-gap: $token-spacer; $token-button-gap: $token-gap;
iOS(tokens.h)
#define TokenSpacer 192.00f #define TokenGap TokenSpacer #define TokenButtonGap TokenGap
Android(tokens.xml)
<resources> <dimen name="token_spacer">192.00dp</dimen> <dimen name="token_gap">@dimen/token_spacer</dimen> <dimen name="token_button_gap">@dimen/token_gap</dimen> </resources>
注意事项
- 自定义格式器中的引用替换逻辑需与你的令牌命名规则匹配,若令牌结构调整需同步修改正则或字符串处理逻辑
- 若存在其他类型令牌(如颜色、字体),需扩展格式器的处理分支,适配对应平台的语法
- 禁用
resolveReferences后,原transformGroup中的单位转换逻辑需手动在自定义格式器中实现,确保单位转换正确
内容的提问来源于stack exchange,提问作者vizin
相关产品推荐
相关产品推荐

