사용자 환경에 따른 유동적인 컴포넌트 로딩하기
Dynamic Import로 컴포넌트 분할하고, 필요할 때만 로딩해봐요.
최근에 내 블로그 구성하는 것을 즐거워하며 개발 중이다.
이모지를 애용하는 나는 이번 블로그 카테고리에는 이모지를 넣었다.
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fdf4a6bfa-f205-4ce2-976c-640d0e875768%252FUntitled.png%3Ftable%3Dblock%26id%3Deb059c42-4698-4975-b5a4-5d7d7e1e763d%26cache%3Dv2&w=3840&q=75)
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F3f0c7dca-d6fc-4741-9e1b-15be277225c0%252FUntitled.png%3Ftable%3Dblock%26id%3Ddef7945f-3e39-4e38-ae22-9431e7e6e652%26cache%3Dv2&w=3840&q=75)
맥에서는 잘 표시되던 이모지가 이상하게 표시되고 있다. 찾아보니까 Microsoft에서도 이 이모지 지원하더라... 왜 저렇게 나오는걸까?
어찌됐던 그러한 이유로, Twitter에서 오픈소스로 공개하고 있는 Twemoji 프로젝트를 이용하여 이모지를 대체하기로 마음 먹었다.
Twemoji 프로젝트에서 제공하는 js는 document.body
에 있는 모든 이모지를 대체할 수 있다.
idea from ridibooks
나는 윈도우와 맥 환경을 자주 왔다갔다한다. 윈도우에서 리디북스를 접속할 때는 분명히 웹폰트로 "나눔고딕"을 사용했었는데, 맥 환경에서는 아무 폰트도 로딩하지 않는게 아니겠는가?
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F15b50a15-0a4c-4187-8c79-60c0d7b5d013%252FUntitled.png%3Ftable%3Dblock%26id%3Dade5a9d6-70d9-48f6-b349-4a5b127b43e0%26cache%3Dv2&w=3840&q=75)
리디는 navigator.userAgent
를 기준으로 폰트 로딩 여부를 가져오는 듯 보인다. 만약 로딩 조건(윈도우) 환경이라면 추가적인 번들 파일을 로딩한다. 해당 번들 파일은 webfontloader를 이용하여 나눔고딕을 로딩하는 것으로 보인다.
이런 방식으로 번들(컴포넌트)를 분리하여 조건에 충족될 때만 로딩할 수 있다면, 정상적으로 표시되는 환경에서도 리소스를 로딩하는 문제를 피할 수 있을 것이다.
Dynamic Import
필요할 때만 해당 컴포넌트를 로딩할 수 있는 기능, Dynamic Import에 대해 잠시 짚고 넘어가자.
내 블로그는 Next.js를 사용하고 있는데, Next.js에서는 Dynamic Import를 기본적으로 지원하고 있다. Dynamic Import는 컴포넌트를 Lazy Loading 해준다. 즉 컴포넌트가 필요할 때에 컴포넌트를 로딩하여 사용할 수 있다는 것이다.
더 많은 설명이 필요하다면, Next.js 공식 문서를 참고하자.
여담이지만, Next.js를 사용하지 않는 환경이라면 loadable components를 고려해보아도 된다. Dynamic Import와 비슷한 역할을 한다.
React.lazy?
React v16.6.0에는 React.lazy
가 추가되었고, 많은 곳에서 React.lazy의 사용을 권장하고 있다. Dynamic Import는 React.lazy와 비슷하게 작동하는 것으로 보인다. 단 다른 점이라면 React.lazy는 SSR을 지원하지 않는다는 정도?
SSR이 필요하지 않을 때 이것을 쓰면 될 것 같지만, Dynamic Import도 No SSR 옵션을 제공한다. 그래서 나는 Dynamic Import만 사용하고 있다.
어느 환경에서 Twemoji를 표시할 것인가?
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fb68d81ed-d28a-4f2f-b344-fabb904a72b2%252FFrame_1.png%3Ftable%3Dblock%26id%3Dc7d824d7-040e-4850-a028-7811474df5cb%26cache%3Dv2&w=3840&q=75)
사실, 내가 사용하는 환경에서는 윈도우 환경 이외에서는 이모지가 파괴되는(...) 일이 일어나지는 않지만, 모든 환경에서 테스트를 한 것은 아니므로 그냥 안드로이드와 애플 기기들을 제외하곤 모두 로딩하는 방안을 채택했다.
구현은 어떻게?
import dynamic from 'next/dynamic';
const TwemojiLoader: React.FC = () => { if ( typeof window !== 'undefined' && !/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) && navigator.userAgent.toLowerCase().indexOf('android') === -1 ) { // 조건 충족 시에 dynamic import const Twemoji = dynamic(() => import('~/components/features/global/twemoji')); return <Twemoji />; } return <></>; // fallback};
<TwemojiLoader />
그나마 나은 구현 방법이 무엇이 있을까 고민하다가, 이렇게 구현하게 되었다.
Next.js Dynamic Import의 사용법이 상당히 간단하게 구현 가능하게 되어 있어서 다행이였다.
결과 🧑💻
지금 여러분이 보고 있는 페이지도 결과물이긴 하나, 윈도우에서만 보일 것이다. 😅
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F4a0da613-e470-48cd-a14f-457c80c6b8a9%252FUntitled.png%3Ftable%3Dblock%26id%3D6adf27e1-cc37-42af-b6e0-767d2c50225a%26cache%3Dv2&w=3840&q=75)
![글 작성자가 업로드 한 이미지](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fea911757-8dfe-4d57-91d2-65d9e73cac4b%252FUntitled.png%3Ftable%3Dblock%26id%3Dedb3c28c-7884-45ef-b720-410a2c8b695a%26cache%3Dv2&w=3840&q=75)
이로써, 사용자 환경에 따라 유동적으로 lazy 로딩되는 컴포넌트를 만들 수 있었다. 끝!