- 웹 개발에 대한 전반적인 배경 지식이 필요합니다.
- 가장 현대적인 웹 구조 중 하나인 Node.js, React, GraphQL, Apollo, Prisma, Next.js에 대해 소개합니다. 개발 강의는 아닙니다.
- 이 단원은 동형 렌더링(Isomorphic Rendering) 또는 유니버설 웹이라 불리는 것에 대해 소개하는 것이 목적입니다.
- http://noooob.xyz:7000/ 예제 페이지 첨부
웹 페이지를 전달하는 방식은 2가지 방식이 있다. 서버에서 렌더링(서버사이드 렌더링)을 끝내고 전달하는 방식, 그리고 클라리언트에서 렌더링(클라이언트사이드 렌더링)을 할 수 있도록 전달하는 방식이다.
먼저 서버사이드 렌더링은 각 페이지별로 서버에서 렌더링해서 페이지를 보여준다.
클라이언트 사이드 렌더링은 클라이언트 쪽에서 페이지를 변경해주는 것이다. 서버에서는 필요한 데이터만 전송을 받는다. (서버 렌더링에서 페이지 전체를 보내는 것과는 달리)
각 방법은 장단이 있는데 그건 다음과 같다.
서버사이드 렌더링
[장점]
웹 페이지 첫 접속이 빠름
완성된 html을 보내기 때문에 검색엔진에서 검색되기 용이
[단점]
웹 내에서 페이지 이동 시, 계속해서 페이지 전체를 새로 내려받음(느림)
전체적으로 웹 페이지 사용이 느릴 수 밖에 없음
클라이언트사이드 렌더링
[장점]
웹 내에서 페이지 이동 시, 페이지가 아닌 필요 데이터만 주고 받기 때문에 속도가 빠름
전체적인 웹 페이지 사용이 빠름
[단점]
처음 접속 시, 다른 페이지의 내용도 한번에 받기 때문에 로딩이 느림
검색엔진에 검색되기 용이하지 않음
대개 오래된 웹은 전부 서버사이드 렌더링이였고 클라이언트사이드 렌더링 위주의 웹은 최근에서야 많이 나오고 있다. 다만 여전히 검색엔진과 관련된 문제, 첫 접속 시 로딩이 길다는 문제는 클라이언트사이드 렌더링에서 큰 이슈였다.
이를 해결하는 방안으로 나온 것이 동형 렌더링(Isomorphic Rendering 또는 Universal Web) 방식이다. (이 글에서는 Lazy Rendering을 포함한다)이는 서버사이드 렌더링과 클라이언트 사이드 렌더링을 적절히 조합한 것으로 두 방식의 장점을 모두 가진다. 이는 첫 접속은 서버사이드 렌더링으로 이뤄지되, 그 이후에는 클라이언트 사이드 렌더링을 사용하는 것이다.
즉, 다음과 같은 장점을 가진다.
첫 접속 시, 필요한 페이지의 내용만 받기 때문에 로딩이 빠르다.
검색엔진에 검색되기 용이하다.
페이지 이동이 빠르다.
전체적으로 개별적인 상황에 맞춰 데이터를 수신하기 때문에 속도가 빠르다.
동형 웹 개념을 기존 기술(JAVA, JSP)로 적용하는 것은 굉장히 어려웠다. 서버 내에서 자바스크립트 코드를 실행해서 렌더링을 할 수 있어야 하는데 이를 적용하는 것이 여간 만만치 않기 때문이다. 체계적으로 구현하는 것이 Python, Java로는 거의 불가능에 가깝다. (유일하게 확인할 수 있었던 Java 기반 React Isomorphic Web도 내부에선 node.js를 사용했다.) 서버에서 js를 실행할 수 있도록 별도의 작업이 필요한데 이게 여간 만만한 작업이 아니다.
다만 이를 Node.js를 사용하면 어느정도 수월하게 할 수 있다. js 인터프리터가 별도로 필요하지도 않고 클라이언트 페이지에서나 서버에서나 같은 코드를 공유할 수 있어, 구현과 설계가 용이해지기 때문이다. Node.js에서 React를 위한 동형 렌더링을 위해 탄생한 것이 Next.js라는 라이브러리다. (Vue에선 Nuxt라는 것이 있다.)
Next.js는 정말로 간단하게 동형 웹을 구현할 수 있도록 도운다. 개인적으로 Node, React 조합으로 사용 시, 서버 렌더링은 굉장히 번거로운 문제였다. 이것을 제일 잘 해결해주는 서비스는 유료 서비스였다.(https://prerender.io/) 이런 나에게 Next.js는 가히 혁명적으로 편리하고 좋은 도구였다. (구체적인 라이브러리 사용법은 본 글의 목적이 아니므로 넘깁니다.)
http://noooob.xyz:7000/ 로 접속하면 간단한 예제 웹 페이지를 확인할 수 있다. nodejs, react, next로 만든 간단한 리스트 페이지이다.
3가지의 케이스를 보며 알아보겠다.
- List Page -> Space 1 -> List Page
- Space 1 -> List Page -> Space 2
- Space 2 -> List Page -> Space 1
- 모든 페이지는 첫 접속 시, 서버 사이드 렌더링으로 제공된다.
- 컨텐츠 데이터는 하드코딩 되어 있으며 ajax는 페이지 구조, 써드파티모듈 로드 시 사용된다.
- List Page -> Space 1 -> List Page
스페이스 1은 react-highlight라는 코드 그리는 모듈이 활용 되었다. 이 모듈은 리스트 로딩 시에 로드될 필요가 없기 때문에 페이지에 접속 시에만 모듈이 로딩이 된다. 이에 따라 모듈이 사용되지 않는 곳에서의 페이지 로딩이 빨라진다.
리스트로 돌아왔을 때, 페이지 구조는 이미 처음에 다 로드하였다. 그래서 어떤 네트워킹 과정 없이 바로 페이지 변환이 일어난다.
2. Space 1 -> List Page -> Space 2
스페이스 1을 처음 접속 시, highlight 모듈과 컨텐츠 페이지 구조(space.js)가 로딩 되었다.
리스트로 돌아갔을 땐, 리스트 구조만 별도로 로딩된다.
스페이스 2를 접속했을 때, 페이지 구조는 이미 로딩되어 있기 때문에 바로 이동된다.
3. Space 2 -> List Page -> Space 1
스페이스 2를 로딩하며 컨텐츠 페이지 구조를 로딩한다.
리스트로 돌아오며 리스트 페이지 구조를 로딩한다.
스페이스 1을 로딩 시, 컨텐츠 페이지 구조를 뺀, highlight 모듈만 로드한다.
위와 같은 결과들을 종합해보면,
- 처음 로딩 시, 필요한 부분만 로딩한다.
- 웹 페이지를 이동 시, 필요한 부분만 로딩한다.
- 방문한 페이지를 다시 방문 시, 로딩된 부분은 로딩하지 않는다.
또한, 기본적으로 첫 페이지 로딩은 전부 서버사이드 렌더링으로 제공된다.
그리하여 이러한 동형 렌더링(Isomorphic, Universal) 개념은 기존의 웹의 속도를 혁신적으로 빠르게 할 수 있는 현대적인 개념이라고 본다. (클라이언트 사이드 렌더링의 한계를 극복하는)
"리스트로 돌아왔을 때, 페이지 구조는 이미 처음에 다 로드하였다. 그래서 어떤 네트워킹 과정 없이 바로 페이지 변환이 일어난다. "
리스트가 바뀌기 전까지는 새로운 DATA 요청 없이 이미 로딩된 데이터를 보여주는거로 이해했는데요.
그렇다면 리스트가 그사이에 바뀌게 되면 그때 새로운 리스트 data를 요청해서 받게 되는거죠?
publish/subscribe 구조를 활용하는건지 궁금합니다.
그리고 이건 좀 다른 질문인데요. 위의 상황을 모든 유저에 대해서 대입해보면요.
리스트 data가 바뀌기 전에는 모든 유저가 리스트 요청시, 실제로 DB 갔다오지 않고 캐시처럼 가지고 있다가 내려줄 수 있을까요?
접속자가 굉장히 많은 환경에서는 이런 방식이 DB 부하를 줄이는데 굉장히 유리할것 같아서요.
Redis는 혹시 어떨까요?
유저가 새로고침을 해야하나요