나한테 이럴순 없지,,, 얼마 안남았는데~ ~~ ~!
며칠 전, 메인 페이지 디자인 구현이 거의 끝났고 (사실 다 끝났다고 생각했는데 쫌쫌따리로 계속 수정할 것이 생긴다 🥲), 반응형 적용도 90% 이상 끝난 상태였다. 하지만 뭔가,,, 더 손을 대고 싶다고 생각하고 있던 중, 문득 헤더를 수정해야겠다는 생각이 들었다.
헤더 위치가 고정이어도 반투명하게 만들었기 때문에 글을 읽을 때 딱히 방해가 되진 않았지만, 스크롤을 내리면 아예 화면에서 사라지는게 전체적인 가독성도 좋을 거 같았고 더 깔끔해 보일 거 같았다.
스크롤 방향에 반응하는 헤더를 참고해서 순탄히 잘 적용하는 듯 했으나,,,! 예기치 못한 문제가 발생한다. 모바일에서 홈페이지에 들어가보고 싶어서 빌드하고 github page
에 올리려고 했는데 yarn build
를 하자 에러가 발생했다.
아니 이럴리가 없는데?? 1초 전까지만 해도 잘됐었는데,,,,?? 라는 생각과 배신감이 들었다. yarn develop
으로는 아무런 에러 없이 잘 작동하고 있었기 때문에 당연히 빌드될 줄 알았기 때문이다.
develop은 빠른 피드백을 위한 개발 모드이고 build는 개발이 끝난걸 패키징하는 걸로만 알았는데, gatsby develop과 gatsby build에는 명확한 차이점이 존재했다. 생각보다 꽤 많기 때문에 일단 여기서는 에러가 발생하게 된 가장 큰 요인만 다뤄보고 나머지는 따로 글을 작성해야겠다.
결론부터 말하자면 gatsby develop은 runtime 방식으로 동작하고, gatsby build는 build time 방식으로 동작한다.
그렇다면 각각 build time, runtime으로 동작한다는 것은 무슨 뜻일까?
웹 브라우저에서 사용자가 클릭을 하는 등의 상호작용이 일어나는 과정을 browser runtime
이라고 한다. JavaScript 코드는 브라우저와 상호작용 할 수 있고 브라우저가 제공하는 API
(ex. window.loation나 AJAX, DOM에 마크업을 동적으로 삽입 등)를 사용할 수 있다.
반대로, build time
은 server process를 사용해서 사이트를 나중에 웹 브라우저에 전달할 수 있는 파일로 컴파일하는 과정을 말한다. 따라서 이때는 window처럼 브라우저가 제공하는 API는 사용할 수 없다. Node.js 서버에는 그런게 존재하질 않아요~!
gastby develop을 실행하면 webpack server
가 실행되고 runtime 방식으로 브라우저에서 사이트를 미리 확인할 수 있게 된다. (브라우저 API도 사용 가능 → document 접근 가능) 반면, gatsby build는 build time으로 동작해서 브라우저를 사용할 수 없기 때문에 브라우저가 제공하는 API를 호출하지 않도록 신경써야한다(?) → 이 부분 번역이 맞는지 잘 모르겠다 🥲
Node.js 같은 server-side language로 페이지와 assets을 브라우저에서 렌더링 될 수 있는 HTML로 변환하는 과정을 server-side rendering, SSR
이라고 한다. Gastby는 렌더링 되기 전, 즉 build time에 사이트 전체를 만들어낸다. 이미 모든게 합쳐지고 컴파일되었기 때문에 사이트가 배포됐을 때 server-side process를 구동할 필요가 없다.
그렇다면 에러에 나와있는 "document" is not available during server side rendering의 이유를 이제는 알 수 있다. SSR은 build time에 HTML이 만들어지고 gatsby build를 사용하면 해당 방식으로 동작하기 때문에 Node.js에는 존재하지 않는, 즉 브라우저 API로 제공되는 document에 접근할 수 없기 때문이다.
최근에 추가한 스크롤 감지 헤더 코드에서 document에 접근했기 때문에 에러가 발생한 것이었다.
const documentRef = useRef(document);
해당 코드에서 useRef
를 사용해 ref 객체를 만들고, 해당 객체에 document
를 설정해 줬다. gatsby build를 실행했을 때, build time이기 때문에 브라우저에 렌더링돼서 DOM이 생성되기 전, 즉 document가 아직 정의되지 않은 상태에서 document에 접근해서 에러가 발생한 것이다. → 8/26일 추가 : 이렇다기 보다는 그냥 server side language인 Node.js에는 window, document가 없으니깐,,, 정의되지 않은 걸로 뜬 게 맞는 것 같다
다행히도 Gatsby에서 해결법 몇 가지를 제안하고있다.
window/document
가 생성됐는지 먼저 확인한다.useEffect
로 감싼다.gatsby-node.js
를 수정한다.내 경우 3번은 해당이 안되므로 1번과 2번을 시도해봤다.
if (typeof document !== 'undefined') {
const documentRef = useRef(document);
...
}
1번을 적용하니 바로 해결됐다,,, ㅋㅋㅋ 하지만 너무 쉽게 해결이 돼서 그런지 찝찝한 느낌에 2번을 시도해봤다. useEffect
에 전달된 함수는 렌더링이 완료된 후 수행되기 때문에 더 안전하다고 생각했기 때문이다. 하지만 Hook 사용이 미숙해서 그런지 실패했다,,,
일단은 1번으로 해결한 것에 만족하고 넘어가기로 했지만 진짜 이 방법으로 해도 문제가 없는건지 의문이 든다.
출처