Script Optimization
Application Scripts
전역에 스크립트 로드
•
사용자 지정 _app에 next/script 를 불러와 적용
•
스크립트는 애플리케이션의 모든 경로에 액세스할 때 로드되고 실행
•
Next.js는 사용자가 여러 페이지를 탐색해도 스크립트를 한 번만 로드
성능 최적화를 위해서는 되도록 특정 페이지에만 스크립트를 포함해야 함
// pages/_app.js
import Script from 'next/script'
export default function MyApp({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Script src="경로명" />
</>
)
}
JavaScript
복사
전략
•
strategy 속성을 사용하여 스크립트의 로드 동작을 조정할 수 있음
전략명 | 동작 |
afterInteractive | [기본값] 페이지에 일부 또는 전체 하이드레이션 발생 후에 스크립트 로드 |
beforeInteractive | Next.js 코드 로딩과 페이지 하이드레이션 발생 전 스크립트 로드 |
lazyOnload | 브라우저 유휴 시간 동안 스크립트를 lazyload |
worker | [실험 기능] 스크립트를 웹 워커에서 로드 |
[Appendix] 하이드레이션이란(Hydration)?
전략별 자세한 내용은 아래 링크에서 확인
web worker에 스크립트 오프로드 (실험 기능)
worker 전략은 stable 아님 / 앱 디렉토리에서 아직 작동하지 않음
[Appendix] 오프로드란(offload)?
•
연산 작업을 외부로 전송해서 처리
계산 오프로딩은 리소스 집약적인 계산 작업을 하드웨어 가속기와 같은 별도의 프로세서 또는 클러스터, 그리드 또는 클라우드와 같은 외부 플랫폼으로 전송하는 것입니다. (…)
Computation offloading is the transfer of resource intensive computational tasks to a separate processor, such as a hardware accelerator, or an external platform, such as a cluster, grid, or a cloud.
•
적용 방법
•
next.config.js 에서 nextScriptWorkers 플래그 활성화
module.exports = {
experimental: {
nextScriptWorkers: true,
},
}
JavaScript
복사
•
npm run dev 실행시 Next.js 가 필요한 패키지 설치 과정 안내
npm run dev
(...)
Please install Partytown by running npm install @builder.io/partytown
JavaScript
복사
•
설치 후 strategy="worker" 정의 시 Partytown이 인스턴스화되고 스크립트가 웹 워커로 오프로드
// pages/home.tsx
import Script from 'next/script'
export default function Home() {
return (
<>
<Script src="https://example.com/script.js" strategy="worker" />
</>
)
}
JavaScript
복사
인라인 스크립트
•
인라인 스크립트 또는 외부 파일에서 로드되지 않은 스크립트도 스크립트 컴포넌트에서 지원
◦
중괄호 안에 JavaScript 작성하는 방법
<Script id="show-banner">
{`document.getElementById('banner').classList.remove('hidden')`}
</Script>
JavaScript
복사
◦
dangerouslySetInnerHTML 속성을 사용하는 방법
<Script
id="show-banner"
dangerouslySetInnerHTML={{
__html: `document.getElementById('banner').classList.remove('hidden')`,
}}
/>
JavaScript
복사
Next.js가 스크립트를 추적 및 최적화하려면 인라인 스크립트에 id 속성을 할당해야 함
추가 코드 실행 (후속 처리 메서드)
핸들러 명 | 실행 타이밍 |
onLoad | 스크립트 로딩 완료 후 코드 실행 |
onReady | 스크립트 로딩 완료 후 컴포넌트가 마운트될 때마다 코드 실행 |
onError | 스크립트 로딩에 실패 시 코드를 실행 |
"use client”가 정의된 클라이언트 컴포넌트 내부에서 사용할 때만 작동
'use client'
import Script from 'next/script'
export default function Page() {
return (
<>
<Script
src="https://example.com/script.js"
onLoad={() => {
console.log('Script has loaded')
}}
/>
</>
)
}
JavaScript
복사
추가 속성
•
nonce 또는 사용자 정의 데이터 속성 포함 시 <script> 요소로 자동 전달
import Script from 'next/script'
export default function Page() {
return (
<>
<Script
src="https://example.com/script.js"
id="example-script"
nonce="XUENAJFW"
data-test="script"
/>
</>
)
}
JavaScript
복사
[Appendix] nonce 란?
25.07.24 업데이트
다른 분이 올린 PR의 코드 리뷰를 보면서 아래와 같은 코드를 보았다
<Script
src= (...)
defer
strategy={"beforeInteractive"}
/>
TypeScript
복사
defer 속성과 strategy의 beforeInteractive 가 동시에 쓰이는 것이 상당히 이상한 부분이었다.
•
기존 native <script> 태그에서의 defer 속성을 next/script 에서도 사용할 수 있는지?
•
defer와 beforeInteractive는 의미상 정반대인데 이렇게 되면 어떻게 동작하는지?
[Appendix] script 의 async , defer 의 과정을 도식화한 장표
아쉽게도 Next.js 공식문서 내 Script 항목에서는 해당 내용을 찾을 수 없었다. 오직 next/script 에서 지원하는 속성에 대한 설명이 나와있었다.
검색에서도 관련 된 내용을 찾기 힘들어서 next/script 의 구현체 파일을 찾아보았다. 파일에는 생각보다 상세한 주석이 나와있었다.
// Before interactive scripts need to be loaded by Next.js' runtime instead
// of native <script> tags, because they no longer have `defer`.
TypeScript
복사
beforeInteractive 를 사용한 경우에는 Next.js에서 자체적으로 관리하는 런타임에 의해 스크립트가 로딩된다는 언급이 있었다. Next.js의 런타임에 대해 궁금한 점이 있었지만, 당장은 시간을 쓰기 어려워 더 찾아보지는 못했다.
단순히 native <script> 를 래핑한 형태가 아니라면 세세한 실행 타이밍 관리에 있어서, 기존 다른 환경에서Next.js로의 마이그레이션 시 문제가 발생할 것 같아 궁금하기도 하고 약간 걱정이 되기도 하였다. 만약, next/script 를 사용할 일이 있으면 다양한 시나리오에 대해 컴토하고, next/script 의 동작원리를 더 살펴볼 필요가 있다는 생각이 들었다.