소스맵 (Source Map)
1. 개요
소스맵(Source Map)이란 빌드 과정에서 변환, 압축, 번들링된 코드와 원본 소스 코드 사이의 대응 관계를 기록한 JSON 형식의 매핑 파일이다.
현대 웹 개발에서는 성능 최적화를 위해 다음과 같은 과정을 거친다.
- 번들링(Bundling): 여러 개의 모듈 파일을 하나 또는 소수의 파일로 합치는 과정
- 미니피케이션(Minification): 공백 제거, 변수명 축약 등을 통해 파일 크기를 최소화하는 과정
- 트랜스파일링(Transpiling): TypeScript나 최신 JavaScript(ES6+) 코드를 구형 브라우저가 이해할 수 있는 ES5 버전으로 변환하는 과정
이러한 과정을 거친 결과물은 컴퓨터가 읽기에는 최적화되어 있으나, 사람이 읽기에는 거의 불가능한 형태가 된다. 이때 런타임 에러가 발생하면 브라우저는 변환된 코드의 라인 번호를 출력하므로, 개발자는 실제 원본 코드의 어느 지점에서 문제가 발생했는지 파악하기 어렵다. 소스맵은 이 간극을 메워 브라우저 개발자 도구에서 원본 코드를 그대로 보며 디버깅할 수 있게 해주는 필수적인 도구이다.
2. 작동 원리
소스맵은 변환된 코드의 특정 위치(행, 열)가 원본 파일의 어느 위치에 해당하는지를 좌표 형태로 저장한다. 브라우저는 변환된 파일 하단에 포함된 //# sourceMappingURL=... 주석을 통해 .map 파일을 찾아 로드하며, 이를 기반으로 원본 코드를 재구성하여 화면에 보여준다.
원본 코드 vs 변환된 코드 대응 예시
| 구분 |
원본 코드 (Original Source) |
변환된 코드 (Generated Code) |
소스맵의 역할 |
| 코드 형태 |
function add(a, b) { return a + b; } |
function n(t,r){return t+r} |
n $\rightarrow$ add 매핑 |
| 위치 |
main.ts / 10행 5열 |
bundle.min.js / 1행 12열 |
1:12 $\rightarrow$ 10:5 매핑 |
| 가독성 |
높음 (의미 있는 변수명) |
낮음 (축약된 변수명) |
원본 변수명 복원 |
소스맵 파일 내부 JSON 구조
소스맵 파일은 표준화된 JSON 형식을 따른다. 아래는 단순화된 .map 파일의 예시이다.
{
"version": 3,
"file": "bundle.min.js",
"sourceRoot": "",
"sources": ["main.ts", "utils.ts"],
"names": ["add", "a", "b"],
"mappings": "AAAA,GAAG,KAAM,CAAC,EAAE,GAAG,CAAC",
"sourcesContent": ["function add(a, b) { return a + b; }", "export const pi = 3.14;"]
}
-
version: 소스맵 표준 버전 (현재 대부분 3 사용)
-
sources: 원본 파일들의 경로 목록
-
names: 변수명, 함수명 등 축약 전의 원래 이름 목록
-
mappings:
Base64 VLQ 방식으로 인코딩된 매핑 데이터. 가변 길이 정수(VLQ)를 Base64로 인코딩하여 파일 크기를 줄인 형태이며, 이는
[생성된 열, 원본 파일 인덱스, 원본 행, 원본 열, 이름 인덱스] 순의 상대적 거리 값을 저장한다.
-
sourcesContent: 원본 소스 코드 내용 (포함 시 별도의 원본 파일 없이도 복구 가능)
3. 소스맵의 종류
빌드 도구(Webpack 등)는 개발 단계와 운영 단계의 요구사항이 다르기 때문에 다양한 소스맵 생성 옵션을 제공한다.
| 옵션 |
빌드 속도 |
디버깅 정확도 |
파일 크기 |
특징 및 용도 |
eval |
매우 빠름 |
낮음 |
매우 큼 |
코드를 eval()로 감싸 생성. 개발 환경 전용. |
cheap-module-source-map |
중간 |
중간 |
중간 |
원본 소스 매핑은 지원하지만 열(column) 단위 디버깅은 불가능하며 행(line) 정보만 제공함. |
source-map |
느림 |
매우 높음 |
큼 |
완전한 소스맵 생성. 별도의 .map 파일 생성. 운영/분석용. |
hidden-source-map |
느림 |
매우 높음 |
큼 |
.map 파일은 생성하지만, JS 파일에 참조 주석을 넣지 않음. |
nosources-source-map |
느림 |
중간 |
작음 |
소스 내용은 제외하고 매핑 정보만 포함. |
4. 설정 및 사용 방법
주요 빌드 도구 설정
가장 널리 쓰이는 Webpack의 경우 devtool 속성을 통해 설정한다.
// webpack.config.js
module.exports = {
// 개발 환경: 빠른 리빌드와 적절한 디버깅
mode: 'development',
devtool: 'eval-cheap-module-source-map',
// 운영 환경: 정확한 에러 추적을 위해 별도 파일 생성
// mode: 'production',
// devtool: 'source-map',
};
Vite의 경우 vite.config.ts에서 다음과 같이 설정한다.
export default defineConfig({
build: {
sourcemap: true, // true, 'inline', 또는 'hidden' 설정 가능
},
});
-
true: 별도의
.map 파일을 생성하고 JS 파일에 참조 주석을 추가한다.
-
inline: 소스맵 데이터를 Base64로 인코딩하여 JS 파일 내부에 직접 포함시킨다. (파일 크기가 매우 커짐)
-
hidden:
.map 파일은 생성하지만, JS 파일에 참조 주석을 추가하지 않는다. (에러 트래킹 도구용)
브라우저 개발자 도구 활용
소스맵이 활성화되면 브라우저의 [Developer Tools] $\rightarrow$ [Sources] 탭에서 변환된 파일이 아닌, 실제 프로젝트 폴더 구조와 원본 파일(.ts, .jsx 등)을 확인할 수 있다.
- 원본 파일 탐색:
webpack:// 또는 vite://와 같은 가상 경로 아래에 프로젝트의 원본 소스 트리 구조가 나타난다.
- 디버깅 수행: 변환된 코드가 아닌 원본 코드의 특정 라인에 브레이크포인트를 설정하여 실행 흐름을 제어할 수 있다.
- 변수 확인: 미니피케이션으로 인해
a, b 등으로 축약된 변수들이 원본의 의미 있는 이름으로 복원되어 표시된다.
[브라우저 개발자 도구 활용 예시]
![Chrome DevTools의 Sources 탭에서 webpack:// 경로를 통해 원본 TypeScript 파일이 보이고, 특정 라인에 브레이크포인트를 설정하여 디버깅하는 화면 캡처]
(실제 환경에서는 가상 경로를 통해 원본 소스가 트리 구조로 나타나며, 원본 파일 상에서 직접 디버깅이 가능합니다.)
소스맵 적용 전후 디버깅 비교
| 비교 항목 |
소스맵 미적용 시 |
소스맵 적용 시 |
| 에러 메시지 |
Error at bundle.min.js:1:1542 |
Error at UserProfile.tsx:42:12 |
| 코드 가독성 |
a.b(c,d)와 같이 난독화된 코드 |
userService.updateUser(id, data) |
| 디버깅 방식 |
추측을 통해 변수 값 확인 |
원본 코드 라인에 브레이크포인트 설정 가능 |
| 분석 시간 |
변환 전 코드를 역추적하는 데 많은 시간 소요 |
즉각적으로 문제 지점 파악 가능 |
5. 보안 고려사항 및 배포 전략
보안 리스크
[Warning] 운영 환경 배포 주의
운영 환경(Production)에서 .map 파일을 공개 서버(Public Path)에 그대로 배포할 경우, 누구나 브라우저 개발자 도구를 통해 서비스의 전체 원본 소스 코드를 그대로 내려받을 수 있습니다. 이는 비즈니스 로직 유출, 내부 API 구조 노출 등 심각한 보안 취약점이 될 수 있으므로 각별한 주의가 필요합니다.
비공개 배포 전략
보안을 유지하면서 에러를 추적하기 위해 다음과 같은 전략을 사용한다.
- Hidden Source Map 사용:
.map 파일은 생성하되, JS 파일 내의 sourceMappingURL 주석을 제거하여 브라우저가 자동으로 로드하지 못하게 한다.
- 외부 에러 트래킹 도구 활용 (Sentry, LogRocket 등):
- 빌드 시 생성된
.map 파일을 공개 서버가 아닌, Sentry와 같은 에러 모니터링 서버에만 비공개로 업로드한다.
- 사용자의 브라우저에서 에러가 발생하면, 서버로 전송된 난독화된 스택 트레이스를 Sentry가 가지고 있는 소스맵과 대조하여 개발자에게만 원본 코드 위치를 보여준다.
- 웹 서버 접근 제어:
.map 파일에 대한 접근 권한을 특정 IP(사내 망)로 제한하거나, 인증된 사용자만 접근 가능하도록 설정한다.
# 소스맵 (Source Map)
## 1. 개요
**소스맵(Source Map)**이란 빌드 과정에서 변환, 압축, 번들링된 코드와 원본 소스 코드 사이의 대응 관계를 기록한 JSON 형식의 매핑 파일이다.
현대 웹 개발에서는 성능 최적화를 위해 다음과 같은 과정을 거친다.
- **번들링(Bundling):** 여러 개의 모듈 파일을 하나 또는 소수의 파일로 합치는 과정
- **미니피케이션(Minification):** 공백 제거, 변수명 축약 등을 통해 파일 크기를 최소화하는 과정
- **트랜스파일링(Transpiling):** TypeScript나 최신 JavaScript(ES6+) 코드를 구형 브라우저가 이해할 수 있는 ES5 버전으로 변환하는 과정
이러한 과정을 거친 결과물은 컴퓨터가 읽기에는 최적화되어 있으나, 사람이 읽기에는 거의 불가능한 형태가 된다. 이때 런타임 에러가 발생하면 브라우저는 변환된 코드의 라인 번호를 출력하므로, 개발자는 실제 원본 코드의 어느 지점에서 문제가 발생했는지 파악하기 어렵다. 소스맵은 이 간극을 메워 브라우저 개발자 도구에서 원본 코드를 그대로 보며 디버깅할 수 있게 해주는 필수적인 도구이다.
---
## 2. 작동 원리
소스맵은 변환된 코드의 특정 위치(행, 열)가 원본 파일의 어느 위치에 해당하는지를 좌표 형태로 저장한다. 브라우저는 변환된 파일 하단에 포함된 `//# sourceMappingURL=...` 주석을 통해 `.map` 파일을 찾아 로드하며, 이를 기반으로 원본 코드를 재구성하여 화면에 보여준다.
### 원본 코드 vs 변환된 코드 대응 예시
| 구분 | 원본 코드 (Original Source) | 변환된 코드 (Generated Code) | 소스맵의 역할 |
| :--- | :--- | :--- | :--- |
| **코드 형태** | `function add(a, b) { return a + b; }` | `function n(t,r){return t+r}` | `n` $\rightarrow$ `add` 매핑 |
| **위치** | `main.ts` / 10행 5열 | `bundle.min.js` / 1행 12열 | `1:12` $\rightarrow$ `10:5` 매핑 |
| **가독성** | 높음 (의미 있는 변수명) | 낮음 (축약된 변수명) | 원본 변수명 복원 |
### 소스맵 파일 내부 JSON 구조
소스맵 파일은 표준화된 JSON 형식을 따른다. 아래는 단순화된 `.map` 파일의 예시이다.
```json
{
"version": 3,
"file": "bundle.min.js",
"sourceRoot": "",
"sources": ["main.ts", "utils.ts"],
"names": ["add", "a", "b"],
"mappings": "AAAA,GAAG,KAAM,CAAC,EAAE,GAAG,CAAC",
"sourcesContent": ["function add(a, b) { return a + b; }", "export const pi = 3.14;"]
}
```
- **version**: 소스맵 표준 버전 (현재 대부분 3 사용)
- **sources**: 원본 파일들의 경로 목록
- **names**: 변수명, 함수명 등 축약 전의 원래 이름 목록
- **mappings**: [Base64 VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) 방식으로 인코딩된 매핑 데이터. 가변 길이 정수(VLQ)를 Base64로 인코딩하여 파일 크기를 줄인 형태이며, 이는 `[생성된 열, 원본 파일 인덱스, 원본 행, 원본 열, 이름 인덱스]` 순의 상대적 거리 값을 저장한다.
- **sourcesContent**: 원본 소스 코드 내용 (포함 시 별도의 원본 파일 없이도 복구 가능)
---
## 3. 소스맵의 종류
빌드 도구(Webpack 등)는 개발 단계와 운영 단계의 요구사항이 다르기 때문에 다양한 소스맵 생성 옵션을 제공한다.
| 옵션 | 빌드 속도 | 디버깅 정확도 | 파일 크기 | 특징 및 용도 |
| :--- | :---: | :---: | :---: | :--- |
| `eval` | 매우 빠름 | 낮음 | 매우 큼 | 코드를 `eval()`로 감싸 생성. 개발 환경 전용. |
| `cheap-module-source-map` | 중간 | 중간 | 중간 | 원본 소스 매핑은 지원하지만 열(column) 단위 디버깅은 불가능하며 행(line) 정보만 제공함. |
| `source-map` | 느림 | 매우 높음 | 큼 | 완전한 소스맵 생성. 별도의 `.map` 파일 생성. 운영/분석용. |
| `hidden-source-map` | 느림 | 매우 높음 | 큼 | `.map` 파일은 생성하지만, JS 파일에 참조 주석을 넣지 않음. |
| `nosources-source-map` | 느림 | 중간 | 작음 | 소스 내용은 제외하고 매핑 정보만 포함. |
---
## 4. 설정 및 사용 방법
### 주요 빌드 도구 설정
가장 널리 쓰이는 Webpack의 경우 `devtool` 속성을 통해 설정한다.
```javascript
// webpack.config.js
module.exports = {
// 개발 환경: 빠른 리빌드와 적절한 디버깅
mode: 'development',
devtool: 'eval-cheap-module-source-map',
// 운영 환경: 정확한 에러 추적을 위해 별도 파일 생성
// mode: 'production',
// devtool: 'source-map',
};
```
Vite의 경우 `vite.config.ts`에서 다음과 같이 설정한다.
```typescript
export default defineConfig({
build: {
sourcemap: true, // true, 'inline', 또는 'hidden' 설정 가능
},
});
```
- **`true`**: 별도의 `.map` 파일을 생성하고 JS 파일에 참조 주석을 추가한다.
- **`inline`**: 소스맵 데이터를 Base64로 인코딩하여 JS 파일 내부에 직접 포함시킨다. (파일 크기가 매우 커짐)
- **`hidden`**: `.map` 파일은 생성하지만, JS 파일에 참조 주석을 추가하지 않는다. (에러 트래킹 도구용)
### 브라우저 개발자 도구 활용
소스맵이 활성화되면 브라우저의 **[Developer Tools] $\rightarrow$ [Sources]** 탭에서 변환된 파일이 아닌, 실제 프로젝트 폴더 구조와 원본 파일(`.ts`, `.jsx` 등)을 확인할 수 있다.
1. **원본 파일 탐색:** `webpack://` 또는 `vite://`와 같은 가상 경로 아래에 프로젝트의 원본 소스 트리 구조가 나타난다.
2. **디버깅 수행:** 변환된 코드가 아닌 원본 코드의 특정 라인에 브레이크포인트를 설정하여 실행 흐름을 제어할 수 있다.
3. **변수 확인:** 미니피케이션으로 인해 `a`, `b` 등으로 축약된 변수들이 원본의 의미 있는 이름으로 복원되어 표시된다.
**[브라우저 개발자 도구 활용 예시]**
> ![Chrome DevTools의 Sources 탭에서 webpack:// 경로를 통해 원본 TypeScript 파일이 보이고, 특정 라인에 브레이크포인트를 설정하여 디버깅하는 화면 캡처]
> *(실제 환경에서는 가상 경로를 통해 원본 소스가 트리 구조로 나타나며, 원본 파일 상에서 직접 디버깅이 가능합니다.)*
### 소스맵 적용 전후 디버깅 비교
| 비교 항목 | 소스맵 미적용 시 | 소스맵 적용 시 |
| :--- | :--- | :--- |
| **에러 메시지** | `Error at bundle.min.js:1:1542` | `Error at UserProfile.tsx:42:12` |
| **코드 가독성** | `a.b(c,d)`와 같이 난독화된 코드 | `userService.updateUser(id, data)` |
| **디버깅 방식** | 추측을 통해 변수 값 확인 | 원본 코드 라인에 브레이크포인트 설정 가능 |
| **분석 시간** | 변환 전 코드를 역추적하는 데 많은 시간 소요 | 즉각적으로 문제 지점 파악 가능 |
---
## 5. 보안 고려사항 및 배포 전략
### 보안 리스크
> **[Warning] 운영 환경 배포 주의**
> 운영 환경(Production)에서 `.map` 파일을 공개 서버(Public Path)에 그대로 배포할 경우, 누구나 브라우저 개발자 도구를 통해 **서비스의 전체 원본 소스 코드를 그대로 내려받을 수 있습니다.** 이는 비즈니스 로직 유출, 내부 API 구조 노출 등 심각한 보안 취약점이 될 수 있으므로 각별한 주의가 필요합니다.
### 비공개 배포 전략
보안을 유지하면서 에러를 추적하기 위해 다음과 같은 전략을 사용한다.
1. **Hidden Source Map 사용:** `.map` 파일은 생성하되, JS 파일 내의 `sourceMappingURL` 주석을 제거하여 브라우저가 자동으로 로드하지 못하게 한다.
2. **외부 에러 트래킹 도구 활용 ([Sentry](https://sentry.io), LogRocket 등):**
- 빌드 시 생성된 `.map` 파일을 공개 서버가 아닌, Sentry와 같은 에러 모니터링 서버에만 비공개로 업로드한다.
- 사용자의 브라우저에서 에러가 발생하면, 서버로 전송된 난독화된 스택 트레이스를 Sentry가 가지고 있는 소스맵과 대조하여 개발자에게만 원본 코드 위치를 보여준다.
3. **웹 서버 접근 제어:** `.map` 파일에 대한 접근 권한을 특정 IP(사내 망)로 제한하거나, 인증된 사용자만 접근 가능하도록 설정한다.