Skip to content

Commit ee69eed

Browse files
jdpigeonclaude
andcommitted
docs: refresh pyodide learnings — protocol scheme + indexURL
- Replace stale port-17173 http-server section with current pyodide:// protocol handler reality - Document the prod resourcesPath/pyodide/ extraResources destination - Add indexURL requirement for prod (siblings of pyodide.mjs aren't bundled, so import.meta.url resolution fails) — gotcha hit during packaging verification Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 0a21e35 commit ee69eed

1 file changed

Lines changed: 7 additions & 7 deletions

File tree

.llms/learnings.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@ The app uses shadcn/ui + Tailwind CSS. CSS modules have been fully removed. Key
2121
- **Background gradient** used on all main screens: `bg-gradient-to-b from-[#f9f9f9] to-[#f0f0ff]`
2222
- **`@radix-ui/react-select`** is installed for the shadcn Select component
2323

24-
## Pyodide Asset Serving — Vite SPA Fallback Problem
24+
## Pyodide Asset Serving — Custom `pyodide://` Protocol
2525

26-
Vite's `historyApiFallback` returns `index.html` for **all** `fetch()` requests from web workers, including `/@fs/` and `publicDir` paths. This breaks Pyodide's package loading entirely.
26+
Vite's `historyApiFallback` returns `index.html` for **all** `fetch()` requests from web workers, breaking Pyodide's package loading. We solved this with a custom Electron protocol scheme registered in `src/main/index.ts` (`protocol.handle('pyodide', ...)`). The web worker uses `pyodide://host` as `PYODIDE_ASSET_BASE` and the handler resolves paths against the local filesystem — no HTTP socket required, works identically in dev and prod.
2727

28-
**Solution (two-part):**
29-
1. A custom Vite middleware in `vite.config.ts` intercepts `/pyodide/` and `/packages/` requests before the SPA fallback and serves them directly from `src/renderer/utils/webworker/src/`.
30-
2. An Electron `http` server on **port 17173** (started in `src/main/index.ts`) serves the same directory. Web workers use `http://127.0.0.1:17173` as `PYODIDE_ASSET_BASE`. This is the authoritative path — web worker `fetch()` calls bypass Vite entirely.
28+
**Filesystem roots resolved by the handler:**
29+
- Dev: `src/renderer/utils/webworker/src/`
30+
- Prod: `process.resourcesPath/pyodide/``package.json` `extraResources` copies `webworker/src/` to a folder named `pyodide`. The protocol handler must match this destination name (mismatched once and broke prod entirely).
3131

32-
Port 17173 is hardcoded in both `src/main/index.ts` and `src/renderer/utils/webworker/webworker.js` and in the CSP (`src/renderer/index.html`).
32+
**`indexURL` is required in prod, not just `packageBaseUrl`.** In dev, `pyodide.mjs` is imported via Vite's `?url` from `node_modules/pyodide/`, and the runtime files (`pyodide.asm.wasm`, `python_stdlib.zip`) load via `import.meta.url`-relative fetch — siblings live alongside it in node_modules. In prod, Vite bundles `pyodide.mjs` into `out/renderer/assets/` *without* its siblings, so `import.meta.url` resolution fails. Setting `indexURL: '${PYODIDE_ASSET_BASE}/pyodide/'` routes runtime fetches through the protocol handler. Set both `packageBaseUrl` (for `.whl` files via `loadPackage`) and `indexURL` (for the runtime).
3333

3434
**Other Pyodide loading gotchas:**
3535
- `pyodide.mjs` must be loaded via dynamic `import()` (not `fetch()`), using a `?url` Vite import — `import()` bypasses the SPA fallback, `fetch()` does not
3636
- The lock file is embedded via `?raw` and wrapped in a `Blob` + `createObjectURL` to avoid an HTTP fetch
37-
- Use `packageBaseUrl` (not `indexURL`) to tell Pyodide where to find `.whl` files; `indexURL` is for WASM/stdlib
3837
- `checkIntegrity: false` is required — SHA256 hashes in the npm lock file don't match CDN-downloaded wheels
3938
- Workers must be created with `type: 'module'` (Pyodide 0.26+ ships `pyodide.mjs` as ESM)
4039
- `optimizeDeps.exclude: ['pyodide']` in `vite.config.ts` prevents Vite from pre-bundling it
40+
- `micropip.install()` only accepts `http://`, `https://`, `emfs://`, and relative paths — it rejects custom schemes like `pyodide://`. Workaround: JS-fetch each `.whl` via the protocol handler, write into Pyodide's emscripten FS at `/tmp/`, then install via `emfs:///tmp/...`.
4141

4242
## Pyodide Offline Package Installation (InstallMNE.mjs)
4343

0 commit comments

Comments
 (0)