Godot로 만든 게임을 웹으로 내보내면 wasm 파일 하나가 40MB 가까이 나옵니다. 그런데 Cloudflare에 정적 파일로 올릴 때는 파일 하나가 25MiB를 넘을 수 없습니다. 배포 명령을 실행하고 한참 기다린 끝에 거절당합니다.
이 글은 그 상황에서 쓴 방법입니다. 게임 다섯 개를 같은 구조로 올려 두었습니다.
방법: 잘라 올리고 워커가 이어 붙인다
원리는 단순합니다.
- 큰 파일을 20MB씩 조각으로 자른다 (
index.wasm.part0,part1, …) - 조각들을 정적 자산으로 올린다 (각각 25MiB 미만이라 통과)
- 브라우저가
index.wasm을 요청하면 워커가 조각을 순서대로 읽어 하나의 응답으로 이어 붙여 내보낸다
브라우저 입장에서는 원본 파일 하나를 받은 것과 같습니다. Godot의 로더도 그대로 씁니다.
자를 때 확인할 것
자르는 코드보다 자른 뒤 확인이 중요합니다.
- 조각이 전부 한도 아래인지 스크립트가 직접 확인하게 하세요. 안 그러면 배포 단계에서야 거절당하는데, 그때는 이미 몇 분을 기다린 뒤입니다
- 조각 개수와 각 크기를 기록해 두세요. 워커가 몇 개를 이어 붙여야 하는지 알아야 합니다
- pck 파일도 같은 처리가 필요할 수 있습니다. 게임 자산이 커지면 pck가 먼저 한도를 넘습니다
반드시 지켜야 하는 헤더
이어 붙이는 것만으로는 안 됩니다. wasm은 헤더가 틀리면 조용히 느려지거나 아예 안 뜹니다.
Content-Type: application/wasm— 이게 아니면 브라우저가 스트리밍 컴파일을 포기하고 전부 받은 뒤에 컴파일합니다. 로딩이 눈에 띄게 느려집니다- 미리 압축해서 올렸다면
Content-Encoding: gzip을 붙이고, 길이 계산을 압축된 크기 기준으로 하세요. 여기를 원본 크기로 두면 응답이 중간에 끊깁니다 - 캐시는 파일 이름에 내용 해시가 들어가는 경우에만 길게 잡으세요. 이름이 고정인데 캐시를 1년으로 걸면 다음 배포가 사용자에게 도달하지 않습니다
마지막 항목으로 한 번 데었습니다. 법적 문서를 정적 자산으로 올렸더니 1년 immutable로 캐시돼서 문서를 고쳐도 안 바뀌었습니다. 자주 고칠 것은 워커가 직접 응답하게 두는 편이 낫습니다.
스레드를 쓸지 정하기
Godot 웹 빌드는 스레드를 쓰는 쪽이 빠르지만, 그러려면 서버가 두 헤더를 보내야 합니다.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
이 헤더가 붙으면 그 페이지 안에서 외부 자원을 불러오는 것이 까다로워집니다. 호스팅이 이 헤더를 못 넣는 곳(예: 일부 정적 호스팅)이라면 단일 스레드로 내보내야 합니다. 어느 쪽이든 내보내기 설정과 서버 헤더가 짝이 맞아야 하고, 안 맞으면 로딩 도중에 멈춥니다.
배포 뒤 확인은 눈이 아니라 해시로
"게임이 뜬다"는 새 빌드가 올라갔다는 증거가 아닙니다. 캐시된 옛 빌드일 수 있습니다. 저는 이렇게 확인합니다.
curl -sS https://example.com/game/ | md5sum
md5sum build/deploy/static/game/index.html
로컬 산출물과 라이브 응답의 해시가 같은지 봅니다. 같으면 확실히 올라간 것이고, 다르면 아직 옛 버전이 나가고 있는 것입니다. 실제로 이 확인 덕분에 "배포했다"고 잘못 보고할 뻔한 것을 여러 번 잡았습니다.
회사망에서 배포한다면
Cloudflare 배포 도구는 Node로 돌기 때문에 사내 TLS 검사 프록시에 막힙니다. 그 명령에만 검증을 끄는 방법은 회사망 TLS 프록시 글에 적어 두었습니다.