| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- 개발
- 스내피
- error
- 코드트리후기
- d3.js
- SNAPPI
- 자막
- 글또
- qknou
- 토폴로지 시각화
- 네트워크 그래프
- 사이트맵
- 브레드크럼
- react
- 유튜브
- 겹침 방지 알고리즘
- 계산기 라이브러리
- 택배api
- npm 배포
- npm
- 사내라이브러리구성
- nextjs
- 번역
- react-query
- TypeScript
- YouTube
- React 시각화
- 우리택배
- 라이브러리
- 큐노
- Today
- Total
목록전체 글 (25)
아임실버 | 프론트엔드 개발 블로그
프로젝트 관리 화면의 사이드바를 개선하면서 첫 번째로 부딪힌 문제는 단순했다.프로젝트 수와 채팅의 갯수가 늘어날수록 사이드바가 감당이 안 됐다.처음엔 전체 목록을 한 번에 불러오는 방식으로 충분했다. 그런데 데이터가 쌓이면서 초기 로딩이 느려지고, 사이드바가 길어져 원하는 프로젝트를 찾는 시간도 길어졌다.목록이 많아질 때 흔히 선택하는 해결책은 Pagination이다. 그런데 이번엔 Pagination이 아니라 Infinite Scroll을 선택했다. "요즘 많이 쓰니까"가 아니라, 사이드바라는 맥락에서 Pagination이 오히려 더 나쁜 선택이었기 때문이다.1. 문제기존 구조는 프로젝트 목록을 한 번에 전부 불러오는 방식이었다.컴포넌트 마운트 → 전체 프로젝트 목록 API 호출 → 전부 렌더링프로젝트..
회사에서 내부 라이브러리를 개발하던 중 문득 이런 생각이 들었다."내가 만든 게 다른 개발자들한테도 쓸모 있으면 어떨까?"마침 사이드 프로젝트에 계산기 UI가 필요했다. 기존 npm 패키지들을 살펴보니 대부분 스타일이 고정되어 있거나 커스터마이징 포인트가 없었다. 그래서 직접 만들기로 했다.목표는 하나였다. 로직은 가져다 쓰되, 생김새는 사용하는 쪽에서 자유롭게 결정할 수 있는 구조.1. 설계 방향 — 로직과 UI의 완전한 분리라이브러리를 쓰는 입장에서 원하는 걸 먼저 정리했다.계산 로직은 신경 쓰고 싶지 않다버튼 배치, 색상, 폰트는 내가 정하고 싶다TypeScript를 쓰니까 타입 지원이 되어야 한다그래서 컴포넌트가 UI를 강제하지 않고, 연산 상태와 핸들러만 외부로 노출하는 구조로 잡았다. 사용자는..
2025년 12월, 방통대 학습을 돕는 서비스 큐노(QKNOU) 를 시작했다.프론트엔드 1명, 백엔드 1명. 2주 단위 스프린트. 그리고 실제 서비스 배포라는 목표를 가지고 있었다.회사 프로젝트가 아닌 내가 직접 기획하고, 결정하고, 만들고, 배포하는 경험이었다.1. 프로젝트 개요큐노는 방통대 학생들의 학습을 돕기 위한 서비스다.Next.js 기반 프론트엔드프론트 1명 + 백엔드 1명, 소규모 팀2주 단위 스프린트로 기능 단위 개발북마크, 오답노트, AI 챗봇 연동, 광고 기능 포함2. 왜 이 프로젝트를 시작했나사실 동기는 단순했다. 시험 준비를 하다보니 불편했기 때문이다.방통대 학생으로 공부하다 보면 반복적으로 막히는 지점이 있었다. 시험 준비 자료를 찾으러 여기저기 다니는데 시간이 너무 오래 걸렸고,..
큐노(QKNOU) 프로젝트에 테스트 코드를 도입하면서 처음으로 "어떤 구조로 테스트를 작성할 것인가"를 진지하게 고민했다.테스트를 작성하는 방법은 알고 있었다. 문제는 작성하는 방식이 달라지면 테스트의 유지보수성과 가독성이 크게 달라진다는 걸 직접 겪으면서 알게 됐다는 것이다.이 글은 AAA와 GWT 두 패턴을 비교하고, 프로젝트에서 GWT를 선택한 기술적 근거를 정리한 것이다.1. 문제테스트를 처음 작성할 때는 별다른 구조 없이 이런 식으로 썼다.test("답안 선택 시 상태 업데이트", () => { const { result } = renderHook(() => useAnswerSelection()); act(() => { result.current.selectAnswer("q1", 2); })..
큐노(QKNOU) 프로젝트는 모노레포 구조다. shared 패키지에 API 훅을 모아두고, apps/web(Next.js)에서 가져다 쓰는 방식이다.그런데 이상한 현상이 생겼다. QueryClientProvider를 앱 루트에 한 번만 감쌌는데, 같은 쿼리 키로 요청이 두 번 발생하고 캐시가 동작하지 않는 것처럼 보였다.1. 문제프로젝트 구조는 이랬다.root/├── shared/ ← useSubjectListQuery, useExamQuestionsQuery 등 훅 제공│ └── package.json└── apps/ └── web/ ← Next.js 앱. @qknou/shared를 불러와 훅 사용 └── package.jsonapps/web의 루트 ..
프로젝트 배경기존 프로젝트(V2)에서는 next-intl을 사용하여 다국어를 지원했지만, 번역 파일 관리 구조에 근본적인 문제가 있었다. 모든 번역 리소스가 단일 파일(en.json, ko.json)에 집중되어 있어 다음과 같은 문제가 발생했다:V2 구조의 문제점messages/ ├── en.json (1,500+ lines) └── ko.json (1,500+ lines)1. 스케일링 문제Homepage, Header, Technology, Business, Solution, Product 등 모든 도메인의 번역이 하나의 파일에 집중파일 크기가 1,500줄 이상으로 비대화특정 섹션 수정 시 전체 파일을 로드하고 검색해야 함2. 번들 사이즈 및 성능 문제사용하지 않는 번역 리소스까지 모두 번들에 포함..
CKEditor5로 콘텐츠 에디터를 구현하던 중 이상한 현상을 발견했다.소스 편집(Source Editing) 모드에서 내용 처럼 인라인 스타일을 직접 입력했는데, 에디터 화면에 반영도 안 되고, 콘솔 로그에도 찍히지 않았다. 저장해도 마찬가지였다. 분명히 textarea에 입력했는데 내용이 사라지는 것처럼 보였다.1. 문제소스 편집 모드에서 아래처럼 HTML을 직접 입력했다.숨김 처리할 내용 그런데 소스 편집 모드를 닫고 나면 style 속성이 사라져 있었다.숨김 처리할 내용에디터 onChange에서 찍는 콘솔 로그에도 style 속성이 없었고, 서버에 저장된 데이터에도 반영되지 않았다.2. 원인원인은 두 가지가 겹쳐 있었다.원인 1 — CKEditor5의 엄격한 HTML 필터링CKEditor5는 기본..
프로젝트에 SEO를 도입하면서 처음엔 메타태그 몇 줄 추가하는 것으로 시작했다.그런데 Google Search Console을 열어보니 예상보다 훨씬 많은 페이지가 "색인 생성 안 됨" 으로 찍혀 있었다.원인을 파고들었더니, 문제는 메타태그가 아니라 URL 구조 자체에 있었다.1. 문제기존 URL은 이런 형태였다./products?page=2&category=outer&sort=popular/products?page=3&category=outer&sort=popular/products?page=2&category=top&sort=popular개발할 때는 편했다. 필터와 페이지 상태를 query string으로 관리하면 코드가 단순해지니까.그런데 검색엔진 입장에서는 이 URL들이 모두 /products라는..