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 的执行流水线分为三个阶段:

  1. Source 读取:加载 JSON/JSON5 格式的设计 文件
  2. Transform 映射:对每个 执行属性转换(颜色空间、尺寸单位、命名规则)
  3. Format 输出:将转换后的 集合渲染为目标代码/文件

通过配置多个 platforms,可在一次构建中同时输出多品牌、多平台产物。

Style Dictionary 处理流水线(多品牌输出) 源 JSON (设计 仓库) Style Dict 配置 (source/transformGroup) Transforms 颜色 → hex/rgba 尺寸 → px/pt/dp Formats CSS / Android / iOS / Flutter 多品牌 Platform ▪ BrandA (Light) ▪ BrandA (Dark) ▪ BrandB (Light) ▪ BrandB (Dark) 关键路径解释: ① 源 + 配置 → Transforms 进行属性映射 ② 转换后的 → Formats 渲染为目标代码 ③ 多 platforms 可共享同一组 Transforms,但指定不同的 Format 和输出路径

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"
      }]
    }
  }
}

核心字段说明:

字段类型说明
sourcestring[] 源文件 glob 模式
includestring[]额外的包含路径(如基础 )
platformsobject输出平台配置,key 为平台标识
transformGroupstring预定义转换组名(如 css、android、ios)
buildPathstring输出目录
filesobject[]每个输出文件指定 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 使用 buildPlatforms API 并发执行
  • 减少 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));
本章实践要点:
  1. 完成 Style Dictionary 安装与会话验证
  2. 实现一个自定义 Transform(如将 Material 的 sys.color.primary 转为 CSS 变量名 --md-sys-color-primary)
  3. 配置至少 2 个品牌 platform,输出不同后缀的 CSS 文件
  4. 使用 --verbose 调试自定义 Transform 的匹配情况

4.11 章节总结

本章完成了从安装到多品牌输出的全链路配置。核心能力:

  • 理解 → Transform → Format → Platform 的流水线逻辑
  • 掌握内置与自定义 Transform/Format 的定义与注册
  • 能够通过多个 platform 一次构建输出多品牌、多平台的主题资源文件