デザイントークンを自動補完するVS Code拡張機能を開発しました
Ubie Discoveryでプロダクト開発をしている@jimboです。
Ubieでは、デザイン生産基盤の整備の一環としてデザイントークンを開発し、npmに公開しています。開発の経緯などは次の記事をごらんください。
今回、このデザイントークン用のVS Code拡張機能を開発したのでご紹介します。
リポジトリはこちら。
主な機能
CSSファイルおよびSCSSファイルの編集時に次のような機能が使えるようになります。
自動補完
color
や margin
など、CSSプロパティのあとに --
を入力すると、デザイントークンのCSSカスタムプロパティが候補として表示されます。
ホバー時のツールチップ表示
入力済みのデザイントークン(CSSカスタムプロパティ)にカーソルを当てると、その値を確認できます。
拡張機能を開発した背景
現在、デザイントークンは症状検索エンジン「ユビー」やユビー病気のQ&Aといったプロダクトに適用されています。
しかし、トークンの数は100を超え、--color-ubie-black-500
や--size-spacing-md
などCSSカスタムプロパティの名前とその値をすべて覚えるのは困難です。プロダクト開発ではその都度FigmaやCSSの定義ファイルを確認するという作業が発生していました。また、rem単位で定義されている値をpx単位に変換して確認したいときも一苦労でした。
こういった作業を効率化するために、VS Codeの拡張機能を開発することにしました。
実装の概要
この拡張機能は、Language Server Extension(言語サーバー拡張機能)として実装されています。
通常の拡張機能でも自動補完やホバー時のツールチップ表示を実装できるようですが、Language Serverを使うほうがパフォーマンス面などメリットが大きいとのことで、今回はそちらを採用しました。
Language Server Extensionとは
Language Server Extensionは、次の2つの要素で構成されています。
- Language Client
- Language Server
全体構成図
Language ClientはVS Code上で実行される通常の拡張機能です。
一方、Language ServerはVS Code本体とは別のプロセスで実行されます。別プロセスのため、言語解析などの重い処理が必要な場合でもVS Code自体のパフォーマンスを落とすことなく、様々な機能を提供できます。
Language ClientとLanguage ServerはJSONベースのLanguage Server Protocolを通じてコミュニケーションを取ります。(vscode-languageclient
とvscode-languageserver
を使えば、このプロトコルの細かい仕様を把握しなくても実装可能です)
今回実装した拡張機能の大まかな処理の流れは、次のようになります。
- Language ClientがLanguage Serverを別プロセスで起動し、待機させる
- Language Clientは自動補完やホバー時に表示するべきコンテンツを(カーソル位置や文書全体の情報とともに)Language Serverにリクエストする
- Language Serverはリクエストを受け取ると、自動補完の候補リストやツールチップに表示するコンテンツを生成し、Language Clientに返す
- それらのコンテンツがVS Code上に表示される
それでは、Language ClientとLanguage Serverの実装を軽くご紹介します。
Language Clientの実装
lsp-sample/clientとほぼ同じコードです。処理の対象がCSSファイルとSCSSファイルなのでここだけ変更しています。
const clientOptions: LanguageClientOptions = {
// CSSファイルとSCSSファイルを処理の対象とする
documentSelector: [
{ scheme: 'file', language: 'css' },
{ scheme: 'file', language: 'scss' },
],
};
Language Serverの実装
まず、初期化の中で、自動補完とホバーをサポートすることをLanguage Clientに伝えています。これによって、Language Clientからは自動補完とホバーのリクエストだけ飛ぶようになります。
connection.onInitialize(() => {
const result: InitializeResult = {
capabilities: {
textDocumentSync: TextDocumentSyncKind.Incremental,
// 自動補完をサポートすることをLanguage Clientに伝える
completionProvider: {
triggerCharacters: ['--'], // 自動補完のトリガーとなる文字
},
// ホバーをサポートすることをLanguage Clientに伝える
hoverProvider: true,
},
};
return result;
});
自動補完
@ubie/design-tokens
のJSファイルから自動補完の候補リストを生成しています。ユーザーが入力したCSSプロパティを見て、できるだけ利用可能なトークンだけを返しています。例えば、color
やbackground
、border
など色に関係するCSSプロパティを入力しているときは、color
系のトークンのみを返す、といった感じです。
ホバー
カーソルがデザイントークンのCSSカスタムプロパティの上にあるときだけ、その値を返すようにしています。
参考
実装はLanguage Server Extension Guideを読みながら進めました。また、次のコードが大変参考になりました。
開発してみた感想
Language Serverの仕組みと拡張機能のデバッグ方法を掴むのに少し学習コストが必要だったものの、全体の流れがわかってしまうと、今回のような機能実装はそれほど難しくありませんでした。ちょっとした社内向けの拡張機能であればわりと簡単に実装できそうなので、みなさんもぜひ試してみてください。
採用宣伝
Ubieではさまざまな職種のエンジニア・デザイナーを募集しています。まずはカジュアルにお話しましょう!
Discussion