[{"data":1,"prerenderedAt":18},["ShallowReactive",2],{"$floTOg2Ict0QjMVUmtqs0ENibt7Kcyw_NIqtP9VUZdUE":3},{"uuid":4,"title":5,"summary":6,"content":7,"createdAt":8,"tags":9},"c3641d72-d1b1-4ee4-8265-8b2b3638a1b1","domi-indexed-sqlite 정적 배포 환경에서 sqlite-wasm 자산 경로 어긋남 문제 해결기","domi-indexed-sqlite 라이브러리를 정적 호스팅 환경에 배포했을 때, sqlite-wasm의 핵심 자산들이 올바른 경로로 로드되지 않아 발생하는 문제를 해결하는 과정을 다룹니다. 특히 Emscripten 기반 WASM 모듈의 자산 로딩 메커니즘과 라이브러리 내부 경로 설정의 중요성을 탐구했습니다.","## 문제 발생: 정적 배포 환경에서 WASM 자산 404 에러\n\n`domi-indexed-sqlite`는 `@sqlite.org\u002Fsqlite-wasm`을 기반으로 하여 브라우저 환경에서 SQLite를 사용할 수 있게 돕는 라이브러리입니다. 개발 환경(예: `npm run dev`)에서는 문제없이 잘 작동하던 이 라이브러리가 GitHub Pages와 같은 정적 호스팅 환경에 배포되자마자 오류를 뿜어내기 시작했습니다. 브라우저 개발자 도구를 열어보니, `sqlite3.wasm`과 `sqlite3-worker1.js` 같은 핵심 WASM 관련 파일들이 404 Not Found 에러를 반환하며 로드되지 못하는 것을 확인했습니다.\n\n이 라이브러리는 `IndexedDB`를 기본 백엔드로 사용하며, `OPFS`나 `Memory` 모드도 지원합니다. 특히, `CDN 폴백 탑재` 기능을 통해 복잡한 WASM 자산 번들러 설정 없이 작동하도록 설계되어 있습니다. 하지만 정적 배포 환경에서는 이 설계가 예상대로 작동하지 않았습니다.\n\n## 초기 진단과 시행착오: 번들링 설정과 상대 경로\n\n가장 먼저 의심한 부분은 빌드 과정이었습니다. `tsup.config.ts` 파일을 확인하여 `sqlite-wasm` 관련 파일들이 빌드 결과물에 제대로 포함되거나 참조되는지 확인했습니다. `tsup`은 TypeScript 프로젝트를 위한 간단한 번들러로, 일반적으로 `.js` 파일을 중심으로 번들링하며 `.wasm` 같은 비-JS 자산은 별도로 처리해야 할 때가 많습니다. 하지만 `domi-indexed-sqlite`는 WASM 자산을 직접 번들링하는 대신, `sqlite-wasm`의 기본 로딩 방식에 의존하거나 CDN 폴백을 사용하도록 설계되어 있었습니다. 따라서 `tsup` 설정 자체를 변경하는 것은 라이브러리의 설계 의도와 맞지 않았습니다.\n\n다음으로, 경로 문제의 고전적인 원인인 상대 경로 계산 오류를 살펴보았습니다. 정적 배포 환경에서는 프로젝트가 웹 서버의 루트 경로(예: `example.com\u002F`)가 아닌 서브 경로(예: `example.com\u002Fmy-repo\u002F`)에 배포되는 경우가 많습니다. 이때 JavaScript 코드 내부에서 `.\u002Fasset.wasm`과 같이 상대 경로로 자산을 요청하면, 브라우저는 이를 현재 페이지의 URL을 기준으로 해석합니다. 만약 페이지가 `example.com\u002Fmy-repo\u002Findex.html`이라면 `.\u002Fasset.wasm`은 `example.com\u002Fmy-repo\u002Fasset.wasm`을 요청해야 합니다. 하지만 때로는 웹 서버의 설정이나 SPA(Single Page Application) 라우팅 방식에 따라 `\u002Fasset.wasm` (루트 기준)을 요청해 버리는 경우가 발생합니다. 이 경우에도 404 에러가 발생합니다.\n\n## 원인 좁히기: Emscripten과 WASM 자산 로딩\n\n`sqlite-wasm`은 Emscripten으로 컴파일된 WASM 모듈입니다. Emscripten으로 생성된 JavaScript 글루 코드(glue code)는 `.wasm` 바이너리 파일과 함께 웹 워커 파일(예: `sqlite3-worker1.js`) 등 추가 자산들을 동적으로 로드해야 합니다. 이때 Emscripten은 `Module.locateFile`이라는 전역 함수를 통해 이러한 자산의 경로를 결정합니다.\n\n`domi-indexed-sqlite` 라이브러리가 `sqlite-wasm`을 래핑하고 있으므로, 이 라이브러리가 내부적으로 `locateFile`을 어떻게 설정하는지가 핵심입니다. `README`에 명시된 `CDN 폴백 탑재` 기능은 이러한 자산 로딩 문제를 추상화하여 사용자가 별도의 설정을 하지 않아도 되도록 설계된 것이 분명했습니다. 하지만 정적 배포 환경에서 404 에러가 발생했다는 것은 이 폴백 로직이 제대로 작동하지 않았거나, 로컬 자산 로딩 경로를 결정하는 로직에 문제가 있었다는 의미입니다.\n\n네트워크 탭을 자세히 확인해 보니, 라이브러리는 `https:\u002F\u002Fsqlite.org\u002Fsqlite-wasm\u002Fsqlite3.wasm` (CDN 경로) 대신, 배포된 웹사이트의 상대 경로인 `https:\u002F\u002F[내-도메인]\u002Fsqlite3.wasm` (또는 `https:\u002F\u002F[내-도메인]\u002Fmy-repo\u002Fsqlite3.wasm`이 아닌 `https:\u002F\u002F[내-도메인]\u002Fsqlite3.wasm`)을 먼저 시도하고 있었습니다. 문제는 `domi-indexed-sqlite`가 WASM 자산을 `public` 디렉토리 등에 복사하여 정적 파일로 제공하는 것이 아니라, `sqlite-wasm`이 설치된 `node_modules` 내부의 경로를 기준으로 상대 경로를 추론하려 했던 것으로 보입니다. 이 방식은 개발 환경에서는 빌드 도구의 가상 파일 시스템 덕분에 작동할 수 있지만, 정적 배포 환경에서는 해당 파일들이 웹 서버의 루트 경로에 없으므로 실패합니다.\n\n## 해결: WASM 자산 경로 명시 및 CDN 폴백 강화\n\n문제의 원인을 파악한 후, `domi-indexed-sqlite` 라이브러리 내부에서 `sqlite-wasm` 모듈을 초기화할 때 `Module.locateFile` 함수를 더욱 견고하게 구성해야 함을 깨달았습니다. 구체적인 해결책은 다음과 같습니다.\n\n1.  **WASM 자산의 기본 경로 설정**: 라이브러리 초기화 시, WASM 자산이 위치할 수 있는 `baseURL` 또는 `wasmAssetsUrl`과 같은 옵션을 `initEasySqlite` 함수에 추가하여 사용자가 명시적으로 경로를 지정할 수 있도록 합니다. 예를 들어, `initEasySqlite({ wasmAssetsUrl: 'https:\u002F\u002Fcdn.example.com\u002Fsqlite-wasm\u002F' })`와 같이 설정하여 모든 WASM 관련 파일을 해당 URL에서 로드하도록 강제할 수 있습니다. 이는 특히 CDN 폴백이 작동하지 않을 때 유용합니다.\n2.  **CDN 폴백 로직 강화**: 라이브러리 내부에서 `locateFile`을 구현할 때, 로컬 경로에서 파일을 찾지 못하면 즉시 미리 정의된 CDN 경로로 폴백하도록 로직을 강화했습니다. 이는 `try-catch` 블록이나 `Promise.any`와 같은 패턴을 사용하여 첫 번째 성공적인 로드를 반환하도록 구현할 수 있습니다.\n\n이러한 변경을 통해, `domi-indexed-sqlite`는 이제 정적 배포 환경에서도 `sqlite-wasm` 자산을 올바르게 로드할 수 있게 되었습니다. 사용자는 라이브러리 초기화 시 `wasmAssetsUrl` 옵션을 통해 직접 경로를 제어하거나, 라이브러리의 견고해진 CDN 폴백 메커니즘에 의존할 수 있게 되었습니다.\n\n```typescript\nimport { initEasySqlite } from \"domi-indexed-sqlite\";\n\nconst db = await initEasySqlite({\n  dbName: \"my_app_database\",\n  debug: true,\n  \u002F\u002F 정적 배포 환경에서 WASM 자산 경로가 어긋날 경우,\n  \u002F\u002F 다음과 같이 명시적인 CDN 경로를 지정하여 해결할 수 있습니다.\n  \u002F\u002F wasmAssetsUrl: 'https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002F@sqlite.org\u002Fsqlite-wasm@latest\u002Fdist\u002F',\n});\n\u002F\u002F ...이후 사용법은 README와 동일\n```\n\n## 다음에 할 것\n\n현재는 명시적인 경로 설정이나 강화된 CDN 폴백으로 문제를 해결했지만, 향후에는 빌드 시스템(예: `tsup`)과 통합하여 WASM 자산을 자동으로 `public` 디렉토리로 복사하고, 라이브러리가 이 복사된 자산의 상대 경로를 자동으로 감지할 수 있도록 하는 메커니니즘을 추가하는 것을 고려하고 있습니다. 이렇게 하면 사용자가 별도로 `wasmAssetsUrl`을 설정할 필요 없이 모든 환경에서 `domi-indexed-sqlite`를 더 쉽게 사용할 수 있을 것입니다.","2026-08-25T14:01:42.076+09:00",[10,11,12,13,14,15,16,17],"CDN","Emscripten","TypeScript","domi-indexed-sqlite","sqlite-wasm","개발기","경로 문제","정적 배포",1788152657282]