WEBコンポーネントでデザインシステム構築した感想(Vite・Vue3)
はじめに
自社内で使いまわしできるデザインシステムをWEBコンポーネントで制作しました。
目的
- メンバー間の技術力に大きな偏りがある中で円滑に保守管理を行う
- 業務の効率化(共通のUI・UXをすぐに利用できる)
- 品質の保持(デザインの統一性やアクセシビリティの共通化など)
事情
なぜWEBコンポーネントという結論になったのかという点については、社内の独特するぎる事情が複雑にあるためここでは割愛させていただきます。
とにかく、この方法しかないという結論に至り決行しました。
技術
おもな開発環境
- Vite
- Vue.js 3系
- TypeScript
- Tailwind CSS
Vue.jsによるWEBコンポーネント書き出しについては以下に詳細なリファレンスがあります。
WEBコンポーネントの利用方法
- WEBコンポーネントの利用方法サイトを設置してそれを見ながら作業してもらう
- HTMLファイルに直接WEBコンポーネントを設置して利用してもらう
よかったところ
- 狙い通りデザインや機能などの品質が崩れにくい
- HTMLファイルのソースコードがすっきり見やすくなる
- 使い方に慣れると作業スピードが向上する
- コンパイルされたファイルの読み込みが意外と早い
こまったところ
コンポーネントごとの例外処理が多くなる
開発環境でTSを使っていても、コンパイルされたコンポーネントを利用する際には当然型チェックは働きません。
そのため、属性値などをとる場合には例外処理が必要になります。
グローバルな状態管理については工夫が必要
Vue.jsであれば通常Piniaなどでグローバルな変数を管理しますが、SPAではないためページ遷移の際にHTMLファイルを跨いでしまい状態が維持されません。
- 基本的にグローバルな値は利用しない
- ローカルストレージなどをうまく利用する
などの工夫が必要です。
Shadow tree(Shadow DOM)の扱いが難しい場面がある
例えばinputタグが内包されたWEBコンポーネントをformタグの中で利用しても、inputタグの値は取得できません。
これはVue.jsでWEBコンポーネントを作る際にはシャドーツリーが強制されるためです。
シャドーツリーの内容はルートのドムツリー(ライトツリーと呼ばれることも)からは見ることはできません。
<templeate>
<div>
<input type="text" name="text" id="text" required />
</div>
</templeate>
<form action="" method="post">
<!-- ↓このコンポーネントの値は取得できない -->
<my-input-text />
<input type="submit" value="送信" />
</form>
このほかにもtableタグをWEBコンポーネントにしてしまうと、その中に<tr><td>などをSlotで渡してもテーブルの要素として認識してくれないことや、グーグルタグマネージャーでイベントを取得できないなど問題は盛りだくさんです。
<my-table>
<!-- ↓my-tableの内部でテーブルタグを使っていても囲まれていない扱いにされてしまう -->
<tr><th>タイトル</th><td>要素</td><td>要素</td></tr>
<tr><th>タイトル</th><td>要素</td><td>要素</td></tr>
<tr><th>タイトル</th><td>要素</td><td>要素</td></tr>
</my-table>
まとめ
当社ではおおむね満足していますが、当社の事情が特殊すぎて他の企業ではあまりおすすめできないです。
せっかく、モダンな開発環境で開発しても結局そのコンポーネントは無秩序な環境で利用されるわけですから。
また、シャドーツリーでの独立性が強すぎてコンポーネント同士の連携が難しいのも難点です。
Discussion