Merpay Tech Fest 2022 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2022年8月23日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。
この記事は、「Tools and Strategies for Frontend UI Libraries」の書き起こしです。
本日はメルペイのフロントエンドUIライブラリを構築するために、私たちが使っている戦略とツールについてお話します。
Merpay Frontend teamのMarco Solazziです。
今日のトピックに入る前に、Frontend開発のこれまでについてお話いたします。
2010年当時、Internet Explorerをクラッシュさせないよう、適切な機能を持つカルーセルのプラグインを見つけることがFrontend開発者にとって最大の課題でした。それから数年が経ち、開発者がシングルページアプリケーションを構築するための最適なFrontendフレームワークを探しています。
参考資料:http://creativecan.com/2013/04/jquery-slider/
今日、開発者はコンポーネントライブラリの構築という、共通の課題に直面しています。
参考資料:https://todomvc.com/
これまでと同じようにさまざまな解決策や使用できるツールがありますが、メルペイではどのようにスタックを定義したかをご紹介します。
さて、はじめる前にまずお断りしなければならないことがあります。メルペイのコンポーネントライブラリは内部ツールのみで使用されているため、スクリーンショットやコードサンプルをお見せすることができません。
しかし、このプレゼンテーションはコンポーネントの構築に関するものではありません。先ほども申し上げたように、舞台裏や戦略やツールについての話が中心です。そのため、スクリーンショットやコードサンプルをお見せできないことは、大きな問題にはならないかと思います。
コンポーネントライブラリを構築するうえで重要なポイントは一つ。
自分が何をしているのかを知ること、です。これはあらゆる開発において言えることだと思います。自分が何をしているのかを知るためには、まず自分のミッションを明確にする必要があります。つまり、「何を実現したいのか」ということです。
私たちの場合は、開発者が惚れ込むようなコンポーネントライブラリを作ることがミッションです。もし開発者がライブラリを気に入れば、そこに新しい機能を作りたいと考えるでしょう。また、多少のバグがあっても大目に見てくれるかもしれません。
一方で、ライブラリを使いにくいと感じさせてしまったら、開発者は独自のコンポーネントを作ってしまい、あなたの努力は無駄になるかもしれません。
まずミッションを定義したら、次はそれをゴールに変換し、より具体化していきます。
私たちのゴールはシンプルなDXと、一貫したデザインのユーザーエクスペリエンスを持つ、共有可能なVue.jsコンポーネントの組織的なセットを作成することです。
なぜシンプルなデザイン、UXというキーワードが、愛されるコンポーネントライブラリを作るために重要なのかを見ていきましょう。
まず、Organaized。
整理されたライブラリはナビゲーションがしやすいため、ブラウジングもしやすくなります。
この領域には、コンポーネント、プロップ、属性の命名規則といったトピックが含まれますが、ここではツールについて話していきます。
ある特定の側面に焦点を当てていきます。
これはコンポーネントレイヤーの定義です。基本的にはコンポーネントを層に分類したいと考えています。
さて、3つのレイヤーに定義していきます。Coreはデザイントークンやスペーシングを含めることができる層です。また、ボタンやテーブル、ダイアログなど基本的なインタラクションもコアに含めます。
2つ目のレイヤーでは、入力や選択といったフォームコンポーネント、プリミティブやグリッドなどのレイアウトコンポーネント、またはトップバーやナビゲーション、コンテナなどのレイアウトブロックなど、より専門的なコンポーネントを含みます。
3つ目のレイヤーはプロジェクトに関するレイヤーです。エンドユーザー定義に関連するレイヤーとなります。このレイヤーでは通常、開発者は前のレイヤーに含まれていない特定のコンポーネントを含めます。
私たちのコンポーネントライブラリは最初の2つのレイヤーに焦点を当て、コア、フォーム、レイアウトという3つの明確なパッケージを定義しています。一度定義すると、コンポーネントを整理する際に、コンポーネントライブラリの土台も定義することができます。
私たちの場合は、モノレポ構造を採用することにしました。パッケージマネージャーには高速で効率的なメモリ管理ができ、ワークスペースにも対応しているpnpmを採用。そして、タスクランナーとしてTurborepoを選択しています。
Turborepoには多くの利点があります。キャッシュビルドをサポートし、単一の設定ファイルで明確なタスクの依存関係グラフをサポートします。また、単一の実行ファイルであるため、node_modulesフォルダーのサイズを小さくできます。
パブリッシュにはLernaを選択しました。Changesetsという選択肢もありましたが、Lernaが私たちのワークフローに合っていたからです。
ワークフローは従来のコミットをベースにしていますが、Lernaはパッケージの新しいバージョンを決定するようなワークフローをサポートしており、独立したバージョンニングもサポート可能です。
さて、最後はCIです。CIにはGitHub Actionsを選択しました。GitHub Actionsは設定が簡単です。GitHubを利用しているため、現在のインフラとの連携が非常にうまくいきます。また、このセットアップを使用することで、既存のセットアップと比較してビルドプロセスにいくつかの改善が見られました。
最初はスタート地点として、npmとLernaを使ったCircleCIから始め、CIに要する時間は14分でした。そこからpnpmとTurborepoに切り替えると、CIは6.5分となり、大きな改善が見られました。その後、GitHub Actionsに切り替えたら、CIが8分程度に増えてしまいました。
しかし、これはワークフローの設定を見直すことで改善できるのではないかと思っています。結局のところ、GitHub Actionsがセットアップも開発者のエクスペリエンスもスムーズなため、CIに要する時間が少し増えたのも許容できる範囲内となっています。
では2つ目のキーワード、Developer experienceに移りましょう。
開発者エクスペリエンスという概念は、ユーザーエクスペリエンスと非常に似ています。
全ての開発者に最適なワークフローをそれぞれ個別に設計することはできないので、カバーしたい主なユースケースのみを定義します。
このユースケースを定義するために、3つの主要な領域を明確化しました。
1つ目は、モジュールの種類、つまりどのJavaScriptモジュールをサポートするかです。私たちは、ESMをデフォルトでサポートし、必要な場合はCommonJSにフォールバックすることにしています。
2つ目はBundlersです。私たちはVue.js環境で作業しているため、Vue CLI、つまりwebpackをサポートすることにしました。
3つ目はFrameworksです。私たちのフレームワークはNuxt.jsです。
これで、ユースケースの定義ができました。
次に、提供する必要のある成果物、アーティファクトをリストアップします。
まず、Vue.jsのプラグインとしてインストール可能なパッケージが必要です。またこのパッケージは、Nuxt.js moduleとして構成できるようにしたいと考えています。
また、コンポーネントはVue.jsの単一ファイルコンポーネントモジュールとして公開したいと思います。これにはいくつかの理由があります。まず、Vue CLIは、ロードモジュールパッケージを使っています。このように、一つのファイルのコンポーネントはエンドユーザーの設定に基づいてコンパイルされます。これにより、異なる設定、異なるブラウザのバージョンをサポートすることが可能です。
最後のポイントは、ユーザーにTypeScriptを使うことを強制しなくても、TypeScriptの宣言ファイルを一緒に入れることです。この要件が満たされれば、いよいよビルドツールを選択することができます。
今回はunbuildを選択しましたが、unbuildには多くのメリットがあります。
これはNuxt.jsチームが開発したパッケージです。一つのビルドツールで、非常にシンプルなセットアップとビルドモードの機能を備えています。最初のものはBundle buildです。Rollupとesbuildで強化されています。
このモードでは、Bundlersは単一のBundleファイルを出力します。我々はこのモードを使用して、Vue.jsのプラグインをBundleします。さらにNuxtモジュールもBundleすると、TypeScript宣言を抽出できます。
次に2つ目のBundle-less buildというビルドモードです。これはNuxt.jsチームによって開発されたmkdistというツールを使っています。Vue.jsの単一ファイルコンポーネントモジュールをトランスパイルし、モジュールからTypeScript宣言を取り除き、個々のコンポーネントのTypeScript宣言とすることができます。
これはVue.jsのライブラリにとって非常に良いソリューションです。しかし、他の種類のスタックにも素晴らしい代替手段はあります。
2つ例があります。TSDXは全般的なツールです。モノレポをサポートしており、またテストとリンティングの機能を統合しています。
そしてもう1つはmicrobundleです。最適化されたRollupの設定を含んでいて、例としてPreactをBundleするために使われています。アウトオブボックスで、ESM、TypeScript、JSXをサポートしています。
さて、ここまではビルドツールをカバーしてきました。では、documentationについてはどうでしょうか。
優れた開発者体験には、documentationも重要ですね。
私たちの場合はdocumentationの強化にStorybookを使っています。
Storybookにはいくつかの重要なメリットがあります。まず、開発者の開発環境として使い、コンポーネントを作成、そして分離してビルドすることも可能です。
また、コンポーネントのvariantsをドキュメント化するのも簡単ですし、markdownのdocumentation supportが組み込まれているのも魅力のひとつですね。
一方で、キャンパスにテーマ性を持たせたい場合、カスタマイズが難しいことがあります。また、ビルド時の初回起動が遅いことがありました。
このようにStorybookは、好き嫌いがわかれるツールです。もちろん、Vue.jsで使える優れた代替ツールはいくつもあります。
Histoireを使ったり、Vue Styleguidistを使ったりすることができます。もしスタックがReactをベースにしているのであれば、React StyleguidistやLadleを使うこともできますね。VitebookはViteで強化されたStorybookの一種でフレームワークを問いません。
開発環境に合わない場合は、documentationだけのツールを選択することができます。
ツールはたくさんありますが、特に人気のあるものはReact製のDocusaurusでしょう。また、VuePressやVitePressもあります。これらはVue環境にとても適しています。他にも新しいプロジェクトのMarkdocがあります。ストライプのチームが公開用のドキュメントのために開発したものです。
さて、最後のキーワードに入ってきます。DesignとUXです。
優れたUXを実現するには、一貫性とユーザビリティを高い水準で維持することが重要です。一貫性とユーザビリティは、3つの重要な分野に焦点を当てることで達成できます。
1つ目はComponent testingです。Component testingは、バグやリグレッションを防ぐためにとても重要です。私たちの現在の設定ではJestを使っていますが、他のオプションも模索中です。例えばVitest。これはVite上で開発、構築されたJestのバージョンで、現時点ではVueエコシステムのデフォルトオプションになっています。またCypressのComponent testingも検討しています。
2つ目はAccessibility監査です。ここでは、自動アクセシビリティ監査のことを指します。この種の監査は、たとえ限られた割合の問題しかカバーしていないとしても、基本的なCIチェックや最低限のAccessibilityを担保するために利用することが望ましいです。
私たちの現在のワークフローは、Storybookに作ったストーリーを再利用し、Cypress CT環境にロード・レンダリング、そしてAxeというツールを実行して、レンダリングされたコンポーネントのAccessibility監査を実行します。
このワークフローの良いところは、基本的にストーリーを再利用しているので他のテストファイルが必要ないことです。またCypress CTを使用することによって、実際のブラウザでコンポーネントをレンダリングし、色やコントラストなどのチェックも可能になります。
3つ目は、Visual regression testingです。これはUIの見栄えを良くし、何かを壊さないことを保証するために非常に重要です。現在の設定にはREG SUITを使っています。このツールの利点は、セルフホスティングであることです。非常に柔軟性があり、基本的にどこでもホスティングできます。
セルフホスティングなのでデメリットもあります。特に重大なデメリットは、全てのワークフローを設定するのに時間がかかるかもしれないことです。
もっとシンプルに設定したいのであれば、他にもオプションがあります。最初に紹介するオプションはchromaticです。これはStorybookチームによって作成されたツールです。
次はpercyです。これはVisual regression testingには優れたツールで、Storybookベースとなっています。最近BrowserStackに買収されたため、BrowserStackを使う用意があったり、使いたかったりする場合はpercyがおすすめです。
まとめです。
冒頭で述べたように、コンポーネントライブラリの構築には「愛」が必要です。そして明確な戦略を持つこと。それが、他の開発者が使いたくなるコンポーネントライブラリを作るため、正しいツールを選択する鍵となります。
以上です。ご清聴ありがとうございました。