Pickle을 만들며 고른 기술들 (03) - 브라우저 익스텐션은 왜 일반 웹 앱과 다른 구조가 필요했을까
Pickle 익스텐션이 iframe 대응, 백그라운드 코디네이션, 상위 프레임 렌더링 구조를 택한 이유를 정리합니다.
브라우저 익스텐션은 그냥 작은 웹 앱이 아닙니다. 이벤트가 어디서 발생하고 UI가 어디에 떠야 하는지부터 다르게 생각해야 합니다.
들어가며
Pickle에서 익스텐션은 저장을 시작하는 가장 중요한 진입점이었습니다. 사용자가 웹페이지를 읽다가 문장이나 링크를 저장하고 싶을 때, 가장 먼저 손이 닿는 곳이기 때문입니다.
처음에는 익스텐션 UI도 웹 앱을 만들듯 생각하기 쉽습니다. 화면에 오버레이를 띄우고, 선택한 내용을 읽고, 저장 요청만 보내면 끝날 것처럼 보이기 때문입니다.
그런데 실제로는 전혀 그렇지 않았습니다. 익스텐션은 내가 만든 화면 위에서만 동작하는 것이 아니라, 남이 만든 수많은 웹페이지 위에서 동작해야 합니다. 어떤 사이트는 단순하지만, 어떤 사이트는 iframe 안에 콘텐츠가 들어 있고, 어떤 사이트는 전역 스타일이나 transform이 강하게 걸려 있습니다. 이 차이를 무시하면 같은 기능도 사이트마다 다르게 깨지기 쉽습니다.
이 글에서는 Pickle 익스텐션을 만들면서 왜 일반 웹 앱과 다른 구조가 필요하다고 느꼈는지, 그리고 그 판단이 어떤 아키텍처 선택으로 이어졌는지를 정리해 보려고 합니다.
왜 모든 프레임에서 감지하고 최상위에서 렌더링했는가
웹페이지를 다루다 보면 생각보다 빨리 iframe 문제를 만나게 됩니다. 대표적으로 실제 콘텐츠가 메인 문서가 아니라 내부 프레임에 들어 있는 페이지들이 그렇습니다. 사용자는 분명 본문 위에서 작업하고 있는데, 기술적으로는 그 이벤트가 다른 프레임 안에서 일어나는 셈입니다.
이 상황에서 한 가지를 먼저 정해야 했습니다. "이벤트가 발생한 곳에서 바로 UI를 띄울 것인가, 아니면 감지와 렌더링을 분리할 것인가"입니다.
Pickle에서는 두 번째를 택했습니다. 이벤트 감지는 모든 프레임에서 하되, 실제 오버레이 UI는 항상 최상위 프레임에서만 렌더링하게 했습니다.
이렇게 한 이유는 단순합니다.
- 사용자가 어느 프레임에 포커스를 두든 단축키는 잘 잡혀야 했습니다.
- 하지만 UI는 작은
iframe안에 갇히면 안 됐습니다. - 저장 흐름은 페이지 구조가 달라도 같은 위치감과 같은 사용성을 유지해야 했습니다.
즉 감지는 분산해도 되지만, 보여주는 화면은 한 군데에서 일관되게 제어하는 편이 더 맞았습니다. 이 선택을 하고 나서야 "어떤 사이트에서는 되고 어떤 사이트에서는 이상하게 뜨는" 문제가 줄기 시작했습니다.
UI는 페이지와 섞이지 않게 다뤄야 했습니다
이 문제는 iframe 감지에서 끝나지 않았습니다. 익스텐션 UI 자체도 웹페이지의 스타일 영향을 받기 시작했기 때문입니다.
웹 앱에서는 크게 신경 쓰지 않아도 되는 문제들이, 익스텐션에서는 바로 화면 품질 문제로 이어졌습니다. 부모 페이지의 font-size, transform, filter 같은 값이 오버레이에 영향을 주기 시작하면 같은 UI도 사이트마다 조금씩 다르게 보이기 때문입니다.
그래서 Pickle에서는 UI도 페이지와 적당히 섞이게 두기보다, 별도 환경에서 다루는 쪽이 더 맞다고 판단했습니다. 정확히 왜 iframe까지 가게 되었는지는 다음 글에서 따로 정리하려고 합니다.
핵심은 "UI를 띄울 수 있는가"보다 "사이트가 달라도 같은 UI처럼 보일 수 있는가"였습니다. 익스텐션은 결국 여러 웹사이트 위에서 동작해야 하므로, 내 UI를 그 페이지의 스타일로부터 얼마나 분리할 수 있는지가 훨씬 중요했습니다.
백그라운드가 상태 조정자가 되어야 했던 이유
익스텐션은 일반 웹 앱처럼 한 화면 안에서 모든 상태를 처리하기 어렵습니다. 프레임은 여러 개일 수 있고, 컨텐트 스크립트는 각 문서 안에서 따로 돌고, 인증이나 저장처럼 민감한 작업은 또 다른 레이어에서 처리하는 편이 더 안전합니다.
그래서 Pickle에서는 백그라운드를 단순한 메시지 중계기가 아니라, 전체 흐름을 조정하는 쪽에 더 가깝게 두었습니다.
흐름은 대체로 이렇습니다.
- 사용자가 어느 프레임에서든 단축키를 누릅니다.
- 해당 프레임은 저장 흐름을 백그라운드에 알립니다.
- 백그라운드는 로그인 상태를 확인하고, 어떤 액션을 실행할지 결정합니다.
- 그리고 최상위 프레임 쪽에 오버레이를 열도록 지시합니다.
이 구조를 택한 이유는 프레임마다 상태를 제각각 들고 가는 편보다, 전체 액션 흐름을 한 군데에서 조정하는 편이 더 설명 가능했기 때문입니다. 특히 로그인 상태나 저장 요청처럼 공통으로 봐야 하는 정보는 더 그렇습니다.
저장은 왜 컨텐트 스크립트가 아니라 백그라운드에서 처리했는가
Pickle에서 저장은 단순히 화면에 떠 있는 값을 읽어와 로컬 상태에 넣는 일이 아니었습니다. 실제로는 인증 정보가 필요했고, 데이터는 Supabase에 써야 했고, 사용자별 권한도 같이 고려해야 했습니다.
이런 종류의 작업을 컨텐트 스크립트 쪽에 두는 것은 부담이 컸습니다. 웹페이지 안에서 실행되는 스크립트에 민감한 인증 흐름을 더 가까이 붙이는 셈이기 때문입니다.
그래서 실제 DB 쓰기와 세션을 이용한 작업은 백그라운드에서 처리하는 쪽을 택했습니다. 컨텐트 스크립트는 사용자의 현재 맥락을 읽고, 백그라운드는 검증과 저장을 담당하는 식입니다.
이렇게 나누면 역할도 분명해집니다.
- 컨텐트 스크립트: 지금 페이지에서 무슨 일이 일어났는지 감지
- 오버레이 UI: 사용자의 입력과 피드백 처리
- 백그라운드: 검증, 인증, 실제 저장
익스텐션을 만들며 느낀 것은, 저장이 중요할수록 오히려 "누가 무엇을 책임지는가"를 더 잘 나눠야 한다는 점이었습니다.
예외를 다루는 방식이 품질을 더 많이 좌우했습니다
익스텐션은 데모 단계에서는 잘 동작해 보이기 쉽습니다. 단순한 사이트 한두 개에서는 금방 완성된 것처럼 느껴집니다. 하지만 실제로는 예외를 얼마나 안정적으로 다루느냐가 품질을 훨씬 더 많이 좌우합니다.
Pickle에서도 비슷했습니다.
- 어떤 사이트는 콘텐츠가
iframe안에 있었습니다. - 어떤 사이트는 전역 스타일 때문에 UI가 영향을 받았습니다.
- 어떤 경우에는 메타데이터를 나중에 다시 가져오려다가 누락될 수 있었습니다.
그래서 저장 직전에 메타데이터를 먼저 수집해 함께 보내거나, 메시지 전송 전에 직렬화 안전성을 더 확인하는 식의 방식을 택하게 됐습니다. 이런 부분은 화려한 기능은 아니지만, 실제로는 서비스 경험을 더 안정적으로 만드는 쪽이었습니다.
결국 Pickle 익스텐션에서 중요했던 것은 "어떻게 띄울까"보다, "웹페이지가 달라도 왜 같은 흐름을 유지할 수 있는가"를 설명할 수 있는 구조였습니다.
마치며
Pickle 익스텐션을 만들며 가장 크게 배운 것은, 브라우저 익스텐션을 웹 앱의 축소판처럼 다루면 금방 한계가 온다는 점이었습니다. 이벤트는 여러 프레임에서 일어나고, UI는 페이지 스타일의 영향을 받고, 저장은 인증과 권한 문제까지 같이 붙습니다.
그래서 Pickle에서는 감지와 렌더링을 분리했고, UI를 페이지 바깥으로 격리했고, 백그라운드가 전체 흐름을 조정하도록 두었습니다. 겉으로 보면 복잡해 보일 수 있지만, 오히려 이런 분리가 있어야 여러 웹페이지 위에서도 같은 경험을 유지할 수 있다고 판단했습니다.
다음 글에서는 여기서 한 걸음 더 나아가, 익스텐션에서 시작된 로그인 상태를 웹 클라이언트와 어떻게 연결했는지, 그리고 왜 그 인증 흐름을 따로 설계해야 했는지를 정리해 보려고 합니다.