모노레포에 쌓인 미사용 코드, Knip으로 찾아내기
·
• R&D
서비스에서 코드를 새로 짜는 것 만큼 안쓰는 레거시 코드들도 관리해주지 않은 점점 산처럼 많아진다. 특히 여러 공용 패키지가 함께 모여있는 모노레포에서는 시간이 지나면서 자연스럽게 쌓이는데 - 기획 변경으로 사용하지 않게 된 컴포넌트- api 스펙이 바뀌면서 남은 interface, adapter- 컴포넌트 수정하면서 남음 styled-component- 더이상 사용되지 않는 util- export 는 되어있지만 어디서도 import하지 않는 함수 근데 이런 코드들이 에러를 발생시키지 않는다..그래서 더 레거시가되고 쌓이게 되는데.. 사용하지 않음 -> 그렇다고 빌드가 깨지는 것도 아님-> 계속 코드베이스에 남아 있음 그러다 보니 검색할때 예전 구현이 같이 나오기도하고, 리팩토링 하다가 이미 사용하지..
Next.js에서 TIFF 이미지가 프로덕션에서만 깨진 이유
·
• Next.js
이미지 일부가 렌더링이 깨지는 문제가 있었다.특이했던 건 API 자체는 정상이고 , 이미지 URL도 전부 정상으로 내려오고 있었다. 이미지 URL이 7r개내려오면 1번째 이미지 → 정상2~7번째 이미지 → 에러 UI처럼 일부만 깨졌다 네트워크 탭을봐도 요청은 전부 200ok 로컬 next dev → 정상Vercel Production → 일부 이미지 깨짐 처음에는 url이나 s3응답 문제라고 생각했는데, API 랑 네트워크가 모두 정상이라 애매했다. 1. Network가 200인데 이미지가 왜 깨지는지 이미지가 안보이면 가장먼저 이걸 확인했다 이미지 url이 잘못됏는지 -> 정상S3 요청이 실패해쓴지 -> 200API 에서 이미지가 누락됐는지 -> 모두 수신 근데 이미지가 깨지고 에러컴포넌트가 뜨고..
Suspense와 useQuery의 로딩 상태 관리, 책임 분리
·
• React
테이블마다 제각각이던 로딩 UI를 하나로 통일하는 작업을 진행했다.처음에는 크게 고민할 부분이 없다고... 생각했다.이미 상위 컴포넌트에서 각각의 테이블을 Suspense로 감싸고 있었고 fallback도 있었다 !! }> 그래서 이미 부모에 Suspense가 있는데 fallback만 공통 로더로 바꾸면 되는거아닌가 라고 생각했다. 근데 실제로는 API 요청은 부모가 아니라 각각의 테이블안에서 useQuery로 실행되고 있었다. const RankingLicenseTable = () => { const { data, isFetching } = useRankingLicenseQuery(); if (isFetching) { return ; } return ;}; 구조로 ..
Next.js 빌드에서 Google Fonts 타임아웃 해결, next/font/local과 @fontsource 적용
·
• TroubleShooting
배포 워크플로에서 빌드가 간헐적으로 실패한다. 배포를 두가지를 동시에 돌리는 경우도 있는데, 그런경우에는 더 큰확률로 폰트 관련해서 빌드가 실패한다. FetchError: request to https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDz8Z11lFd2JQEl8qw.woff2 failed type: 'system', errno: 'ETIMEDOUT', code: 'ETIMEDOUT'Failed to compile.src/app/layout.tsx`next/font` error:Failed to fetch `Poppins` from Google Fonts.`ETIMEDOUT`는 파일이 없다는 뜻이 아니라 연결 자체가 시간 안에 끝나지 않았다는..
React Server Component (RSC)와 SSR 함께 보기
·
• Next.js
리액트 컴포넌트의 Data fetching하나의 페이지에서 서버에서 받은 데이터를 활용해 뷰를 그려주는 컴포넌트를 만들어야한다면,어떤식으로 구성하는것이 좋을까. 1️⃣ 부모 컴포넌트에서 API 호출 후 자식컴포넌트로 전달하기 이 방법은 클라이언트에서 서버로 요청해야하는 API요청을 줄일 수 있다. 하지만 이방법은 부모컴포넌트에서 -> 자식으로 데이터를 내려줘야하기 때문에 부모- 자식 컴포넌트 사이의 결합성이 커지고, 유지보수가 어려워진다. 만약 자식 컴포넌트 중 하나가 위치를 옮겨야하거나 데이터가 바뀌는 이슈가 발생한다면수정작업에 드는 리소스로 인해 생산성이 떨어진다. 2️⃣각 자식 컴포넌트에서 필요한 API 직접 호출하기 특정 컴포넌트만 가져야할 데이터 라면, 해당 컴포넌트만 가디게하는게 더 좋은 것..
모바일 PWA 에서 FCM 푸시알림이 노트북으로만 오던 버그
·
• TroubleShooting
무비부키를 운영하면서 가장 힘들고 어려웠던 부분은 FCM 알림이였다. 어렵고 헤맸던 만큼 지금 돌아보면서 해결까지 복잡하게 돌아왔던 것 같은데 왜 그랬었는지 , 시행착오를 지금이나마 기록으로 남겨보자!! 일단 처음에는 알림을 "수신"이 1차 목표였다. 하지만 PWA환경이 메인 서비스에서 PC로 수신이 되고있었다. 알림이 가긴가는데 엉뚱한 기기로 가고있는것인데... 모바일 PWA에서는 알림이 전혀오지 않았고, PC 에서는 무비부키가 꺼져있는데도, localhost:3000으로 알림이 수신됐다. 처음 문제보고 추측했던 원인들은..1. 모바일에서 권한 문제인가? => notification.permission은 "granted"였다 => 권한 문제 x2. service worker 등록이 제대로안됐나? ..
Tailwind 정적 분석 한계와 CSS 변수 배경색 문제 해결과정
·
• TroubleShooting
무한스크롤에서 스크롤 맨위로 가는 플로팅 버튼을 만들었다.디자인 토큰을 CSS 변수로 정의해 두고,Tailwind에서 bg-buttonBg, text-buttonText 같은 커스텀 색상 유틸을 써서라이트/다크 모드 색 전환을 구현하려 했었다. 그런데 .....다크 모드에서 버튼 배경이 투명(transparent) 처럼 보였다...텍스트 색(text-buttonText)은 잘 바뀌는데, 배경색만 안 먹는 문제를 마주했다. 1. 기존코드:root { --color-button-bg: #ffffff; --color-button-hover: #2563eb; --color-button-text: #111827;}.dark { --color-button-bg: #1e1e1e; --color-butto..
Masonry 레이아웃에서 스크롤하단에서 이미지가 갑자기 바뀌는 문제
·
• TroubleShooting
틴터레스트 같은 벽돌형 레이아웃 Mansonry 를 구현하고싶어서 columns 속성을 사용했는데, 스크롤을 내려서 새로운 이미지가 로드될 때마다 이미 보고 있던 이미지들이 갑자기 다른 이미지로 바뀌고 있었다.. 내의도는 로드된 이미지들은 그대로 있고, 하단부터 새 이미지목록들이 불러왔어야하는데, 깜빡거리면서 자연스럽지 못한 사용자 경험을 겪고있다... 초기 코드 {images.map((img) => ( ))}const fetchImages = async () => { const res = await fetch(`https://picsum.photos/v2/list?page=${page}&limit=20`); const data = await res.json(); ..
모든 링크가 같은 썸네일로 보이던 문제, 동적 OG 태그로 이벤트별 미리보기
·
• Next.js
영화를 함께 볼 이벤트를 만들고 링크를 공유할 때,카카오톡이나 트위터, 페이스북에서 어떤 썸네일 이미지와 제목, 설명이 미리보기로 노출되느냐가 사용자 클릭률에 큰 영향을 준다..나라도 설명을 보기보다는 썸네일 이미지에 더 눈길이 먼저간다. 하지만 정적 웹사이트라면 모든 링크가 동일한 OG 메타데이터를 가지기 때문에,이벤트나 게시물 같은 동적 페이지에서는 "어떤 링크를 공유해도 똑같은 썸네일" 이 보여진다. 그리고 실제 서비스를 운영하면서사용자 유입 경로를 GA4로 분석했을 때, 직접 검색해서 접속하는 수단보다는, 인스타그램/카카오톡 링크 공유 → 인앱브라우저 접속이 주요 패턴이었다.. 하지만 인앱브라우저 환경에서는 공유된 링크 미리보기가 단순 텍스트로만 노출되어, 실제 이벤트 참여로 이어지는 비율(참여..
실행 컨텍스트, 어떻게 설명할 수 있을까?
·
• JavaScript & CSS
Excution Context (실행 컨텍스트) 란 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다. JS에는 동일한 환경에 있는 환경정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장할 수 있게 된다. 풀어서 설명하면 스택의 경우 FILO (First In, Last Out) 의 구조이기에 순서를 보장,콜스택 내부에 쌓인 실행 컨텍스트의 정보를 통해 환경을 보장할 수 있는 것이다. 여기서 환경이란 전역공간이 될 수 있고, 함수 즉 함수 내부의 환경이 될 수 있다var temp = 'temp'; function b (){ console.log('안녕하세용');} function a (){ b();} a();처음 자바스크립트 코드를 실행하는 순..
이벤트 페이지 성능최적화 (LCP 37 => 2.5, CLS 0.219=>0.006)
·
• Project
이벤트 목록을 보러 들어온 사용자가 첫 화면을 보기까지 30초 이상 기다린다면,이미 절반은 떠났다고 봐야 한다..스크롤도, 탭 전환도, 버튼 클릭도 먹지 않는 멈추는 순간이 길어질수록새로고침을 누르거나 뒤로가기를 누르게 되는 경험을 해봐서 더욱이 초기 렌더링의 중요성을 크게 생각하고있다. 문제 상황0. 페이지 전체가 Client Component기존에는 페이지 전체가 use client로 감싸진 클라이언트 전용 렌더링(CSR) 구조였고, 서버는 사실상 빈 HTML을 내려보낸 뒤 브라우저가 모든 컴포넌트를 다운받아 하이드레이션을 마칠 때까지 화면에 보여줄 게 거의 없었다.반대로 SSR 을 쓰면 서버가 곧바로 HTML을 만들어 보내기 때문에 -> 사용자는 즉시 UI의 뼈대를 확인할 수 있다 1. 무거운 컴포..
10,000건 테스트, MSW 기반 대용량 가상+무한 스크롤 적용
·
• Project
백오피스 서비스에서는 생각보다 데이터 양이 엄청 많은 상황을 마주하게 된다. 서울우유 백오피스에서 진행했던 전자세금계산서 진위 검증 업무 역시,한 번에 수천에서 수만 건의 데이터가 처리 대상이 되는 구조였다. “실제 기업에서 이런 규모의 데이터를 다뤄야 한다면?”이라는 가정에서 시작했다. 무한스크롤, 가상스크롤의 차이 무한 스크롤 무한 스크롤은 사용자가 화면을 아래로 내릴 때마다서버나 API에서 새로운 데이터를 조금씩 불러오는 방식이다.한 번에 모든 데이터를 가져오지 않기 때문에네트워크 요청 측면에서는 효율적이다. 하지만 불러온 데이터가 계속 DOM에 쌓이기 때문에,1만 건의 데이터를 모두 조회하면 브라우저는1만 개의 DOM 노드를 동시에 렌더링하고 유지해야 한다. 데이터가 많아질수록 렌더링과 레이..
카카오톡에서 앱 설치 유도하기: PWA 외부 브라우저 리다이렉션 전략
·
• TroubleShooting
프로그레시브 웹 앱(PWA)이란프로그레시브 웹 앱은 웹 기술을 사용하여 개발된 애플리케이션으로, 사용자가 웹 브라우저에서 접속할 수 있으며 모바일 앱과 비슷한 사용자 경험을 제공한다.사용자는 PWA를 스마트폰에 설치할 수 있으며, 설치 후에는 홈 화면에 아이콘이 생성되고 별도의 앱처럼 실행된다. 무엇보다도 PWA는 운영체제(iOS/Android), 디바이스(폰/태블릿), 브라우저(Safari/Chrome 등)에 구애받지 않고 거의 모든 환경에서 동작할 수 있다는 장점이 있다. PWA의 단점 브라우저/OS별 지원 격차특히 iOS Safari에서는 PWA 관련 기능이 제한적이라, 설치를 자연스럽게 유도할 수 있는 API가 아예 제공되지 않는다.그래서 같은 기능이라도 안드로이드와 iOS에서 사용자 경험이 달라..
[Next.js] 에러핸들링, 서버액션( revalidatePath()
·
• Next.js
에러핸들링 error.tsx 파일을 만들어서 해당 파일의 위치와 하위폴더의 에러는 error.tsx가 대신사용된다.기본적으로 오류는클라이언트 서버 어떤환경이든 발생할 수 있기때문에 클라이언트 컴포넌트 설정해준다 - next.js는 에러발생시 에러컴포넌트에서 js에러타임의 에러객체를props로 전달해준다.- reset : error가 발생한 컴포넌트 복구하기위해 재렌더링하는 함수 ( 서버컴포넌트 다시 실행 x, 클라이언트 컴포넌트에서 발생한 에러만 복구 가능) 'use client';import { useEffect } from 'react';export default function Error({ error, reset }: { error: Error; reset: () => void }) { useE..
[Next.js] Vercel 빌드 속도를 60% 단축하기
·
• Next.js
❓ 문제 상황: 빌드 시간이 너무 오래 걸린다우리 팀의 Next.js 기반 프로젝트는 Vercel을 통해 배포되고 있었는데, 어느 순간부터 배포 빌드 시간이 3분 41초를 넘기기 시작했다.버셀에서 배포하면 프리뷰로 먼저배포되고, promote to production 할수 있는데pwa 웹앱을 구현중에서는 브라우저의 모바일기기 보다 실제 모바일 pwa 앱으로 확인해야할 때가 있었는데(fcm,노치 등)빌드시간이 너무 오래걸려서 빠르게 수정해서 배포하고 확인하기가 어려웠다. 페이지 수나 컴포넌트 수가 많지 않은 비교적 경량 프로젝트였기 때문에, 이 빌드 시간은 너무 과하다고 판단했음 Vercel의 Serverless 환경에서 빌드가 오래 걸리면 생산성에 직접적인 영향을 미치기 때문에, 해결해보자 🔍 문제 ..