デザイントークンのすゝめ

:::note info
この記事は、[LITALICO Engineers Advent Calendar 2023](https://qiita.com/advent-calendar/2023/litalico)シリーズ３の20日目の記事です！
:::

# はじめに
皆様初めまして！
今年の７月から内定者インターンとして活動し、来年の４月からLITALICOに入社する[＠ryunosuke_sako](https://qiita.com/ryunosuke_sako)です！
今回は、最近（？）トレンドになっていそうなデザインシステムにまつわるトピックの中から**デザイントークン**を選んで記事を書きました！
記事前半でデザイントークンについて語り、後半でデザイントークンの導入方法についてまとめています！

# そもそもデザイントークンとは？
デザインシステムの著名な支持者であり、デザイントークンの発案者の一人でもあるJina Anneさんは[自身の動画](https://youtu.be/q5qIowMyVt8?feature=shared)にて、次のように話しています。

> Design tokens are not just variables,but variables are a very large part of how they work.
> And it kind has a correlation to responsive design because responsive design's all about having a good experience on different sized screens where design tokens is taking that a little bit further and thinking about scaling your design, at an atomic level, to iOS, Android.
> So it's also platforms.
> 訳）デザイントークンは単なる変数ではないものの、その機能には変数が非常に大きく関わっています。
> なぜなら、レスポンシブデザインとは異なるサイズのスクリーンでも優れた操作性を提供することであり、デザイントークンはそれをもう少し進めて、iOSやAndroidにデザインを拡張することを原子レベルで考えることだからです。
> つまり、デザイントークンはプラットフォームでもあるのです。

どうやら色やサイズの値を単語と結びつけてマッピングすることが目的ではなく、より広範囲の開発領域で共通のデザイン言語を使えるようにするための概念のようですね！

# 導入によるメリット
デザイントークンによって得られるメリットは、大きく分けて二つになるかと思います。

### １： SINGLE SOURCE OF TRUTH
デザインの中でも、例としてサービス全体で使われている色の変更が必要になった場合を想定します。
1. デザイナーチームが修正する内容を<font color="red">**決定**</font>する
1. それを各サービスのチームに<font color="red">**伝達**</font>する
1. 各チームでの開発環境に応じて<font color="red">**修正**</font>する

このフローにおいて、<font color="red">**伝達**</font>の際に発生しうるコミュニケーションミスとチームごとの環境の差異で発生しうる修正ミスは、サービス全体の規模が大きくなればなるほどリスクを増していくと予想できます。
そこで、全てのサービスやチームのデザインにおける共通言語としてデザイントークンを利用することで、上記のリスクを抱えることなく自然に<font color="red">**修正**</font>を加えることができるようになります。（実際の運用時にはビジュアルリグレッションテストやスナップショットテスト等も必要ですが！）

このようなメリットは、情報システムの設計用語から引用して***SINGLE SOURCE OF TRUTH***(信頼できる唯一の情報源)と呼ばれています。

[theo](https://github.com/salesforce-ux/theo?tab=readme-ov-file#overview)や[Style Dictionary](https://amzn.github.io/style-dictionary/#/)などのツールを使用すれば、例えばサイズに関して「Androidでは16DP」で「Webでは1rem」というような差分を自動で吸収してくれるので、環境が異なることによる修正ミスも無くすことができます！

### ２： 最強のスタイル共通言語
例えば、画面内のアニメーションでどのように何秒移動するかという会話があるとします。いわゆるdurationやeasingです。

デザイントークンが無い世界では、「◯秒から◯秒にこのようなeasingで」と説明するのが一般的でしょうか。
ですがデザイントークンが有る世界では、その値が名前付きのエンティティにマッピングされてさえいれば、webエンジニアもAndroidエンジニアもiOSエンジニアも果てはデザイナーも、「`＄animation-short-smooth`で」というように、簡潔に伝えることができるのです！

この、利用できる関係者の幅の広さと意味の伝わり易さは、正しく共通言語と呼べると感じました。

# プロジェクトへの導入方法
こんな素敵なデザイントークンですが、なんと導入も簡単です！

今回は、[Style Dictionary](https://amzn.github.io/style-dictionary/#/)とTokens Studioを使ってNextのプロジェクトに組み込んでいきます。
StyleDictionary単体でもjson形式でトークンを管理することは可能ではありますが、デザイナーとも語り合える共通言語なことを意識してデザインツールでトークンのjsonファイルを生成するようにします。
Figmaの拡張であるTokens Studioを利用すれば、Gitを使ったバージョン管理もできるようになってよりシステマチックにデザイントークンを活用できます！

https://tokens.studio/

### ０： Nextのセットアップ
皆様が使い馴染みのある方法でプロジェクトをセットアップしてください。もちろんNext.jsではなくても問題ありません！
参考までに、私のセットアップ手順を載せます!
````shell
% npx create-next-app@latest
✔ What is your project named? … designtoken
✔ Would you like to use TypeScript? … No / "Yes"
✔ Would you like to use ESLint? … No / "Yes"
✔ Would you like to use Tailwind CSS? … No / "Yes"
✔ Would you like to use `src/` directory? … No / "Yes"
✔ Would you like to use App Router? (recommended) … No / "Yes"
✔ Would you like to customize the default import alias (@/*)? … No / "Yes"
✔ What import alias would you like configured? … "@/*"
````

### １： 必要なパッケージをインストールする
FigmaのプラグインとしてTokens Studioをインストール（リンクは[こちら](https://www.figma.com/community/plugin/843461159747178978)）
````shell
$ npm install -D token-transformer #Tokens　Studioのjsonから余分な情報を取り除く
$ npm install -D style-dictionary
````

### ２： トークンのjsonファイルを取り込む
FigmaでTokens Studioを起動し、`Tools>Export to file/folder`で`tokens.json`を生成してプロジェクトのルートに配置します。
![スクリーンショット 2023-12-19 11.25.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641629/897174fb-88ed-462d-8cf3-cdc845ad9221.png)

### ３： コンフィグを配置する
StyleDictionaryを実行するには`config.json`が必須ですので、こちらのファイルをルートに配置します。
````config.json
{
    "source": ["adjusted.json"],
    "platforms": {
      "scss": {
        "transformGroup": "scss",
        "buildPath": "src/tokens/",
        "files": [{
          "destination": "tokens.scss",
          "format": "scss/map-deep",
          "mapName":"css-tokens",
          "options": {
            "outputReferences": true
          }
        }]
      },
      "ts": {
        "transformGroup": "js",
        "buildPath": "src/tokens/",
        "files": [
          {
            "format": "javascript/module",
            "destination": "tokens.js"
          },
          {
            "format": "typescript/module-declarations",
            "destination": "tokens.d.ts"
          }
        ]
      }
    }
}
````
<table>
  <caption>各オプションについて</caption>
  <thead>
    <tr>
      <th>オプション名</th> <th>概要</th>
    </tr>
  </thead>
  <tr>
    <td>source</td> <td>ベースとなるtokenファイルのディレクトリを指定する</td>
  </tr>
  <tr>
    <td>platforms</td> <td>変換後の単位で、好きなだけ作ることができる</td>
  </tr>
  <tr>
    <td>transformGroup</td> <td>変換する際に、どの値を変換するか決定する</td>
  </tr>
  <tr>
    <td>buildPath</td> <td>変換後のファイルがビルドされるパス</td>
  </tr>
  <tr>
    <td>files</td> <td>同じプラットフォームで複数のファイルを生成できる</td>
  </tr>
  <tr>
    <td>format</td> <td>変換方式。この値に則ってsourceが変換される</td>
  </tr>
  <tr>
    <td>destination</td> <td>変換されたファイルの名前</td>
  </tr>
</table>
<br>
上記の他にもさまざまな設定があるので、Style-Dictionaryのドキュメントを参照してご自身の環境に最適な形でご利用ください！

https://amzn.github.io/style-dictionary/#/config

### ４： コマンドを実行する
package.jsonに以下のスクリプトを追加し、`npm run token`を実行してください！
````package.json
"scripts": {
    "token": "./node_modules/.bin/token-transformer tokens.json adjusted.json && style-dictionary build"
}
````
`./node_modules/.bin/token-transformer tokens.json adjusted.json`
によってTokens Studioのjsonから余分な情報を取り除いた`adjusted.json`が生成され、`style-dictionary build`で以下のようにディレクトリとファイルが追加されたかと思います！
````shell
.
├── adjusted.json
├── config.json
├── package-lock.json
├── package.json
├── src
│   └── tokens #追加
│       ├── tokens.d.ts #追加
│       ├── tokens.js   #追加
│       └── tokens.scss #追加
└── tokens.json
````

### ５： トークンを利用する
ここまで来たら、あとはお好みの方法でスタイルをインポートしてください！
例として、Next.jsのボタンコンポーネントでの実装例を記載します。
````tsx:Button.tsx
'use client'
import variables from "@/tokens/tokens.js"

interface ButtonProps {
    text: string
}

const Button = ({ text }: ButtonProps) => {
    return (
      <button
        type="button"
        style={{
            backgroundColor: variables.colors.blue[400].value,
            margin: variables.spacing.md.value
        }}
        onClick={() => alert('OK!!')}
      >
        <span style={{color: variables.colors.white.value}}>{text}</span>
      </button>
    );
  };
  
  export default Button
````

# おわりに
初めてデザインシステムおよびデザイントークンと正面から向き合ってみて、開発体験の向上というよりはコミュニケーションや設計などもっとスケールの大きい課題を解決するための技術なのだと実感しました！
デザイントークン道はまだまだ奥が深く、Tailwindのconfigへトークンを自動で割り当て、ネイティブアプリのスタイリングに変換、などなど当記事では扱いきれなかった内容は多くあります。皆様もぜひ、デザイントークンを使って優雅なスタイリングライフをお過ごしください！

ここまで読んで下さった皆様、アドカレへの参加にご協力頂いた皆様、本当に有難うございます！
明日のアドベントカレンダー２１日目は、
- @kazuisさん
- @gate9さん
- @enochanさん

です！引き続き、お楽しみください！