세분화된 청크 분할로 Next.js 및 Gatsby 페이지 로드 성능 개선

Next.js 및 Gatsby의 새로운 웹팩 청크 전략은 중복 코드를 최소화하여 페이지 로드 성능을 개선합니다.

Chrome은 도구 및 기술과 공동작업을 통해 프레임워크에 대해 알아봤습니다. 최근 몇 가지 새로운 최적화가 Next.js개츠비입니다. 이 도움말에서는 개선된 세분화된 청킹 전략을 다룹니다. 이 두 가지 프레임워크가 기본적으로 제공됩니다.

소개

많은 웹 프레임워크와 마찬가지로 Next.js와 Gatsby는 webpack을 핵심 프레임워크로 사용합니다. Bundler webpack v3 출시 CommonsChunkPlugin를 사용하면 단일 또는 소수의 "공통"에 있는 서로 다른 진입점 간에 공유되는 출력 모듈 청크 (또는 제공합니다. 공유 코드는 별도로 다운로드하여 브라우저 캐시에 일찍 저장할 수 있으며, 로드 성능이 향상됩니다.

이 패턴은 진입점과 API를 채택하는 많은 단일 페이지 애플리케이션 프레임워크에서 번들 구성이 다음과 같이 표시됩니다.

공통 진입점 및 번들 구성

실용적이기는 하지만 모든 공유 모듈 코드를 단일 청크로 묶는 개념은 한계가 있습니다 일부 진입점에서 공유되지 않는 모듈은 모듈을 사용하지 않는 경로의 경우 다운로드할 수 있습니다. 필요 이상으로 많은 코드가 다운로드될 수 있습니다. 예를 들어 page1가 로드되는 경우 common 청크에서 page1moduleC를 사용하지 않더라도 moduleC의 코드를 로드합니다. 이러한 이유로 webpack v4는 다른 몇 가지 버전과 함께 플러그인을 제거했으며 1개: SplitChunksPlugin

청킹 개선

SplitChunksPlugin의 기본 설정은 대부분의 사용자에게 적합합니다. 여러 분할 청크는 여러 조건에 따라 생성되거나 여러 경로에서 중복된 코드를 가져오는 것을 방지합니다.

그러나 이 플러그인을 사용하는 많은 웹 프레임워크는 여전히 '단일 공통'을 따릅니다. 접근하는 방법을 있습니다. 예를 들어, Next.js는 commons 포함된 모든 모듈을 포함하는 번들을 페이지와 모든 프레임워크 종속 항목 (react, react-dom 등)의 50% 이상에서 사용됩니다.

const splitChunksConfigs = {
  …
  prod: {
    chunks: 'all',
    cacheGroups: {
      default: false,
      vendors: false,
      commons: {
        name: 'commons',
        chunks: 'all',
        minChunks: totalPages > 2 ? totalPages * 0.5 : 2,
      },
      react: {
        name: 'commons',
        chunks: 'all',
        test: /[\\/]node_modules[\\/](react|react-dom|scheduler|use-subscription)[\\/]/,
      },
    },
  },

프레임워크 종속 코드를 공유 청크에 포함하더라도 이를 다운로드하여 모든 진입점에서 캐시되며, 한 개 이상의 애플리케이션에서 사용되는 공통 모듈을 포함하는 페이지의 절반은 그다지 효과적이지 않습니다. 이 비율을 수정하면 다음 두 결과 중 하나만 나오게 됩니다.

  • 이 비율을 줄이면 불필요한 코드가 더 많이 다운로드됩니다.
  • 이 비율을 늘리면 여러 경로에서 더 많은 코드가 중복됩니다.

이 문제를 해결하기 위해 Next.js는 다양한 SplitChunksPlugin의 구성으로 코드가 필요하지 않습니다.

  • 충분히 큰 서드 파티 모듈 (160KB 초과)은 모두 자체 개별 모듈로 분할됩니다. 청크
  • 별도의 frameworks 청크가 프레임워크 종속 항목 (react, react-dom 및 등)
  • 필요한 만큼의 공유 청크가 생성됩니다 (최대 25개).
  • 생성될 청크의 최소 크기가 20KB로 변경됩니다.

이 세분화된 청킹 전략은 다음과 같은 이점을 제공합니다.

  • 페이지 로드 시간이 개선되었습니다. 단일 청크 대신 여러 공유 청크 방출 진입점에 대한 불필요한 (또는 중복된) 코드의 양을 최소화합니다.
  • 탐색 중 캐싱이 개선되었습니다. 대규모 라이브러리 및 프레임워크 종속 항목 분할 둘 다 캐시 무효화를 처리할 가능성이 낮기 때문에 캐시 무효화 가능성을 줄일 수 있습니다. 변경할 수 없습니다.

Next.js가 webpack-config.ts에서 채택한 전체 구성을 확인할 수 있습니다.

추가 HTTP 요청

SplitChunksPlugin는 세분화된 청크 분할의 기반을 정의했으며 이 접근 방식을 Next.js와 같은 프레임워크는 완전히 새로운 개념이 아니었습니다. 하지만 많은 프레임워크가 여전히 단일 휴리스틱과 '커먼즈'를 몇 가지 이유가 있습니다 여기에는 더 많은 HTTP 요청이 사이트 성능에 부정적인 영향을 줄 수 있습니다.

브라우저는 단일 출처 (Chrome의 경우 6개)에 대해 제한된 수의 TCP 연결만 열 수 있으므로 번들러가 출력하는 청크 수를 최소화하면 총 요청 수를 이 기준점 미만으로 유지됨 그러나 이는 HTTP/1.1에만 적용됩니다. HTTP/2의 멀티플렉싱 단일 연결을 통해 단일 연결을 사용하여 여러 요청을 동시에 스트리밍할 수 있습니다. 출처입니다. 즉, 일반적으로는 청크 수 제한에 대해 걱정할 필요가 없습니다. 배출됩니다.

모든 주요 브라우저는 HTTP/2를 지원합니다. Chrome 및 Next.js팀 Next.js의 단일 'commons'를 분할하여 요청 수가 증가하는지 확인하고자 했습니다. 번들 여러 공유 청크로 분할하면 로드 성능에 어떤 식으로든 영향을 미칠 수 있습니다. 이들은 먼저 최대 동시 요청 수를 수정하면서 단일 사이트의 성능 maxInitialRequests 속성

요청 수 증가에 따른 페이지 로드 성능

단일 웹페이지에서 평균 3회의 시도를 반복할 때 load님, start-render 최대 초기 페이지 조회수와 첫 번째 콘텐츠 페인트 횟수는 요청 수 (5~15)입니다. 흥미롭게도, 약간의 성능 오버헤드만 발생했으며 100% 증가합니다.

수백 건의 요청을 통한 페이지 로드 성능

이는 신뢰할 수 있는 기준 (20~25개의 요청)을 유지하는 것이 적절한 균형을 이루었음을 보여줍니다. 주요 차이점이 있습니다 기준 테스트를 거친 후 25개가 maxInitialRequest 개수

동시에 발생하는 최대 요청 수를 수정한 경우 두 개 이상이 발생했습니다. 각 진입점에 맞게 분리하여 작업 속도를 크게 필요한 양의 코드를 생성할 수 있습니다.

JavaScript 페이로드 감소로 청킹 증가

이 실험은 요청 횟수를 수정하여 부정적인 영향을 미칩니다. 결과는 maxInitialRequests를 테스트 페이지의 25는 속도 저하 없이 JavaScript 페이로드 크기를 줄였으므로 최적이었습니다. 표시됩니다. 페이지를 하이드레이션하는 데 필요한 총 JavaScript 양이 그대로 남아 있습니다. 이는 페이지 로드 성능이 개선되지 않았다는 것을 알 수 있습니다. 만들 수 있습니다

webpack은 30KB를 생성할 청크의 기본 최소 크기로 사용합니다. 그러나 maxInitialRequests 값 25(최소 크기 20KB) 대신 캐싱이 개선되었습니다.

세분화된 청크로 크기 축소

Next.js를 비롯한 많은 프레임워크가 (JavaScript에서 처리) 클라이언트 측 라우팅을 사용하여 스크립트 태그를 업데이트해야 합니다. 하지만 빌드 시에 이러한 동적 청크를 어떻게 미리 결정할까요?

Next.js는 서버 측 빌드 매니페스트 파일을 사용하여 출력된 청크를 다양한 진입점이 있습니다 이 정보를 클라이언트에게도 제공하기 위해 요약된 클라이언트 측 빌드 매니페스트 파일은 모든 진입점의 모든 종속 항목을 매핑하기 위해 생성되었습니다.

// Returns a promise for the dependencies for a particular route
getDependencies (route) {
  return this.promisedBuildManifest.then(
    man => (man[route] && man[route].map(url => `/_next/${url}`)) || []
  )
}
Next.js 애플리케이션에 있는 여러 공유 청크의 출력

이 새롭고 세분화된 청킹 전략은 플래그 뒤의 Next.js에서 처음 출시되었으며, 얼리 어답터 수 많은 사람이 IT 지원에 사용되는 전체 JavaScript를 전체 사이트:

를 통해 개인정보처리방침을 정의할 수 있습니다.
웹사이트 총 JS 변경 차이(%)
https://www.barnebys.com/ -238 KB 23% 감소
https://sumup.com/ -220 KB 30% 감소
https://www.hashicorp.com/ -11 MB 71% 감소
모든 경로에서 JavaScript 크기 감소 (압축)

최종 버전은 버전 9.2에 기본적으로 포함되어 있습니다.

개츠비

개츠비는 용도 기반 모델을 사용하는 것과 동일한 접근 방식을 따랐습니다. 일반적인 모듈을 정의하기 위한 휴리스틱입니다.

config.optimization = {
  …
  splitChunks: {
    name: false,
    chunks: `all`,
    cacheGroups: {
      default: false,
      vendors: false,
      commons: {
        name: `commons`,
        chunks: `all`,
        // if a chunk is used more than half the components count,
        // we can assume it's pretty global
        minChunks: componentsCount > 2 ? componentsCount * 0.5 : 2,
      },
      react: {
        name: `commons`,
        chunks: `all`,
        test: /[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/,
      },

유사한 세분화된 청킹 전략을 채택하도록 webpack 구성을 최적화함으로써 많은 대형 사이트에서 JavaScript가 상당히 크게 줄어든 것을 확인했습니다.

를 통해 개인정보처리방침을 정의할 수 있습니다.
웹사이트 총 JS 변경 차이(%)
https://www.gatsbyjs.org/ -680 KB 22% 감소
https://www.thirdandgrove.com/ -390 KB -25%
https://ghost.org/ -1.1 MB 35% 감소
https://reactjs.org/ -80KB -8%
모든 경로에서 JavaScript 크기 감소 (압축)

PR을 살펴보고 v2.20.7에 기본적으로 포함되어 있는 webpack 구성에 이 로직을 구현했습니다.

결론

세분화된 청크를 배송한다는 개념은 Next.js, Gatsby 또는 웹팩에만 국한되지 않습니다. 모든 사람 대규모 '공통점'을 따르는 경우 애플리케이션의 청크 전략 개선을 고려해야 함 사용하는 프레임워크나 모듈 번들러와 상관없이 모든 번들을 지원합니다.

  • 기본 React 애플리케이션에 동일한 청킹 최적화가 적용된 것을 보려면 이 샘플 React를 앱을 엽니다. Kubernetes는 단순화된 버전의 세분화된 청킹 전략과 동일한 전략을 적용하는 데 일종의 로직을 사용해야 합니다.
  • Rollup의 경우 청크가 기본적으로 세분화되어 생성됩니다. 살펴볼 항목 manualChunks(직접 설정) 동작을 구성합니다.