코드 분할로 자바스크립트 페이로드 줄이기

대부분의 웹페이지와 애플리케이션은 여러 다른 부분으로 구성됩니다. 첫 페이지가 로드되는 즉시 애플리케이션을 구성하는 모든 JavaScript를 전송하는 대신 JavaScript를 여러 단위로 분할하면 페이지 성능이 향상됩니다.

이 Codelab에서는 코드 분할을 사용하여 세 개의 숫자를 정렬하는 간단한 애플리케이션의 성능을 개선하는 방법을 보여줍니다.

숫자를 입력할 수 있는 3개의 필드와 정렬 버튼이 있는 Magic Sorter라는 이름의 애플리케이션이 브라우저 창에 표시되어 있습니다.

측정

항상 그렇듯이 최적화를 추가하기 전에 먼저 웹사이트의 성능을 측정하는 것이 중요합니다.

  1. 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.
  2. `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  3. 네트워크 탭을 클릭합니다.
  4. 캐시 사용 중지 체크박스를 선택합니다.
  5. 앱을 새로고침합니다.

71.2KB 자바스크립트 번들을 보여주는 네트워크 패널

간단한 애플리케이션에서 몇 개의 숫자를 정렬하는 데 필요한 71.2KB 상당의 JavaScript입니다. 어떻게 된 일인가요?

소스 코드 (src/index.js)에서 lodash 라이브러리를 가져와서 이 애플리케이션에서 사용합니다. Lodash는 여러 유용한 유틸리티 함수를 제공하지만 여기서는 패키지의 하나의 메서드만 사용됩니다. 일부만 사용되는 서드 파티 종속 항목 전체를 설치하고 가져오는 것은 흔히 발생하는 실수입니다.

최적화

번들 크기를 자를 수 있는 몇 가지 방법이 있습니다.

  1. 서드 파티 라이브러리를 가져오는 대신 맞춤 정렬 방법 작성
  2. 내장된 Array.prototype.sort() 메서드를 사용하여 숫자 정렬
  3. 전체 라이브러리가 아닌 lodash에서 sortBy 메서드만 가져옵니다.
  4. 사용자가 버튼을 클릭할 때만 정렬용 코드 다운로드

옵션 1과 2는 번들 크기를 줄이는 데 완벽하게 적합한 방법입니다 (아마도 실제 애플리케이션에 가장 적합할 수 있음). 하지만 이 튜토리얼은 이 튜토리얼에서 윤리를 가르치기 위해 사용되지 않습니다.

옵션 3과 4 모두 이 애플리케이션의 성능을 개선하는 데 도움이 됩니다. 이 Codelab의 다음 섹션에서 이러한 단계를 다룹니다. 다른 코딩 튜토리얼과 마찬가지로 항상 복사하여 붙여넣는 대신 직접 코드를 작성해 보세요.

필요한 항목만 가져오기

lodash에서 단일 메서드만 가져오려면 일부 파일을 수정해야 합니다. 시작하려면 package.json에서 이 종속 항목을 바꿉니다.

"lodash": "^4.7.0",

다음과 같이 바꿉니다.

"lodash.sortby": "^4.7.0",

이제 src/index.js에서 다음 특정 모듈을 가져옵니다.

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

값이 정렬되는 방식을 업데이트합니다.

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

애플리케이션을 새로고침하고 DevTools를 연 다음 Network 패널을 다시 한번 살펴봅니다.

15.2KB 자바스크립트 번들을 보여주는 네트워크 패널

이 애플리케이션의 경우 거의 작업하지 않고도 번들 크기가 4배 이상 줄어들었지만 여전히 개선의 여지가 있습니다.

코드 분할

webpack은 현재 가장 많이 사용되는 오픈소스 모듈 번들러 중 하나입니다. 즉, 웹 애플리케이션을 구성하는 모든 자바스크립트 모듈 (기타 애셋 포함)을 브라우저에서 읽을 수 있는 정적 파일로 번들합니다.

이 애플리케이션에 사용되는 단일 번들은 다음과 같이 두 개의 개별 청크로 분할할 수 있습니다.

  • 초기 경로를 구성하는 코드를 담당하는 사람은
  • 정렬 코드가 포함된 보조 청크

동적 가져오기를 사용하면 보조 청크를 지연 로드하거나 주문형으로 로드할 수 있습니다. 이 애플리케이션에서 청크를 구성하는 코드는 사용자가 버튼을 누를 때만 로드할 수 있습니다.

먼저 src/index.js에서 정렬 메서드의 최상위 가져오기를 삭제합니다.

import sortBy from "lodash.sortby";

또한 버튼을 누르면 실행되는 이벤트 리스너 내에서 가져옵니다.

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

import() 기능은 모듈을 동적으로 가져오는 기능을 포함하는 제안 (현재 TC39 프로세스의 3단계)의 일부입니다. webpack에는 이 기능에 관한 지원이 이미 포함되어 있으며 제안서에 나와 있는 것과 동일한 구문을 따릅니다.

import()가 프로미스를 반환하고, 프로미스가 해결되면 별도의 청크로 분할된 선택된 모듈이 제공됩니다. 모듈이 반환된 후 module.default는 lodash에서 제공하는 기본 내보내기를 참조하는 데 사용됩니다. 프로미스는 sortInput 메서드를 호출하여 입력 값 3개를 정렬하는 또 다른 .then와 체이닝됩니다. 프로미스 체인의 마지막에는 .catch()는 오류로 인해 프로미스가 거부된 경우를 처리하는 데 사용됩니다.

마지막으로 해야 할 작업은 파일 끝에 sortInput 메서드를 작성하는 것입니다. lodash.sortBy에서 가져온 메서드를 가져오는 함수를 반환하는 함수여야 합니다. 그러면 중첩된 함수가 3개의 입력 값을 정렬하고 DOM을 업데이트할 수 있습니다.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

모니터링

애플리케이션을 마지막으로 한 번 새로고침하고 Network(네트워크) 패널을 다시 자세히 확인합니다. 앱이 로드되는 즉시 작은 초기 번들만 다운로드됩니다.

2.7KB 자바스크립트 번들을 보여주는 네트워크 패널

버튼을 눌러 입력 번호를 정렬하면 정렬 코드가 포함된 청크를 가져와 실행합니다.

2.7KB 자바스크립트 번들과 13.9KB 자바스크립트 번들이 차례로 표시된 네트워크 패널

숫자가 계속 정렬되는 것을 볼 수 있습니다.

결론

코드 분할 및 지연 로드는 애플리케이션의 초기 번들 크기를 줄이는 매우 유용한 기법이며, 이로 인해 페이지 로드 시간이 직접적으로 크게 단축될 수 있습니다. 그러나 이 최적화를 애플리케이션에 포함하기 전에 고려해야 할 중요한 사항이 있습니다.

지연 로드 UI

코드의 특정 모듈을 지연 로드할 때는 네트워크 연결이 약한 사용자에게 어떤 환경이 제공될지 고려하는 것이 중요합니다. 사용자가 작업을 제출할 때 매우 큰 코드 청크를 분할하고 로드하면 애플리케이션이 작동을 멈춘 것처럼 보일 수 있으므로 로드 표시기를 표시하는 것이 좋습니다.

서드 파티 노드 모듈 지연 로드

애플리케이션에서 서드 파티 종속 항목을 지연 로드하는 데 항상 최선의 방법은 아니며 종속 항목을 사용하는 위치에 따라 다릅니다. 일반적으로 서드 파티 종속 항목은 자주 업데이트되지 않으므로 캐시할 수 있는 별도의 vendor 번들로 분할됩니다. 이를 수행하는 데 SplitChunksPlugin의 지원 방법에 대해 자세히 알아보세요.

JavaScript 프레임워크를 사용한 지연 로드

webpack을 사용하는 여러 인기 프레임워크 및 라이브러리는 애플리케이션 중간에 동적 가져오기를 사용하는 것보다 지연 로드를 더 쉽게 만드는 추상화를 제공합니다.

동적 가져오기의 작동 방식을 이해하는 것이 유용하지만 항상 프레임워크/라이브러리에서 권장하는 메서드를 사용하여 특정 모듈을 지연 로드하세요.

미리 로드 및 미리 가져오기

가능하면 <link rel="preload"> 또는 <link rel="prefetch">와 같은 브라우저 힌트를 활용하여 중요한 모듈을 더 빨리 로드해 보세요. webpack은 import 문에서 매직 주석을 사용하여 두 힌트를 모두 지원합니다. 자세한 내용은 중요 청크 미리 로드 가이드에 설명되어 있습니다.

코드 이상의 지연 로드

이미지는 애플리케이션의 중요한 부분을 구성할 수 있습니다. 스크롤해야 볼 수 있는 부분이나 기기 표시 영역을 벗어난 콘텐츠를 지연 로드하면 웹사이트 속도가 빨라질 수 있습니다. 자세한 내용은 Lazysizes 가이드를 참고하세요.