React

[Next.js] 로컬은 폰트 로드되는데 프로덕션은 로드 안됨(Development VS Production 간단 설명)

Bittersweet- 2024. 10. 14. 15:33
728x90

프로젝트 진행 중 한번은 개발(이하 로컬)에서는 멀쩡히 가져오던 font 소스가 Production(이하 프로덕션)에서는 제대로 가져오지도 적용하지도 못한 이슈를 확인해 본 적이 있다.

 

프로젝트 구성

  • Next.js 14
  • React 18(page router)
  • font: Pretendard, Montserrat

 

신규 배포가 아니라 이미 3개월 동안은 font가 제대로 사용되고 있었던 지라 당최 이유가 뭔지 알 수 없었다.

적용 코드.

font를 global.scss 파일에서 cdn import 함. 로컬에서 실행 시에는 network를 통해 font 다운로드가 확인됨.

사용 CDN

https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css

https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swape

프로덕션 적용 코드.

cdn이 적용되지 않음. network를 통해 다운되는 font가 없음.

 확인 사항

  1. cdn의 경로가 절대 경로인지 check - yes!
  2. 빌드된 css, html 확인 및 실제 정적 파일 유무 확인 - yes!
  3. cors 설정과 같은 외부 cdn 관련 문제를 확인하여 폰트가 제대로 로드되는지 확인 - cors 에러 안나고 아예 font가 로드되지 않음

 

결론.

_document.tsx 파일의 특성을 활용하여 <link> 태그를 이용해서 font를 런타임 시점에 로드하거나 public 폴더 내부에 font 파일을 저장해서 빌드 시점에 프로젝트에 font를 이미 가져가도록 설정하는 방법 중 전자의 방법을 택!!

 

 

Next.js는 _document.tsx파일을 사용하여 HTML 문서의 기본 구조를 설정한다.

_document.tsx는 서버에서 한 번만 렌더링 되며, 모든 페이지에 대해 공통으로 적용되어 font와 같은 리소스를 가져오면, Next.js가 서버에서 HTML을 생성할 때 해당 <link> 태그를 포함한다.

하지만 실제로 font는 HTML을 수신한 후 클라이언트 측 런타임(브라우저가 페이지를 로드할 때) 다운로드 된다.

 

rel="preload"를 사용하면 브라우저가 페이지 로드 중에 폰트를 미리 다운로드하게 되어 font 로딩 시간을 줄일 수 있다.

 

외부 CDN에서 font를 로드하는 경우, CORS 설정이 제대로 되어 있어야 font가 제대로 로드되므로, 

crossOrigin="anonymous"를 사용할 수 있다.

이는 CORS(Cross-Origin Resource Sharing) 설정과 관련된 속성으로, 브라우저가 외부 리소스(예: 폰트, 이미지, 비디오 등)를 다른 도메인에서 가져올 때 **자격 증명(쿠키, 인증 헤더 등)**을 포함하지 않고 요청하도록 설정하는 옵션이다.

 

_document.tsx 코드를 수정했더니 로컬도 프로덕션도 폰트 적용이 잘 됐다.

 

나중에 알게된 사실은 next.js는 google font를 지원하기 때문에 최적화로 적용하는 방식이 따로 있었고, 그 외 폰트는 로컬 적용(즉, 폰트 파일을 프로젝트에 포함시켜 빌드 시 가지고 있음)이 공식문서에 기재되어 있었다. 하핫..

그렇게 하면 되지 뭐. 수정하면 되지 뭐~ 헤헷

다시 수정하는 story는 다음 기회에.. 헤헤

 

Next.js font 최적화 적용하기

 

 

 

 

 

음.. 근데 왜 로컬이랑 prod랑 왜 달라??? (왜 나를 힘들게 해...)

 

그래서 알아봤다!!! 개발 모드랑 프로덕션 모드랑 뭐가 다르냐!!!!

 

 

<h1> 개발 모드 vs 프로덕션 모드 </h1>

로컬 실행 (개발 모드)

  • Next.js는 빠른 피드백을 제공하기 위해 개발 모드에서 소스 코드가 실시간으로 컴파일되고, 핫 리로딩(Fast Refresh)이 활성화되어 저장할 때마다 자동으로 페이지가 새로고침된다.
  • 또한, 코드 타입 안정성을 확보하고, 코드 스타일 및 품질 검사를 실시간으로 수행하여 오류를 빨리 찾아 수정할 수 있게 해준다.(TypeScript, ESLint integeration 등)
  • 개발 모드에서는 오류 메시지가 더 상세히 표시되어 디버깅에 최적화되어 있으며, 성능 최적화는 크게 고려되지 않는다.
  • 즉, Next.js는 개발 모드에서 개발을 위한 최적화된 빌드를 제공한다.

빌드 및 배포(프로덕션 모드)

  • build 명령어를 사용하여 프로젝트의 소스 코드를 프로덕션 모드로 컴파일 한다. 이 과정에서 코드가 최적화되고, 불필요한 부분은 제거(minigying) 되며, React는 디버깅을 위한 개발용 코드 대신 최적화된 코드로 교체된다.
  • 이 때, 코드 스플리팅, 트리 쉐이킹 등 성능 최적화가 적용되어 최종 번들의 크기가 줄어든다.
  • 프로덕션 모드는 애플리케이션을 사용할 유저와 유저의 경험을 최적화 해준다. 이때 성능과 접근성을 향상시키기 위해 코드를 변환하는 것을 목표로 한다.
구분 로컬 실행(개발 모드) 빌드 및 배포(프로덕션 모드)
정적 최적화 * Next.js가 동적 페이지도 실시간으로 렌더링하여 서버 측에서 매번 데이터를 가져와 페이지를 그린다. * 빌드 시 정적 사이트 생성(SSG)나 서버 사이드 렌더링(SSR)이 설정된 페이지는 미리 렌더링된다.
* 정적 페이지는 배포 후에도 그대로 사용되며, 필요에 따라 API 요청으로 데이터를 가져온다.
* 정적 최적화로 인해 배포된 웹사이트는 더 빠르게 로드될 수 있다.
성능 최적화 * 개발 모드에서 성능 최적화는 거의 적용되지 않고, 주로 디버깅과 빠른 개발을 위한 설정이 반영된다. * 프로덕션 빌드에서는 성능 최적화가 핵심으로 React에서 불필요한 코드가 제거되고, 번들 크기가 줄어들며, CSS와 JavaScript 파일들이 압출된다.
* 또한, 이미지 최적화도 자동으로 수행된다.
소스맵(Source Map) * 소스맵이 기본적으로 포함되어 있어 디버깅 시 원본 소스 코를 쉽게 추적할 수 있다. * 프로덕션 환경에서는 소스맵을 포함하지 않거나 외부로 공개되지 않도록 설정하여 보안을 유지한다.

 

내용이 더 길어지면 (나의) 집중력 저하와 졸음을 유발하므로 이쯤에서 THE END - 끗!!

 

그럼 이만.. 총총총