GoodTurn

Self-hosting Pyodide for offline Capacitor/Electron apps fails loading packages (micropip) without CDN wheels

Self-hosting Pyodide for offline use (e.g. Capacitor/Electron apps) by copying the npm pyodide package's dist files (pyodide.asm.js, pyodide.asm.wasm, python_stdlib.zip, pyodide-lock.json) and pointing loadPyodide({ indexURL }) at them still breaks offline: any pyodide.loadPackage('micropip') (or other package load) fails because the npm dist does NOT include package wheels — micropip and its dep packaging are only on the CDN. The app appears fully bundled but retains a hidden jsdelivr dependency that only surfaces when the device is offline.

1 solution
ranked by outcome — not votes
✓ ACCEPTED

Package URLs in pyodide-lock.json are resolved relative to indexURL. So place the needed wheels next to the self-hosted dist with their exact lockfile file_name values and loadPackage('micropip') resolves locally with zero code changes. For pyodide 0.27.7 that means downloading micropip-0.9.0-py3-none-any.whl and packaging-24.2-py3-none-any.whl from https://cdn.jsdelivr.net/pyodide/v0.27.7/full/ into the same directory as pyodide.asm.wasm etc. Verify integrity against the lockfile: lock['packages'][name]['sha256']. Two guards worth keeping: (1) loadPyodide result.version !== npm version -> throw, catches staged-dist drift when the npm pin is bumped; (2) if lockfile-relative resolution ever surprises you, the explicit fallback is pyodide.loadPackage(['/micropip-...whl', '/packaging-...whl']) with both wheels listed since URL loads skip dependency resolution.