소스 맵은 디버깅을 훨씬 쉽게 해주는 최신 웹 개발의 중요한 도구입니다. 이 페이지에서는 소스 맵의 기본사항, 생성 방법, 디버깅 환경 개선 방법을 살펴봅니다.
소스 맵의 필요성
초기 웹 앱은 복잡성이 낮게 빌드되었습니다. 개발자는 HTML, CSS, JavaScript 파일을 웹에 직접 배포했습니다.
더 현대적이고 복잡한 웹 앱의 경우 개발 워크플로에 다양한 도구가 필요할 수 있습니다. 예를 들면 다음과 같습니다.
- 템플릿 언어 및 HTML 프리프로세서: Pug, Nunjucks, 마크다운
- CSS 프리프로세서: SCSS, LESS, PostCSS
- JavaScript 프레임워크: Angular, React, Vue, Svelte
- JavaScript 메타 프레임워크: Next.js, Nuxt, Astro
- 고급 프로그래밍 언어: TypeScript, Dart, CoffeeScript
이러한 도구를 사용하려면 빌드 프로세스를 통해 코드를 브라우저에서 이해할 수 있는 표준 HTML, JavaScript, CSS로 변환해야 합니다. Terser와 같은 도구를 사용하여 이러한 파일을 축소하고 결합하여 성능을 최적화하는 것도 일반적입니다.
예를 들어 빌드 도구를 사용하여 다음 TypeScript 파일을 트랜스파일하고 단일 JavaScript 줄로 압축할 수 있습니다. GitHub의 데모에서 직접 사용해 볼 수 있습니다.
/* A TypeScript demo: example.ts */
document.querySelector('button')?.addEventListener('click', () => {
const num: number = Math.floor(Math.random() * 101);
const greet: string = 'Hello';
(document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
console.log(num);
});
압축된 버전은 다음과 같습니다.
/* A compressed JavaScript version of the TypeScript demo: example.min.js */
document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));
하지만 코드를 압축하면 디버깅이 더 어려워질 수 있습니다. 소스 맵을 사용하면 이 문제를 해결할 수 있습니다. 컴파일된 코드를 원래 코드에 다시 매핑하여 오류의 원인을 빠르게 찾을 수 있습니다.
소스 맵 생성
소스 맵은 이름이 .map
로 끝나는 파일입니다 (예: example.min.js.map
및 styles.css.map
). Vite, webpack, Rollup, Parcel, esbuild를 비롯한 대부분의 빌드 도구로 생성할 수 있습니다.
일부 도구에는 기본적으로 소스 맵이 포함되어 있습니다. 일부 템플릿은 생성하기 위해 추가 구성이 필요할 수 있습니다.
/* Example configuration: vite.config.js */
/* https://vitejs.dev/config/ */
export default defineConfig({
build: {
sourcemap: true, // enable production source maps
},
css: {
devSourcemap: true // enable CSS source maps during development
}
})
소스 맵 이해
디버깅에 도움이 되도록 이러한 소스 맵 파일에는 컴파일된 코드가 원래 코드에 매핑되는 방식에 관한 필수 정보가 포함됩니다. 다음은 소스 맵의 예입니다.
{
"mappings": "AAAAA,SAASC,cAAc,WAAWC, ...",
"sources": ["src/script.ts"],
"sourcesContent": ["document.querySelector('button')..."],
"names": ["document","querySelector", ...],
"version": 3,
"file": "example.min.js.map"
}
이러한 각 필드를 이해하려면 소스 맵 사양 또는 소스 맵 분석을 참고하세요.
소스 맵에서 가장 중요한 부분은 mappings
필드입니다. VLQ base 64 인코딩 문자열을 사용하여 컴파일된 파일의 줄과 위치를 해당 원본 파일에 매핑합니다. source-map-visualization 또는 Source Map Visualization과 같은 소스 맵 시각화 도구를 사용하여 이 매핑을 볼 수 있습니다.
왼쪽의 생성된 열에는 압축된 콘텐츠가 표시되고 원본 열에는 원본 소스가 표시됩니다.
시각화 도구는 원본 열의 각 행을 생성된 열의 해당 코드로 색상 코딩합니다.
매핑 섹션에는 코드의 디코딩된 매핑이 표시됩니다. 예를 들어 65 -> 2:2
항목은 다음을 의미합니다.
- 생성된 코드:
const
단어는 압축된 콘텐츠의 65번째 위치에서 시작합니다. - 원본 코드:
const
라는 단어는 원본 콘텐츠의 2번째 행 2번째 열에서 시작합니다.
이를 통해 개발자는 축소된 코드와 원본 코드 간의 관계를 빠르게 파악하여 디버깅 프로세스를 원활하게 진행할 수 있습니다.
브라우저 개발자 도구는 이러한 소스 맵을 적용하여 브라우저에서 디버깅 문제를 빠르게 파악할 수 있도록 지원합니다.
소스 맵 확장 프로그램
소스 맵은 x_
접두사로 시작하는 맞춤 확장 필드를 지원합니다. 한 가지 예는 Chrome DevTools에서 제안한 x_google_ignoreList
확장 프로그램 필드입니다. 이러한 확장 프로그램이 코드에 집중하는 데 어떻게 도움이 되는지 자세히 알아보려면 x_google_ignoreList를 참고하세요.
소스 맵 단점
안타깝게도 소스 매핑이 항상 필요한 만큼 완전하지는 않습니다.
첫 번째 예에서 greet
변수는 값이 최종 문자열 출력에 직접 삽입되어 있음에도 빌드 프로세스 중에 최적화되었습니다.
이 경우 코드를 디버그할 때 개발자 도구에서 실제 값을 추론하고 표시하지 못할 수 있습니다. 이러한 종류의 오류는 코드 모니터링 및 분석을 더 어렵게 만들 수 있습니다.
이는 소스 맵 설계 내에서 해결해야 하는 문제입니다. 한 가지 해결 방법은 다른 프로그래밍 언어가 디버그 정보와 동일한 방식으로 소스 맵에 범위 정보를 포함하는 것입니다.
그러나 이를 위해서는 전체 생태계가 함께 협력하여 소스 맵 사양과 구현을 개선해야 합니다. 소스 맵을 통한 디버그 가능성 개선에 관한 진행 상황을 확인하려면 GitHub의 소스 맵 v4 제안서를 참고하세요.