๐ OPFS (Origin Private File System)
OPFS๋ ์น ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊ณตํ๋ ๊ณ ์ฑ๋ฅ, ์ ์ง์ฐ ์ ์ฉ ํ์ผ ์์คํ ์ด๋ค. ์น ์ ํ๋ฆฌ์ผ์ด์ (๋๋ฉ์ธ/Origin)๋ณ๋ก ์์ ํ ๊ฒฉ๋ฆฌ๋ ๊ฐ์ ํ์ผ ์์คํ ๊ณต๊ฐ์ ์ ๊ณตํ๋ฉฐ, ์ฌ์ฉ์์ ๊ฐ๋ณ ํ์ผ ์ ํ ์ฐฝ์ด๋ ๊ถํ ์น์ธ ํ์ ์์ด๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ณ ์์ ํ๊ฒ ์ฝ๊ณ ์ธ ์ ์๋๋ก ๋๋๋ค.
๊ธฐ์กด์ ์น ์คํ ๋ฆฌ์ง๋ ๋์ฉ๋ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ์ ํ๊ณ๊ฐ ๋ช ํํ์ต๋๋ค. LocalStorage๋ ์ฉ๋์ด ๋๋ฌด ์๊ณ ๋ฌธ์์ด๋ง ์ ์ฅํ ์ ์์ผ๋ฉฐ, IndexedDB๋ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ์ ์ข์ง๋ง ๋์ฉ๋ ๋ฏธ๋์ด ํธ์ง์ด๋ WebAssembly(Wasm) ๊ธฐ๋ฐ์ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ(์: ๋ธ๋ผ์ฐ์ ์ฉ SQLite)์ ์ฒ๋ฆฌํ ๋๋ ์ ์ถ๋ ฅ(I/O) ๋ณ๋ชฉ ํ์์ด ์ฌํ์ต๋๋ค.
์ด์ ๋ฐ๋ผ ๋์คํฌ I/O ์ฑ๋ฅ์ ๊ทน๋ํํ์ฌ ๋ฐ์คํฌํฑ ๋ค์ดํฐ๋ธ ์ฑ ์์ค์ ํ์ผ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋๋ก ์ค๊ณ๋ ์น ํ์ค ๊ธฐ์ ์ด ๋ฐ๋ก OPFS์ ๋๋ค.
๐ OPFS์ ํต์ฌ ํน์ง
OPFS๋ ์ฌ์ฉ์ ๋์ ๋ณด์ด๋ ์ผ๋ฐ์ ์ธ ํ์ผ ์์คํ (๋ฐ์คํฌํฑ, ๋ค์ด๋ก๋ ํด๋ ๋ฑ)๊ณผ ๋ถ๋ฆฌ๋์ด ๋ธ๋ผ์ฐ์ ๋ด๋ถ์ ์จ๊ฒจ์ง ์ต์ ํ ๊ณต๊ฐ์์ ๋์ํฉ๋๋ค.
- ์ฌ์ฉ์ ๊ฐ์ ์์ (No UX Prompt): ์ผ๋ฐ์ ์ธ File System Access API์ ๋ฌ๋ฆฌ, ํ์ผ ์์ฑ ๋ฐ ์์ ์ ์ ์ ์๊ฒ ๊ถํ ํ์ฉ ํ์ ์ ๋์ฐ์ง ์์ ๋งค๋๋ฌ์ด UX๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ณด์ ๋ฐ ๊ฒฉ๋ฆฌ (Sandbox): ํด๋น ํ์ผ์ ์์ฑํ ์์ฒ(Origin)์์๋ง ์ ๊ทผํ ์ ์์ต๋๋ค. ๋ค๋ฅธ ์ฌ์ดํธ์์ ์ ๋๋ก ๋ด ํ์ผ ์์คํ ์ ๋ค์ฌ๋ค๋ณผ ์ ์์ต๋๋ค.
- ์๋์ ์ธ ์๋ (Exclusive Write Locks): ์น ์์ปค(Web Worker) ํ๊ฒฝ์์ ๋น๋๊ธฐ ์ ์ฉ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, ํ์ผ์ ๋ํ ๋ ์ ์ ์ ๊ธ(Lock)์ ํ๋ํ์ฌ ๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ๋ฐฉํดํ์ง ์๊ณ ์ด๊ณ ์์ผ๋ก ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์๋๋ค.
- ์์์ฑ ๋ฐ ๋ธ๋ผ์ฐ์ ๊ด๋ฆฌ: ์ฌ์ฉ์๊ฐ ์ง์ ์ง์ธ ์๋ ์์ง๋ง, ๋ธ๋ผ์ฐ์ ๊ฐ ๋์คํฌ ์ฉ๋ ๋ถ์กฑ ๋ฑ์ ์ด์ ๋ก ์คํ ๋ฆฌ์ง ์ ๋ฆฌ ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ผ ์ญ์ ํ ์ ์์ต๋๋ค.
๐ฅ ํต์ฌ ์ฐจ๋ณ์
- ์ฑ๋ฅ ์ต์ ํ: ๋ธ๋ผ์ฐ์ ๊ฐ OS์ ํ์ผ ์์คํ ๋ ์ด์ด์ ์ต๋ํ ๊ฐ๊น๊ฒ ์ํตํ๋๋ก ์ค๊ณ๋์ด, IndexedDB ๋๋น ์ ๋ฐฐ์์ ์์ญ ๋ฐฐ ๋น ๋ฅธ ํ์ผ ์ฐ๊ธฐ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- Wasm ์นํ์ : C/C++๋ Rust๋ก ์์ฑ๋ ํค๋นํ ํ๋ก๊ทธ๋จ์ WebAssembly๋ก ์ปดํ์ผํ์ฌ ์น์์ ๋๋ฆด ๋, ํ์ผ I/O ๋ฐฑ์๋๋ก OPFS๋ฅผ ์ง์ ํ๋ฉด ๋ค์ดํฐ๋ธ ์ฑ๊ณผ ์ ์ฌํ ์๋๊ฐ ๋์ต๋๋ค.
๐งฑ ์ ํต์ ์คํ ๋ฆฌ์ง์์ ์ฐจ์ด์
| ๋ฐฉ์ | ์ ๊ทผ ๊ถํ ํ์ | ์ฃผ ์ฌ์ฉ ๋ชฉ์ | ๋์ฉ๋ ๋ฐ์ด๋๋ฆฌ ์ฑ๋ฅ |
|---|---|---|---|
| LocalStorage | ์์ | ๊ฐ๋จํ ํค-๊ฐ(String) ์ค์ ์ ์ฅ | ๋งค์ฐ ๋์จ (์ง์ ์ ๋จ) |
| IndexedDB | ์์ | ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ, ๊ฐ์ฒด ์ฟผ๋ฆฌ ๊ฒ์ | ๋ณดํต (์ค๋ฒํค๋ ์กด์ฌ) |
| Standard File System | ํ์ (๋งค๋ฒ ์น์ธ) | ์ ์ ๋์คํฌ์ ์ค์ ํ์ผ ํธ์ง | ๋ณดํต (๋ณด์ ๋ ์ด์ด ๊ฑฐ์นจ) |
| OPFS | ์์ (์ต์ด 1ํ๋ ์ ๋ธ) | ๊ณ ์ฑ๋ฅ ๊ฐ์ ํ์ผ ์์ฑ ๋ฐ ํธ์ง | ๋งค์ฐ ๋ฐ์ด๋จ (์ต์ ํ) |
๐ป ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ (์ฝ๋ ์์ )
OPFS๋ ๋ฉ์ธ ์ค๋ ๋์์๋ ์ ๊ทผ์ด ๊ฐ๋ฅํ์ง๋ง, ์ง์ ํ ๊ณ ์ฑ๋ฅ(๊ฐ๋ ฅํ ํ๋ฌ์ ๋ฐ ์ ๊ธ ๊ธฐ๋ฅ)์ ํ์ฉํ๋ ค๋ฉด ์น ์์ปค(Web Worker) ๋ด๋ถ์์ createWritable() ๋์ createSyncAccessHandle()์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ์์
๋๋ค.
1. ๋ฉ์ธ ์ค๋ ๋์์ ํ์ผ ๋ค๋ฃจ๊ธฐ (๊ธฐ๋ณธ ๋น๋๊ธฐ)
async function writeToOPFS() {
// 1. OPFS ๋ฃจํธ ๋๋ ํ ๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ
const root = await navigator.storage.getDirectory();
// 2. ํ์ผ ์์ฑ ๋๋ ์ด๊ธฐ
const fileHandle = await root.getFileHandle("example.txt", { create: true });
// 3. ์ฐ๊ธฐ ์คํธ๋ฆผ ์์ฑ ๋ฐ ๋ฐ์ดํฐ ๊ธฐ๋ก
const writable = await fileHandle.createWritable();
await writable.write("Hello, Origin Private File System!");
await writable.close();
console.log("ํ์ผ ์ฐ๊ธฐ ์๋ฃ!");
}2. ์น ์์ปค์์ ๋๊ธฐ์ ์ด๊ณ ์ ํ์ผ ์ ๊ทผ (์ถ์ฒ)
// Worker.js ๋ด๋ถ ์ฝ๋
self.onmessage = async (e) => {
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle("heavy_data.bin", { create: true });
// ๋๊ธฐ์ ์ก์ธ์ค ํธ๋ค ํ๋ (๋ฉ์ธ ์ค๋ ๋์์๋ ํธ์ถ ๋ถ๊ฐ)
const accessHandle = await fileHandle.createSyncAccessHandle();
// ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ๋ฒํผ ์ฐ๊ธฐ
const encoder = new TextEncoder();
const writeBuffer = encoder.encode("High performance data string");
const bytesWritten = accessHandle.write(writeBuffer, { at: 0 });
// ๋์คํฌ์ ์์ ํ ํ๋ฌ์(์ ์ฅ) ํ ๋ซ๊ธฐ
accessHandle.flush();
accessHandle.close();
self.postMessage(`์ฑ๊ณต์ ์ผ๋ก ${bytesWritten} ๋ฐ์ดํธ๋ฅผ ๊ธฐ๋กํ์ต๋๋ค.`);
};๐ญ ๊ณ ์ฐฐ
OPFS๋ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ๋จ์ํ ํ์ด์ง ๋ทฐ์ด์์ '๊ฐ๋ ฅํ ์ ํ๋ฆฌ์ผ์ด์ ํ๋ซํผ'์ผ๋ก ์งํ์ํจ ํต์ฌ ๊ธฐ์ ์ ๋๋ค. Figma ๊ฐ์ ์น ๊ธฐ๋ฐ ๊ทธ๋ํฝ ํด, ์์ ํธ์ง๊ธฐ, ์น๋ธ๋ผ์ฐ์ ๋ด๋ถ์์ ๋์๊ฐ๋ ๊ฐ๋ฒผ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค(SQLite Wasm) ๋ฑ์ด ๋ชจ๋ ์ด OPFS ๋๋ถ์ ๋งค๋๋ฝ๊ฒ ๊ตฌ๋๋ฉ๋๋ค.
๋ค๋ง, ์ ์ ๋์ ๋ณด์ด์ง ์๋ ๊ฒฉ๋ฆฌ๋ ์ ์ฅ์์ธ ๋งํผ ๋์คํฌ ์ฉ๋ ๊ด๋ฆฌ(Quota ๊ด๋ฆฌ)์ ์ ๊ฒฝ ์จ์ผ ํ๋ฉฐ, ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ ๋ฐ๋ผ ์๊ธฐ์น ์๊ฒ ์ ๋ฆฌ๋ ์ ์์ผ๋ฏ๋ก ์ ์ ๊ฐ ์๊ตฌ ๋ณด์กดํด์ผ ํ๋ ์ต์ข ๊ฒฐ๊ณผ๋ฌผ์ ๋ฐ๋์ ์ผ๋ฐ ๋ค์ด๋ก๋ API๋ฅผ ํตํด ๋ก์ปฌ ๋์คํฌ๋ก ๋ด๋ณด๋ด๋๋ก ์ ๋ํ๋ ์ค๊ณ๊ฐ ํ์ํฉ๋๋ค.