Skip to content

πŸ’Ž 트리 μ‰μ΄ν‚ΉμœΌλ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈ νŽ˜μ΄λ‘œλ“œ 쀄이기 #24

@seungyeub

Description

@seungyeub

트리 μ‰μ΄ν‚ΉμœΌλ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈ νŽ˜μ΄λ‘œλ“œ 쀄이기


원문 : https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking/#go_shake_some_trees

κ°€μ Έμ˜¨ κΈ€ : https://ui.toast.com/weekly-pick/ko_20180716/

μ˜€λŠ˜λ‚  μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜λ“€μ€ ꡉμž₯히 크고, λŒ€λΆ€λΆ„ μžλ°”μŠ€ν¬λ¦½νŠΈλ‘œ λ§Œλ“€μ–΄μ§„ 것이닀. 2018λ…„ μ€‘μˆœ, HTTP Archiveκ°€ 보여쀀 λͺ¨λ°”일 μž₯μΉ˜μ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 평균 전솑 ν¬κΈ°λŠ” μ•½ 350 KB 이닀. 이것은 λ‹¨μˆœνžˆ 전솑 크기이닀! μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ„€νŠΈμ›Œν¬ 전솑될 λ•Œ 주둜 μ••μΆ•λœλ‹€. μ΄λŠ” 압좕을 ν’€κ³  λ‚˜λ©΄ μžλ°”μŠ€ν¬λ¦½νŠΈ μ‹€μ œ 크기가 더 λŠ˜μ–΄λ‚œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. μ€‘μš”ν•œ ν¬μΈνŠΈλ‹€. μžμ› ν”„λ‘œμ„Έμ‹±μ΄ κ±±μ •λœλ‹€λ©΄, 압좕은 μ μ ˆν•˜μ§€ μ•Šλ‹€. μ••μΆ•λ˜μ§€ μ•Šμ€ 900 KB의 μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” νŒŒμ„œμ™€ μ»΄νŒŒμΌλŸ¬μ—μ„œ μ—¬μ „νžˆ λ™μΌν•œ 크기λ₯Ό κ°€μ§€κ³ , μ••μΆ•λ˜λ©΄ 300 KBκΉŒμ§€ μ€„μ–΄λ“€κ²Œ 될 것이닀.

img

κ·Έλ¦Ό 1. μžλ°”μŠ€ν¬λ¦½νŠΈ λ‹€μš΄λ‘œλ“œμ™€ μ‹€ν–‰ κ³Όμ •. 슀크립트의 전솑 ν¬κΈ°λŠ” 300 KB둜 μ••μΆ•λ˜μ§€λ§Œ, νŒŒμ‹±λ˜κ³  컴파일 및 μ‹€ν–‰λ˜λ©΄ 900 KB둜 λŠ˜μ–΄λ‚œλ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μˆ˜ν–‰ν•˜λŠ”λ° λΉ„μš©μ΄ 많이 λ“œλŠ” μžμ›μ΄λ‹€. λ‹€μš΄λ‘œλ“œν•˜λŠ” λ™μ•ˆμ—λ§Œ 잠깐 λ””μ½”λ”© μ‹œκ°„μ΄ λ°œμƒν•˜λŠ” 이미지와 λ‹€λ₯΄κ²Œ, μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” νŒŒμ‹±λ˜κ³  컴파일되고 λ§ˆμΉ¨λ‚΄ μ‹€ν–‰λœλ‹€. λ°”μ΄νŠΈ λ‹¨μœ„μ˜ 전솑은, λ‹€λ₯Έ μ’…λ₯˜μ˜ μžμ›λ³΄λ‹€ μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ 더 λ§Žμ€ λΉ„μš©μ„ λ°œμƒμ‹œν‚¨λ‹€.

img

κ·Έλ¦Ό 2. 170 KB 크기의 μžλ°”μŠ€ν¬λ¦½νŠΈ νŒŒμ‹±/컴파일링 μˆ˜ν–‰ λΉ„μš© vs λ™μΌν•œ 크기의 JPEG 이미지 λ””μ½”λ”© μ‹œκ°„ (좜처)

μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„ νš¨μœ¨μ„±μ„ ν–₯μƒμ‹œν‚€κΈ° μœ„ν•œ 지속적인 κ°œμ„ μ΄ μ΄λ£¨μ–΄μ§€λŠ” 반면 늘 κ·Έλ ‡λ“―, μžλ°”μŠ€ν¬λ¦½νŠΈ μ„±λŠ₯ ν–₯상은 개발자의 λͺ«μ΄λ‹€. κ²°κ΅­, μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ 섀계λ₯Ό κ°œμ„ ν•˜λŠ”λ° 개발자 μžμ‹ λ³΄λ‹€ 더 λ‚˜μ€ μ‚¬λžŒμ΄ μžˆμ„κΉŒ?

λ§ˆμ§€λ§‰μ€ μžλ°”μŠ€ν¬λ¦½νŠΈ μ„±λŠ₯을 κ°œμ„ ν•˜κΈ° μœ„ν•œ κΈ°μˆ λ“€μ΄ μžˆλ‹€. μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…(Code Splitting)은 μžλ°”μŠ€ν¬λ¦½νŠΈ 청크둜 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λΆ„ν• ν•˜κ³ , 청크λ₯Ό ν•„μš”λ‘œ ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ κ²½λ‘œμ—λ§Œ 이 청크듀을 λ°°λΆ„ν•˜μ—¬ μ„±λŠ₯을 κ°œμ„ ν•˜λŠ” κΈ°μˆ μ΄λ‹€. κ·ΈλŸ¬λ‚˜ 이 κΈ°μˆ μ„ μ‚¬μš©ν•œλ‹€κ³  ν•΄μ„œ, μ‚¬μš©λ˜μ§€ μ•ŠλŠ” μ½”λ“œλ₯Ό ν¬ν•¨ν•œ 무거운 μžλ°”μŠ€ν¬λ¦½νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 일반적인 문제λ₯Ό ν•΄κ²°ν•˜μ§€λŠ” λͺ»ν•œλ‹€. 이 문제의 해법을 트리 쉐이킹(Tree Shaking)μ—μ„œ 찾을 수 μžˆλ‹€.

트리 μ‰μ΄ν‚Ήμ΄λž€ 무엇인가?

트리 쉐이킹은 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ½”λ“œλ₯Ό μ œκ±°ν•˜λŠ” 방식이닀. 이 μš©μ–΄λŠ” Rollup에 μ˜ν•΄ 인기λ₯Ό μ–»κ²Œ λ˜μ—ˆμœΌλ‚˜, μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ½”λ“œ μ œκ±°μ— λŒ€ν•œ κ°œλ…μ€ 이미 μ‘΄μž¬ν–ˆμ—ˆλ‹€. λ˜ν•œ 이 κ°œλ…μ€ webpackμ—μ„œλ„ μ°Ύμ•„λ³Ό 수 있고, 이번 μ•„ν‹°ν΄μ—μ„œ 예제 앱을 톡해 μ„€λͺ…ν•œλ‹€.

"트리 쉐이킹" μš©μ–΄λŠ” 당신이 λ§Œλ“  μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λ©˜νƒˆ λͺ¨λΈ(mental model)κ³Ό λ””νŽœλ˜μ‹œ 트리 κ΅¬μ‘°μ—μ„œ μœ λž˜λ˜μ—ˆλ‹€. 트리 λ‚΄ 각 λ…Έλ“œλ“€μ€ 앱을 μœ„ν•΄ νŠΉμ§•μ μΈ κΈ°λŠ₯듀을 μ œκ³΅ν•˜λŠ” λ””νŽœλ˜μ‹œλ“€μ„ λ‚˜νƒ€λ‚Έλ‹€. μ΅œμ‹  μ•±μ—μ„œλŠ” μ΄λŸ¬ν•œ λ””νŽœλ˜μ‹œλ“€μ„ λ‹€μŒκ³Ό 같이 정적 import ꡬ문으둜 κ°€μ Έμ˜¬ 수 μžˆλ‹€:

// λͺ¨λ“  λ°°μ—΄ μœ ν‹Έλ¦¬ν‹°λ“€μ„ κ°€μ Έμ˜¨λ‹€.
import arrayUtils from "array-utils";

μ°Έκ³ : ES6 λͺ¨λ“ˆμ΄ 무엇인지 λͺ¨λ₯Έλ‹€λ©΄, Pony Foo의 ν›Œλ₯­ν•œ μ„€λͺ…을 μΆ”μ²œν•œλ‹€. 아티클을 읽닀가 아무 것도 λͺ¨λ₯΄κ² λ‹€λ©΄, 이 κ°€μ΄λ“œλŠ” ES6 λͺ¨λ“ˆ λ™μž‘μ— λŒ€ν•œ 지식을 μ–»λŠ”λ° 도움이 될 것이닀.

λ‹Ήμ‹ μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 이제 막 λ§Œλ“€μ–΄μ‘Œλ‹€λ©΄ 비ꡐ적 적은 μ–‘μ˜ λ””νŽœλ˜μ‹œλ₯Ό κ°€μ§ˆ 것이닀. λ˜ν•œ μΆ”κ°€λœ λ””νŽœλ˜μ‹œ λŒ€λΆ€λΆ„μ„ μ‚¬μš©ν•  것이닀. ν•˜μ§€λ§Œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 였래될수둝 더 λ§Žμ€ λ””νŽœλ˜μ‹œλ“€μ΄ 좔가될 수 μžˆλ‹€. λ³΅μž‘ν•œ λ¬Έμ œλ“€μ„ μœ„ν•΄ 였래된 λ””νŽœλ˜μ‹œλ“€μ„ λΉΌμ§€λ§Œ, μ½”λ“œμ—μ„œλŠ” μ œκ±°λ˜μ§€ λͺ»ν•  수 μžˆλ‹€. λ§ˆμ§€λ§‰μ€ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λŒ€λŸ‰μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ“€κ³Ό ν•¨κ»˜ 앱이 λλ‚˜λŠ” 것이닀. 트리 쉐이킹은 정적 ES6 λͺ¨λ“ˆμ˜ νŠΉμ • 뢀뢄을 κ°€μ Έμ˜€λŠ” import ꡬ문의 이점을 μ‚¬μš©ν•΄ μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•  것이닀:

// μœ ν‹Έμ˜ μΌλΆ€λ§Œ κ°€μ Έμ˜¨λ‹€.
import { unique, implode, explode } from "array-utils";

이전에 λ³Έ import ꡬ문과 차이점은, 이전 μ˜ˆμ œμ—μ„œλŠ” "array-utils" λͺ¨λ“ˆμ„ λͺ¨λ‘ κ°€μ Έμ˜€μ§€λ§Œ 이 μ˜ˆμ œμ—μ„œλŠ” λͺ¨λ“ˆμ˜ νŠΉμ • λΆ€λΆ„λ§Œ κ°€μ Έμ˜¨λ‹€. 개발 λΉŒλ“œμ—μ„œλŠ” μ–΄λ–€ 것도 μ„€μ •ν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— import 된 것과 상관 없이 전체 λͺ¨λ“ˆμ„ κ°€μ Έμ˜¨λ‹€. κ·ΈλŸ¬λ‚˜ ν”„λ‘œλ•μ…˜ λΉŒλ“œμ—μ„œλŠ” λͺ…μ‹œμ μœΌλ‘œ import λ˜μ§€ μ•Šμ€ ES6 λͺ¨λ“ˆλ‘œλΆ€ν„° exportλ₯Ό "떨어버리기(shake)" μœ„ν•΄μ„œ webpack을 μ„€μ •ν•˜κ³ , λΉŒλ“œ κ²°κ³Όλ¬Ό 크기λ₯Ό 더 μž‘κ²Œ λ§Œλ“€ 수 μžˆλ‹€. 이번 κ°€μ΄λ“œμ—μ„œ μ–΄λ–»κ²Œ 이것을 ν•  수 μžˆλŠ”μ§€ 배우게 될 것이닀.

트리 쉐이킹 ν•  수 μžˆλŠ” 지점 μ°ΎκΈ°

이해λ₯Ό 돕기 μœ„ν•΄ ν•„μžλŠ” 예제 앱을 λ§Œλ“€μ—ˆλ‹€. 이 μ˜ˆμ œλŠ” 트리 쉐이킹이 μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”μ§€ μ„€λͺ…ν•˜κΈ° μœ„ν•΄ webpack을 μ‚¬μš©ν–ˆλ‹€. 당신은 리포지터리λ₯Ό ν΄λ‘ ν•˜κ³  따라할 수 μžˆμ§€λ§Œ 이 κ°€μ΄λ“œμ—μ„œ λ°©μ‹μ˜ λͺ¨λ“  단계λ₯Ό ν•¨κ»˜ λ‹€λ£° 것이기 λ•Œλ¬Έμ— 클둠을 κΌ­ ν•  ν•„μš”λŠ” μ—†λ‹€.

예제 앱은 기타 μ΄νŽ™νŠΈ νŽ˜λ‹¬μ„ 검색 ν•  수 μžˆλŠ” 맀우 κ°„λ‹¨ν•œ λ°μ΄ν„°λ² μ΄μŠ€μ΄λ‹€. 당신이 쿼리λ₯Ό μž…λ ₯ν•˜λ©΄ νŒμ—…μ— μ΄νŽ™νŠΈ νŽ˜λ‹¬ λͺ©λ‘μ΄ λ‚˜νƒ€λ‚œλ‹€.

img

κ·Έλ¦Ό 3. 예제 μ•± μŠ€ν¬λ¦°μƒ·

μ˜ˆμƒλŒ€λ‘œ, 앱을 κ΅¬λ™ν•˜λŠ” λ™μž‘μ€ 벀더(Preact와 Emotion ν•΄λ‹Ή)와 μ•±-νŠΉμ • μ½”λ“œ λ²ˆλ“€(webpackμ—μ„œλŠ” "청크"둜 λΆ€λ₯Έλ‹€)둜 λΆ„λ¦¬λ˜μ—ˆλ‹€.

img

κ·Έλ¦Ό 4. 두 κ°€μ§€ μ•± μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€. 이 νŒŒμΌλ“€μ€ μ••μΆ•λ˜μ§€ μ•Šμ€ 크기이닀.

μœ„ μ΄λ―Έμ§€λŠ” ν”„λ‘œλ•μ…˜ λΉŒλ“œμ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ„ 보여주고, μ΄λŠ” μ–΄κΈ€λ¦¬νŒŒμ΄λ₯Ό ν†΅ν•΄μ„œ μ΅œμ ν™”λ˜μ—ˆλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. 청크 파일이 21.5 KB이면 그리 λ‚˜μ˜μ§€ μ•Šλ‹€. κ·ΈλŸ¬λ‚˜! 무엇이든지 간에 트리 쉐이킹이 μΌμ–΄λ‚˜μ§€ μ•Šμ•˜λ‹€λŠ” 것에 μ£Όλͺ©ν•΄μ•Ό ν•œλ‹€. μ•± μ½”λ“œλ₯Ό ν•¨κ»˜ μ‚΄νŽ΄λ³΄λ©΄μ„œ 무엇을 μˆ˜μ •ν•΄μ•Όν• μ§€ 보자.

μ°Έκ³ : μž₯ν™©ν•œ μ„€λͺ…μ΄λ‚˜ μ½”λ“œλ₯Ό 보길 μ›ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, μ•žμœΌλ‘œ λŒμ•„κ°€ μ•± κΉƒν—™ λ¦¬ν¬μ—μ„œ 트리 쉐이킹에 λŒ€ν•œ 브랜치λ₯Ό 체크아웃 ν•  수 μžˆλ‹€. λ˜ν•œ 트리 쉐이킹이 λ™μž‘ν•  λ•Œ μ •ν™•ν•˜κ²Œ 무엇이 λ³€κ²½λ˜μ—ˆλŠ”μ§€ 보기 μœ„ν•΄ λ§ˆμŠ€ν„° λΈŒλžœμΉ˜μ™€ diff ν•  수 μžˆλ‹€.

μ–΄λ–€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 트리 쉐이킹 ν•  수 μžˆλŠ” 지점을 μ°ΎλŠ” 것은 정적 import ꡬ문을 μ°ΎλŠ” 것이닀. 메인 μ»΄ν¬λ„ŒνŠΈ 파일의 맨 μœ— λΆ€λΆ„μ—μ„œ λ‹€μŒκ³Ό 같이 된 것을 λ³Ό 수 μžˆλ‹€.

import * as utils from "../../utils/utils";

μ•„λ§ˆλ„ 당신은 이전에 λΉ„μŠ·ν•œ 것을 λ³΄μ•˜μ„ 것이닀. import 될 수 μžˆλŠ” ES6 λͺ¨λ“ˆμ„ λ‚΄λ³΄λ‚΄λŠ” 방법은 ꡉμž₯히 λ§Žμ§€λ§Œ, 이와 같은 방식이 λ‹Ήμ‹ μ˜ 관심을 끌 것이닀. 이 νŠΉμ • 라인은 "이봐, utils λͺ¨λ“ˆλ‘œλΆ€ν„° λͺ¨λ“  것 을 import ν•΄μ„œ utils λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— 넣어라"라고 λ§ν•œλ‹€. μ—¬κΈ°μ„œ 큰 ꢁ금증이 생길 것이닀. "κ·Έ λͺ¨λ“ˆ μ•ˆμ— μ–Όλ§ˆλ‚˜ λ§Žμ€ 것 듀이 μžˆμ„κΉŒ?"

자, utils λͺ¨λ“ˆμ˜ μ†ŒμŠ€ μ½”λ“œλ₯Ό 보면 ꡉμž₯히 λ§Žλ‹€. 1,300 쀄 정도 λœλ‹€.

κ·ΈλŸ¬λ‚˜ κ±±μ •ν•˜μ§€ 마라. μ•„λ§ˆλ„ λͺ¨λ“  것듀이 μ‚¬μš©λ˜μ—ˆμ„ 것이닀. κ·Έλ ‡μ§€? 그럼 μš°λ¦¬λŠ” 이 λͺ¨λ“  것듀을 ν•„μš”λ‘œ ν• κΉŒ? utils λͺ¨λ“ˆμ„ import ν•˜λŠ” 메인 μ»΄ν¬λ„ŒνŠΈ 파일λ₯Ό λ‹€μ‹œ ν™•μΈν•˜λ©΄μ„œ, μ–Όλ§ˆλ‚˜ λ§Žμ€ λ„€μž„μŠ€νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€κ°€ μžˆλŠ”μ§€ 보자. ν™•μ‹€ν•˜κ²Œ, μš°λ¦¬λŠ” 무언가 λ₯Ό μœ„ν•΄ 메인 μ»΄ν¬λ„ŒνŠΈμ— μžˆλŠ” 것듀을 μ‚¬μš©ν•΄μ•Όλ§Œ ν•œλ‹€.

img

κ·Έλ¦Ό 5. 메인 μ»΄ν¬λ„ŒνŠΈ νŒŒμΌμ—μ„œ import 된 μˆ˜λ§Žμ€ λͺ¨λ“ˆ 쀑에 utils λ„€μž„μŠ€νŽ˜μ΄μŠ€λŠ” μ„Έ 번만 ν˜ΈμΆœλ˜μ—ˆλ‹€.

λ¬Όλ‘  그것은 μ’‹μ§€ μ•Šλ‹€. μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œμ—μ„œ μ„Έκ΅°λ°μ„œλ§Œ utils λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν–ˆλ‹€. 근데 μ–΄λ–€ κΈ°λŠ₯을 ν•˜λŠ”κ°€? 메인 μ»΄ν¬λ„ŒνŠΈ νŒŒμΌμ„ λ‹€μ‹œ 보면, 이 μ½”λ“œλ“€μ€ utils.simpleSort ν•¨μˆ˜μ—μ„œλ§Œ λ‚˜νƒ€λ‚œλ‹€. 이 ν•¨μˆ˜λŠ” λ“œλ‘­λ‹€μš΄ 메뉴가 변경될 λ•Œ κΈ°μ€€ 번호둜 검색 κ²°κ³Ό λͺ©λ‘μ„ μ •λ ¬ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.

if (this.state.sortBy === "model") {
  // simpleSortλŠ” μ—¬κΈ°μ—μ„œ μ‚¬μš©λœλ‹€...
  json = utils.simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  // ..그리고 μ—¬κΈ°...
  json = utils.simpleSort(json, "type", this.state.sortOrder);
} else {
  // ..그리고 μ—¬κΈ°.
  json = utils.simpleSort(json, "manufacturer", this.state.sortOrder);
}

κ·Έλ ‡λ‹€. export 더미듀과 ν•¨κ»˜ 1,300쀄 μ€‘μ—μ„œ, 이 ν•¨μˆ˜λ§Œ λ³Ό 것이닀. μ›Ή μ„±λŠ₯에 ꡉμž₯히 λ‚˜μœ 것을 λ°ν˜€λƒˆλ‹€.

μ°Έκ³ : 이 ν”„λ‘œμ νŠΈλŠ” μ˜λ„μ μœΌλ‘œ λ‹¨μˆœν•˜κ²Œ μž‘μ„±λ˜μ—ˆκΈ° λ•Œλ¬Έμ—, ν™•μž₯ν•  곳을 μ°ΎκΈ° ꡉμž₯히 쉽닀. κ·ΈλŸ¬λ‚˜ λ§Žμ€ λͺ¨λ“ˆμ„ μ‚¬μš©ν•˜λŠ” 큰 ν”„λ‘œμ νŠΈμ—μ„œλŠ” μ–Όλ§ˆλ‚˜ λ§Žμ€ λ²ˆλ“€μ΄ import λ˜μ—ˆλŠ”μ§€ μ•ŒκΈ° μ–΄λ ΅λ‹€. webpack λ²ˆλ“€ 뢄석기와 source-map-explorerκ°€ 도움이 될 수 있고, μ΄λŸ¬ν•œ 보쑰 도ꡬ듀은 μ—¬μ „νžˆ 개발되고 μžˆλ‹€.

λ¬Όλ‘ , μ§€κΈˆ 이 μ˜ˆμ œλŠ” 아티클을 μœ„ν•΄ 쑰금 κ°€κ³΅λ˜μ—ˆλ‹€. κ·ΈλŸ¬λ‚˜ 쒅합적인 μ‹œλ‚˜λ¦¬μ˜€κ°€ μ‹€μ œ μ•±μ—μ„œ 일어날 수 μžˆλŠ” μ΅œμ ν™” κΈ°νšŒμ™€ μœ μ‚¬ν•˜λ‹€λŠ” 사싀은 λ³€ν•˜μ§€ μ•ŠλŠ”λ‹€. 당신은 μœ μš©ν•œ 트리 쉐이킹 기회λ₯Ό μ°Ύμ•˜κ³ , μ‹€μ œλ‘œλŠ” μ–΄λ–»κ²Œ ν• κΉŒ?

Babel둜 ES6 λͺ¨λ“ˆμ΄ CommonJS λͺ¨λ“ˆλ‘œ λ³€ν™˜λ˜λŠ” 것 막기

Babel은 λ§Žμ€ μ•±μ—μ„œ μ—†μ–΄μ„œλŠ” μ•ˆλ  도ꡬ이닀. λΆˆν–‰ν•˜κ²Œλ„, Babel이 ν•˜λŠ” μ–΄λ–€ 것 λ•Œλ¬Έμ— 트리 쉐이킹 같은 κ°„λ‹¨ν•œ μž‘μ—…μ„ μ–΄λ ΅κ²Œ λ§Œλ“€ 수 μžˆλ‹€. babel-preset-envλ₯Ό μ‚¬μš©ν•˜λ©΄, ES6 λͺ¨λ“ˆμ„ λ²”μš©μ μœΌλ‘œ ν˜Έν™˜λ˜λŠ” CommonJS λͺ¨λ“ˆ(즉, import λŒ€μ‹  require λͺ¨λ“ˆ)둜 λ³€ν™˜ν•΄μ€€λ‹€. 이것은 트리 쉐이킹을 ν•˜κΈ° μ „κΉŒμ§€λŠ” μ’‹λ‹€.

트리 쉐이킹은 CommonJS λͺ¨λ“ˆμ—μ„œ ν•˜κΈ° μ–΄λ ΅κ³ , webpack은 μ‚¬μš©ν•˜λ €λŠ” λ²ˆλ“€μ—μ„œ 무엇을 μ œκ±°ν•΄μ•Όν• μ§€ λͺ¨λ₯Έλ‹€. 해결책은 κ°„λ‹¨ν•˜λ‹€: ES6 λͺ¨λ“ˆλ§Œ 남도둝 babel-preset-envλ₯Ό μ„€μ •ν•œλ‹€. Babel을 μ„€μ •ν•œ κ³³ μ–΄λ””μ„œλ“ (.babelrc λ˜λŠ” package.json) μ•½κ°„μ˜ μ˜΅μ…˜μ„ μΆ”κ°€ν•΄μ•Ό ν•œλ‹€.

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ]
}

babel-preset-env μ„€μ •μ—μ„œ κ°„λ‹¨νžˆ "modules": false둜 μ„€μ •ν•˜λ©΄ Babel은 우리의 λ°”λžŒλŒ€λ‘œ λ™μž‘ν•œλ‹€. webpack이 λ””νŽœλ˜μ‹œ 트리λ₯Ό λΆ„μ„ν•΄μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λ””νŽœλ˜μ‹œλ“€μ„ μ œκ±°ν•œλ‹€. κ²Œλ‹€κ°€ 이 과정은 ν˜Έν™˜μ„± 문제λ₯Ό μΌμœΌν‚€μ§€ μ•ŠλŠ”λ‹€. κ²°κ΅­ webpack이 μ½”λ“œλ₯Ό λ²”μš©μ μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” ν˜•νƒœλ‘œ λ³€ν™˜ν•΄μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€.

μ‚¬μ΄λ“œ μ΄νŽ™νŠΈ κ³ λ €ν•˜κΈ°

μ•±μ—μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λ””νŽœλ˜μ‹œλ“€μ„ μ œκ±°ν•  λ•Œ κ³ λ €ν•΄μ•Ό ν•  점은 ν”„λ‘œμ νŠΈμ˜ λͺ¨λ“ˆλ“€μ΄ μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό λ°œμƒμ‹œν‚€λŠ”μ§€ 여뢀이닀. μ‚¬μ΄λ“œ μ΄νŽ™νŠΈμ˜ ν•œ μ˜ˆλŠ” ν•¨μˆ˜κ°€ μŠ€μ½”ν”„ λ°–μ˜ 무언가λ₯Ό λ³€κ²½ν•  λ•Œμ΄λ‹€. μ΄λŠ” 싀행에 λŒ€ν•œ μ‚¬μ΄λ“œ μ΄νŽ™νŠΈ λ‹€.

let fruits = ["apple", "orange", "pear"];

console.log(fruits); // (3) ["apple", "orange", "pear"]

const addFruit = function(fruit) {
  fruits.push(fruit);
};

addFruit("kiwi");

console.log(fruits); // (4) ["apple", "orange", "pear", "kiwi"]

이것은 ꡉμž₯히 λ‹¨μˆœν•œ 예제둜, addFruit ν•¨μˆ˜λŠ” fruits 배열을 λ³€κ²½ν•  λ•Œ μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό λ°œμƒμ‹œν‚¨λ‹€. 이 fruits 배열은 addFruit ν•¨μˆ˜ μŠ€μ½”ν”„ 밖에 μžˆλ‹€. μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλŠ” ES6 λͺ¨λ“ˆμ—λ„ 적용되며, 트리 μ‰μ΄ν‚Ήμ˜ μ»¨ν…μŠ€νŠΈμ—μ„œ λ¬Έμ œκ°€ λœλ‹€. 예츑 κ°€λŠ₯ν•œ μž…λ ₯을 κ°€μ§€κ³  λ™μΌν•˜κ²Œ ν•¨μˆ˜μ˜ μŠ€μ½”ν”„ λ°–μ˜ μ–΄λ–€ 것도 λ³€κ²½ν•˜μ§€ μ•ŠμœΌλ©΄μ„œ 예츑 κ°€λŠ₯ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λŠ” λͺ¨λ“ˆμ΄ μ•ˆμ „ν•˜κ²Œ 트리 쉐이킹을 ν•  수 μžˆλŠ” λ””νŽœλ˜μ‹œμ΄λ‹€. 이것듀은 자체적으둜 ν¬ν•¨λœ μ½”λ“œμ˜ λͺ¨λ“ˆμ‹ 쑰각이닀. 즉, "λͺ¨λ“ˆλ“€(modules)"이닀.

webpackμ—μ„œ κ³ λ €ν•΄μ•Ό ν•  뢀뢄은, ν”„λ‘œμ νŠΈμ˜ package.json νŒŒμΌμ—μ„œ "sideEffects": false둜 μ„€μ •ν•˜λ©΄ νŒ¨ν‚€μ§€μ™€ λ””νŽœλ˜μ‹œλ“€μ΄ μ‚¬μ΄λ“œ μ΄νŽ™νŠΈλ₯Ό λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것이닀:

{
  "name": "webpack-tree-shaking-example",
  "version": "1.0.0",
  "sideEffects": false
}

μ„ νƒμ μœΌλ‘œ, μ‚¬μ΄λ“œ μ΄νŽ™νŠΈμ˜ 영ν–₯을 λ°›μ§€ μ•Šμ„ νŠΉμ • νŒŒμΌλ“€μ„ μ§€μ •ν•  μˆ˜λ„ μžˆλ‹€.

{
  "name": "webpack-tree-shaking-example",
  "version": "1.0.0",
  "sideEffects": [
    "./src/utils/utils.js"
  ]
}

μ•„λž˜ μ˜ˆμ œμ—μ„œ, μ§€μ •λ˜μ§€ μ•Šμ€ νŒŒμΌμ€ μ‚¬μ΄νŠΈ μ΄νŽ™νŠΈκ°€ μ—†λ‹€κ³  κ°€μ •ν•  것이닀. package.json νŒŒμΌμ— 이 μ˜΅μ…˜μ„ μΆ”κ°€ν•˜κΈ° μ›ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, webpack μ„€μ • νŒŒμΌμ— module.rules ν”Œλž˜κ·Έ 값을 μ§€μ •ν•  수 μžˆλ‹€.

μ›ν•˜λŠ” κ²ƒλ§Œ κ°€μ Έμ˜€κΈ°

μš°λ¦¬λŠ” ES6 λͺ¨λ“ˆμ„ κ·ΈλŒ€λ‘œ 두렀고 Babel을 μ„€μ •ν–ˆμ§€λ§Œ, utils λͺ¨λ“ˆμ—μ„œ ν•„μš”ν•œ ν•¨μˆ˜λ§Œ κ°€μ Έμ˜€κΈ° μœ„ν•΄ import ꡬ문을 쑰금 μˆ˜μ •ν•˜λ €κ³  ν•œλ‹€. κ°€μ΄λ“œ μ˜ˆμ œμ—μ„œ ν•„μš”λ‘œ ν•˜λŠ” 것은 simpleSort ν•¨μˆ˜μ΄λ‹€:

import { simpleSort } from "../../utils/utils";

이 ꡬ문을 μ‚¬μš©ν•˜λ©΄μ„œ μ΄λ ‡κ²Œ 말할 것이닀. "이봐, utils λͺ¨λ“ˆμ—μ„œ simpleSort만 가져와." simpleSort ν•¨μˆ˜λ§Œ κ°€μ Έμ˜€κ³  μ „μ—­ μŠ€μ½”ν”„μ— utils λͺ¨λ“ˆμ΄ μ—†κΈ° 떄문에, utils.simpleSort의 λͺ¨λ“  μΈμŠ€ν„΄μŠ€λ₯Ό simpleSort둜 λ³€κ²½ν•΄μ•Ό ν•œλ‹€:

if (this.state.sortBy === "model") {
  json = simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  json = simpleSort(json, "type", this.state.sortOrder);
} else {
  json = simpleSort(json, "manufacturer", this.state.sortOrder);
}

이제 트리 쉐이킹을 μœ„ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν–ˆμœΌλ‹ˆ, μž μ‹œ λ’€λ‘œ λ¬ΌλŸ¬μ„œμ„œ 보자.

이것은 λ””νŽœλ˜μ‹œ 트리 쉐이킹을 ν•˜κΈ° μ „ webpack 결과이닀:

                 Asset      Size  Chunks             Chunk Names
js/vendors.16262743.js  37.1 KiB       0  [emitted]  vendors
   js/main.797ebb8b.js  20.8 KiB       1  [emitted]  main

그리고 이것은 트리 쉐이킹을 ν•œ ν›„ 결과이닀:

                 Asset      Size  Chunks             Chunk Names
js/vendors.45ce9b64.js  36.9 KiB       0  [emitted]  vendors
   js/main.559652be.js  8.46 KiB       1  [emitted]  main

두 λ²ˆλ“€ νŒŒμΌλ“€μ„ μ••μΆ•ν–ˆμ„ λ•Œ, main λ²ˆλ“€ νŒŒμΌμ— 이점이 생겼닀. utils λͺ¨λ“ˆμ˜ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 뢀뢄을 μ‰μ΄ν‚Ήν•˜μ—¬, λ²ˆλ“€ νŒŒμΌμ—μ„œ μ•½ 60%의 μ½”λ“œλ₯Ό μ œκ±°ν•˜μ˜€λ‹€. μ΄λ ‡κ²Œν•˜λ©΄ 슀크립트λ₯Ό λ‹€μš΄λ‘œλ“œν•˜λŠ”λ° λ“œλŠ” μ‹œκ°„ 뿐만 μ•„λ‹ˆλΌ 처리 μ‹œκ°„λ„ λ‹¨μΆ•λ˜μ–΄μ„œ μ’‹λ‹€.

잘 λ˜μ§€ μ•Šμ„ λ•Œ

λŒ€λΆ€λΆ„μ˜ 경우, 이런 μ‚¬μ†Œν•œ 변경이 μžˆμ„ λ•Œ 트리 쉐이킹은 webpack μ΅œμ‹  λ²„μ „μ—μ„œ 잘 λ™μž‘ν•˜μ§€λ§Œ 항상 μ˜ˆμ™ΈλŠ” μžˆλ‹€. 예λ₯Ό λ“€μ–΄, Lodashκ°€ μœ„μ˜ κ°€μ΄λ“œλŒ€λ‘œ 트리 쉐이킹이 잘 λ™μž‘ν•˜μ§€ μ•ŠλŠ” μ΄μƒν•œ κ²½μš°μ— ν•΄λ‹Ήλœλ‹€. Lodash 섀계 방식 λ•Œλ¬Έμ—, a) 였래된 ν‘œμ€€ lodash λŒ€μ‹  lodash-esλ₯Ό μ„€μΉ˜ν•˜κ³  b) λ‹€λ₯Έ λ””νŽœλ˜μ‹œλ₯Ό μ‰μ΄ν‚Ήν•˜κΈ° μœ„ν•΄ 쑰금 λ‹€λ₯Έ ꡬ문("cherry-picking"이라고도 ν•œλ‹€)을 μ‚¬μš©ν•œλ‹€.

// 섀정이 잘 λ˜μ–΄μžˆμ–΄λ„ lodash λͺ¨λ“  것듀을 κ°€μ Έμ˜¨λ‹€.
import { sortBy } from "lodash";

// sortBy κ²½λ‘œμ—μ„œ κ°€μ Έμ˜¨λ‹€.
import sortBy from "lodash-es/sortBy";

μΌκ΄€λ˜κ²Œ import ꡬ문을 μ‚¬μš©ν•˜κΈΈ μ„ ν˜Έν•œλ‹€λ©΄, ν‘œμ€€ lodash νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš© ν•  수 μžˆλ‹€. babel-plugin-lodashλ₯Ό μ„€μΉ˜ν•œλ‹€. Babel μ„€μ • νŒŒμΌμ— ν”ŒλŸ¬κ·ΈμΈμ„ μΆ”κ°€ν•˜λ©΄, import ꡬ문을 μ‚¬μš©ν•˜λ©΄μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λͺ¨λ“ˆλ“€μ„ μ œκ±°ν•  수 μžˆλ‹€.

μ‹€ν–‰ν•œ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ 트리 쉐이킹에 λ°˜μ‘ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, ES6 ꡬ문을 μ‚¬μš©ν•˜μ—¬ λ©”μ„œλ“œλ₯Ό λ‚΄λ³΄λ‚΄λŠ”μ§€ ν™•μΈν•˜λΌ. λ§Œμ•½ CommonJS ν˜•μ‹(예: module.exports)으둜 내보내고 μžˆλ‹€λ©΄, ν•΄λ‹Ή μ½”λ“œλŠ” 트리 쉐이킹을 ν•  수 μ—†λ‹€. λͺ‡λͺ‡ ν”ŒλŸ¬κ·ΈμΈλ“€μ€ CommonJS λͺ¨λ“ˆμ„ μœ„ν•œ 트리 쉐이킹 κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€. (예: webpack-common-shake) κ·ΈλŸ¬λ‚˜ 이 ν”ŒλŸ¬κ·ΈμΈλ“€μ€ 트리 쉐이킹을 ν•  수 μ—†λŠ” λͺ‡ κ°€μ§€ CommonJS νŒ¨ν„΄λ§ŒνΌμ΄λ‚˜ 갈 길이 λ©€λ‹€. λ‹Ήμ‹ μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λ””νŽœλ˜μ‹œλ“€μ„ ν™•μ‹€ν•˜κ²Œ μ œκ±°ν•˜κΈ°λ₯Ό μ›ν•œλ‹€λ©΄, μ•žμœΌλ‘œ ES6 λͺ¨λ“ˆμ„ μ‚¬μš©ν•΄μ•Ό ν•  것이닀.

트리 쉐이킹을 ν•΄λ³΄μž!

트리 쉐이킹이 κ°€λŠ₯ν•œ μ •λ„λŠ” μ•±κ³Ό μ•±μ—μ„œ μ‚¬μš©ν•˜κ³  μžˆλŠ” λ””νŽœλ˜μ‹œ 및 섀계 ꡬ쑰에 따라 λ‹€λ₯΄λ‹€. μ‹œλ„ν•΄λ³΄λΌ! λͺ¨λ“ˆ λ²ˆλ“€λŸ¬μ— 트리 쉐이킹을 μœ„ν•œ μ˜΅μ…˜μ΄ μ„€μ •λ˜μ§€ μ•Šμ•˜λ‹€λŠ” 것을 μ•Œκ³  μžˆλ‹€λ©΄, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μ–΄λ–€ 이점이 μžˆλŠ”μ§€ 보고 ν•΄λ³΄λŠ”λ° μ•„λ¬΄λŸ° ν•΄κ°€ μ—†λ‹€. λ²ˆλ“€ νŒŒμΌμ—μ„œ 제거 κ°€λŠ₯ν•œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ–΄λ–€ μ½”λ“œλŠ” κ°€μΉ˜ μžˆλŠ” μ΅œμ ν™”λ‹€.

트리 μ‰μ΄ν‚ΉμœΌλ‘œλΆ€ν„° λ§Žμ€ 이읡을 μ–»κ±°λ‚˜ κ·Έλ ‡μ§€ μ•Šμ„ μˆ˜λ„ μžˆλ‹€. κ·ΈλŸ¬λ‚˜ ν”„λ‘œλ•μ…˜ λΉŒλ“œμ—μ„œ 트리 μ‰μ΄ν‚Ήμ˜ 이점을 μœ„ν•΄ λΉŒλ“œ μ‹œμŠ€ν…œμ„ κ΅¬μ„±ν•˜κ³  μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ ν•„μš”λ‘œ ν•˜λŠ” κ²ƒλ§Œ μ„ νƒμ μœΌλ‘œ κ°€μ Έμ˜€λŠ” κ²ƒμœΌλ‘œμ¨, λ‹Ήμ‹ μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°€λŠ₯ν•œ ν•œ κ°€λ³κ²Œ μœ μ§€μ‹œμΌœμ€„ 것이닀. 트리 쉐이킹은 μ„±λŠ₯κ³Ό ν™•μž₯, μ‚¬μš©μžλ“€μ—κ²Œ μ’‹λ‹€.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions