모듈 그래프: 빌드 도구는 어떤 파일이 필요한지 어떻게 찾는가
진입점에서 정적 import를 따라가며 모듈과 의존 관계를 발견하는 과정을 작은 예제로 익히고, 예상하지 못한 코드가 포함되거나 빠졌을 때 확인할 지점을 찾는다.
목차
표준·구현·측정·해석 표시는 무엇인가요?
- 표준웹 표준이나 언어 명세가 정한 동작
- 구현특정 기술이나 브라우저가 실제로 구현한 동작
- 측정명시한 환경에서 직접 실행해 관찰한 결과
- 해석앞선 근거에서 도출한 설계 판단
- 미확인아직 공식 근거나 재현 결과를 확인하지 못한 내용
30초 요약
이 글에서 기억할 것은 네 문장이다.
- 빌드 도구는 지정된 진입점에서 출발한다.
- 각 모듈의 정적
import를 따라 다음 모듈을 찾는다. - 찾은 모듈은 점으로, 의존 관계는 방향 있는 선으로 기록한다.
- 예상과 다른 포함·누락은 진입점에서 이어지는 경로부터 확인한다.
여기서 빌드 도구는 여러 모듈을 실행 가능한 결과로 준비하는 프로그램을 뜻한다.
import는 다른 모듈이 내보낸 값을 가져오겠다고 선언하는 자바스크립트 문법이다.
이 글을 붙잡을 실무 질문은 하나다.
첫 화면에서 쓰지 않는 차트 코드가 왜 클라이언트 JavaScript에 들어왔을까?
뒤에서 폴더 크기를 추측하는 대신, 클라이언트 진입 경계에서 차트 모듈까지 이어지는
import 경로를 찾는 방식으로 이 질문에 답한다.
모듈 그래프는 폴더 트리가 아니다
먼저 같은 폴더에 네 파일만 있는 작은 프로그램을 보자.
main.js
├─ header.js
│ └─ theme.js
└─ profile.js
└─ theme.js이 그림만 보면 theme.js가 두 번 있는 것처럼 보인다. 실제 의존 관계를 방향으로
적으면 다음과 같다.
main.js ──▶ header.js ──┐
├──▶ theme.js
main.js ──▶ profile.js ──┘폴더 트리는 한 항목의 부모가 하나라는 모양을 전제로 한다. 모듈 그래프에서는 여러 모듈이 같은 모듈을 가져올 수 있고, 서로를 가져오는 순환도 생길 수 있다. 따라서 “어느 폴더 안에 있는가”와 “현재 실행 결과에 왜 필요한가”는 다른 질문이다.
진입점에서 도달할 수 있는 모듈을 찾는다
예제의 코드는 다음처럼 연결된다.
// main.js
import "./header.js"
import "./profile.js"
// header.js
import "./theme.js"
// profile.js
import "./theme.js"모듈 지정자(module specifier)는 "./header.js"처럼 import의 from 뒤나 위
예제의 따옴표 안에 적는 문자열이다. 그 문자열이 실제 어느 파일을 가리키는지 정하는
과정은 모듈 해석(module resolution)이라고 하며 다음 글에서 다룬다.
과정을 짧게 적으면 다음과 같다.
main.js를 진입점으로 놓는다.main.js의 두import에서header.js와profile.js를 찾는다.- 두 모듈의
import를 읽어theme.js를 찾는다. - 더 따라갈 새 의존 관계가 없으면 탐색을 마친다.
프로젝트에 debug-only.js가 존재하더라도 이 경로와 이어지지 않았다면 이 예제의
그래프에는 들어오지 않는다. 다만 실제 도구에서는 여러 진입점이나 플러그인 설정이
새 출발점 또는 관계를 추가할 수 있으므로, “정적 import만 본다”를 모든 도구의
보편 규칙으로 확대하면 안 된다.
같은 모듈을 둘이 가져와도 점은 하나다
이 구분은 “왜 같은 코드가 여러 곳에서 필요해 보이는가”를 이해하는 출발점이다. 하지만 최종 출력 파일에 코드가 정확히 몇 번 들어가는지는 아직 답할 수 없다. 빌드 도구는 모듈 그래프를 만든 뒤 코드를 변환하고, 필요 없는 내보내기를 제거하거나, 여러 청크로 나눌 수 있다. 이 글의 그래프는 그 뒤의 출력 모양이 아니라 필요 관계를 발견한 결과다.
도구가 달라도 출발 질문은 같다
변하지 않는 질문은 “어느 진입점에서 어떤 의존 관계를 따라 이 모듈에 도달했는가”다. 현재 도구들은 이 질문을 각자의 처리 과정과 화면으로 보여준다.
도구 이름과 화면은 바뀔 수 있다. 그래서 먼저 그래프의 점·선·진입점을 이해하고, 현재 도구의 화면은 그 모델을 관찰하는 수단으로 사용하는 편이 낫다.
React에서는 클라이언트 경계를 설명해 준다
React 자체의 컴포넌트 트리와 모듈 그래프는 같은 것이 아니다. 컴포넌트 트리는 화면을 구성하는 관계이고, 모듈 그래프는 코드가 다른 코드를 가져오는 관계다. 한 파일에서 여러 컴포넌트를 내보낼 수도 있으므로 둘의 모양은 일치하지 않을 수 있다.
따라서 클라이언트에서 필요하지 않은 큰 모듈이 포함되었을 때는 컴포넌트 이름만 보는
것보다, 어느 "use client" 경계 아래의 import가 그 모듈까지 이어지는지 확인하는
편이 원인에 더 가깝다. 이것은 Next.js의 현재 구현 경계를 설명하는 예이며 모든 React
환경이 같은 지시문을 사용한다는 뜻은 아니다.
차트 코드가 들어온 경로를 끝까지 따라간다
대표 상황을 하나 따라가 보자. 대시보드의 첫 화면에는 요약 숫자만 보이고, 사용자가 분석 탭을 열 때만 차트가 필요하다고 하자. 그런데 운영 빌드에서 초기 클라이언트 JavaScript가 예상보다 커졌다.
DashboardShell.tsx "use client"
└─ import ChartPanel.tsx
└─ import chart-library차트가 처음부터 화면에 보이지 않는다는 사실은 모듈 그래프에서 제외된다는 뜻이 아니다.
DashboardShell.tsx가 클라이언트 경계이고 정적 import 경로가 이어져 있다면 차트
라이브러리도 그 클라이언트 그래프에 들어간다.
이때 차트 패키지 안의 파일부터 지우거나 압축 설정부터 바꾸면 왜 포함됐는가는 남는다. 먼저 도구의 모듈 그래프나 분석 결과에서 다음 경로가 실제로 존재하는지 확인한다.
클라이언트 경계 → ChartPanel → chart-library경로를 확인한 뒤에야 선택할 수 있다.
- 차트가 클라이언트에서 즉시 필요하다면 포함을 받아들이고 크기·사용량을 측정한다.
- 상호작용이 필요한 작은 부분만 클라이언트라면
"use client"경계를 더 아래로 옮긴다. - 나중에만 필요한 코드라면 동적
import()로 경로를 나누는 방법을 4편에서 검토한다. - 실제로 서버에서만 필요한 계산이라면 클라이언트 경계 아래의 import를 제거한다.
변경 뒤에는 같은 분석에서 불필요한 정적 경로가 사라졌는지 먼저 확인하고, 운영 빌드의 초기 JavaScript와 실제 화면 동작을 함께 비교한다. 그래프는 해결책을 자동으로 고르지 않지만, 어떤 경계를 바꿔야 하는지는 보여 준다.
포함과 누락은 그래프의 경로부터 확인한다
확인 순서는 다음처럼 짧게 유지할 수 있다.
| 관찰한 문제 | 먼저 묻는 질문 | 다음 글에서 이어질 질문 |
|---|---|---|
| 예상하지 못한 모듈이 들어옴 | 어느 진입점과 import 경로가 끌어왔는가? | 그 문자열은 왜 그 파일로 연결됐는가? |
| 필요한 모듈이 보이지 않음 | 현재 진입점에서 의존 관계가 이어지는가? | 해석 규칙이 다른 파일을 선택했는가? |
| 공유 모듈이 큼 | 어떤 모듈들이 같은 점을 필요로 하는가? | 최종 출력은 어떻게 나뉘는가? |
그래프 경로가 확인되면 그다음에야 경계를 옮길지, 가져오는 방식을 바꿀지, 출력 묶음을 나눌지 판단할 수 있다. 경로를 모른 채 파일 크기만 줄이면 포함된 이유는 남아 있을 수 있다.
이 글의 경계
이번 글은 정적 import로 발견하는 기본 그래프에 집중했다. 다음 내용은 의도적으로
분리한다.
- 모듈 지정자를 실제 파일로 연결하는 규칙: 모듈 해석
- TypeScript나 JSX를 실행 가능한 코드로 바꾸는 과정: 변환
- 동적
import()와 여러 출력 파일: 코드 분할 - 사용하지 않는 내보내기를 제거하는 과정: 트리 셰이킹
- 모듈을 어떤 순서로 평가하고 실행하는가: 실행 순서
다음 글에서는 "./theme.js", 패키지 이름, 확장자, 플랫폼별 파일이 어떤 규칙으로
하나의 모듈에 연결되는지 살펴본다.
Active recall
기억에서 꺼내 보기
답을 쓰지 않아도 됩니다. 먼저 머릿속으로 답한 뒤 펼쳐서 정답·이유·흔한 오해를 비교하세요.
01모듈 그래프에서 점과 방향 있는 선은 각각 무엇을 뜻할까?
정답
점은 모듈이고, 방향 있는 선은 한 모듈이 다른 모듈을 필요로 한다는 의존 관계다.
관련 설명 다시 읽기왜 그런가
파일 배치가 아니라 코드가 선언한 필요 관계를 그린 구조라는 점이 핵심이다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
02빌드 도구는 모듈 그래프를 어디서부터 찾기 시작할까?
정답
설정이나 실행 명령으로 지정된 진입점에서 시작해 그 모듈의 의존 관계를 따라간다.
관련 설명 다시 읽기왜 그런가
프로젝트에 파일이 존재한다는 사실만으로는 그 파일이 현재 진입점의 그래프에 포함되지 않는다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
03`header.js`와 `profile.js`의 요청이 같은 `theme.js` 파일로 해석되면 그래프의 `theme.js`는 몇 개인가?
정답
하나다. 같은 파일로 해석된 하나의 `theme.js` 모듈 점으로 두 의존 관계가 들어온다.
관련 설명 다시 읽기왜 그런가
이 모양 때문에 모듈 그래프는 각 항목에 부모가 하나뿐인 트리와 다르다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
04예상하지 못한 모듈이 클라이언트 결과에 포함되었다면 가장 먼저 무엇을 확인할까?
정답
현재 진입점에서 그 모듈까지 이어지는 의존 관계를 확인한다. 도구가 그래프 경로를 보여주면 그것을 우선 사용한다.
관련 설명 다시 읽기왜 그런가
포함 경로를 찾으면 어떤 import나 경계가 모듈을 끌어왔는지 좁힐 수 있다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
출처와 검증 범위
아래 날짜는 링크를 마지막으로 열어 본 날입니다. 문서 상단의 검증일은 글의 설명과 적용 범위를 다시 확인한 날입니다.
- ECMAScript Language Specification — Scripts and ModulesEcma International · 표준 명세 · 확인 2026-08-04
- LoadRequestedModulesEcma International · 표준 명세 · 확인 2026-08-04
- Dependency Graphwebpack · 공식 문서 · 확인 2026-08-04
- Entry Pointswebpack · 공식 문서 · 확인 2026-08-04
- ConceptsMetro · 공식 문서 · 확인 2026-08-04
- Rolldown DevToolsVite · 공식 문서 · 확인 2026-08-04
- Server and Client ComponentsNext.js · 공식 문서 · 확인 2026-08-04