Next.js 앱에서 클릭이 한 박자 느리게 느껴질 때 살펴본 것들
서버가 멀면 응답이 느린 건 어쩔 수 없습니다. 제 경우 오리진 응답 지연에 CDN 우회 경로까지 겹쳐 페이지 응답에 1초 가까이 걸리는 상황이었고, 네트워크 쪽은 당장 손댈 수 없었습니다. 그래서 응답 속도 대신 "눌렀을 때 반응하는 속도"를 올리는 쪽으로 방향을 잡았습니다. 느린 것과 느리게 느껴지는 것은 생각보다 다른 문제였습니다.
처음에는 버튼 컴포넌트를 의심했습니다. 그런데 디자인시스템 버튼에는 이미 active:scale-95가 들어 있었고, 서버 액션을 부르는 버튼들도 누르는 즉시 스피너가 뜨게 돼 있었습니다. 버튼 탓이 아니었습니다. 한참 눌러보다가 찾은 구멍은 세 군데였습니다.
클릭하고 아무 일도 안 일어나는 페이지
loading.tsx가 없는 라우트가 세 개 있었습니다. Next.js 앱 라우터는 라우트에 loading.tsx가 있으면 이동하는 순간 스켈레톤을 먼저 그려주는데, 이게 없는 페이지는 클릭 후 서버 렌더가 끝날 때까지 화면에 아무 변화가 없습니다. 하필 그중 하나가 three.js를 불러오는 3D 페이지라 청크만 876KB였습니다. 클릭, 1초 정지, 화면 전환. "버튼이 늦게 눌린다"는 느낌의 절반은 여기서 나왔던 것 같습니다.
스켈레톤 파일 세 개를 추가하는 게 이번 작업에서 가성비가 제일 좋았습니다. 늦게 뜨는 건 그대로인데, 클릭한 순간 화면이 반응하니까 체감이 다릅니다.
눌렀다는 확인이 없는 링크
사이드바 링크에는 hover 색 전환(transition-colors)만 있었습니다. 누른 순간에는 아무 변화가 없다가, 이동이 끝나야 활성 하이라이트가 옮겨갑니다. 응답이 1초 걸리는 환경에서는 이 1초 동안 "눌린 건가?" 하게 됩니다.
링크에 active:scale와 100ms 트랜지션을 넣어서 누르는 순간 살짝 눌리는 느낌을 줬습니다. CSS 한 줄이지만, 눌렀다는 확인이 즉시 오는 것과 안 오는 것의 차이가 큽니다.
응답을 기다리게 만드는 부수 작업
서버 액션의 응답 경로에 부수 작업이 끼어 있었습니다. 얼마 전 감사 로그와 알림 기능을 넣으면서 권한 검사를 통과할 때 로그를 남기고, 상태가 바뀔 때 알림을 적재하게 해뒀는데, 이게 전부 액션 응답을 기다리게 하는 위치에 있었습니다. 버튼 하나 누를 때마다 본 작업에 DB insert가 두 번 더 순차로 붙는 셈입니다.
Next.js의 after()로 옮겨서 응답을 보낸 뒤에 실행되게 했습니다. 문서를 보니 after 콜백은 액션이 에러를 던져도 실행된다고 해서, 권한 거부 기록이 유실될 걱정도 없었습니다. 로깅이나 알림처럼 응답에 꼭 필요하지 않은 쓰기는 처음부터 여기에 두는 게 맞았습니다.
남은 것
이 세 가지를 고쳐도 네트워크 지연 자체는 1초 그대로입니다. 그래도 클릭하는 순간 반응이 오고 스켈레톤이 뜨는 것만으로 "느리다"는 인상은 꽤 줄었습니다. 응답 시간을 줄일 수 없을 때 남는 선택지는 첫 반응까지의 시간을 줄이는 것이고, 그 첫 반응은 대부분 서버가 아니라 CSS와 파일 하나에서 나옵니다.
같은 작업에서 겪은 다른 문제:
우리 서비스에 적용할 계획이 있으신가요?
홈페이지·웹서비스 개발 살펴보기 →함께 읽기
- 클릭했는데 화면이 늦게 바뀌는 느낌을 줄이는 방법사용자가 버튼이나 링크를 눌렀는데 아무 반응이 없는 것처럼 보이면, 실제 로딩 시간이 길지 않아도 서비스가 느리다고 느낍니다. 이 문제는 단순한 성능 문제가 아니라 체감 성능과 피드백의 문제입니다.
- Next.js loading.tsx와 404: 버튼이 화면보다 먼저 살아나게 하기관리 화면 왼쪽 위에 사이드바를 접고 펴는 ☰ 버튼이 있습니다. 폭 하나 바꾸는 버튼인데, 대시보드에서 누르면 2초 넘게 아무 반응이 없었습니다. 레이아웃만 바꾸는 일이 왜 이렇게 오래 걸리는지부터 들여다봤습니다. Next.js 16 App Router 로 만든 제조 공장의 생산 관리 앱입니다.
- Next.js에서 링크를 눌렀는데 로딩 뒤 이전 화면이 다시 나타나는 이유페이지 이동을 빠르게 보이게 만드는 장치는 대개 눈에 잘 띄지 않습니다. 미리 다음 화면을 받아 두거나, 서버 응답을 기다리는 동안 스켈레톤을 보여주는 식입니다. 이번에는 그 두 가지가 한꺼번에 작동하면서 오히려 이동을 늦추고 화면 상태까지 헷갈리게 만들었습니다.
- Next.js는 운영에서 멀쩡한데 로컬 개발 서버에서만 UI가 먹통이 되는 이유Next.js 애플리케이션은 운영 빌드가 안정적이면 개발 서버도 같은 방식으로 움직일 것 같지만, 둘은 클라이언트 코드의 수명이 다릅니다. 제가 확인한 환경은 Next.js 16.2.7과 Turbopack이었고, 운영 사이트에서는 잘 눌리던 상단 메뉴가 로컬 개발 서버에서만 간헐적으로 먹통이 됐습니다.
- Next.js 랜딩 페이지의 Lighthouse 점수가 폰트 하나로 해결되지 않는 이유성능 최적화에서 가장 당황스러운 순간은 개발 환경에서는 빠른데 배포 후 측정값만 크게 느릴 때입니다. 이번 랜딩 페이지가 그랬습니다. 개발 환경에서 관찰한 LCP는 약 1.68초였지만 PageSpeed Insights의 첫 측정은 5.5초까지 늘어났습니다. 이후 배포본을 다시 측정했을 때도 성능 점수 72점, LCP 4…