SW/Typescript

[Typescript] Zod에서 Superstruct로의 전환기

BetaMan 2024. 2. 21. 10:53
728x90
반응형
[Typescript] Zod에서 Superstruct로의 전환기

서론

이번 포스팅에선, 필자가 CHINGOO.BE 프로젝트(GitHub repo.)를 진행하면서 여러가지 최적화들을 시도하다가 번들 사이즈 관련 최적화의 일환으로 기존 프로젝트에서 사용중이던 zod 라이브러리를 superstruct로 전환하게 된 과정을 소개한다.

Zod를 다른 라이브러리로 전환하려는 이유

Zod에서 다른 라이브러리로의 전환을 통해 달성하려던 목표는 "번들 사이즈" 절감이었다.

CHINGOO.BE 프로젝트의 client 측 번들 그래프

CHINGOO.BE는 Next.js 기반의 프로젝트라서 next-bundle-analyzer를 돌려보았었다. 여러가지 눈에 띄는 큼직큼직한 패키지들이 보인다. react-dom에나 next관련 패키지는 대체 가능한 패키지가 없으니 건너뛰고, 그 다음으로 가장 눈에 띄는 패키지는 위 이미지에서 빨간 박스가 쳐진 Zod 패키지였다.

next-bundle-analyzer 분석 결과 내 Zod의 번들 사이즈

Zod가 제공하는 기능이 많긴하지만... validation 하나를 위해서 혼자 12.37kB를 차지하고 있었다... next.config.js에서 optimizePackageImports를 Zod에 적용했음에도 불구하고, react-hook-form와 hookform/resolver를 합친것보다 보다 Zod의 번들 사이즈가 더 컸다.
그래서 validation 라이브러리는 다양한 종류가 있으니, 좀 더 번들 사이즈가 작고 zod를 통해 이용중이던 기능들을 모두 제공하는 라이브러리를 찾아보게 되었다.
optimizePackageImports에 대한 참고자료: 

[Typescript] optimizePackageImports 옵션으로 Next.js 번들 사이즈 줄이기 (modularizeImports 대체재)

서론 이번 포스팅에선 Next.js에서 번들 사이즈 최적화를 위해 제공하는 optimizePackageImports 옵션을 소개해보려고 한다. 점점 날이 갈수록 뚱뚱해지는 우리의 Next.js 프로젝트를 다이어트 시켜보자. o

blog.betaman.kr

Zod보다 번들 사이즈가 작은 라이브러리 찾기

Zod보다 번들 사이즈가 작으면서 비슷한 기능을 제공하는 라이브러리를 찾기 위해 BundlePhobia를 이용했다.
zod를 검색해보니 Zod와 비슷한 여러 라이브러리들의 리스트가 나타났다.
그 중, Zod보다 무려 74% 작다는 Superstruct가 있었다.

Zod와 유사한 라이브러리 리스트

Zod의 용량과 Superstruct의 용량을 비교해보니
Zod: 13.2kB, Superstruct: 3.4kB 로, 9.8kB 더 작았다. 그래서 필자는 Superstruct를 이용해 Zod를 대체할 수 있는지 검토를 시작했다.

Zod와 Superstruct의 번들 사이즈 비교

Superstruct, 과연 쓸만한가?

필자가 그동안 많고 많은 Validation 라이브러리들 중, Zod를 이용했던 이유는 다음과 같다.

필자가 Zod를 대체하기 위해선 위 4가지 요소가 충족되어야 하고, 다행히도 대부분 Superstruct는 충족하는 것으로 확인되었다.
다만, 문제가 하나 있었던 것이 Invalid 타입별 오류 메시지 지정이 간편한 점이었다. 기본적으로 Superstruct는 오류 메시지 커스텀이 불가능한 점이 문제가 되었다.
하지만 이 또한 해결책은 있었고, 이를 위한 해결법은 아래 포스팅으로 남겨두었다.
그리고 Zod에 비해 조금 아쉬운 점이 하나 더 있었다면, 비동기를 지원하지 않는다는 것이었다.
하지만 필자는 validation에서 비동기를 이용할 일이 없어서 이 사실이 큰 문제가 되진 않을 것으로 예상했다.
일단 Zod로의 전환 가능성은 확인이 완료됐다.

[Typescript] superstruct 오류메시지 커스텀하기

서론 최근 필자는 supersturct를 사용해보다가 superstruct는 기본적으로 오류메시지를 커스텀할 수 없다는 점을 알게됐다. 이는, 개발자가 임의로 오류메시지를 수정하여 부정확한 validation 결과를 내

blog.betaman.kr

Zod를 Superstruct로 전환하기

Zod와 Superstruct의 Validation Schema

Zod와 Superstruct의 validation schema를 선언하는 방식이 조금 모양이 다르긴하지만... 사실 크게 다르진 않다.
Superstruct를 사용하기 전에 확인해야할 프로젝트 세팅이 있다.
tsconfig.json에서 strict나 strictNullChecks 옵션이 true로 지정되어있는지 확인해야한다. Superstruct의 optional 함수를 엄격하게 이용하기 위해선 해당 옵션이 활성화 되어야 한다.

Zod는 method chaining을 제공하지만, Superstruct는 이를 제공하진 않는다. 그래서 Zod의 schema와 Superstruct의 schema를 비교하면 다음과 같다.

예제에서 사용된 message 함수는 Superstruct에서 공식적으로 제공하는 함수는 아니다. 이 함수에 대한 정보는 이전 포스팅을 참고하길 바란다.
Zod에서 parse 메서드에 해당하는 함수로 Superstruct는 assert와 validate 함수를 제공한다.
다만 조금 차이점이 있다면, 기존 parse 메서드의 기능을 반반(?) 쪼게서 assert와 validate 함수가 기능을 제공하는게 차이점이다.
assert 함수는 첫번째 인자로 전달된 value값이 두번째 인자로 전달된 schema에 충족하는지 검사하고, 충족하지 않을 경우 Throw를 하는 함수이다. 단, 별도의 return 값은 반환하지 않는다.
validate 함수는 assert와 달리 배열을 반환하는 함수이다. 반환되는 배열의 첫번째 요소는 isInvalid로, 값 검증을 실패했을때 true가 되는 값이다. 그리고 두번째 요소가 validate된 결과값으로, 값 검증을 성공했을때 검증된 값을 넘겨주며 실패했을땐 undefined가 된다. 첫번째 인자로 전달된 value값이 두번째 인자로 전달된 schema에 충족하는지 검사하지만, 충족하지 않을 경우 Throw 대신 return 배열값의 첫번째 인자를 false로 반환한다는 점이 assert와 차이가 있다.

Superstruct와 react-hook-form의 연동

다행히 react-hook-form에서 @hookform/resolvers를 통해 공식적으로 Superstruct의 resolver를 지원하고 있다. Zod를 통해 사용했던 방법과 큰 차이는 없다.

resolver만 @hookform/resolvers/supersturct의 superstructResolver로 교체해주면 바로 Zod+react-hook-form과 동일하게 이용 가능하다.

Superstruct로의 전환 결과

CHINGOO.BE 프로젝트 내 모든 Zod 관련 코드를 Superstruct로 마이그레이션 했다. 다행히 미리 검토했던대로 기능 상 차이점은 발생하지 않았다.

CHINGOO.BE 빌드 결과(좌: Zod 버전, 우: Superstruct 버전)

빌드를 해보니 Zod를 사용하던 기존 페이지들의 용량이 13kB씩 절감되었다.

CHINGOO.BE next-bundle-analyzer 분석 결과(좌: Zod 버전, 우: Superstruct 버전)

번들 분석 결과를 보아도, 왼쪽 이미지에 큼지막하게 있던 Zod가 사라진 모습도 확인할 수 있다.

CHINGOO.BE next-bundle-analyzer 분석 결과 내 Zod 와 Superstruct 번들 사이즈 차이

개별적인 Zod와 Superstruct의 용량을 비교해보아도
Zod는 Gzip된 용량이 12.37kB였던 반면, Superstruct는 1.8kB이다.

728x90
반응형