Profile Picture

윤찬의 개발노트

2024. 12. 29.

서버로부터 받는 Html 양식 변경

SSRNext.jsRendering
"알 때까지, 계속보자"

서버에서 받는 HTML

내가 아는 서버 사이드 렌더링은 프론트서버로부터, 태그안의 내용이 채워진 파일을 받는 것이었다.

<!DOCTYPE html>
<html>
  <head>
    <title>News Website</title>
  </head>
  <body>
    <div id="root">
      <h1>제목 ㅋ</h1>
      <p>내용 ㅋ</p>
    </div>
    <script src="chunk.js"></script>
  </body>
</html>

그래서 이렇게 h1, p 태그를 보면 내용이 있었고 우리가 개발자 도구를 열고 네트워크 탭을 보면, preview에서 제일 처음 내용을 볼 수 있다. 그리고 Interactive 하기 위해서 우리는 연결된 js를 다운로드 받아야 하는거다. 그러기 위해서 html의 js는 chunk로 링크가 달려있다.

그래서 ssr방식에서 받아오는 Html의 <script></script> 태그는 chunk의 링크만 있는 줄 알았으며, 인라인 방식으로 적는 경우는 없을 줄 알았다.


Velog의 개발자도구

학부 때 내가 이용했던 velog의 개발자 도구를 보게 되었는데, 최초 html에 인라인 js가 있었다.

velog에서 js기능을 중지해도 렌더링이 되었다. 즉 ssr로 만들었다는 것인데 왜 초기 html의 js의 일부분은 링크로 달려있지 않고, 바로 써있는지 궁금했고, 혹시 내가아는 SSR의 개념이 꼬인 것이 아닌가? 라는 생각이 들었다.


리엑트 창시자

Alex Grigoryan이라는 사람이 ssr, csr에 대한 글을 작성한 적이 있고, 그 내용을 보게 되면

거의 없는 이라는 말에 집중하기로 했다. 즉, 절대는 아니고 있을 수 있다는 것인데, 그게 아마 인라인 스크립트가 아닐까라는 추측이 생겼다. 그래도 확실한거는 직접 물어보는게 제일 빠를 것 같았다. 그리고 Alex Grigoryan은 React 창시자중 한 명이다.

문자를 일단 보냈고, 답을 기다리는데, 그냥 뭔가 안볼것 같았다. 그래서 일단은 가만히 있을 수는 없어서 오픈소스로 되어있는 velog 코드를 분석하는게 빠르겠다는 생각이 들었다.


velog 코드 분석

우선 index.html에는 따로 추가적인 js를 root안에 적지 않았다. 그렇다면 드는 생각은 어디선가 서버에서 html을 생성할 때, 추가적인 동작이 있을것 같았고, 그 부분이 server 라는 디렉토리 에서 발생하고 있었다. 정리하면 다음과 같았다.

velog는 React를 ssr방식으로 변경을 한 상태이다. 그곳에서 초기 렌더링을 할 때 바로 테마를 적용을 위해서, 페이지가 로드되기 전에 설정에 맞는 theme을 적용하고 있었다.


서버 html 커스터마이징

그래서 이제, SSR에서 받아오는 html에는 태그 말고도, 커스터마이징이 가능하다는 것을 알게되었다. 적용을 해보고 싶은데, 지금 내 블로그에서 문제되는 부분이 있다. Next로 만든 내 블로그에서는 다크모드일 때, 새로고침을 하면, 잠시 화이트모드에서 다크모드로 깜빡임이 보인다.

그렇다면, 최초 렌더링이 진행될 때 스크립트가 실행되어 동기적으로 다크 모드가 바로 적용되도록 하면 해결할 수 있다.

1. 서버 측에서 dark 모드 처리하도록 하여, 2. 브라우저가 페이지를 처음 로딩할 때, 서버에서 렌더링된 HTML은 dark 모드에 맞는 스타일이 적용된 상태로 이미 전달되었으니, 3. JavaScript 코드가 실행되면서 로컬 스토리지에서 dark-mode 설정을 읽어 오도록 하여, JavaScript가 실행되더라도 4. 스타일의 깜빡임이나 변경 없이 페이지가 그대로 유지되도록 하는 것이다.

최상단 layout.tsx에서 코드를 script태그를 삽입했다.

이후 새로고침을 하고, 개발자 도구를 보면 서버로 부터 받은 html이 아까 velog처럼 script관련 부분이 인라인 js로 적혀있고, 실제로 새로고침을 해도 화면 깜빡임이 사라진 것을 확인할 수 있다.

직접 스크립트를 서버 Html에 삽입하는 방식이 깜빡임이 사라진 이유를 좀 더 알아보면, 렌더링 이후에 발생하는 useEffect때문에, 스크립트 삽입이 없다면, 다크모드/라이트모드 로직은 한 번더 렌더링이 발생한다. 즉, 2번이 발생하는 상황이다. 이를 훅 말고, <script></script>에 바로 관리하게 된다면, 크리티컬 렌더링 과정에서 js를 읽을 때 이미 theme을 적용하여 렌더링이 보여지기 때문에(useEffect로 로컬스토리지에서 가져오는 작업이 없기 때문에), 재렌더링이 없다. 그래서 깜빡임이 없는 것이다.

근데 사실은 dangerouslySetInnerHTML의 경우는 HTML을 직접 삽입할 수 있도록 허용해서 XSS에 위험하다. 하지만 지금은 input이 아닌, 직접 작성된 스크립트를 넣었다는 점과, 그 스크립트의 동작이 외부 데이터와 상호작용하지 않는다는 점에서 비교적 안전하다고 판단했다.

Profile Picture

CHAN

과정은 복잡하되, 결과는 단순하게

Thank You for Visiting My Blog, Have a Good Day 😆
ⓒYoonchan Cho