본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Tools

DevTools로 JavaScript 디버깅하기

작성 2026. 10. 17.추가
목차11개 항목
출처와 참고

Chrome for Developers의 「Chrome DevTools 문서」를 바탕으로, javascript.info(모던 JavaScript 튜토리얼)의 「개발자 콘솔」, 「Chrome으로 디버깅하기」 글과 「크롬 개발자 도구를 이용한 자바스크립트 디버깅」을 더해 재구성한 노트다.

왜 console.log 대신 중단점인가

console.log로 디버깅하려면 코드를 찾아 로그를 넣고, 볼 값을 하나하나 적고, 새로고침해야 한다. 중단점은 코드 구조를 몰라도 관련 지점에서 멈추게 하고, 그 순간의 모든 변수를 보여 준다. 기본 흐름은 이렇다.

flowchart LR
    A["버그 재현"] --> B["중단점으로 멈춤"] --> C["한 줄씩 실행"] --> D["Scope·Watch·Console로 값 확인"] --> E["편집기에서 고쳐 저장"] --> F["다시 실행"]

Sources 패널은 세 영역으로 나뉜다. 왼쪽 Page 탭(페이지가 받은 파일 트리), 가운데 편집기, 오른쪽 디버거(Breakpoints·Scope·Watch·Call Stack). 명령 메뉴(Ctrl+Shift+P / Cmd+Shift+P)에서 sources로도 연다.

DevTools는 F12(macOS Cmd+Opt+I, 콘솔로 바로 열기는 Cmd+Opt+J)로 연다. 다른 패널을 보는 중에도 Esc를 누르면 아래쪽 서랍에 Console이 열려, 멈춘 상태의 값을 바로 평가할 수 있다. 콘솔에서 여러 줄을 입력하려면 Shift+Enter로 줄을 바꾼다. 페이지의 스크립트 오류는 사용자에게 보이지 않고 Console에 빨간 메시지와 파일:줄 링크로만 남는다. Safari는 설정 → 고급에서 「웹 개발자용 기능 보기」를 켜야 개발 메뉴와 Web Inspector(Cmd+Opt+C 콘솔)가 생긴다.

중단점 고르기

상황중단점거는 곳
멈출 줄을 정확히 안다코드 줄줄 번호 클릭 (파란 표시)
코드에서 바로 멈추고 싶다debugger; 문소스 코드
한 줄에 이어진 호출 중 하나인라인(열)줄 중단점을 건 뒤 그 줄에 뜨는 화살표 표시 중 원하는 위치를 클릭. a().then(b).then(c)나 압축된 한 줄 코드에서
루프에서 특정 경우만조건부줄 번호 우클릭 → 조건부 중단점 추가 (주황 ?)
멈추지 않고 값만 남기기로그포인트줄 번호 우클릭 → Logpoint 추가 (분홍 ..). "합계 " + sum, obj처럼 console.log 인수 문법
누가 이 요소를 바꾸나DOM 변경Elements에서 요소 우클릭 → 중단 → 하위 트리 수정·속성 수정·노드 삭제
잘못된 URL을 요청하는 코드 찾기XHR/fetch디버거의 XHR/가져오기 중단점에 URL 일부 입력
클릭 뒤 무엇이 실행되나이벤트 리스너이벤트 리스너 중단점에서 click이나 카테고리 전체 선택. 워커 이벤트에서도 멈춘다
예외가 던져진 줄예외Breakpoints의 「포착되지 않은 / 포착된 예외에서 일시중지」. Promise 거부도 다룬다
함수가 불릴 때마다함수콘솔에서 debug(fn). 함수가 그 스코프에 보여야 한다
XSS 싱크·정책 위반Trusted TypesCSP 위반 중단점
  • debugger 문은 DevTools가 열려 있을 때만 멈추고, 닫혀 있으면 무시된다. 그래도 커밋 전에는 지운다.
  • 시끄러운 예외나 debugger에서 계속 멈추면 그 줄을 우클릭해 「여기에서 일시중지 안 함」 을 고른다. 실체는 조건이 false인 조건부 중단점이다.
  • Breakpoints 영역에서 중단점은 파일별로 묶인다. 체크박스로 켜고 끄고, 우클릭으로 일괄 삭제한다. 툴바의 중단점 비활성화 버튼은 모든 중단점을 잠시 무시한다.
  • 엉뚱한 줄의 click 리스너에서 멈춘다면 확장 프로그램의 리스너일 가능성이 크다. 시크릿 창에서 확인한다.

멈춘 다음: 단계 실행과 값 확인

컨트롤동작
재개 (F8)다음 중단점까지 실행. 길게 누르면 강제 실행(모든 중단점 무시)
Step over (F10)현재 줄의 함수 호출을 안으로 들어가지 않고 실행. 내부가 궁금하지 않은 함수에
Step into (F11)호출되는 함수 안으로 들어간다. setTimeout 콜백 같은 비동기 호출도 실행될 때까지 따라 들어간다
Step out (Shift+F11)현재 함수의 나머지를 실행하고 호출한 곳으로 나온다. 실수로 들어온 함수에서 빠져나올 때
Step (F9)다음 문장으로 한 걸음. 함수 호출이면 안으로 들어간다. 압축 코드의 a(),b(),42 같은 쉼표 식도 하나씩 밟는다
여기로 계속줄 우클릭. 중단점 없이 그 줄까지 실행
창쓰는 법
편집기 인라인 값멈춘 함수 안 변수의 현재 값이 선언 옆에 뜬다. 클래스·함수 이름에 마우스를 올리면 속성 미리보기
ScopeLocal·Closure·Global 변수. 값을 더블클릭해 바꿀 수 있다
Watchtypeof sum 같은 임의의 식을 등록. 단계마다 갱신된다
Console멈춘 스코프에서 식을 평가한다. parseInt(a) + parseInt(b)처럼 수정안을 먼저 시험한다
전역 변수로 저장Scope·콘솔의 값을 우클릭 → 「Store as global variable」. temp1 같은 이름으로 남아 재개한 뒤에도 콘솔에서 계속 만진다
Call Stack여기까지 온 호출 경로. 항목을 누르면 그 호출 위치로 간다. 우클릭으로 프레임 다시 시작, 「Copy stack trace」
Threads웹 워커·서비스 워커 컨텍스트로 전환
  • 프레임 다시 시작은 실행 위치만 함수 처음으로 되돌린다. 바뀐 값은 되돌리지 않는다. async·generator·WebAssembly 함수는 다시 시작할 수 없다.
  • 프레임워크가 지원하면 Call Stack에 비동기 프레임이 이어져 보인다. 비동기 실행 순서는 이벤트 루프에 있다.

고쳐 보기

  • 편집기에서 JS를 고치고 Ctrl+S / Cmd+S를 누르면 V8에 패치된다. 스크립트 전체를 다시 실행하지는 않으므로 함수 안의 변경만 효과가 있다.
  • 멈춘 상태에서 현재 함수를 고쳐 저장하면 디버거가 그 함수를 다시 시작한다. 콜 스택 맨 위 함수만, 재귀 중이 아닐 때만 된다.
  • 압축 파일은 기본으로 보기 좋게 정렬(pretty print)되어 보인다. 편집기 왼쪽 아래 {} 버튼으로 원본 한 줄을 볼 수 있다.
  • 새로고침하면 모든 수정이 사라진다. 남기려면 아래의 Workspaces나 로컬 재정의를 쓴다.

스니펫

콘솔에 같은 코드를 반복해 붙여 넣는다면 Sources → Snippets에 저장한다. 어느 페이지에서든 페이지 컨텍스트로 실행되는 북마클릿 대용이다.

  • 실행: 편집기에서 Ctrl+Enter / Cmd+Enter, 또는 Ctrl+O / Cmd+O 뒤 !스니펫이름.
  • 로컬 환경설정에 저장된다. 설정 동기화가 안 되고 파일로 꺼낼 수도 없다.

소스 맵: 작성한 코드로 디버깅

번들러·트랜스파일러가 만든 파일 끝의 //# sourceMappingURL= 주석이 원본과의 매핑 파일을 가리킨다. 소스 맵이 있으면 브라우저는 압축 코드를 실행하지만 중단점·로그·오류 위치는 원본 파일 기준으로 보인다.

  1. 빌드 도구(Babel, TypeScript, terser, webpack, Vite, esbuild, Parcel 등)에서 소스 맵 생성을 켜고 서버가 .map을 제공하게 한다.
  2. 설정 → 환경설정 → 소스의 「JavaScript 소스 맵」(CSS도 따로 있다)이 켜져 있는지 본다.
  3. Page 탭 메뉴에서 Authored/Deployed 그룹화를 켜고 Authored 쪽 원본에 중단점을 건다.

eval()로 만든 코드에는 //# sourceURL=이름.js 주석을 달면 그 이름으로 파일 트리에 나타난다. 번들러가 왜 코드를 묶는지는 번들러의 역사와 Vite에 있다.

무시 목록: 내 코드에만 집중

무시 목록(Ignore list)에 오른 스크립트는 Call Stack과 콘솔 스택 트레이스에서 접히고, 단계 실행 때 안으로 들어가지 않으며, 파일 트리와 파일 열기 결과에서 흐리게 처리되거나 숨는다.

방법위치
기본/node_modules/, /bower_components/는 처음부터 무시
소스 맵의 ignoreList 필드설정 → 무시 목록의 「알려진 서드 파티 스크립트를 무시 목록에 자동으로 추가」(기본 켬)
확장 프로그램 코드「무시 목록에 콘텐츠 스크립트 추가」
파일·폴더 하나씩파일 트리·편집기·Call Stack에서 우클릭 → 무시 목록에 추가
정규식 패턴설정 → 무시 목록 → 맞춤 제외 규칙

ignoreList(과거 이름 x_google_ignoreList)는 소스 맵의 sources 배열 중 서드 파티인 항목의 인덱스 목록이다. Angular·Nuxt는 이미 채워 주고, Vite·Rollup은 sourcemapIgnoreList 빌드 옵션으로 정한다. 숨긴 프레임까지 보려면 Call Stack의 「무시 목록에 있는 프레임 표시」를 켠다.

{ "version": 3, "sources": ["app.js", "Button.ts", "node_modules/.../framework.js"], "ignoreList": [2] }

Workspaces와 로컬 재정의: 수정 남기기

Workspaces로컬 재정의 (Overrides)
하는 일DevTools에서 고친 내용을 내 프로젝트 소스 파일에 저장네트워크 응답을 로컬 사본으로 바꿔 끼운다
대상로컬 서버로 띄운 내 사이트아무 사이트. 운영 사이트, 남의 API 응답도
저장 위치프로젝트 폴더 (소스 맵으로 원본 파일에 매핑)따로 고른 재정의 폴더
쓰는 때DevTools를 편집기처럼 쓰고 싶을 때백엔드 수정 전에 응답·헤더를 바꿔 시험할 때

Workspaces 연결

  • 자동: 프로젝트 루트의 .well-known/appspecific/com.chrome.devtools.json에 {"workspace": {"uuid": "<v4 UUID>", "root": "<절대 경로>"}}를 두고 로컬 서버가 제공하게 한 뒤, Sources → Workspace에서 「연결」을 누른다.
  • 수동: Sources → Workspace에서 폴더를 추가하거나 끌어다 놓고 접근을 허용한다.
  • 매핑된 파일 옆에 초록 점이 뜬다. CSS는 저장 즉시, HTML·JS는 새로고침이나 개발 서버 재로딩 뒤 반영된다.
  • Elements 패널에서 바꾼 DOM은 저장되지 않는다. DOM 트리는 HTML에 JS·CSS가 더해진 결과라 되돌려 쓸 파일을 정할 수 없다. HTML은 Sources에서 고친다.
  • 제외할 폴더 패턴은 설정 → 작업공간에서 바꾼다.

로컬 재정의

  1. Network에서 요청을 우클릭 → 콘텐츠 재정의 또는 헤더 재정의. 처음이면 저장 폴더를 고르고 허용한다.
  2. 콘텐츠는 Sources 편집기에서, 헤더는 Network → Headers → 응답 헤더에서 고치고 저장한 뒤 새로고침한다.
  3. 재정의된 요청은 보라색 점으로 표시된다. 전체 목록은 Sources → Overrides, 변경 내역은 Changes 서랍 탭에서 본다.
  • fetch·XHR 응답 JSON을 바꿔 API 응답을 모의하거나, Access-Control-Allow-Origin 같은 헤더를 추가해 CORS·Permissions-Policy 수정을 미리 시험한다.
  • 여러 요청에 같은 헤더를 붙이려면 .headers 파일에 *·? 와일드카드 규칙을 쓴다.
  • 재정의가 켜져 있으면 캐시가 꺼진다. 소스 맵으로 매핑된 원본 파일 자체는 재정의할 수 없다.

그 밖의 디버깅 도구

도구쓰는 법
JavaScript 사용 중지명령 메뉴 → 「JavaScript 사용 중지」. DevTools가 열려 있는 동안 그 탭에만 적용된다. JS 없이 페이지가 어떻게 보이는지 확인한다
백그라운드 서비스Application → 백그라운드 서비스에서 백그라운드 가져오기·동기화·알림·푸시 이벤트를 기록한다. DevTools를 닫아도 3일간 기록된다. 자세한 내용은 DevTools Application 패널: 저장소·서비스 워커
WebAssemblyEmscripten에서 -g로 DWARF 디버그 정보를 넣고 「C/C++ DevTools Support (DWARF)」 확장을 설치하면 C/C++ 원본에 중단점을 건다

Recorder: 사용자 흐름 녹화·재생

Recorder 패널(명령 메뉴 → Recorder)은 클릭·입력 같은 사용자 흐름을 녹화해 단계 목록으로 만든다.

  • 재생: 요소가 보이고 클릭 가능해질 때까지 기다린다. 느린 네트워크로 재생하거나, 속도를 늦추거나, 단계에 중단점을 걸 수 있다.
  • 수정: 선택자·단계를 고치고, waitForElement 같은 어설션 단계를 추가한다. 선택자는 ARIA 선택자를 먼저, 그다음 data-testid·data-test·data-cy 같은 테스트 속성, id 순으로 잡는다. 클래스가 자동 생성되는 프레임워크에서는 테스트 속성을 달아 두면 녹화가 덜 깨진다.
  • 성능 측정: 흐름을 재생하면서 Performance 패널에 트레이스를 남긴다.
  • 내보내기: JSON, @puppeteer/replay, Puppeteer 스크립트, Lighthouse 분석이 들어간 Puppeteer 스크립트로 내보내 CI에서 돌린다. E2E 테스트 전반은 프론트엔드 테스트의 종류와 도구에 있다.

정리

  • 멈출 곳을 모르면 줄 중단점보다 이벤트 리스너·DOM·XHR·예외 중단점이 빠르다.
  • 로그가 필요하면 코드를 고치지 말고 로그포인트를 건다. 코드에 남긴 debugger는 커밋 전에 지운다.
  • 멈춘 뒤에는 Scope·Watch로 값을 보고, Console에서 수정안을 먼저 시험한다.
  • 빌드된 코드는 소스 맵으로 원본을 보고, 라이브러리는 무시 목록으로 걷어 낸다.
  • 고친 것을 남기려면 내 프로젝트는 Workspaces, 남의 응답은 로컬 재정의.

관련 노트: DevTools Console 활용, DevTools Network 패널, DevTools로 성능·메모리 분석하기, DevTools Application 패널: 저장소·서비스 워커, 번들러의 역사와 Vite, 브라우저에서 JavaScript가 동작하는 원리: 이벤트 루프, VS Code 설정과 활용

원본 기록20

댓글

GitHub 계정으로 댓글을 남길 수 있어요.