ํธ๋ฆฌ์ ฐ์ดํน(Tree Shaking)
ํธ๋ฆฌ์ ฐ์ดํน(Tree Shaking)์ ํ๋ก์ ํธ์์ ์ฌ์ฉ๋์ง ์๋ ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋ ์ต์ ํ ๊ธฐ๋ฒ์ด์์. ๋ง์น ๋๋ฌด๋ฅผ ํ๋ค์ด ๋ถํ์ํ ์์ ๋จ์ด๋จ๋ฆฌ๋ฏ, ์ค์ ๋ก ์ฌ์ฉํ์ง ์๋ ์ฝ๋(Dead Code)๊ฐ ๋ฒ๋ค ํ์ผ์ ํฌํจ๋์ง ์๋๋ก ํด์.
์๋ฅผ ๋ค์ด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํน์ ํจ์ ํ๋๋ง ์ฌ์ฉํ๋๋ฐ๋ ์ ์ฒด ์ฝ๋๊ฐ ๋ฒ๋ค์ ํฌํจ๋ผ ํ์ผ ํฌ๊ธฐ๊ฐ ๋ถํ์ํ๊ฒ ์ปค์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์. ์ด๋ด ๋ ํธ๋ฆฌ์ ฐ์ดํน์ ์ ์ฉํ๋ฉด ์ค์ ๋ก ์ฌ์ฉํ๋ ์ฝ๋๋ง ๋ฒ๋ค์ ๋จ๊ธฐ๊ธฐ ๋๋ฌธ์ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ด์.
๋ฒ๋ค ํฌ๊ธฐ๊ฐ ์ค์ด๋ค๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก๋ฉ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ , ์ฌ์ฉ์ ๊ฒฝํ๋ ๊ฐ์ ํ ์ ์์ด์. ์ด์ ํธ๋ฆฌ์ ฐ์ดํน์ ์ฃผ์ ํน์ง์ ๋ํด ์ดํด๋ณผ๊ฒ์.

ํธ๋ฆฌ์ ฐ์ดํน์ด ๋์ํ๋ ํ๊ฒฝ
ํธ๋ฆฌ์ ฐ์ดํน์ ์ ์ ๋ถ์(Static Analysis) ๊ธฐ๋ฐ์ผ๋ก ์๋ํด์. ์ ์ ๋ถ์์ ์ฝ๋๊ฐ ์คํ๋๊ธฐ ์ ์ ๊ตฌ์กฐ๋ฅผ ๋ถ์ํด, ์ฌ์ฉ๋์ง ์๋ ์ฝ๋๋ฅผ ์ ํํ ์ฐพ์๋ผ ์ ์๋ ๊ธฐ๋ฒ์ด์ฃ . ๋ฐ๋ผ์ ํธ๋ฆฌ์ ฐ์ดํน์ ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ๋ฒ๋ค๋งํ๋ ๋น๋ ํ์์ ์ ์ฉ๋ผ์.
ํธ๋ฆฌ์ ฐ์ดํน์ด ์ ๋์ํ๋ ค๋ฉด, ๋ฒ๋ค๋ฌ๊ฐ ๋ชจ๋ ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ช ํํ๊ฒ ๋ถ์ํ ์ ์๋๋ก ๋ชจ๋์ด ๊ตฌ์ฑ๋์ด์ผ ํด์. ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ์์คํ ์๋ ESM๊ณผ CJS ๋ ๊ฐ์ง ๋ฐฉ์์ด ์๋๋ฐ, ESM์ ์ ์ ์ธ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ๋น๋ ํ์์ ๋ถ์์ด ๊ฐ๋ฅํ๊ณ , ํธ๋ฆฌ์ ฐ์ดํน์ด ํจ๊ณผ์ ์ผ๋ก ์ ์ฉ๋ผ์.
ESM๊ณผ CJS์ ๊ตฌ์กฐ์ ์ธ ํน์ฑ์ ๋น๊ตํ๋ฉด์ ํธ๋ฆฌ์ ฐ์ดํน์ด ESM์์ ํจ๊ณผ์ ์ธ ์ด์ ๋ฅผ ๋ ์์ธํ ์ดํด๋ณผ๊ฒ์.
ESM
ESM์ import์ export ๊ตฌ๋ฌธ์ผ๋ก ๋ชจ๋ ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ถ์ํด ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๋ง๋ค์ด์. ์ด ์์กด์ฑ ๊ทธ๋ํ๋ก ๋ฒ๋ค๋ฌ๊ฐ ๋ถํ์ํ ์ฝ๋๋ฅผ ์ฝ๊ฒ ํ๋จํ๊ณ ์ ๊ฑฐํ ์ ์์ด์.
์์กด์ฑ ๊ทธ๋ํ๋ ์ถ์ ๊ตฌ๋ฌธ ํธ๋ฆฌ(AST)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋ผ์. AST๋ ๋ฒ๋ค๋ฌ๊ฐ ๋ฌธ์์ด๋ก ๋ ์ฝ๋๋ฅผ ํธ๋ฆฌ ํํ๋ก ๋ณํํ ์๋ฃ๊ตฌ์กฐ๋ก, ์ฝ๋์ ๊ตฌ์กฐ์ ๋ชจ๋ ๊ฐ ๊ด๊ณ๋ฅผ ๋ถ์ํ๋ ๋ฐ ํ์ฉ๋๋ ์๋ฃ๊ตฌ์กฐ์์.
๋ฒ๋ค๋ฌ๋ AST๋ฅผ ๋ถ์ํด ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๋ง๋ค๊ณ , ์ด ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์ฐธ์กฐ๋์ง ์๋ ์ฝ๋๋ฅผ ์ฐพ์ ์ ๊ฑฐํด ์ต์ ํ๋ ๋ฒ๋ค์ ์์ฑํ ์ ์์ด์.
์ด๋ฌํ ํน์ฑ ๋๋ถ์ ESM์์๋ ๋ถํ์ํ ์ฝ๋๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ๊ฑฐํ ์ ์์ด์.
- importํ ๋ชจ๋์ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ฌํ ๋นํ ์ ์์ด์
import { math } from "./math.js"; math = {}; // Error - ESM์ import๋ ์ฝ๊ธฐ ์ ์ฉ(immutable)์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ ธ์จ ๋ชจ๋์ ์ฌํ ๋นํ ์ ์์ด์.
์ด๋ ๋ชจ๋ ๊ฐ์ ์์กด์ฑ์ ๋ช ํํ๊ฒ ์ ์งํ๊ณ , ์ ์ ๋ถ์์ ์ฉ์ดํ๊ฒ ํ๊ธฐ ์ํ ์ค๊ณ์์. - import ๋ฐ export ๊ตฌ๋ฌธ์ ํญ์ ํ์ผ์ ์ต์๋จ์ ์์นํด์ผ ํด์ ESM์์๋ import์ export๊ฐ ์ฝ๋๊ฐ ์คํ๋๊ธฐ ์ ์ ์ ์ ์ผ๋ก ๋ถ์๋๋ฏ๋ก, ์คํ ๋์ค ๋์ ์ผ๋ก ํ๊ฐ๋ ์ ์์ด์. ๋ฐ๋ผ์ ์กฐ๊ฑด๋ฌธ ์์์ import๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ํญ์ ์ต์๋จ์ ์์นํด์ผ ํด์.
-
if (condition) { import { func } from "./module.js"; // Error } - ESM์ import() ๊ตฌ๋ฌธ์ ์ง์ํด์ ํ์ํ ์์ ์ ๋ชจ๋์ ๋์ ์ผ๋ก ๋ถ๋ฌ์ฌ ์ ์๊ณ , ์ด๋ฅผ ํตํด ์ด๊ธฐ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ผ ์ ์์ด์.
-
async function loadUtils() { const { deepEqual } = await import("lodash-es"); console.log(deepEqual(a, b)); }
CJS
CJS๋ require๋ฅผ ์ฌ์ฉํด ํญ์ ๋๊ธฐ ๋ฐฉ์์ผ๋ก ๋ชจ๋์ ๋ถ๋ฌ์์. ์ฆ, ์ฝ๋๊ฐ ์คํ๋ ๋ ์ฆ์ ํด๋น ๋ชจ๋์ ๋ถ๋ฌ์ผ ํ๊ณ ๋น๋๊ธฐ ๋ก๋ฉ์ ์ง์ํ์ง ์์์.
์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์๋ CJS์ ๋์์ ์ ํํ ์์ธกํ๊ธฐ ์ด๋ ค์์.
1. ํจ์๋ ์กฐ๊ฑด๋ฌธ ์์์ ๋์ ์ผ๋ก ๋ชจ๋์ ๋ก๋ํ ๋
๋ค์ ์ฝ๋์ฒ๋ผ require๋ import ๊ฐ์ ๋ชจ๋ ๋ก๋๋ฅผ ํจ์๋ ์กฐ๊ฑด๋ฌธ ์์์ ๋์ ์ผ๋ก ์ฌ์ฉํ ๋, ๋ฒ๋ค๋ฌ๋ ์ฝ๋ ์คํ ์ ์๋ ์ ํํ ์ด๋ค ๋ชจ๋์ด ๋ก๋๋ ์ง ์ ์ ์์ด์.
๊ทธ๋์ ๋ฒ๋ค๋ฌ๊ฐ ์ ์ฒด ์์กด์ฑ์ ๋ฏธ๋ฆฌ ํ์ ํ๊ฑฐ๋ ์ต์ ํํ๊ธฐ ์ด๋ ค์์ ธ์.
let foo;
if (SOME_CONDITION) {
foo = require("something");
} else {
foo = require("something_else");
}
2. ๋ชฝํค ํจ์นญ ๋ฑ์ผ๋ก ์์ํ์ง ๋ชปํ ๋์์ด ์๊ธธ ๋
๋ชฝํค ํจ์นญ์ ์ด๋ฏธ ์กด์ฌํ๋ ๋ชจ๋์ด๋ ํจ์์ ๋์์ ๋ฐํ์ ์ค์ ๋ฎ์ด์จ์ ์ํ๋ ๋๋ก ๋ฐ๊พธ๋ ๊ธฐ๋ฒ์ด์์. ์ด ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋ฒ๋ค๋ฌ ์ ์ฅ์์๋ ์ฝ๋๊ฐ ์คํ๋๊ธฐ ์ ์๋ ์ด๋ค ๋ชจ๋์ด, ์ด๋ค ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ๋ ์ง ์ ์ ์์ด์. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฒ๋ค๋ฌ๋ ์ฝ๋ ๋ถ์์ด ์ด๋ ค์์ง๊ณ , ์์ํ์ง ๋ชปํ ๋์์ด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ด์.
ESM ๊ธฐ๋ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์
๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ์ํ ๊ธฐ๋ฅ๋ง ๊ฐ์ ธ์ค๋๋ผ๋, ๋ชจ๋ ์์คํ ์ด๋ ๋ฒ๋ค ์ค์ ์ด ์ ๋๋ก ๋์ด ์์ง ์์ผ๋ฉด ์ ์ฒด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํฌํจ๋ผ ๋ฒ๋ค ํฌ๊ธฐ๊ฐ ์ปค์ง ์ ์์ด์.
์๋ฅผ ๋ค์ด, lodash ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ deepEqual ํจ์ ํ๋๋ง ์ฌ์ฉํ๋ค๊ณ ํด๋ณผ๊ฒ์.
import { deepEqual } from "lodash";
ํ์ง๋ง lodash๋ CJS ๋ฐฉ์์ผ๋ก ์์ฑ๋ผ ํธ๋ฆฌ์ ฐ์ดํน์ด ์ ์ ์ฉ๋์ง ์์์. ๊ฒฐ๊ณผ์ ์ผ๋ก deepEqual ์ธ์๋ lodash์ ๋ชจ๋ ์ฝ๋๊ฐ ๋ฒ๋ค์ ํฌํจ๋ ์ ์์ด์.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด lodash ๋์ ESM์ ์ง์ํ๋ es-toolkit์ ์ฌ์ฉํด์ผ ํด์.
import { isEqual } from "es-toolkit";
const result = isEqual(a, b);
es-toolkit๋ ESM ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํด ํ์ํ ํจ์๋ง ์ ํ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๊ณ , ํธ๋ฆฌ์ ฐ์ดํน์ ์ฌ์ฉํด ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ค์ผ ์ ์์ด์.
์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ฝ๋ ์ ๊ฑฐ
์ฌ์ด๋ ์ดํํธ(Side-Effect)๋ ์ฝ๋๊ฐ ์์์น ๋ชปํ ๋ฐฉ์์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ๋ถ์์ฉ์ ์ค ์ ์๋ ๊ฐ๋ฅ์ฑ์ ์๋ฏธํด์. ์ฆ, ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ฝ๋๋ ๋ฒ๋ค๋ง๋ ์ฝ๋๊ฐ ์คํ๋ ๋ ๋์์ ์ํฅ์ ์ฃผ์ง ์๋ ์ฝ๋์์.
์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ฝ๋๋ฅผ ๋ช ๊ฐ์ง ์๋ฅผ ๋ค์ด ๋ณผ๊ฒ์.
1. ํธ์ถ๋ ๋ ์ธ๋ถ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ํจ์
let count = 0;
function incrementCount() {
count = count + 1; // ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋ค ์ ์ญ ๋ณ์ ๊ฐ์ด ๋ณ๊ฒฝ๋จ (์ฌ์ด๋ ์ดํํธ ๋ฐ์)
}
incrementCount();
2.์ง์ ์ ์ผ๋ก DOM ๋ณ๊ฒฝ
function updateDOM() {
document.body.innerHTML = "<h1>Hi Toss!</h1>"; // DOM์ด ๋ณ๊ฒฝ๋จ
}
3.์กฐํ๋ฅผ ํ ๋๋ง๋ค ๋ค๋ฅธ ๊ฒฐ๊ณผ ๋ฐํ
const user = {};
// Object.defineProperty๋ฅผ ์ด์ฉํ ์์ฑ ์กฐ์
Object.defineProperty(user, "name", {
get() {
console.log("์ด๋ฆ์ด ๋ญ์์?");
this._name = this._name ? this._name + "!" : "Hany"; // ๊ฐ์ ๋ณ๊ฒฝํ๋ ๋ถ์์ฉ ๋ฐ์
return this._name;
}
});
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany"
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany!"
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany!!"
๋ฐ๋๋ก ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์์.
- ์์ํจ์: ์ธ๋ถ ๋ณ์๋ ์ ์ญ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ์ ๋ ฅ๊ฐ์ ๋ฐ๋ผ ํญ์ ๋์ผํ ๊ฒฐ๊ณผ ๋ฐํ
function add(a, b) {
return a + b;
}
const result = add(2, 3);
console.log(result);
2. ์กฐํ ์ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ
const user = {
_name: "Hany",
get name() {
console.log("์ด๋ฆ์ด ๋ญ์์?");
return this._name; // ๊ฐ์ ๋ณ๊ฒฝํ์ง ์๊ณ ๊ทธ๋๋ก ๋ฐํ
}
};
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany"
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany"
console.log(user.name); // "์ด๋ฆ์ด ๋ญ์์?" ์ถ๋ ฅ ํ "Hany"
3.์๋ณธ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ์๋ก์ด ๊ฐ์ ๋ฐํํ๋ ๋ด์ฅ ํจ์
arr.slice(1);
arr.map((num) => num * 2);
arr.filter((num) => num > 1);
str.toUpperCase();
str.repeat(3);
Math.floor(4.8);
Math.abs(-10);
์ด์ฒ๋ผ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ์ฝ๋๋ ๋ฒ๋ค๋ฌ๊ฐ ์์ ํ๋ค๊ณ ํ๋จํ๋ฉด, ์ต์ข ๋ฒ๋ค์์ ์ ๊ฑฐ๋ผ์.
ํธ๋ฆฌ์ ฐ์ดํน ์ต์ ํ๋ฅผ ์ํ ์ถ๊ฐ ์ค์
์ค์ ๋ก ์์ฑํ๋ ์ฝ๋์๋ ์ฌ์ด๋ ์ดํํธ๊ฐ ํฌํจ๋ ๋๊ฐ ๋ง์์. ๋ฒ๋ค๋ฌ๊ฐ ์ด๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์๋๋ก, ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ฑฐ๋, ๋ฒ๋ค๋ฌ๊ฐ ์๋์ผ๋ก ์ต์ ํ๋ฅผ ์ํํ ์๋ ์์ด์.
๋ํ์ ์ธ ๋ฐฉ๋ฒ์ ๋ค์ ๋ ๊ฐ์ง์์.
์ฃผ์ ์ค์
/* @__PURE__ */ ์ฃผ์์ ์ด ์ฝ๋๊ฐ ์คํ๋๋๋ผ๋ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ค๋ ๊ฒ์ ๋ฒ๋ค๋ฌ์๊ฒ ๋ช ์์ ์ผ๋ก ์๋ฆฌ๋ ์ญํ ์ ํด์. ์ฆ, ์ธ๋ถ ์ํ์ ์ํฅ์ ์ฃผ์ง ์๋๋ค๊ณ ๋จ์ธํ๋ ๊ฑฐ์์. ํธ๋ฆฌ์ ฐ์ดํน ์ต์ ํ๋ฅผ ์ํด ๋ฒ๋ค๋ฌ๊ฐ ๋ฒ๋ค๋ง ๊ณผ์ ์์ ์๋์ผ๋ก ์ถ๊ฐํ ์๋ ์๊ณ , ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ช ์์ ์ผ๋ก ์ถ๊ฐํ ์๋ ์์ด์.
๋ค์๊ณผ ๊ฐ์ด /* @__PURE__ */ ์ฃผ์์ด ํฌํจ๋ ์ฝ๋๋ฅผ ๋ฒ๋ค๋งํ๋ฉด,
const Icon = /* @__PURE__ */ React.createElement(...);
๋ฒ๋ค๋ฌ๋ ํด๋น ์ฝ๋๊ฐ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ค๊ณ ํ๋จํ ์ ์์ด์. ๊ทธ ๊ฒฐ๊ณผ, ์ต์ ํ ๊ณผ์ ์์ ํ์ํ์ง ์์ ๊ฒฝ์ฐ ์๋์ฒ๋ผ ์ ๊ฑฐ๋ ์ ์์ด์.
const Icon = /* @__PURE__ */ React.createElement(...);
sideEffects ํ๋ ํ์ฉ
package.json ํ์ผ์ sideEffects ํ๋๋ ํน์ ํ์ผ์ด๋ ์ฝ๋๊ฐ ๋ฒ๋ค๋ง ๊ณผ์ ์์ ์ ๊ฑฐ๋์ง ์๋๋ก ๋ฒ๋ค๋ฌ์ ์๋ ค์ฃผ๋ ์ญํ ์ ํด์.
๋ชจ๋ ํ์ผ์ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ค๊ณ ์ ์ธํ๊ธฐ
// package.json
{
"sideEffects": false
}
์ด๋ ๊ฒ ์ค์ ํ๋ฉด, ๋ฒ๋ค๋ฌ๋ ์ฌ์ฉ๋์ง ์๋ ๋ชจ๋ ํ์ผ์ ์์ ํ๊ฒ ์ ๊ฑฐํ ์ ์์ด์.
ํน์ ํ์ผ์ด๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ๊ฑฐํ์ง ์๋๋ก ์ค์ ํ๊ธฐ
// package.json
{
"sideEffects": ["*.css", "./src/global.js"]
}
์ด ์ค์ ์ CSS ํ์ผ๊ณผ ํน์ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ด ์ ๊ฑฐ๋์ง ์๋๋ก ๋ช ์ํ๋ ๋ฐฉ์์ด์์. ์๋ฅผ ๋ค์ด, global.js ํ์ผ์ด ์ ์ญ ๋ณ์๋ฅผ ์ค์ ํ๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๊ธฐํ๋ฅผ ๋ด๋นํ๋ ๊ฒฝ์ฐ, ํธ๋ฆฌ์ ฐ์ดํน ๊ณผ์ ์์ ์ค์๋ก ์ ๊ฑฐ๋์ง ์๋๋ก ๋ณดํธํ ์ ์์ด์.
์ด๋ ๊ฒ ํ์ํ ํ์ผ์ ์ง์ ํ๋ฉด, ํธ๋ฆฌ์ ฐ์ดํน์ ํจ๊ณผ๋ฅผ ์ ์งํ๋ฉด์๋ ํ์์ ์ธ ์ฝ๋๊ฐ ๋ฒ๋ค์์ ๋น ์ง๋ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ด์. ์ด๋ก์จ ๋น๋ ์ฑ๋ฅ์ ์ต์ ํํ ์ ์์ด์.
๋ฒ๋ค๋ฌ ์ธํ ๊ฐ์ด๋
ํธ๋ฆฌ์ ฐ์ดํน์ผ๋ก ์ฌ์ฉํ์ง ์๋ ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋๋ผ๋, ๋น๋ ๊ฒฐ๊ณผ๋ฌผ์๋ ์ฌ์ ํ ๋ถํ์ํ ๊ณต๋ฐฑ, ์ฃผ์, ์ต์ ํ๋์ง ์์ ํํ ๋ฑ์ด ๋จ์ ์์ ์ ์์ด์. ํ๋ก๋์ ๋น๋์์๋ ์ด ์์ฌ ์์๋ฅผ ์์ถ(minify)ํด ์ฝ๋ ํฌ๊ธฐ๋ฅผ ์ถ๊ฐ๋ก ์ค์ฌ์ผ ์ต์ข ๋ฒ๋ค์ ์ฑ๋ฅ์ ๊ทน๋ํํ ์ ์์ด์.
์ค์น ๋ฐฉ๋ฒ
npm install --save-dev terser-webpack-plugin
์ค์ ์์
// webpack.config.js
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [new TerserPlugin()]
}
};
๐ค ๊ทธ๋ ๋ค๋ฉด Webpack์ ์ด๋ป๊ฒ ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๋ง๋ค๊ณ , AST ๋ถ์์ ํตํด ํธ๋ฆฌ ์์ดํน(Tree Shaking)์ ์ํํ ๊น์?
์์กด์ฑ ๊ทธ๋ํ
- ์ํธ๋ฆฌ(entry)์์ ์์ : Webpack์ index.js๋ฅผ ์ฝ๊ณ import/require ๊ตฌ๋ฌธ์ ์ถ์ ํ๊ธฐ ์์ํฉ๋๋ค.
- entry: "./src/index.js"
- ๋ชจ๋ ํ์
- import A from './A.js'
- import { B } from './B.js'
์ด๋ฐ ๊ตฌ๋ฌธ์ ๋ฐ๋ผ๊ฐ๋ฉฐ ๋ชจ๋๋ค์ ์์งํฉ๋๋ค.
- ๊ทธ๋ํ ๊ตฌ์ฑ
- ๊ฐ ๋ชจ๋์ ๋ ธ๋(node)๋ก, import ๊ด๊ณ๋ฅผ ์ฃ์ง(edge)๋ก ์ฐ๊ฒฐ
- ์ต์ข ์ ์ผ๋ก ํ๋์ Directed Graph(์์กด์ฑ ๊ทธ๋ํ)๊ฐ ๋ง๋ค์ด์ง
AST ๋ณํ
- Webpack ์์ฒด๋ AST๋ฅผ ์ง์ ๋ค๋ฃจ์ง ์๊ณ , acorn(JS ํ์) ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด์ ์์ค๋ฅผ AST(Abstract Syntax Tree)๋ก ๋ณํํฉ๋๋ค.
- ๊ฐ ๋ชจ๋์ ์์ค ์ฝ๋๋ฅผ AST๋ก ํ์ฑ → import/export ๊ตฌ๋ฌธ์ ํ์ง → ๊ทธ๋ํ์ ์ฐ๊ฒฐ
์:
import { add } from "./math.js";
console.log(add(2, 3));
์ด๋ฅผ AST๋ก ๋ณํํ๋ฉด:
- ImportDeclaration ๋ ธ๋ (math.js๋ฅผ ๊ฐ์ ธ์ด)
- CallExpression ๋ ธ๋ (add ํจ์ ํธ์ถ)
- MemberExpression, Identifier ๋ฑ๋ฑ
Webpack์ ์ด AST๋ฅผ ํด์ํด์ ์ค์ ๋ก ์ด๋ค ์ฌ๋ณผ์ด ์ฌ์ฉ๋๋์ง๋ฅผ ๋ถ์ํฉ๋๋ค.
ํธ๋ฆฌ ์์ดํน (Tree Shaking)
https://webpack.kr/guides/tree-shaking/
Tree Shaking | ์นํฉ
์นํฉ์ ๋ชจ๋ ๋ฒ๋ค๋ฌ์ ๋๋ค. ์ฃผ์ ๋ชฉ์ ์ ๋ธ๋ผ์ฐ์ ์์ ์ฌ์ฉํ ์ ์๋๋ก JavaScript ํ์ผ์ ๋ฒ๋ค๋ก ๋ฌถ๋ ๊ฒ์ด์ง๋ง, ๋ฆฌ์์ค๋ ์ ์ ์ ๋ณํํ๊ณ ๋ฒ๋ค๋ง ๋๋ ํจํค์งํ ์๋ ์์ต๋๋ค.
webpack.kr
ํธ๋ฆฌ ์์ดํน์ ๋๋ฌด๋ฅผ ํ๋ค์ด์ ์ฃฝ์ ๋๋ญ์์ ๋จ์ดํธ๋ฆฌ๋ ๊ฒ์ฒ๋ผ ๋น๋ ๊ณผ์ ์์ ์ฌ์ฉ๋์ง ์๋(exported but unused) ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋ ์ต์ ํ ๊ธฐ๋ฒ์ ๋๋ค.
Webpack ๋ฌธ์์์ ๋งํ๋ Tree Shaking
- Tree Shaking์ด๋ ์ฌ์ฉ๋์ง ์๋ ์ฝ๋(์: exportํ์ง๋ง import๋์ง ์๊ฑฐ๋ ํธ์ถ๋์ง ์๋ ํจ์/๋ณ์/๋ชจ๋)๋ฅผ ๋ฒ๋ค์์ ์ ๊ฑฐํ๋ ์ต์ ํ ๊ธฐ๋ฒ.
- ์ด๊ฒ์ด ๊ฐ๋ฅํ๋ ค๋ฉด ES2015 ๋ชจ๋(์ฆ, import / export) ๊ตฌ๋ฌธ์ ์ฌ์ฉํด์ผ ํจ. ์ ์ ๊ตฌ์กฐ(static structure)์ด ๋ณด์ฅ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ.
- Webpack 2๋ถํฐ๋ ESM์ export ์ค ์ฌ์ฉ๋์ง ์๋(export๋ง ๋๊ณ ์ฌ์ฉ๋์ง ์๋) export๋ฅผ ๊ฐ์ง ๊ฐ๋ฅํ๋ฉฐ, Webpack 4์์๋ package.json์ "sideEffects" ํ๋๋ฅผ ํตํด “์ด ํ์ผ/๋ชจ๋์ด side effects(๋ถ์ํจ๊ณผ)๊ฐ ์๋๊ฐ ์๋๊ฐ”๋ฅผ ์ฌ์ฉ์/๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ์๊ฐ ํ์ํ ์ ์๊ฒ ํ์ฅ๋จ.
ํธ๋ฆฌ ์์ดํน์ ์๋ ํ๋ฆ
Webpack ๋ฌธ์ ์์ ๋ฅผ ๋ฐํ์ผ๋ก ํ๋ฆ์ ์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ESM ๋ชจ๋ ์์ฑ
- ์๋ฅผ ๋ค๋ฉด src/math.js ํ์ผ์ square ์ cube ํจ์๋ฅผ export ํจ.
- ์ํธ๋ฆฌ(entry) ์ฝ๋์์ ์ผ๋ถ๋ง ์ฌ์ฉ
- index.js์์ cube๋ง import ์ฌ์ฉ. square๋ ์ฌ์ฉ๋์ง ์์.
- Webpack ์ค์ : usedExports ์ต์
ํ์ฑํ
- usedExports: true ์ค์ ์ ํตํด Webpack์ด ์ด๋ค export๊ฐ “์ฌ์ฉ๋จ(used)”์ธ์ง ๋งํนํจ.
- ๋น๋ ๊ฒฐ๊ณผ ์ดํด๋ณด๊ธฐ
- ์ฌ์ฉ๋์ง ์๋ square ํจ์ ์์ /* unused harmony export square */ ์ด๋ฐ ์ฃผ์์ด ๋ถ์. ์ด๋ “square๋ ์ฌ์ฉ๋์ง ์๋ export”๋ผ๋ ํ์.
- ํ์ง๋ง ๊ฐ๋ฐ ๋ชจ๋(dev mode)์์๋ ์ฝ๋๊ฐ ์ ๊ฑฐ๋์ง ์๊ณ ์ฌ์ ํ ๋ฒ๋ค์ ๋จ์ ์ ์์.
- sideEffects ์ค์ ์ง์
- package.json์ "sideEffects": false ๋๋ ์ด๋ค ํ์ผ๋ง sideEffect๊ฐ ์๋์ง ๋ฐฐ์ด๋ก ๋ช ์ํ๋ ๋ฐฉ์์ผ๋ก ์ค์ ๊ฐ๋ฅ.
- ์: ์ฌ์ด๋ ์ดํํธ ์๋ ํ์ผ์ ์ฌ์ฉ๋์ง ์์ผ๋ฉด ์์ ํ ์ ๊ฑฐ ๊ฐ๋ฅ. CSS ํ์ผ ๋ฑ์ฒ๋ผ import ์ ์คํ์ผ ์ ์ฉ ๊ฐ์ ๋ถ์์ ํจ๊ณผ๊ฐ ์๋ ํ์ผ์ sideEffects ๋ฆฌ์คํธ์ ํฌํจ์์ผ์ผ ์ ๊ฑฐ๋์ง ์์.
- Production ๋ชจ๋๋ก ๋น๋ → Minification ํฌํจ
- mode: "production" ์ค์ ์ Webpack์ ์ฌ๋ฌ ์ต์ ํ ์ต์ ์ ์๋์ผ๋ก ์ฌ์ฉ (์: ModuleConcatenationPlugin, Terser ๋ฑ)
- ์ด ๊ณผ์ ์์ ์ค์ ๋ก “์ฌ์ฉ๋์ง ์๋ ์ฝ๋”๊ฐ ์ ๊ฑฐ๋จ.
“sideEffects”์ "usedExports"์ ๊ด๊ณ ๋ฐ ์ ์์
Webpack ๋ฌธ์์์๋ usedExports ๋ง์ผ๋ก๋ ๋ถ์กฑํ ๊ฒฝ์ฐ๋ ๋ง๋ค๋ฉฐ, sideEffects ํ๋๊ทธ์ ์ค์์ฑ์ ๊ฐ์กฐํฉ๋๋ค. ์ฃผ์ ์ ์์ ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- sideEffects: false → “์ด ๋ชจ๋ ํน์ ํ์ผ์ import ๋์์ ๋ ๋ถ์์ ํจ๊ณผ(side effect)๊ฐ ์๋ค”๋ ํํธ. ์๋ชป ์ค์ ํ๋ฉด ํ์ํ ์ฝ๋(์: CSS, ํด๋ฆฌํ, ๊ธ๋ก๋ฒ ์ด๊ธฐํ ์ฝ๋ ๋ฑ)๊ฐ ์ ๊ฑฐ๋ ์ํ์ด ์์.
- ๋ถ์ ํจ๊ณผ๊ฐ ์๋ ํ์ผ → sideEffects ํ๋์ ๋ช ์ํด์ผ ํจ. ์: CSS ํ์ผ, ๊ธ๋ก๋ฒ ์ค์ฝํ ์กฐ์ ๋ฑ์ด ์๋ ํ์ผ.
- ์ฌ์์ถ(re-export) ํจํด์์๋ ํนํ ์กฐ์ฌํด์ผ ํจ.
์: ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ export * from './components' ๋ฑ์ผ๋ก ์ฌ๋ฌ ํ์ผ์ ์ฌ์์ถํ๋ ๊ฒฝ์ฐ, ์ผ๋ถ ํ์ผ๋ค์ด sideEffects ์๋ค๊ณ ํ์๋์๋๋ผ๋ ๋ด๋ถ ์์กด์ฑ ๋๋ฌธ์ ์์ ํ ์ ๊ฑฐ๋์ง ์๊ฑฐ๋ ์์๊ณผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์ ์์.
๊ฒฐ๋ก
Webpack ๊ณต์ ๊ธ์ ์์ ๋ค์ ํฉ์น๋ฉด, ํธ๋ฆฌ ์์ดํน์ด ์ ๋๋ก ์๋ํ๋ ค๋ฉด ๋ค์ ์กฐ๊ฑด๋ค์ด ํ์ํฉ๋๋ค.
- ES2015 ๋ชจ๋ ๊ตฌ๋ฌธ (import/export) ์ฌ์ฉ
- usedExports ์ต์ ํ์ฑํ
- production mode ์ฌ์ฉํ์ฌ minification ๋ฑ์ ์ต์ ํ ํ์ฑํ
- package.json์ sideEffects ํ๋๋ก “์ด๋ ํ์ผ์ด ๋ถ์ ํจ๊ณผ(side effects)๊ฐ ์๋์ง ์๋์ง” ๋ช ํํ ํ์
- ์คํ์ผ(css), ํด๋ฆฌํ, ๊ธ๋ก๋ฒ ์ด๊ธฐํ ์ฝ๋์ฒ๋ผ ๋ถ์ ํจ๊ณผ๊ฐ ์๋ ์ฝ๋๊ฐ ์๋ชป ์ ๊ฑฐ๋์ง ์๋๋ก ์ฃผ์
์ด๋ฐ ์์๋ค์ด ์กฐํฉ๋๋ฉด ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๋ฉด์๋ ๊ธฐ๋ฅ์ด ๊นจ์ง์ง ์๋ ์ต์ ํ๊ฐ ๊ฐ๋ฅํด์ง๋๋ค.
Webpack์ ๋ค์ ๋จ๊ณ๋ก ์ํ๋ฉ๋๋ค.
- ESM(ECMAScript Module) ๊ธฐ๋ฐ๋ง ์ง์
- import / export ๊ตฌ๋ฌธ์ ์ ์ ๋ถ์(static analysis)์ด ๊ฐ๋ฅ
- CommonJS(require)๋ ๋ฐํ์์ ๋์ ์ผ๋ก ๊ฒฐ์ ๋๋ฏ๋ก ํธ๋ฆฌ ์์ดํน์ด ์ด๋ ค์
- AST๋ฅผ ํตํ ์ฌ์ฉ ์ฌ๋ถ ์ถ์
- export function foo() {} ๊ฐ์ ์ ์ธ์ ์ฐพ์
- ์์กด์ฑ ๊ทธ๋ํ์์ ์ค์ ๋ก foo๊ฐ import + ์ฌ์ฉ๋๋์ง ํ์ธ
- ์ฌ์ฉ๋์ง ์์ผ๋ฉด “dead code”๋ก ํ์
- ๋งํน ๋จ๊ณ (Mark phase)
- Webpack์ Terser(์์ถ๊ธฐ)๋ฅผ ํธ์ถํ๊ธฐ ์ , ์ฌ์ฉ๋์ง ์๋ export๋ฅผ "unused"๋ก ๋งํนํฉ๋๋ค.
- ์ด๋ ๋จ์ํ import ๋์ง ์์ ํจ์·๋ณ์๋ “์ ๊ฑฐ ๊ฐ๋ฅ(dead)”๋ก ํ๊ทธ
- ์์ถ ๋จ๊ณ (Sweep phase)
- ์ต์ข ๋ฒ๋ค๋ง ์ Terser ๊ฐ์ minifier๊ฐ AST๋ฅผ ๋ค์ ๋ถ์ํ์ฌ, dead code๋ฅผ ์ค์ ๋ก ์ญ์
- ์ฆ, Webpack์ unused code๋ฅผ ํ์ํ๊ณ , Terser๊ฐ ์ฝ๋ ์ ๊ฑฐ๋ฅผ ์คํ
- Webpack์ ์ํธ๋ฆฌ์์ ์์ํด import/require๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉฐ ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ์์ฑ
- ๊ฐ ๋ชจ๋ ์์ค๋ฅผ AST๋ก ํ์ฑํด ์ด๋ค export/import๊ฐ ์ฐ์ด๋์ง ๋ถ์
- ํธ๋ฆฌ ์์ดํน: ์ฌ์ฉ๋์ง ์๋ export๋ ๋งํน → Terser ๊ฐ์ ์ต์ ํ ๋๊ตฌ๊ฐ ์ค์ ์ญ์
'๐ ํ๋ก ํธ์๋(FE)' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์ง๋ ๋ทฐํฌํธ ๊ธฐ๋ฐ ์ค์๊ฐ ์์ ๊ฒ์ ๊ตฌํ (0) | 2026.01.14 |
|---|---|
| ์น ์ ๋๋ฉ์ด์ ์ ๋๋ก ํ์ฉํ๊ธฐ: Transition, Keyframes, rAF, WAAPI ๋น๊ต์ ํ์ฉ๋ฒ (0) | 2025.09.24 |
| Webpack + Babel + TypeScript ์ค์ ๊ฐ์ด๋ (0) | 2025.09.16 |
| MVC ๊ตฌ์กฐ - ์ต์ ๋ฒ ํจํด ( Observer Pattern ) (0) | 2025.09.08 |
| [Javascript] ์ด๋ฒคํธ ์ ํ & ์ด๋ฒคํธ ์์ (1) | 2025.09.08 |