3-6. CSS 도메인과 Styles 탭 25.12.29
Elements 탭의 절반만 동작하던 상태
여기까지 만들면서 콘솔, 네트워크, DOM, 스토리지, 세션 리플레이까지는 잘 돌아갔다. Elements 탭에서 DOM 트리를 보는 것도 됐다. 그런데 Elements 탭의 오른쪽, 그러니까 Styles 패널이 비어 있었다.
Chrome DevTools에서 Elements 탭을 열면 왼쪽에 DOM 트리, 오른쪽에 선택한 요소의 CSS 스타일이 나온다. 이 오른쪽 패널이 동작하려면 CSS 도메인을 구현해야 하는데, 지금까지 미뤄두고 있었다.
CSS 도메인이 까다로운 이유
CDP의 CSS 도메인은 다른 도메인에 비해 구현이 복잡하다. 단순히 element.style을 읽어서 보내주는 수준이 아니다.
CSS.getMatchedStylesForNode라는 명령 하나만 봐도, 해당 노드에 적용된 모든 CSS 규칙을 찾아야 한다. 인라인 스타일, 스타일시트의 셀렉터 매칭, 상속된 스타일, UA(User Agent) 기본 스타일까지 전부 포함해서 응답해야 한다. 각 규칙의 소스 파일 위치(파일명, 라인 번호)까지 알려줘야 DevTools에서 "어떤 CSS 파일의 몇 번째 줄에서 이 스타일이 적용됐는지" 표시할 수 있다.
게다가 CSS.setStyleTexts(스타일 수정), CSS.getComputedStyleForNode(계산된 스타일), CSS.getInlineStylesForNode(인라인 스타일) 같은 명령도 구현해야 한다.
구현 과정
12월 29일, CSS 도메인 구현에 착수했다(PR #43).
먼저 document.styleSheets에서 모든 스타일시트를 읽어서 CDP 형식으로 변환하는 작업부터 했다. CSSStyleSheet 객체에서 cssRules를 순회하면서, 각 규칙의 셀렉터, 속성, 값, 소스 위치를 추출한다.
그 다음 CSS.getMatchedStylesForNode를 구현했다. 특정 DOM 노드에 대해 window.getMatchedCSSRules()... 는 비표준이라 못 쓰고, 직접 모든 스타일시트의 셀렉터를 순회하면서 element.matches(selector)로 매칭 여부를 확인하는 방식으로 구현했다.
인라인 스타일은 element.style에서 직접 읽고, 상속된 스타일은 부모 노드를 타고 올라가면서 수집했다. 계산된 스타일은 window.getComputedStyle()로 한 방에 가져올 수 있어서 그나마 편했다.
FSD 구조 정리
같은 날 Inspector 쪽의 리플레이 유틸리티도 FSD(Feature-Sliced Design) 구조로 재정리했다(PR #42). 기존에 이것저것 섞여 있던 리플레이 관련 코드를 features/replay 아래로 모았다. 빌드 스크립트도 개선해서, devtools-frontend 빌드와 Inspector 빌드가 더 깔끔하게 연결되게 했다.
devtools-frontend rebase
CSS 도메인을 구현하면서 devtools-frontend 코드도 상당히 수정해야 했다. 그런데 upstream의 devtools-frontend가 계속 업데이트되고 있어서, 내 커스텀 패치와 충돌이 나기 시작했다.
그래서 devtools-frontend rebase 작업을 했다(PR #44). 기존에 적용한 패치들(Welcome 패널, Session Replay 패널, 지원하지 않는 패널 숨기기)을 최신 코드 위에 다시 올리는 작업인데, 이게 생각보다 노동이었다. 자동 머지가 안 되는 부분을 일일이 수동으로 해결해야 했다.
다만 이 rebase 덕분에 최신 DevTools 프론트엔드의 개선사항(성능, 버그 수정)을 가져올 수 있었고, CSS 도메인도 더 잘 동작했다.
PR 리뷰 피드백 반영
CSS 도메인 PR(#43)을 올리고 나서 코드를 다시 보니 구조가 좀 지저분했다. 그래서 PR 리뷰 피드백을 스스로 반영하는 리팩토링을 했다(PR #45). CSS 도메인의 파일 구조를 정리하고, 중복 코드를 제거했다.
결과: Styles 탭이 살아나다
CSS 도메인 구현이 끝나니, Elements 탭 오른쪽의 Styles 패널이 드디어 동작하기 시작했다. 요소를 선택하면 적용된 CSS 규칙이 보이고, 인라인 스타일, 상속 스타일, 계산된 스타일까지 전부 표시된다.
DevTools에서 스타일을 수정하면 실시간으로 타깃 페이지에 반영되는 것까지 확인했다. 원격 디버깅에서 CSS를 실시간으로 수정할 수 있다는 건, 모바일 웹뷰 디버깅할 때 특히 유용하다. "이 버튼 왼쪽으로 10px만 옮겨봐" 같은 걸 Inspector에서 바로 해볼 수 있으니까.
CDP CSS 도메인을 구현해서 Elements 탭의 Styles 패널을 살려냈고, devtools-frontend rebase를 통해 최신 DevTools와 동기화했다.