원문 https://dev.to/napoleon039/what-is-code-splitting-22ni

img1

코드 스플리팅

  • 코드를 다양한 청크(chunk)로 나눌 수 있으며 필요에 따라 로드할 수 있다.
  • 페이지 렌더링에 필요한 초기 응답 크기를 줄이는 데 도움이 된다.

코드 스플리팅을 통해 사이트의 효율성을 높이는 방법


여러분이 웹사이트를 만들었다고 가정해보자. 색상 대비도 좋고, 작은 애니메이션들을 사용해서 상호작용하기에도 편하고, 전반적으로 좋아 보이는 웹사이트를 만들었다.

하지만 첫 로드에 걸리는 시간이 길다고 느껴졌다. 왜 이렇게 오래 걸리는 걸까? 코드에는 아무런 문제가 없는 것 같아 더 의문에 빠졌다.

이유는 한 페이지만 로드하면 되는 첫 시작 페이지에서 필요로 하지 않는 여러 페이지(또는 프레임워크를 사용하는 경우 import한 컴포넌트 파일)를 로딩하기 때문이다.

웹팩은 이러한 문제점에 대한 해결책으로 코드 스플리팅(code-splitting)을 제공한다. 코드 스플리팅 기능은 특정 프레임워크에 속한 기능이 아니므로 웹팩을 사용하여 언제든지 적용할 수 있다.

소개

이 글은 Vue에서 코드 수플리팅의 대한 내용을 다룬다. 자세히 말하면, Vue 컴포넌트를 경로별로 코드 스플리팅을 사용하였다. 코드 스플리팅은 웹 사이트를 더 빠르게 운영하는 데 도움이 되는 중요한 주제이다. 페이지에 필요한 컴포넌트만 로드되고, 원한다면 다른 컴포넌트도 함께 로드할 수 있다. 많은 컴포넌트를 작성하고 여러 경로를 설정(라우팅)해 주어야 하는 대형 프로젝트에서 코드 스플리팅을 사용하면 로드 시간을 단축하여 사이트 성능을 향상시킬 것이다.

이 글을 최대한 활용하려면 Vue Router가 설치된 Vue 프로젝트가 좋겠다. 경로 설정에 코드 스플리팅 기능을 적용할 것이기 때문에 라우터(Router)가 필요하다. 물론, Vue가 아닌 다른 프레임워크에서도 코드 스플리팅 기능을 사용할 수 있다. 앞서 언급했듯이, 코드 스플리팅 기능은 프레임워크와는 관련이 없다. 코드를 분할하기 위한 세 가지 접근방식이 있다. 여기서는 세 가지 접근방식 중 동적 가져오기(dynamic import)에 대한 내용만 다룰 것이다. 코드 스플리팅에 대한 더 자세한 정보를 얻고 싶다면 웹팩 문서를 확인하자.

개념 비유

그릇에 있는 주스를 마시고 싶다고 가정해보자. 전체를 한 번에 다 마시지 말고 원하는 양만큼 따라 마신 다음, 그릇에 다시 넣는다. 우리가 하는 일은 주스를 유리잔에 마실 만큼 따르고, 더 먹고 싶다면 조금씩 더 따라 마시는 것이다. 코드 스플리팅도 이와 비슷한 개념이다. 큰 설정 작업이 필요할 것 같지만 빠르게 적용할 수 있다. 바로 시작해보자.

프로젝트 설정

Vue 라우터를 사용하는 Vue 프로젝트가 필요하다. 만약에 없다면, 간단한 샘플 코드를 만들어보자. 코드가 분할된 결과를 명확히 확인하기 위해 두 개 이상의 컴포넌트가 필요하다. 여기에서 컴포넌트 내용이 <h1>로만 이루어져 있는 것은 중요하지 않다. 실제로 코드 스플리팅이 어떻게 적용되는지 이해하는 것이 중요하다. 아직 프로젝트가 없다면 어서 프로젝트를 설정해보자. 여기 샘플 코드가 있다.

img1

img2

우선, 바벨의 동적 가져오기 플러그인을 설치한다.

img3

바벨이 이 플러그인을 요구하는 이유는 웹팩이 동적 가져오기를 이해하고 이에 맞게 번들링 하는데, 서버 측에서 바벨이 import 구문을 해석하고 트랜스파일하기 위함이다. Satyajit Sahoo는 babeljs 슬랙에서 이에 대해 꽤 잘 설명해주었다.

img4

syntax-dynamic-import는 바빌론(babylon)에서 구문 사용만 가능하게 해준다. 즉, 바빌론이 구문 오류 없이 코드를 구문 분석할 수 있다는 말이다. 여전히 이해할 수 없는 import(...)코드가 남아있으며, 트랜스 파일 해야 한다. dynamic-import-nodeimport(...)를 이해할 수 있는 require로 트랜스파일한다. 클라이언트 측에서, 웹팩이 구문을 이해하고 번들링 하므로 트랜스파일 단계가 필요 없다.

다음은 새로 설치된 플러그인을 바벨 설정 파일에 포함한다.

img5

프로젝트 설정은 끝났다. 이제 주요 내용을 살펴보자.

코드 스플리팅 구현

router.js파일에 포함할 컴포넌트를 가져오는 일반적인 방법은 아래와 같다.

img6

현재 코드를 저장하고 개발 서버를 띄운다.

# 개발 서버 실행
npm run dev # Vue v2.x 용

npm run serve # Vue v3.x 용

크롬, 파이어폭스 또는 원하는 브라우저를 띄어 사이트에 접속한다. 개발자 도구를 열고[F12 키보드 사용] 네트워크 탭으로 이동하여 페이지를 리로드해보자. 컴포넌트가 둘 다 로딩되는 것을 볼 수 있다. (역자주: 번들된 app.js 파일을 보면 두 개의 컴포넌트 내용이 모두 포함되어 있다) 필터에서 JS를 선택하면, (결과 목록 살짝 위쪽에 배치되어 있음, 아래 스크린샷 참조), app.js가 보일 것이며 크기를 확인해보자.

img7

코드 스플리팅 없이 초기 로드 시 About 컴포넌트는 아직 필요하지 않더라도 Home 컴포넌트와 함께 번들 파일로 제공된다. 초기 로드가 필요하지 않은 컴포넌트는 번들 파일에 포함되지 않도록 수정해보자. 프로미스(Promise) 방식으로 가져오는 방법이 있다. 프로미스를 지원하지 않는 구형 브라우저를 위해 폴리필을 포함하는 것도 잊지 말자.

img8

import 구문을 반환하는 함수를 작성해주기만 하면 끝이다. 이것이 동적 가져오기 구문이다. 웹팩은 import 구문을 만날 때마다 프로미스에 대한 응답으로 코드 스플리팅이라고 불리는 청크를 생성한다. 이제 코드를 저장하고 페이지를 리로드 한 다음 네트워크 탭을 확인해보자. 컴포넌트가 모두 로드되지 않는다. 경로를 바꿔 하나씩 방문하면 컴포넌트가 결과 창에 차례로 추가되는 것을 확인할 수 있다. 아래 이미지는 네트워크 탭에서 경로를 바꿔가며 하나씩 방문해본 결과이다.

img9

img10

해냈다! 앞에서 개념 비유를 들면서 주스를 나눠 마시라고 했다. 한 번에 다 먹지 말라고 했던걸 기억해라. ;)

잠깐! 네트워크 탭에 표시된 파일 이름이 숫자로 표시되어 있어 직관적이지 않다. import 구문에 주석을 추가하여 문제를 해결해보자.

img10

웹팩은 주석에 있는 문자 그대로 청크 이름으로 해석한다. webpackChunkName에 입력한 값은 숫자 대신 컴포넌트를 나타내는 이름이 된다. 이제 개발자 도구에서도 보고 있는 파일이 무엇인지 알 수 있다. 아마 About 컴포넌트가 여전히 초기 로드시에도 존재한다는 것을 볼 수 있다. 그러나 파일 크기를 확인해보면 0바이트로 실제 컴포넌트가 로드되는 것이 아니다. 아마도 Vue 개발 서버 내부에서 이루어지는 동작일 것이다. 실제 컴포넌트는 해당 경로를 방문할 때만 로드된다.

좀 더 실질적인 예

코드 스플리팅을 주스 나눠 마시기에 비유하였는데, 현실에서 코드 스플리팅이 어떻게 활용되었을까?

실제 앱에서 어떻게 작동하는지 살펴보자. 예를 들어, 이미지가 많은 웹 사이트가 있다고 가정하자. 홈 경로도 있고, 여러 경로를 포함하고 있는데, 각각의 경로에서 이미지를 많이 포함하고 있다. 처음 웹 사이트에 접속하면 홈 컴포넌트가 로드될 것이다. 홈 컴포넌트에는 적은 개수의 애니메이션과 이미지가 포함되어있지만 다른 경로에 있는 컴포넌트가 많은 이미지를 사용하기 때문에 홈 컴포넌트가 느리게 렌더링 될 것이다. 또 다른 컴포넌트에서는 애니메이션 몇 개를 포함할 수 도있다. 홈페이지에서 이러한 모든 컴포넌트들을 다 가져올 것이다. 이미지가 많아 무거운 페이지가 왜 느리게 렌더링하고 로드되는지 이해될 것이다. 그러나 웹 사이트의 홈페이지는 빠르게 로딩되어야 한다. 경로에 따라 컴포넌트 코드를 분할하여 로드하는 것이 이상적인 해결책이 될 것이다. 이러한 문제점을 직면할 수 있는 현실적인 예시로 인스타그램이나 핀터레스트를 들 수 있겠다.

웹팩 문서에 방문해서 다른 두 가지 접근법에 관해서도 확인해보자. 동적 가져오기만으로 해결되지 않는 경우 다른 접근법이 도움이 될지 모른다. 처음 코드 스플리팅에 대해 접했던 Egghead.io의 커뮤니티 리소스도 방문해 보면 도움이 될 것이다.

이쯤에서 글을 마치겠다. 이 글에 대한 생각과 얼마큼 도움이 되었는지 아래 코멘트에 알려주길 바란다. 만약 질문이나 제안이 있다면 언제든지 작성해주길 바란다.