-
Notifications
You must be signed in to change notification settings - Fork 0
Nextjs suck
정적 웹사이트를 위해 NextJS를 사용해왔는데, 이는 Amplify 호스팅 경험이 너무나도 편리하기 때문입니다. AWS 콘솔에서 GitHub 저장소를 연결하기만 하면 바로 작동하고, Lambda와 함께 실행되며, (DDoS 공격을 받지 않는 한) 매우 저렴하다는 점... 이건 어떤 경우에는 거절하기 힘든 장점입니다. 구글이 콘텐츠를 인덱싱하고 찾는 데 서버 사이드 렌더링이 몇 년 전부터 필요하지 않았음에도 불구하고, 토이 프로젝트용 웹사이트를 위한 개발자 경험이 너무 좋아서 놓치기 아깝습니다.
하지만 복잡한 SaaS 프로젝트의 경우, NextJS의 이점은 거의 없고 오히려 심각한 단점들이 있습니다.
NodeJS는 SSR에 부적합합니다
서버에서 React 렌더링을 하면 애플리케이션에 복잡성이 추가됩니다. 이는 NodeJS가 잘 하지 못하는 일을 시키기 때문입니다. NodeJS는 싱글 스레드입니다. 설계된 이상적인 경우라면, 요청들은 I/O 바운드여야 합니다. SSR이 필요한 복잡한 페이지는 동시 요청을 처리하는 능력을 제한하게 됩니다. 제 전 동료가 대규모 트래픽 급증 상황에서 서버 사이드 렌더링을 최적화한 경험에 대해 발표한 내용이 있습니다.
물론 대부분의 앱들은(여러분의 앱을 포함해서) 월마트가 블랙프라이데이에 겪는 것과 같은 급증을 경험하지는 않을 것입니다. 하지만 여러분은 항상 무엇을 얻는 대신 무엇을 포기하는지 생각해야 합니다. 제가 기억하기로는, 제 친구의 월마트 상황은 결국 NodeJS가 페이지 렌더링에 너무 오래 걸리면서, 운영체제의 HTTP 요청 큐가 너무 커지게 되었고, 부하 분산이 제대로 설정되지 않아서 그 로드 셰딩 문서에 설명된 것처럼 서버들이 응답하지 않게 되었습니다.
자동 확장 인프라가 새로운 서버들을 계속해서 스핀업하면서 구조를 구했지만, 그들은 여기에 수백만 달러를 썼고, 여전히 가용성 손실(사용자들이 깨진 경험을 하고 새로고침을 해야 하는 상황)을 겪었습니다. 이를 해결하기 위해 제 친구는 기본적으로 앱을 렌더링할 때 setTimeout을 도처에 주입해야 했습니다. 물론 정적 사이트 사전 생성이나 서버리스 호스팅과 같은 이 모든 것을 피하는 방법들이 있습니다. 이것이 서버리스가 NextJS에서 인기 있는 선택인 이유 중 하나입니다. 하지만 이러한 특정 복잡성을 피하는 제가 가장 선호하는 방법은 그냥 nodejs에서 react를 서버 렌더링하지 않는 것입니다. 보안이 멋진 기능보다 뒷전입니다.
많은 NextJS 기능들은 브라우저가 인라인 스크립트를 주입하는 것을 허용해야 합니다. NextJS의 Suspense 구현, appDir 기능 사용(거의 항상 사용하게 되는), next/font 사용, 그리고 rootLayout에 넣는 모든 것들이 인라인 스크립트로 앱에 주입됩니다. 아무 NextJS 웹사이트나 열어보면 아래 스크린샷처럼 많은 인라인 스크립트들을 볼 수 있습니다.
이것들은 전부 인라인 스크립트들입니다. 인라인 스크립트는 좋지 않은데, 리플렉티드 XSS 공격을 막는 유일하게 신뢰할 수 있는 방법이 인라인 스크립트 실행을 막는 콘텐츠 보안 정책(CSP) 헤더이기 때문입니다. 강력한 CSP 정책이 XSS 예방의 황금 기준입니다. 그리고 CSP 관점에서 해야 할 주요한 일은 인라인 스크립트를 피하는 것입니다. 브라우저에게 인라인 스크립트를 실행하지 말라고 지시하기만 하면, 저장된 XSS는 불가능합니다. 하지만 인라인 스크립트가 필요한 NextJS 기능들을 사용한다면, 인라인 스크립트를 금지하는 CSP 정책을 가질 수 없습니다. 그 때문에, 더 안 좋은 방법인 특정 nonce(로드 시 무작위로 계산됨)와 일치하는 인라인 스크립트만 허용하는 것으로 타협해야 합니다.
NextJS에서 이를 하려면 상당한 양의 코드를 작성하고 여러 절차를 거쳐야 합니다(머리가 어지러워지길 원한다면 문서를 보세요). 이의 재미있는 부작용은, NextJS 클러스터 앞에 CDN을 둔다 해도 nonce가 모든 세션마다 달라야 하기 때문에(그렇지 않으면 nonce의 목적이 무의미해지고 그냥 인라인 스크립트를 허용하는 것과 다름없습니다) 엣지 로케이션 캐싱이 전혀 없을 것이라는 점입니다. NextJS는 여러분의 시간을 존중하지 않습니다
그들의 API는 매우 불안정하고 계속해서 깨뜨립니다. 기본적으로 6개월마다 그렇습니다. 13에서 14로의 업그레이드는 힘들었습니다. 호스팅 인프라가 훨씬 더 나쁩니다 CDN으로 SPA를 호스팅한다면, 한 달에 3천만 고객을 몇 달러로 서비스할 수 있습니다. 대신 NextJS를 사용한다면 몇 가지 선택지가 있습니다.
- 서버리스를 사용하고 단순한 DDOS로 인한 엄청난 요금에 취약해지거나
- ECS/EC2를 사용하고 수요 급증 시 너무 느린 스케일 업으로 인해 가용성을 잃을 수 있음(위의 1번 포인트와 관련)
두 선택 모두 좋지 않습니다. 두 선택 모두 비용이 많이 들 것입니다. 게다가, CDN의 전 세계적 분산 특성을 포기하게 됩니다. CDN은 사용자 근처에서 파일을 캐시합니다. 또한 사용자와 엣지 로케이션 사이의 캐싱(e-tag 기반)도 처리합니다. 포기하기에는 너무 많은 것들이며, 이것이 좋은 생각이라고 생각하는 많은 사람들이 CDN이 무엇인지, 또는 CDN이 여러분을 위해 무엇을 하는지 전혀 모른다고 확신합니다. 그들은 이 기사의 히어로 이미지에 나오는 개발자와 같습니다.
Betting duck
- [지호] 베팅 생성 페이지에서 아이콘이 함께 리렌더링 되는 문제 해결
- [정민] 채팅 시스템을 위한 IRC 프로토콜
- [정민, 지호] 소켓 이벤트가 무한리필 되는 문제 해결하기
- [정민, 지호] 소켓 관리 실패로 인한 서버 다운 문제 개선하기
- [석호] 베팅 종료 API 개선하기
- [동교] 베팅 프로세스 흐름도
- [동교] 실시간 베팅에서 레디스 원자성 테스트
- [석호] Redis에서의 트랜잭션
- [석호] Redis를 이용한 메시지 큐 구현(1)
- [석호] Redis를 이용한 메시지 큐 구현(2)
- [동교] Redis에서 O(N) 관련 명령어는 주의하기
- [동교] 베팅덕에 적용한 다양한 캐시 전략
- [동교] 레디스의 메모리 설정 최적화
- [정민] 브라우저에서 렌더가 일어나는 방식
- [정민] Layered frontend application
- [정민] sessionStorage를 이용하여 전역 상태를 관리해도 될까?
- [정민] 왜 css는 내 마음대로 적용이 안될까?
- [공통] 브랜치에서 push 했는데 dev로 바로 병합된다?
- [공통] Cross-Origin WebSocket에서 쿠키 전송 문제: 삽질 기록과 해결
- [FE] Cannot find package 'prettier-plugin-tailwindcss'
- [BE] NestJS에서의 @Injectable() - WebSocketGateway 싱글톤 이슈
- 유저 스토리는 무엇인가?
- GitFlow vs Trunk-based 협업 방식
- The Front End Developer/Engineer Handbook 2024
- 코드 리뷰 in 뱅크샐러드 개발 문화
- Optimize Largest Contentful Paint
- The Looper Mini Web Machine
- Best practices for fonts
- React Folder Structure in 5 Steps [2024]
- Speeding up the JavaScript ecosystem - The barrel file debacle