4. Style Dictionary 配置:安装、基本配置、transform 与 format 自定义、多品牌输出
4.1 本章定位
Style Dictionary 是设计 到多平台代码的编译引擎。在 Material 3 主题资源云分发中,它负责将统一的 JSON 转换为 Android XML、iOS Swift、CSS 变量、Flutter 常量等平台产物,配合 CDN 分发实现“一次定义,多处同步”。本章覆盖安装、核心配置、Transform/Format 扩展以及多品牌输出管道搭建。
前置知识:已完成 源文件设计(§3);Node.js ≥16.0、npm ≥8.0。
4.2 处理原理
Style Dictionary 的执行流水线分为三个阶段:
- Source 读取:加载 JSON/JSON5 格式的设计 文件
- Transform 映射:对每个 执行属性转换(颜色空间、尺寸单位、命名规则)
- Format 输出:将转换后的 集合渲染为目标代码/文件
通过配置多个 platforms,可在一次构建中同时输出多品牌、多平台产物。
4.3 安装 Style Dictionary
全局安装或作为项目依赖:
# 作为项目依赖安装(推荐)
npm install style-dictionary --save-dev
# 全局安装
npm install -g style-dictionary
# 验证安装
npx style-dictionary --version
# 或
style-dictionary --version
版本要求:使用 ≥3.9.0 以获得完整的 Transform 配置能力。运行
npm view style-dictionary version 查看最新稳定版。
4.4 基本配置结构
在项目根目录创建 config.json 或 config.js(推荐 JS 以获得动态配置能力)。最小配置示例:
{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"buildPath": "dist/web/",
"files": [{
"destination": "variables.css",
"format": "css/variables"
}]
}
}
}
核心字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
source | string[] | 源文件 glob 模式 |
include | string[] | 额外的包含路径(如基础 ) |
platforms | object | 输出平台配置,key 为平台标识 |
transformGroup | string | 预定义转换组名(如 css、android、ios) |
buildPath | string | 输出目录 |
files | object[] | 每个输出文件指定 destination 和 format |
4.5 Transform 自定义
当预定义的 transformGroup 不能满足 Material 3 的语义化命名或特殊颜色空间转换时,需要自定义 Transform。
4.5.1 创建自定义 Transform
在 config.js 中通过 property 对象定义:
const StyleDictionary = require('style-dictionary');
StyleDictionary.registerTransform({
name: 'size/remToPx',
type: 'value',
matcher: (prop) => prop.attributes.category === 'size',
transformer: (prop) => {
// 假设 值为 rem 字面量,如 '1.5rem'
const remValue = parseFloat(prop.original.value);
return `${remValue * 16}px`;
}
});
// 然后可以在 platform 中引用
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transforms: ['size/remToPx', 'color/css'],
buildPath: 'dist/web/',
files: [{ destination: 'variables.css', format: 'css/variables' }]
}
}
};
4.5.2 Transform 类型说明
| 类型 | 用途 | 示例 |
|---|---|---|
attribute | 修改 属性(category/type/item) | 根据命名模式添加分类 |
name | 修改输出变量名 | 驼峰 → 中划线 |
value | 修改 值 | rem → px, rgb → hex |
4.6 Format 自定义
当内置 Format 不满足输出样式时(例如需要带版权注释的 CSS 变量文件),自定义 Format:
StyleDictionary.registerFormat({
name: 'custom/css-variables',
formatter: function({ dictionary, platform, options }) {
// dictionary.allTokens 包含所有已转换的
const lines = dictionary.allTokens.map( =>
` --${.name}: ${.value};`
);
const header = `/* Material 3 Theme - Generated ${new Date().toISOString().slice(0,10)} */\n`;
return `${header}:root {\n${lines.join('\n')}${lines.length ? '\n' : ''}}\n`;
}
});
// config.js 中引用
files: [{ destination: 'tokens.css', format: 'custom/css-variables' }]
4.7 多品牌输出配置
在 platforms 中定义多个品牌。每个品牌可以有不同的 Transform、Format 和文件输出。示例配置实现 BrandA / BrandB 的 Light / Dark 主题:
module.exports = {
source: ['tokens/global/**/*.json'],
platforms: {
'brandA-light': {
transformGroup: 'css',
buildPath: 'dist/brandA/light/',
files: [{ destination: 'tokens.css', format: 'css/variables' }]
},
'brandA-dark': {
transformGroup: 'css',
buildPath: 'dist/brandA/dark/',
files: [{ destination: 'tokens.css', format: 'css/variables' }]
},
'brandB-light': {
transforms: ['color/css', 'size/remToPx'],
buildPath: 'dist/brandB/light/',
files: [
{ destination: 'tokens.scss', format: 'scss/variables' },
{ destination: 'tokens.json', format: 'json/flat' }
]
}
}
};
每个 platform 的 source 也可单独指定,用于覆盖不同品牌的 文件:
platforms: {
'brandX': {
source: ['tokens/global/*.json', 'tokens/brandX/*.json'],
// ...
}
}
4.8 构建与调试命令
| 命令 | 说明 |
|---|---|
npx style-dictionary build | 读取默认 config.json/config.js 执行构建 |
npx style-dictionary build --config ./path/to/config.js | 指定配置文件路径 |
npx style-dictionary init | 快速生成示例项目骨架 |
npx style-dictionary --help | 查看所有 CLI 选项 |
调试时使用 --verbose 输出详细的 处理信息:
npx style-dictionary build --verbose
# 会打印每个 的原始值、变换后值以及匹配的 transform/format
4.9 常见错误与排查
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
构建报错 Cannot find module 'style-dictionary' | 未安装或全局安装未识别 | 使用 npx 或检查 node_modules |
| 值未转换直接输出 | 自定义 Transform 未加入 platform 的 transforms 数组 | 确认 platform 中显式声明了 transforms |
| 输出路径重复、文件内容为空 | 多个 platform 使用相同 buildPath + destination | 分配唯一输出路径,或使用 platform 变量 |
matcher 不命中 | 的 attribute 命名与 matcher 条件不匹配 | 使用 --verbose 查看 实际 attributes |
| 多品牌构建顺序有隐式依赖 | 共享的 tokens 文件被不同 platform 同时写入 | 确保每个 platform 有独立输出目录 |
4.10 性能与稳定性优化
- 增量构建:使用
style-dictionary搭配 chokidar 文件监听,只重新构建变更 platform - 缓存 Transform 结果:对于不变 跳过重复转换(可利用
build-time插件) - 并行构建:多 platform 使用
buildPlatformsAPI 并发执行 - 减少 source 范围:避免使用过于宽泛的 glob(如
**/*.json),应精确到目录 - 配置分离:将多品牌配置拆分为独立的
config.brandA.js,通过 CI 并行调用
// 并行构建示例(Node.js 脚本)
const StyleDictionary = require('style-dictionary');
const configs = ['config.brandA.json', 'config.brandB.json'];
Promise.all(configs.map(cfg => StyleDictionary.extend(cfg).buildAllPlatforms()))
.then(() => console.log('All brands built'))
.catch(err => console.error(err));
本章实践要点:
- 完成 Style Dictionary 安装与会话验证
- 实现一个自定义 Transform(如将 Material 的
sys.color.primary转为 CSS 变量名--md-sys-color-primary) - 配置至少 2 个品牌 platform,输出不同后缀的 CSS 文件
- 使用
--verbose调试自定义 Transform 的匹配情况
4.11 章节总结
本章完成了从安装到多品牌输出的全链路配置。核心能力:
- 理解 → Transform → Format → Platform 的流水线逻辑
- 掌握内置与自定义 Transform/Format 的定义与注册
- 能够通过多个 platform 一次构建输出多品牌、多平台的主题资源文件