Nuxt3 의 Universal Rendering 이란 무엇인가..

이 글은 제가 회사에서 Nuxt3 에 대해 발표하기 위해 준비했던 자료를 정리 한 글입니다.

때는 2023년 초 추운겨울.. 회사에 새로운 프로젝트가 시작된다는 소식이 들려왔다. 해당 프로젝트의 요구사항 중 하나는 Search Engine Optimization(이하 SEO) 를 적용시키는 것 이었다. 그 동안의 프로젝트는 관리자사이트에 치중되어있었기에 기존 Vue 만으로 충분했지만 이제는 SEO 를 위해 다른것을 시도할 때 였다. 마침 2022년 말 Nuxt3 의 stable 버전이 출시되었다. 우리 회사는 이 나온지 얼마 안된 Nuxt3 를 도입해보기로 결정한다. 나는 docs 를 보며 간단하게 CRUD 를 만들어 본 뒤에 Nuxt3 에서 개발할때 꼭 알아야 할 중요하다고 생각되는 점 몇가지를 회사에서 발표하기로 결정했다. 그 중 Universal Rendering을 이 글을 통해 설명해보겠다.

 

Universal Rendering 이란

Nuxt 는 Default 렌더링 방식을 Universal Rendering 을 채택했다고 한다. 나는 지금까지 렌더링은 Server Side Rendering(이하 SSR) 과 Client Side Rendering(이하 CSR)만 있는줄 알았는데 아니었다. 그럼 Nuxt 에서 말하는 Universal Rendering 이란 무엇일까? 공식 문서에서는 이렇게 설명하고 있다.

서버로 요청이 오면 서버에서 JavaScript (Vue.js) 코드를 실행 시켜서 HTML 을 만들어낸 뒤 응답한다. (기존 SSR 방식) 그리고 응답을 받은 브라우저는 HTML 을 다운 받은 뒤 서버에서 실행시켰던 JavaScript 를 받은 후 실행한다. 그 뒤 Vue.js 는 해당 문서에 대한 제어를 시작하게 되고 상호작용 할 수 있게 된다. 이 과정을 Hydration 이라고 한다.

 

간단하게 정리하면 처음 페이지 요청이 오면 Server 에서 JavaScript (Vue.js)파일을 이용해 페이지를 만들어 HTML 을 먼저 전달하고, 필요한 JavaScript 파일을 받은 뒤 Client 에서 다시 실행한다. 그 이후부터의 모든 router 이동은 CSR 로 작동하게끔 한다고 할 수 있다. 그 중간중간에는 또 prefetch components 라고 사용자 화면에 <NuxtLink> 가 보이는 순간 해당 링크의 컴포넌트 렌더링에 필요한 script 파일을 가져오는 기술을 써 CSR 을 최적화 한다.

 

Universal Rendering 의 장단점

  • 장점

SSR 이 가지고 있던 장점이자 CSR 의 단점인 초기 페이지 로딩속도를 보안했다.

한번 페이지를 받은 뒤에는 전부 CSR 로 작동하기에 SSR 의 단점이자 CSR 의 장점인 화면의 부드러운 전환을 할 수있다.

또한 CSR 의 단점인 SEO 가 안된다는 점도 보안한 장점을 가지고 있다.

  • 단점

개발시 주의해야 할 점이 있어 항상 신경 써야한다.

 

Universal Rendering 개발의 주의할점

Browser API 활용의 제한

위의 설명을 보면 첫 페이지 요청이 Server로 오면 JavaScript 를 Server에서 한번 실행, 그리고 브라우저에서 한번 더 실행한다고 되어있다. 바로 이 부분에서의 개발에 어려움이 있다. 기존에 Vue.js 를 통해 개발할 당시에는 당연하게 쓰이던 DOM API 같은  Browser API 들을 마음껏 쓰지 못하게 된다는 점이다. 당연하듯 Server 환경에서는 해당 API 들이 존재하지 않아 실행 시 해당 에러를 발견할 수 있다.

document is not defined

Nuxt docs 에서는 그렇기에 해당 Browser API 들을 사용하는 곳은 Client-Side 에서만 실행되게끔 잘 사용하라고 되어있다.

When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects.

즉 내가 작성하는 코드가 어디서 어떻게 실행되는지 항상 생각하고 작성해야한다는 뜻이며 또한, 내가 사용하는 라이브러리가 Browser API 를 사용한다면 해당 라이브러리는 Client-Side 에서만 작동하게끔 조작을 해야한다는 뜻이다. 대표적으로는 WYSIWYG 에디터를 예를 들 수 있겠다. 사용법에 대한 내용은 다음 포스팅에서 이어서 작성해보겠다.

 

HTTP 통신의 중복호출

또 다른 어려움은 바로 http request 이다. 보통 Vue 를 이용해 개발시 제일 많이 써오던 Axios 를 Nuxt3 는 채택하지 않았다. 기본적으로 채택한 라이브러리는 ofetch. 그 이유는 여기서 찾아볼 수 있었다. 해당 라이브러리는 환경에 따라 Server 면 node-fetch-native, Browser 면 브라우저의 기본 fetch 을 선택해 사용한다고 한다. 해당 라이브러리는 $fetch 라는 메서드를 이용해 사용할 수 있다. 문제를 확인해보기 위해 해당 메서드를 사용해 코드를 작성했다고 생각해보자.

<!--  pages/index.vue  -->
<template>
  <div>Hello {{ data }}!</div>
</template>
<script setup>
const data = await $fetch("/api/temp");
console.log(data);
</script>


<!--  server/api/temp.ts  -->
export default defineEventHandler(() => {
  console.log("api call");
  return Math.random();
});

해당 index 페이지를 처음 들어가면 api 호출이 두번 실행 되었다는 사실을 확인할 수 있다.

server console 이 2번찍힌 모습.

만약 api 호출 결과가 만약 그 사이에 달라진다면 끔찍한 Hydration mismatch warning 을 볼 수 있다.

Hydration mismatch 란 Server 에서 만든 HTML 과 Client 에서 렌더링된 HTML 의 결과가 다를때 나는 warning 으로 Nuxt는 Hydration 이 일어날때마다 서로의 결과가 같은지 확인한다. 다르다면 문제가 있다는 뜻이므로 확인을 요한다.

 

그 뿐만 아니라 Server 는 불필요하게 두번의 api 호출을 받게 되므로 서버 성능의 저하를 일으킬수 있다.

실제 Nuxt 문서에서는 이러한 문제점이 일어날수 있다는것에 대해 설명하고 있다.

However, using $fetch in components without wrapping it with useAsyncData causes fetching the data twice: initially on the server, then again on the client-side during hydration, because $fetch does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again.

이 문제를 해결하기 위해 Nuxt 에서 제시한것은 useFetchuseAsyncData 이다. 이 두가지의 차이점과 사용법은 다음 글에서 확인 할 수 있다.

 

 

Nuxt3 $fetch, useAsyncData, useFetch 의 차이

이 글은 제가 회사에서 Nuxt3 에 대해 발표하기 위해 준비했던 자료를 토대로 정리 한 글입니다. 읽기 전 Universal Rendreing 이 뭔지 알아야 하므로 먼저 이전글을 읽어주세요. Nuxt3 의 Universal Rendering

jongmin4943.tistory.com

 

결론

이 글 만을 통해 Universal Rendering 이 뭔지 정확히 전달하기 쉽지않다고 느낀다. 회사에서 발표한것이 벌써 수개월전이기도 하고 그 당시 작은 자료만 준비하고 말로 설명하며 그 순간순간 질문답을 하며 발표했다. 간단하게 설명하자면 처음에 SSR 이고 그 이후는 CSR 이며 개발시 코드가 실행되는 환경에 대해 잘 생각해 개발해야한다. 가 될것이다.

중간중간 중요한 키워드 몇가지가 나왔는데 그것들도 하나의 주제가 되기에 다른 글에서 설명해보도록 하겠다.