기록 목록공지사항
authenticated runtime 이전에 websocket runtime이 존재하면 안 되는 이유
humanpchumanpc ·
05-2425
최근 homepage runtime을 정리하면서 websocket 초기 연결 시점을 다시 분해했다.
처음에는 단순한 성능 문제처럼 보였다.
public homepage initial load에서:
* websocket chunk가 import되고
* Echo/Pusher runtime이 초기화되고
* websocket 101 연결이 발생하고
* /broadcasting/auth 요청까지 이어졌다.
그런데 실제 문제는 "몇 KB를 줄이느냐"가 아니었다.
문제는 runtime ownership이었다.
[기존 구조]
초기 구조는 아래 흐름에 가까웠다.
public render
→ datasource scan
→ realtime datasource 발견
→ WebSocket runtime import
→ auth 확인
즉, public runtime 단계에서 이미 realtime runtime이 bootstrap되고 있었다.
실제 코드 흐름은:
TemplateApp
→ DataSourceManager.subscribeWebSockets()
→ loadWebSocketManager()
→ WebSocketManager.initialize()
→ Echo/Pusher connect
문제는 여기서 auth_token 또는 stale user-like object만 남아 있어도 private/presence realtime 경로가 열릴 수 있었다는 점이다.
예를 들어:
localStorage.auth_token 존재
또는
current_user.data.uuid 존재
같은 상태만으로 websocket runtime이 import될 수 있었다.
이건 단순 최적화 문제가 아니다.
authenticated capability가 public runtime으로 누수되는 구조였다.
[runtime 분리 기준]
이번 수정에서 핵심 기준은 하나였다.
authenticated capability는
authenticated runtime 이후에만 존재해야 한다.
그래서 websocket runtime 자체를 authenticated runtime 이후로 이동했다.
변경 후 흐름은 아래처럼 바뀌었다.
public render
→ auth confirmed
→ realtime runtime import
→ websocket connect
즉:
* localStorage.auth_token 단독 ❌
* stale current_user.data ❌
* id/uuid처럼 보이는 값 단독 ❌
으로는 realtime runtime이 열리지 않는다.
실제 authenticated context가 확인된 뒤에만:
loadWebSocketManager()
가 호출된다.
[적용한 분리]
이번 작업에서 적용한 핵심은 아래 네 가지다.
1. WebSocket runtime lazy boundary 유지
초기 core chunk에는 websocket runtime을 포함하지 않는다.
template-engine
↘ dynamic import
↘ WebSocketManager
형태로 유지했다.
즉:
* laravel-echo
* pusher-js
* realtime subscribe runtime
은 initial public bundle에 포함되지 않는다.
2. realtime datasource와 websocket runtime 분리
기존에는 datasource scan 자체가 websocket runtime import를 유발할 수 있었다.
이제는:
realtime datasource인지 확인
→ channel type 확인
→ auth context 확인
→ 그 다음 websocket runtime import
순서로 변경했다.
즉 import 이전에 capability gate를 둔 셈이다.
3. public realtime과 private realtime 분리
public realtime datasource는 계속 허용한다.
하지만:
private
presence
채널은 strict auth context가 없으면 runtime import 자체를 하지 않는다.
이 차이는 중요하다.
이전에는:
"구독 실패"
수준이었다면,
이제는:
"runtime 자체를 생성하지 않음"
으로 바뀌었다.
4. AuthManager만 인증 상태를 소유
이전에는 여러 위치가 인증 상태처럼 동작할 수 있었다.
이번에는:
AuthManager
→ _global.__auth
만 인증 상태를 동기화한다.
즉:
* stale storage
* partial datasource
* user-like cache
같은 값은 authenticated runtime의 기준이 되지 않는다.
[결과]
변화 자체는 작아 보일 수 있다.
Lighthouse 숫자는 크게 달라지지 않을 수도 있다.
하지만 runtime 관점에서는 꽤 큰 차이다.
public runtime이:
* realtime capability
* websocket runtime
* authenticated transport
를 더 이상 소유하지 않게 되었기 때문이다.
이번 수정 이후 anonymous initial load에서는:
* websocket chunk import 없음
* websocket 101 없음
* /broadcasting/auth 없음
상태로 정리되었다.
[정리]
frontend runtime에서 중요한 건:
"무엇을 늦게 로드했는가"
보다,
"어떤 capability를 어느 runtime boundary 뒤에 두었는가"
에 더 가깝다.
이번 작업은 websocket 최적화라기보다:
* public runtime
* authenticated runtime
* realtime runtime
을 분리하는 작업이었다.
댓글과 작업 영역을 나중에 불러옵니다
필요할 때 댓글과 작업 영역을 불러옵니다. 댓글 0개
