5분
Nextjs + React Server Component
React 18이 RC가 된지 꽤 된 것 같습니다.
Nextjs는 이에 대한 준비를 미리 계속 해오고 있었던 것 같습니다.(사실 발표는 2020년 말? 2021년 초에 되었으니...)
그에 맞춰 example repo도 공개하여 사람들이 익숙해지도록 하는 것 같습니다. next.config.js
도 계속해서 바뀌고 있고...
(너무 어려워...)
이 예제를 따라가면서 무엇이 바뀌었는지 체감만 해보는 형태로 진행했습니다. (사실 아직 stable이 아니라 내가 잘못했는지 라이브러리에 문제가 있는건지 조차 잘 구분을 못하게습니다.)
날짜별로 시간날 때마다 진행해서 일기형태로 작성했습니다.
들어가면서
React 18 rc with Nextjs. 해보자?
- CSR, SSR, SSG, HTTP Streaming, RSC, Concurrent, ...
day1
Init: project
- nextjs
- tailwindcss
늘 그렇듯이 개발의 세계는 무한에 가까운 속도로 변화되고 있습니다.
React를 쓰고는 있지만 진정 어떻게 잘 쓰는건지는 잘 모르면서 다음 것으로 넘어가도 되는지 불안감이 있지만, 그래도 앞으로 나아가야할 것 같았습니다.
요점은 React 18이 rc가 되면서 꽤 큰 변화를 야기하게 될 것 같아 미리 공부하는 느낌으로 진행합니다.
아직 18버전이 정식 릴리즈가 되지 않았지만 Nextjs, Remix 등 주요 프레임워크에서는 이미 준비가 거의 완료된 느낌이었습니다.
저 또한 Nextjs를 많이 쓰고 있는 입장에서 어떤 것들이 획기적으로 바뀌고 얼마나 좋아졌는지 알고 싶습니다.
이렇게 조그만하게라도 시작하려 합니다.
Nextjs의 RSC example 프로젝트를 따라가면서 하나하나 차이점에 대해서 살펴볼까 합니다.
day2
nextjs의 experiment 기능 중 concurrentFeatures(next 정식 release 12버전)를 켜면 middleware가 동작하지 않는 버그가 있습니다.(https://github.com/vercel/next.js/issues/31654)
(너무 늦게 발견했어...ㅜㅜ 왜 안되는지 너무 답답했는데 진작 알아볼걸 그랬습니다...)
여기에 시간을 꽤 뺏기면서 반 포기상태로 잠들었습니다.
next.js canary 버전을 사용하게 되도 문제가 발생합니다. 이런 문제가 해결되는지 지켜봐야 될 것 같습니다.
개인적으로 vue nuxt를 써본 경험이 있었는데 middleware에 대한 경험은 미리 nuxt를 통해 했습니다. 그것과 거의 동일한 page middleware 형태로 보였습니다. 사용법은 nextjs가 친숙해서 더 좋았습니다.
day3
전날 문제를 해결하고 다음 스텝인 SSR practice page를 진행했습니다. 앞에도 말했지만 clone practice이기 때문에 js를 ts로 옮긴것 빼곤 동일한 코드입니다.
그래도 네트워크 탭이라던지 내부 로그등을 찍어보며 확인하면서 진행하니 아주 조금은 공부가 되는 것 같습니다.
day4
CSR concurrent mode를 쓰기 위해 suspense component를 사용하여 진행하였습니다.
그런데 server side에서 initial page를 generate하기 위해서 typeof window === 'undefined'
를 썼는데 hydration에서 계속해서 오류가 나서 지웠습니다. 예제에는 분명히 동작하는 것으로 되어있지만
위 오류가 나타났습니다. server 에서 만든 html에 client 에서 hydration할 때 해당 컴포넌트를 mismatch하면서 나타나는 오류로 적혀져 있는데(throwOnHydrationMismatchIfConcurrentMode
) reconciliation시에 current가 null이면 이 오류를 던지게 되어있습니다.
current 트리가 null이면 이런 오류가 발생하는데 이런 오류는 어떻게 해결할 수 있을까요?
React reconcilation은 VDOM을 더블 버퍼링(current, workInProgress)을 구성하여 변경 사항이 있을 때만 업데이트 하는 방식입니다. 각 노드들은 Fiber라고 하는 객체로 관리되며 실제적으로 React의 가장 중심이 되는 부분입니다. root에서 쭈우우욱 트리형태로 그려진다고 생각하시면 됩니다. 근데 그게 2개(current, wip)로 구성되어있고, 변경점만 업데이트한다! 라고 생각하는데 그게 맞나? 어째뜬 그렇습니다...(너무 어렵습니다...)
이 부분은 여기까지 생각하고... 왜 안되었는지를 해당 위치에 comment를 살펴보면...알 수 있을까?
사실 읽어도 잘 모르겠습니다. 어째뜬 concurrent 모드 일 경우 hydration에서 문제가 발생하여 에러가 뜬다는 점 정도만 알 수 있을 것 같습니다. 카나리 버전이 아닌 12버전에서 concurrent 기능을 껐을 땐 에러가 발생하진 않았습니다.
day5
SSR
SSR(getServerSideProps
) 할 시에 에러가 계속 나길래 어떤 문제인지 확인하는데 시간이 걸렸습니다.
에러 내용은 getServerSideProps
의 return props가 serialize 가 안되었다는 내용이었습니다.
몇 가지 확인 결과 값이 없었을 때 JSON 타입으로 serialize를 하지 못하는 원인이 있었습니다.
이전에 react-query 사용 시에 hydrateState를 넘겨줄 때도 발생했던 적이 있었는데, 그 때 해결책은
위 형태로 반환해서 넘겨주는 것으로 해결했습니다. 아마 JSON 형태가 아닌 값이 있을 때 문제가 생기는 것 같아 한 번 감싸서 처리하도록 변경했습니다. (특이한 것은 edge runtime 시에만 에러가 나고, nodejs runtime 시에는 에러가 나지 않았는데 원인은 잘 모르겠습니다.)
SSG
SSG(getStaticProps
)는 서버사이드라는 관점에서는 SSR과 거의 동일합니다. 개발 시에는 완전하게 동일하다고 볼 수 있습니다. 그 이유는 빌드 시에 generate를 하게 되는데 개발 모드에서는 매 요청마다 빌드를 하기 때문입니다.
SSR과 SSG의 차이점은 빌드 시점에 있습니다. next build 시에 SSG(getStatcProps
)를 통해 만들어진 페이지는 빌드 시에 페이지를 pre-rendering하게 됩니다. 그래서 배포된 환경에서는 SSR이 매 요청마다 페이지를 생성하는 것에 비해 만들어진 페이지를 받아오기 때문에 훨씬 빠르게 사용자는 페이지를 받아올 수 있습니다.
RSC
React Server Component. React 18 feature 중 하나입니다.
기존 Next.js에서도 서버에서, 클라이언트에서 동작을 구분하기 위해서는 pages 하위에 page에 해당하는 파일에서만 getServerSideProps
getStatisProps
등을 통해서만 가능했습니다. 개별 컴포넌트 파일에서는 불가능 했죠.
RSC는 이것을 좀 더 명시적으로 구분하여 사용가능하게 합니다. 그러면 어떻게 서버에서 동작할 component와 클라이언트에서 동작할 component를 구분하는걸까?
파일명에 .server.js .client.js .js 형태로 구분합니다.
- .server.js: 서버에서 동작
- .client.js: 클라이언트에서 동작
- .js: 서버, 클라이언트 둘 다 사용 가능
또한 서버에서 동작할 때 필요한 번들들을 클라이언트로 내려받게 하지 않음으로 인해 번들사이즈가 줄어드는 효과도 있습니다.
Streaming
Concurrent features in React 18 include built-in support for server-side Suspense and SSR streaming support, allowing you to server-render pages using HTTP streaming.
concurrent기능은 react component들을 json처럼 직렬화해서 서버에서 맹글어서 HTTP Streaming합니다.
클라이언트에서 React는 직렬화된 streaming 정보를 api 결과 받는것처럼 받아서 UI를 그릴 수 있습니다. 이 구조를 통해 더 나은 사용자 경험을 제공하는게 목표로 보입니다.
(잘 못 이해한걸 수도 있습니다.)
build
모든 페이지가 Streaming 페이지(입실론) 로 만들어집니다.(맞나?) 이제 맞는건지 잘 모르겠지만...당분간 좀 더 파봐야겠다는 생각이 듭니다.
느낀점
CSR이 혁신적인 느낌으로 다가온적이 있었는데 프론트 커뮤니티진영에서는 이젠 흐름이 바뀌는 것 같습니다. Nextjs처럼 SSR 프레임워크들이 대세가 되고, Remix가 무료로 공개되는 것처럼 이젠 CSR는 점점 져물고 있는 것처럼 보입니다.
가능하면 서버사이드를 통해 static한 파일을 사용자들에게 던져주고, interactive한 모든 것들을 Streaming이라는 기술로 대체해버리는 느낌으로 가고 있는 것 같습니다.
아마 React 18이 가져다 줄 영향은 React가 처음 나왔을 때의 그 느낌에 준하지 않을까 싶습니다.
이젠 React가 라이브러리를 넘어서 프레임워크로 가는 느낌이 강하게 듭니다... next.js, remix, solid.js 처럼 이젠 프레임워크라는 느낌이 들기도 합니다.
프론트엔드 개발자라면 이젠 Server, ci/cd등 devOps, Docker, k8s, as-a-service 등 반드시 알아야 하는 시대가 곧 올 것 같습니다. 아니 벌써 왔는지도 모르겠습니다.
다시 돌아가자면 저는 아직까진 Nextjs가 개인적으로 너무 좋습니다. 순수 React로 구현하는 것보다는 Nextjs를 사용하는 것이 훨씬 편하다고 느끼게 됩니다.
또한 프론트엔드 영역이 무한히 확장된다는 느낌이 강합니다. 트렌드도 상당히 빠르게 진행됩니다. 현재 사용되는 기술들도 다 알지 못하고 불안함에 휩싸이지만 그래도 해야됩니다. 지금 당장 해야됩니다. 그게 부족한 저에게 가장 중요한 것이라고 생각합니다. (그게 잘 안돼...)
해당 코드 예제는 아래에 공개되어있습니다.
원본 코드는 아래 주소입니다.
마지막 업데이트
2/13/2022