JavaScript

266 posts
TanStack Markdown과 Highlight

TanStack Markdown과 Highlight

문서 사이트를 만들다 보면 이상한 순간이 옵니다. 정작 보여주려는 건 글자 몇 천 개인데, 그걸 그리려고 내려받는 자바스크립트가 1MB를 넘어가는 거죠. 😅 TanStack 팀이 딱 이 상황이었습니다. tanstack.com의 문서 페이지 하나가 스크립트만 약 1.1MiB를 전송하고 있었는데, 그중 358KiB 정도가 오직 코드 구문 강조에 쓰이고 있었어요. 이걸 React Server Components로 감추는 대신, 팀은 도구 자체를 작게 만드는 쪽을 택했습니다. 그렇게 나온 게 TanStack Markdown과 TanSta

Discord 게이트웨이로 실시간 이벤트 받기

Discord 게이트웨이로 실시간 이벤트 받기

봇 개발을 하다 보면 결국 마주치는 통로가 **게이트웨이(Gateway)**입니다. 슬래시 커맨드를 만들 때 client.login() 한 줄로 봇을 온라인으로 띄웠는데, 그 순간 봇은 바로 이 게이트웨이로 디스코드와 연결을 맺은 거였어요. 이번 글에서는 그 통로의 안쪽을 들여다보며, 봇이 어떻게 서버의 모든 일을 실시간으로 지켜보는지, 그리고 그렇게 만든 봇을 어떻게 24시간 운영하는지까지 살펴봅니다. 게이트웨이는 항상 열려 있는 WebSocket REST API가 "내가 물어보면 답해주는" 요청-응답 방식이었다면, 게이트웨이는

실시간 단방향 통신을 위한 Server-Sent Events(SSE)

실시간 단방향 통신을 위한 Server-Sent Events(SSE)

ChatGPT에게 질문을 던지면 답변이 한 글자씩 타이핑되듯 흘러나오는 모습, 다들 익숙하시죠? 증권 앱의 시세가 새로고침 없이 실시간으로 바뀌거나, 웹 대시보드에 알림이 띵 하고 도착하는 것도 마찬가지인데요. 이런 화면들의 공통점은 서버에서 새로운 데이터가 생길 때마다 클라이언트가 곧바로 받아본다는 것입니다. 실시간 양방향 통신을 위한 웹소켓(WebSocket) 글에서 우리는 HTTP의 한계와 이를 극복하는 웹소켓을 살펴봤는데요. 그런데 위 예시를 가만히 보면 한 가지 공통점이 더 있습니다. 데이터가 서버에서 클라이언트로 한 방향

Satteri: Rust로 파싱하고 JavaScript로 확장하는 마크다운 처리기

Satteri: Rust로 파싱하고 JavaScript로 확장하는 마크다운 처리기

블로그나 문서 사이트를 운영하다 보면 빌드 시간이 슬금슬금 늘어나는 순간이 옵니다. 글이 수백 개를 넘어가면 마크다운 파싱과 변환에만 수십 초가 쓰이고, 거기에 remark/rehype 플러그인을 몇 개 더 끼우면 1분을 훌쩍 넘기는 경우도 흔하죠. 저도 이 블로그를 운영하면서 빌드 로그를 보다가 "마크다운 처리에 이만큼 시간을 쓴다고?"라는 생각을 한두 번 해본 게 아닌데요 😅 최근 Astro 6.4에서 markdown.processor API가 새로 등장하면서, unified 생태계가 아닌 다른 마크다운 처리기로 갈아탈 수 있

Web Crypto API로 브라우저에서 암호화 다루기

Web Crypto API로 브라우저에서 암호화 다루기

자바스크립트로 무언가를 만들다 보면 의외로 자주 마주치는 순간이 있습니다. 세션 토큰을 만들거나, 비밀번호를 해시하거나, 파일 무결성을 검증하거나, 쿠키에 서명을 넣어야 할 때인데요. 예전 같으면 별도의 라이브러리를 깔아야 했지만, 요즘은 브라우저와 서버 런타임 모두 이런 일을 표준 API로 해낼 수 있습니다. 바로 Web Crypto API입니다. 이 글에서 Web Crypto API의 사용법을 먼저 다루지만, 그 뒤에 깔린 대칭키와 비대칭키 암호화의 원리가 궁금하다면 별도 글에서 따로 풀어 두었습니다. 이름만 들으면 브라우저 전

Rolldown, Rust로 다시 쓴 Rollup 알아보기

Rolldown, Rust로 다시 쓴 Rollup 알아보기

Rollup은 이미 잘 만들어진 번들러인데, 왜 갑자기 이름이 비슷한 Rolldown이라는 도구가 등장했을까요? 🤔 게다가 Vite는 8 버전부터 오랫동안 써 온 Rollup을 두고 이 Rolldown을 기본 번들러로 채택했습니다. 멀쩡히 돌아가던 도구를 갈아엎은 데는 그만한 이유가 있겠죠. 최근 JavaScript 도구들이 하나둘 Rust로 다시 작성되는 흐름 위에 Rolldown도 놓여 있습니다. SWC가 Babel을, Oxc가 ESLint를 겨냥했다면, Rolldown은 Rollup의 자리를 노립니다. 이번 글에서는 Roll

Void: Vite 네이티브 배포 플랫폼

Void: Vite 네이티브 배포 플랫폼

Vite+가 로컬 개발 도구를 하나로 통합했다면, 이번에는 배포까지 먹으러 왔습니다. VoidZero가 내놓은 Void는 Vite 앱에 플러그인 하나를 추가하고 void deploy 한 방이면 데이터베이스, 인증, KV 스토리지, 큐까지 갖춘 풀스택 애플리케이션이 Cloudflare Workers 위에 올라가는 배포 플랫폼입니다. "자바스크립트에 드디어 Rails 순간이 온 건가, 아니면 그냥 Cloudflare 종속에 리본을 달아놓은 건가?" 궁금해서 Void가 뭘 하는 건지 직접 파헤쳐봤습니다. Vite+와 Void의 관계 먼저

Vite+로 웹 개발 도구 통합하기

Vite+로 웹 개발 도구 통합하기

웹 프론트엔드 프로젝트 하나를 제대로 셋업하려면 도구가 정말 많이 필요하죠. 번들러는 Vite, 테스트 러너는 Vitest, 린터는 ESLint, 포맷터는 Prettier... 거기에 Node.js 버전 관리자랑 패키지 매니저까지 더하면 package.json의 devDependencies가 금세 길어지고 설정 파일도 여기저기 흩어집니다. 2026년 3월, Vite의 창시자 Evan You가 이끄는 VoidZero가 이 문제에 대한 답을 내놓았는데요. Vite+ — Vite, Vitest, Oxlint, Oxfmt, Rolldown

Oxc로 자바스크립트 린팅과 포맷팅을 압도적으로 빠르게

Oxc로 자바스크립트 린팅과 포맷팅을 압도적으로 빠르게

자바스크립트 프로젝트를 하나 세팅하려면 설치해야 할 도구가 한두 개가 아닙니다. 코드 린팅에는 ESLint, 포맷팅에는 Prettier, 트랜스파일링에는 Babel이나 SWC, 번들링에는 Webpack이나 Vite... 각각 다른 팀이 다른 언어로 만든 도구들을 조합해서 쓰다 보니 설정 파일만 여러 개, 플러그인 간 버전 충돌에 빌드 속도는 답답하고. 😩 이 파편화된 자바스크립트 도구 생태계를 하나로 통합하겠다는 프로젝트가 있는데요, 바로 Oxc입니다. 이번 포스팅에서는 Oxc가 무엇이고, 어떤 도구들로 구성되어 있으며, 실제 프

Sharp로 자바스크립트에서 이미지 처리하기

Sharp로 자바스크립트에서 이미지 처리하기

웹 서비스를 운영하다 보면 이미지를 다뤄야 하는 일이 참 많은데요. 사용자가 올린 프로필 사진을 썸네일로 줄이거나, 상품 이미지를 WebP로 변환하거나, 여러 이미지를 하나로 합쳐야 할 때가 있죠. 이런 작업을 브라우저가 아닌 서버 쪽에서 처리하려면 어떻게 해야 할까요? Sharp는 Node.js에서 가장 널리 쓰이는 이미지 처리 라이브러리입니다. 내부적으로 C 기반의 libvips 엔진을 사용하기 때문에 ImageMagick보다 4~5배 빠르고, 메모리 사용량도 적습니다. JPEG, PNG, WebP, AVIF, GIF, TIFF

Cloudflare Workers AI로 서버리스 AI 추론하기

Cloudflare Workers AI로 서버리스 AI 추론하기

AI 기능을 서비스에 넣으려면 OpenAI API 키를 발급받고 서버를 세팅하고 요청을 중계하는 백엔드까지 구성해야 하잖아요. 이 과정이 꽤 번거롭고 GPU 인프라를 직접 관리하는 건 비용도 만만치 않습니다 😅 Cloudflare Workers AI를 쓰면 별도의 GPU 인프라 없이 전 세계 엣지에서 AI 모델을 바로 실행할 수 있습니다. Cloudflare Workers에 코드 몇 줄만 추가하면 텍스트 생성, 이미지 생성, 번역, 음성 인식 같은 AI 기능을 서버리스로 제공할 수 있어요. 이번 글에서는 Workers AI의 기본

agent-browser: AI 에이전트를 위한 브라우저 자동화 CLI

agent-browser: AI 에이전트를 위한 브라우저 자동화 CLI

AI 에이전트에게 브라우저를 맡기는 시대가 점점 현실이 되고 있습니다. 이전에 Playwright MCP를 소개하면서 AI 에이전트가 MCP 서버를 통해 브라우저를 조작하는 방법을 다뤘는데요. 이번에는 좀 다른 접근 방식을 가져온 도구를 살펴보려고 합니다. Vercel Labs에서 만든 agent-browser는 AI 에이전트가 쉘 명령어만으로 브라우저를 제어할 수 있게 해주는 CLI 도구입니다. MCP 프로토콜이나 프로그래밍 언어에 종속되지 않고 터미널에서 바로 agent-browser open example.com처럼 실행할 수

자바스크립트 Temporal API 사용법

자바스크립트 Temporal API 사용법

자바스크립트로 날짜를 다뤄본 분이라면 한 번쯤은 Date 객체에 좌절해본 경험이 있을 텐데요. 월(month)이 0부터 시작하는 건 왜 그런 건지, 시간대 변환은 왜 이리 복잡한 건지, setDate()를 호출했더니 원본 객체가 변해버리는 건 또 뭔지... 🤦 그래서 moment.js나 date-fns, Day.js 같은 외부 라이브러리 없이는 날짜를 제대로 다루기 어려웠죠. 그런데 드디어 자바스크립트에 Temporal이라는 새로운 날짜/시간 API가 등장했습니다! State of JS 설문에서 "가장 기대하는 새 기능" 1위를

Biome: 포맷팅과 린팅을 하나로 통합하기

Biome: 포맷팅과 린팅을 하나로 통합하기

자바스크립트 프로젝트를 세팅하다 보면 ESLint 설정하고, Prettier 설정하고, 둘이 충돌하지 않게 연동하고... 이런 과정이 꽤 번거롭죠? 거기에 Stylelint까지 더하면 설정 파일만 서너 개가 됩니다. 🤯 이런 불편함을 해결하려는 도구가 바로 Biome입니다. 포맷터와 린터를 하나의 도구로 합쳐서, 설정도 간단하고 속도도 빠른 올인원 웹 개발 도구를 표방하고 있는데요. 이번 글에서는 Biome이 어떤 도구인지, 어떻게 설치하고 사용하는지, 기존의 ESLint/Prettier와 비교하면 어떤 차이가 있는지 살펴보겠습니

State of JS 2025 설문 결과

State of JS 2025 설문 결과

매년 자바스크립트 개발자라면 한 번쯤 챙겨보게 되는 설문이 있는데요. 바로 State of JS입니다. 올해도 어김없이 결과가 공개됐고, 저는 이번에도 처음부터 끝까지 꼼꼼히 살펴봤습니다. 이 글에서는 설문 결과 중 지극히 개인적인 관점에서 흥미롭게 본 부분들을 골라서 제 나름의 방식으로 해석하여 공유드리겠습니다. 달레줄레 팟캐스트에서 State of JS 2025 설문 결과에 대한 에피소드도 올라왔으니 한번 들어보시면 재미있을 겁니다 😄 새 기능, 얼마나 쓰고 있나요? State of JS 설문에는 자바스크립트에 새로 추가된 기

Discord 권한과 역할 이해하기

Discord 권한과 역할 이해하기

버튼으로 "삭제" 같은 UI를 만들다 보면, 그 버튼을 아무나 누르면 곤란하다는 생각이 들죠. 봇을 운영하다 보면 "이 명령은 관리자만", "이 채널에서는 봇이 말을 못 하네?" 같은 권한 문제를 반드시 마주칩니다. 이번 글에서는 Discord의 권한 체계를 라이브러리 없이 제대로 이해해 봅니다. 권한은 비트 플래그다 Discord의 권한은 하나하나가 **비트(bit)**입니다. 메시지 보내기, 멤버 차단하기, 채널 관리하기 같은 각 권한이 2진수의 한 자리를 차지하고, 여러 권한을 가지면 그 비트들을 OR 연산(|)으로 합쳐 하나

Tauri로 가벼운 데스크톱 앱 만들기

Tauri로 가벼운 데스크톱 앱 만들기

웹 개발자라면 한 번쯤 "내가 만든 웹 앱을 데스크톱 앱으로 배포할 수 있으면 좋겠다"고 생각해 보신 적 있을 겁니다. Electron이 이 영역을 오랫동안 지배해 왔지만, 앱 하나에 Chromium 전체를 번들하다 보니 설치 파일이 100MB를 넘어가는 건 일상이었죠 😅 Tauri는 이 문제를 풀려고 만들어진 프레임워크입니다. 프론트엔드는 기존 웹 기술을 그대로 쓰되 백엔드를 Rust로 작성하고, OS의 네이티브 웹뷰를 활용해서 앱 크기를 수 MB 수준으로 줄여 줘요. 이번 글에서는 Tauri 2로 데스크톱 앱을 처음부터 만들어

Discord 버튼, 셀렉트 메뉴, 모달 다루기

Discord 버튼, 셀렉트 메뉴, 모달 다루기

슬래시 커맨드로 사용자 입력을 받는 방법을 봤는데요. 사용자가 매번 명령어를 타이핑하는 대신 버튼을 누르거나 메뉴에서 고르게 하면 훨씬 편하겠죠. Discord의 메시지 컴포넌트가 바로 그걸 가능하게 합니다. 이번 글에서는 버튼, 셀렉트 메뉴, 입력 폼인 모달을 Discord 공식 문서처럼 라이브러리 없이 다뤄볼게요. 버튼이나 모달도 결국 슬래시 커맨드와 같은 인터랙션이라, 서버리스 봇 만들기에서 만든 HTTP 인터랙션 워커에 그대로 얹힙니다. 아래 코드는 모두 그 워커의 fetch 핸들러 안에서 돌아가는 코드예요. 서명 검증 뼈대

Discord 인터랙션과 슬래시 커맨드 완전 정복

Discord 인터랙션과 슬래시 커맨드 완전 정복

디스코드 봇을 만들어 서버에 초대하고 REST로 디스코드에 요청도 보내봤다면, 이제 반대로 사용자가 우리 앱을 부르는 쪽을 볼 차례입니다. /를 입력하면 뜨는 슬래시 커맨드가 대표적이죠. 그런데 슬래시 커맨드는 생각보다 깊어서, 옵션으로 입력을 받고, 시간이 걸리는 작업을 처리하고, 나만 볼 수 있는 답장을 보낼 수 있어요. 이번 글에서는 이걸 Discord 공식 문서처럼 라이브러리 없이 파헤쳐 봅니다. 커맨드 등록은 REST 요청으로, 사용자가 부를 때 받고 응답하는 건 서버리스 봇 만들기에서 만든 HTTP 인터랙션 워커에 얹어서

Vite 플러그인 직접 만들어 보기

Vite 플러그인 직접 만들어 보기

Vite로 프로젝트를 만들다 보면 @vitejs/plugin-react나 vite-plugin-svgr 같은 플러그인을 한두 개쯤은 꼭 설치하게 되는데요. vite.config.js의 plugins 배열에 함수 하나 넣었을 뿐인데 JSX가 변환되고, SVG가 컴포넌트로 바뀌고, 환경 변수가 주입됩니다. 도대체 이 플러그인이라는 게 안에서 무슨 일을 하길래 빌드 과정에 이렇게 자연스럽게 끼어들 수 있는 걸까요? 🤔 사실 Vite 플러그인은 생각보다 훨씬 단순한 구조로 되어 있습니다. 객체 하나에 약속된 이름의 함수 몇 개를 넣어주면

Discord