본문 바로가기
React

Next.js의 CJK(한중일) 폰트 최적화 이슈, 오픈소스 생태계

by 돈민찌 2023. 5. 5.
반응형

깃허브 항상 고맙고...

Next.js 써보셨나요? 매우 진지하게 추천합니다...

React는 대화형 사용자 인터페이스를 구축하기 위한 자바스크립트 라이브러리입니다. 여기서 사용자 인터페이스(UI)는 사용자가 화면에서 보고 상호작용하는 요소를 의미합니다. 라이브러리라는 UI를 구축하는 데 유용한 함수를 제공하지만 해당 함수를 어디에 사용할지는 개발자에게 맡긴다는 뜻입니다. React의 성공 요인 중 하나는 애플리케이션 구축의 다른 세세한 측면에 대해 상대적으로 의견이 분분하지 않아 자유도가 높다는 점입니다. 그 결과 서드파티 도구와 솔루션으로 구성된 생태계가 번성하게 되었습니다. 그러나 이는 또한 완벽한 React 애플리케이션을 처음부터 구축하려면 약간의 노력이 필요하다는 것을 의미합니다. 일반적인 웹 애플리케이션을 구축할 때 다음과 같이 고려해야 할 몇 가지 사항이 있습니다. 개발자는 애플리케이션의 각 부분에 대한 솔루션을 직접 구축할지 아니면 라이브러리 및 프레임워크와 같은 다른 도구를 사용할지 결정해야 합니다. 

* 사용자 인터페이스 - 사용자가 애플리케이션을 소비하고 상호 작용하는 방식.
* 라우팅 - 사용자가 애플리케이션의 여러 부분을 탐색하는 방법.
* 데이터 가져오기 - 데이터의 위치 및 가져오기 방법.
* 렌더링 - 정적 또는 동적 콘텐츠를 렌더링하는 시기와 위치.
* 통합 - 사용하는 타사 서비스(CMS, 인증, 결제 등) 및 해당 서비스에 연결하는 방법.
* 인프라 - 애플리케이션 코드를 배포, 저장 및 실행하는 위치(서버리스, CDN, 엣지 등).
* 성능 - 최종 사용자를 위해 애플리케이션을 최적화하는 방법.
* 확장성 - 팀, 데이터 및 트래픽이 증가함에 따라 애플리케이션을 조정하는 방법.
* 개발자 경험 - 팀의 애플리케이션 구축 및 유지 관리 경험.

Next.js는 웹 애플리케이션을 만드는 데 필요한 빌딩 블록을 제공하는 React 프레임워크입니다. 프레임워크는 Next.js가 React에 필요한 도구와 구성을 처리하고 애플리케이션을 위한 추가 구조, 기능 및 최적화를 제공한다는 의미입니다. React를 사용하여 UI를 구축한 다음 Next.js 기능을 점진적으로 채택하여 라우팅, 데이터 불러오기, 통합과 같은 일반적인 애플리케이션 요구 사항을 해결하는 동시에 개발자와 최종 사용자 경험을 개선할 수 있습니다. 개인 개발자이든 대규모 팀의 일원이든 관계없이 React와 Next.js를 활용하여 완전히 인터랙티브하고 동적이며 성능이 뛰어난 웹 애플리케이션을 구축할 수 있습니다.

다음은 Next.js로 만든 저의 이력서 웹페이지입니다. Andrew Dong-min, Yoo

next/font는 자동으로 폰트(사용자 지정 폰트 포함)을 최적화하고 외부 네트워크 요청을 제거하여 개인 정보 보호 및 성능을 개선합니다. next/font에는 모든 폰트 파일에 대한 자동 자체 호스팅 기능이 내장되어 있습니다. 즉, 기본 CSS 크기 조정 속성을 사용하여 레이아웃 이동 없이 웹 폰트를 최적으로 로드할 수 있습니다. 또한 이 새로운 폰트 시스템을 사용하면 성능과 개인정보 보호를 염두에 두고 모든 Google Font를 편리하게 사용할 수 있습니다. CSS 및 폰트 파일은 빌드 시 다운로드되며 나머지 정적 에셋과 함께 동일한 도메인에서 자체 호스팅됩니다. 사용자가 페이지에 접속했을 때 브라우저에서 Google Font에 요청을 보내지 않습니다. next/font/google에서 사용하려는 Font를 함수로 가져와서 시작하세요. 최상의 성능과 유연성을 위해 가변 Font를 사용하는 것이 좋습니다.

제 페이지의 App.tsx입니다. Noto Sans KR 폰트를 사용했습니다. 

import '@/styles/globals.css';
import '@fortawesome/fontawesome-svg-core/styles.css';
import * as customPack from '@/components/common/icons';
import type { AppProps, NextWebVitalsMetric } from 'next/app';
import { config, library } from '@fortawesome/fontawesome-svg-core';
import Head from 'next/head';
import { Noto_Sans_KR } from 'next/font/google';

config.autoAddCss = false;
library.add(customPack);

const NS_KR = Noto_Sans_KR({
    style: 'normal',
    display: 'swap',
    subsets: ['latin'],
    weight: ['300', '400', '500', '700', '900'],
    variable: '--noto-sans-kr',
});

const App = ({ Component, pageProps }: AppProps) => {
   return (
      <>
         <Head>
            <meta name='viewport' content='width=device-width, initial-scale=1.0' />
            <meta name='theme-color' content='#0969da' />
            <meta httpEquiv='x-ua-compatible' content='ie=edge' />
         </Head>
         <main className={NS_KR.className}>
            <Component {...pageProps} />
         </main>
      </>
   );
};

App.reportWebVitals = (metric: NextWebVitalsMetric) => {
   console.debug(metric);
};

export default App;

NS_KR.className 변수는 이렇게 CSS 모듈화에 의해서 고유 문자열 클래스명으로 생성됩니다. 저는 전역적으로 적용했는데, 이렇게 클래스 이름으로 만들거나 CSS 변수명으로 만들어 각각 다른 폰트를 적용해도 좋아요!!


그런데 이렇게 잘 쓰고 있었는데, 로컬 개발 서버에서 이런 에러가 발생합니다. Noto Sans KR 폰트 불러오기에 실패해, 미리 정해놓은 fallback 폰트로 대체한다는 내용이었습니다. 같은 폰트 계열로 대체되기 때문에 유의해서 보지않으면 티는 안나지만, 아무튼 아닌건 아닌거죠.

error - Failed to download `Noto Sans KR` from Google Fonts. Using fallback font instead.

얼른 next.js 레포지토리에 이슈를 보고하려 했더니, 저 뿐만 아니라 꽤 많은 개발자들이 겪고 있는 문제였습니다. 대부분이 저처럼 CJK (한중일) 폰트를 적용하려는 개발자들이었지만 보다 보편적인 폰트를 적용한 개발자들도 있었습니다. 일단 정확하게 어떤 상황에서 어떤 폰트를 로드하는데 실패하는 건지 이슈 제보자들도 Next.js 개발자들도 파악이 안된 상태였기 때문에 저도 이슈 템플릿에 따라 이슈를 올리고 나서 제 프로젝트에도 해당 이슈를 등록했습니다.

--- 이후 한달 정도 동안 코멘트가 생길 때마다 메일이 와서 어느정도 파악하고 있었어요.

Next.js 프레임워크를 사용하는 개발자들이 구글 폰트에서 웹 폰트를 불러오는 도중 발생하는 에러에 대한 이슈를 분석하며 각자의 사례를 공유하고 해결하기 위해 시도해 본 것들을 Next.js 개발자들에게 전하고 있었습니다. 이 문제는 특히 한중일 언어를 포함한 폰트를 불러올 때 발생하는 것으로 보여졌지만 그렇지 않은 경우에도 발생을 하는 것으로 보였습니다. 어느 정도의 토론과 연구 끝에 커뮤니티의 개발자들은 Next.js 개발진들이 개발 환경에서 웹 폰트를 불러오는 로직(fetch-font-file.js)에 3000 밀리 초의 타임아웃을 설정해두었다는 것을 알게 되었습니다. 이것은 개발 환경에서 핫리로드 등의 퍼포먼스를 위해 설정된 것이었지만, 이 짧은 타임아웃 설정이 개발 환경에서 폰트 로딩에 실패하는 원인이 되어(CJK 폰트들이 영어권 뿐만 아니라 다른 언어 폰트에 비해서도 사이즈가 더 큽니다.) 개발자들이 어려움을 겪고 있는 것이었습니다. 오늘 받은 메일에서는 일본 개발자 @ReoHakase가 로컬 node_modules 내의 Next.js 소스파일에서 fetch-font-file.js를 직접 수정해 10배의 타임아웃을 적용하니 폰트가 정상적으로 로드되었다고 보고했습니다. 문제의 원인이 밝혀졌으니 일단 개인 개발자들은 patch-package 같은 툴로 해당 코드에 0 하나를 더해 폰트 로딩 타임아웃을 늘릴 수 있으니 임시방편을 할 수 있을 것 같고, 곧 공식적으로 폰트 로딩에 관련된 문제가 해결된 패치가 릴리즈에 올라올 수 있을 것으로 보입니다. 저도 깃허브를 통해 관심있는 오픈소스 프레임워크나 라이브러리의 이슈, 릴리즈, 보안 관련 사항 등을 구독해 보고 있긴 하지만, 제가 겪은 이슈가 이렇게 해결되는 과정을 직접 보는 경험이 귀하게 느껴졌습니다.

개발자들이 사용하는 개발 도구들은 오픈소스 생태계에서 발전하고 있습니다. 이것은 개발자들이 각자의 방식으로 자신에게 도구를 설정을 맞춰 사용하면서 자신이 사용하는 도구를 개선하고, 문제가 생기면 커뮤니티를 통해 다른 개발자들의 도움을 받아 도구를 보완하는 과정을 통해 이루어지고 있습니다. 이러한 과정에서 이슈는 개발자들이 소프트웨어를 보완하고 문제를 해결하는 데 있어서 중요한 역할을 합니다. 이번 이슈 역시 주로 한중일 아시아 국가의 개발자들이 토론과 연구를 통해 우리들 스스로 얻어낸 결과였으며, 이 과정에서 소스 코드 수정, 타임아웃 설정 등 다양한 방법을 시도하며, 이를 통해 문제를 해결습니다. 이러한 과정들은 개발 도구가 살아있는 생명체처럼 계속해서 보완되고 개선되는 것을 보여줍니다.

오픈소스 생태계에 뭐라도 기여를 하는 게 좋다고 다들 알고는 있지만, 타인이 짠 코드를 꼼꼼히 들여다보고 거기에 부족한 점을 찾아 수정까지 하는 과정이 처음에는 너무 어렵게 느껴질 때도 있습니다. 하지만 이러한 과정이 어떤 것보다도 자신이 사용하는 도구에 대한 이해에 가장 큰 도움이 됩니다. 따라서 개발자들은 이러한 변화에 적극적으로 개입하고, 자신이 사용하는 도구를 개선하는 데 기여하는 것이 중요합니다. 이를 통해 각 개발자들은 10배는 빠른 성장을 이룰 수 있을 것입니다.

본인도 한달만 지나면 까먹을 에러 로그를 복사해서 제대로 된 해결 과정도 없는 트러블 슈팅으로 블로그에 포스팅하는 개발자들이 많습니다. 그런데 당연하게도 제가 React.js, Next.js를 쓰면서 생기는 에러들은 한글로 작성된 국내 블로그 포스팅(저도 지금 쓰고 있지만)보다는 스택오버플로우 같은 곳에 있는 재야의 고수들이, 그리고 그들보다도 더 깊이 그 도구를 잘 알고 이해하고 있는 사람들이 이 상황에서는 React.js, Next.js 개발자들입니다. 누구보다 빠르게 단계를 올라가려면, 튼튼한 동아줄을 잡고 올라가야 합니다. 공식 문서나 깃헙 리포지토리만큼 오픈소스 도구를 잘 설명해줄 수 있는 곳은 드물 것입니다. 우리는 오픈소스 생태계에서 발생하는 이슈에 대해 적극적으로 참여하고, 이를 통해 성장하는 자세를 가져야 합니다. 그렇게 하면 어느 순간 돌아봤을 때 깃허브 잔디가 커밋과 푸시 뿐만 아니라 컨트리뷰트 수 높은 찐 개발자의 실력을 갖출 수 있을 것입니다.

반응형

댓글