2023年7月30日 • ☕️ 5 min read

Valibotが最近Builder.io(Qwik)の紹介で話題に上がっているスキーマベースのバリデーションライブラリとなります。

We ♥️ Open Source.

Happy to feature @FabianHiller on our blog with this introduction to his new library, Valibot! https://t.co/WZl6rjJgWK

— Builder.io (@builderio) July 25, 2023

一番注目されているのはバンドルサイズの部分だと思います。Zodと比較すると、98%のバンドルサイズの削減ができると言われています。さらに、モジュール化されていて、非常にtree-shakingしやすく、確かにバンドルサイズが大幅に減少できるでしょう。

早速使ってみた感想をシェアしようと思います。

メリット:拡張しやすいアーキテクチャ

非常にわかりやすい構造になっており、ソースコードが読みやすいです。そして、モジュール化やピュア関数化が行われているため、非常にテストしやすくなっています。驚くべきことに、テストのカバレッジはなんと100%となっています。

構造がシンプルのため、非常に拡張しやすいです。例えば、日本の郵便番号をチェックするバリデータを簡単に作成できます。

postCode.ts
Copy
import { ValiError } from 'valibot';

import type { ValidateInfo } from 'valibot';

// xxx-xxxx
const postCodeWithHyphenReg = /^\d{3}-\d{4}$/;
// xxxxxxx
const postCodeWithoutHyphenReg = /^\d{7}$/;

/**
 * Creates a validation function that validates a post code in Japan.
 * 100-9999 or 1009999
 * @param hyphened
 * @param error
 * @returns
 */
export function postCode<TInput extends string>(
  hyphened = false,
  error?: string,
) {
  return (input: TInput, info: ValidateInfo) => {
    if (
      (hyphened && !postCodeWithHyphenReg.test(input)) ||
      (!hyphened && !postCodeWithoutHyphenReg.test(input))
    ) {
      throw new ValiError([
        {
          validation: postCode.name,
          origin: 'value',
          message: error || 'Invalid post code',
          input,
          ...info,
        },
      ]);
    }
    return input;
  };
}

デフォルトのものと同じように使えます。

Copy
const personalInfoSchema = object({
  firstName: string(),
  lastName: string(),
  postCode: string([postCode()]),
});

もちろん、Zodのrefineを使えば、バリデーションのカスタマイズもできますが、Valibotほどテストしやすくないでしょう。

postCode-zod.ts
Copy
import { z } from 'zod';

export const zPostCode = (hyphened = false) =>
  z
    .string()
    .refine(
      (value) =>
        (hyphened && postCodeWithHyphenReg.test(value)) ||
        (!hyphened && postCodeWithoutHyphenReg.test(value)),
      {
        message: 'Invalid post code',
      },
    );

Valibotを基礎として、信頼性の高い拡張ライブラリを簡単に作成できることは、Valibotの最大の魅力の1つだと思います。さらに、拡張ライブラリを使用してもtree-shakingが効果的に行われるため、バンドルサイズが増えることがありません。本当に素晴らしい特徴ですね。

デメリット:多言語対応

これはValibotの問題より、モジュール化(ピュア関数化)の特性として考えられるかもしれません。Valibotを見た瞬間、これが好きだと思いました。このライブラリはdate-fnsを思い起こさせます。Moment.jsの代替としてのdate-fnsは同じピュア関数の塊で、もう1つの代替であるdayjsと競合していると思われます。dayjsがtree-shakingに向いていない一方、言語の切り替えが容易です。一方、date-fnsがtree-shakingに向いているが、言語の設定が難しいです。

同じように、ZodsetErrorMapを通して、デフォルトのエラーメッセージを簡単に上書きできる一方、Valibotが各バリデータに直接エラーメッセージを渡さなければいけないのです。

Valibotにもグローバルのメッセージを導入できる可能性はありますが、この部分のtree-shakingは難しいと感じることがあるかもしれません。実際に、ピュア関数がグローバルな要素を参照するのは少し奇妙に感じます。通常、ピュア関数は引数に依存し、外部の状態を変更しないように設計されますが、グローバルなメッセージを参照する場合はこの原則が崩れる可能性があります。そのため、この点を考慮して設計を検討することが重要です。適切な設計することで、tree-shakingを有効に活用しつつ、グローバルなメッセージを導入する方法を見つけることができるかもしれません。

完了

Zodと比べると、Valibotが一長一短です。英語圏ではかなり有力な代替候補者となりますが、多言語対応ができるまで、日本語圏では厳しいかもしれません。極端なパフォーマンスを求められるウェブアプリが少ないからなのです。Valibotの成長を見守っていきましょう。

興味があれば試してみたらいかがでしょうか。では。

https://github.com/fabian-hiller/valibot/


ThunderMiracle

Blog part of ThunderMiracle.com