Skip to main content

funcnodes-pyodide

Run FuncNodes completely in the browser by executing the backend worker inside Pyodide (Python compiled to WebAssembly) and driving it from the standard React Flow editor UI.

This package exists so FuncNodes workflows can be:

  • Embedded as live, interactive examples in static sites / documentation (no server-side worker needed).
  • Shipped as a “try it in your browser” demo.
  • Used in environments where running a Python worker process is inconvenient, but browser-only execution is acceptable.

In the “normal” FuncNodes architecture, the React UI talks to a Python funcnodes-worker process via WebSockets. Here, the “worker process” is replaced by a browser Web Worker that boots Pyodide, installs the needed Python packages, and then runs a RemoteWorker-compatible worker inside that Pyodide interpreter.


What’s in this folder

This repo subtree contains two deliverables plus a prebuilt demo:

1) Python package: funcnodes-pyodide (AGPL-3.0)

Located in src/funcnodes_pyodide/.

Key pieces:

  • funcnodes_pyodide.worker.PyodideWorker
    • A minimal funcnodes_worker.RemoteWorker transport that doesn’t use sockets.
    • Instead it forwards JSON + binary messages to a JavaScript “receiver” (the Web Worker global scope) via receivepy(...) / receivepy_bytes(...).
  • funcnodes_pyodide.patch.patch()
    • Disables file-based logging handlers (Pyodide environments typically don’t have a normal writable filesystem).
    • This patch auto-runs on import when sys.platform == "emscripten".
  • python -m funcnodes_pyodide
    • Serves the prebuilt static demo UI from src/funcnodes_pyodide/static/ on a random free local port.

2) JavaScript/TypeScript package: @linkdlab/funcnodes_pyodide_react_flow (MIT)

Located in src/react/.

Key pieces:

  • FuncnodesPyodideWorker (src/react/src/pyodineworker.ts)
    • A @linkdlab/funcnodes_react_flow-compatible worker implementation.
    • Talks to a (Shared)WebWorker that runs the Pyodide runtime + Python worker.
  • Web Worker runtime (src/react/src/pyodideWorkerLogic.mts, src/react/src/pyodideWorkerLayout.mts)
    • Loads Pyodide via dynamic import(...).
    • Uses micropip to install Python packages at runtime.
    • Imports funcnodes_pyodide, creates Python worker instances via funcnodes_pyodide.new_worker(...), and bridges messages between JS ↔ Python worker.

3) Prebuilt static demo bundle

Located in src/funcnodes_pyodide/static/ and includes:

  • index.html
  • funcnodes_pyodide_react_flow.es.js (+ .iife.js)
  • funcnodes_pyodide_react_flow.css

How it works (high level)

  1. The page loads the FuncNodes React Flow UI bundle.
  2. The UI creates a FuncnodesPyodideWorker instance (JS).
  3. That JS worker spins up a (Shared)WebWorker.
  4. The WebWorker:
    • Dynamically imports Pyodide (pyodide.mjs),
    • Installs Python dependencies via micropip,
    • Imports funcnodes_pyodide,
    • Creates a PyodideWorker (Python) and attaches the WebWorker as its “receiver”.
  5. From then on, the UI uses the regular FuncNodes worker protocol:
    • UI → WebWorker → Python RemoteWorker.receive_message(...)
    • Python events/results → WebWorker → UI

Quickstart: run the local demo page

Recommended environment variables (keep caches/config local):

  • UV_CACHE_DIR=.cache/uv
  • FUNCNODES_CONFIG_DIR=.funcnodes

From this repo (this folder contains its own uv.lock):

cd funcnodes_pyodide
uv sync
FUNCNODES_CONFIG_DIR=.funcnodes uv run python -m funcnodes_pyodide

Open the printed http://localhost:<port> URL in a browser.

The first load is expected to be slow because the WebWorker will download Pyodide and install Python packages.

You can preload an example workflow export via URL, e.g. ?load=examples/cat.fnw.


Using it from JavaScript (embedding)

The build registers a few helpers on window.FuncNodes (which is a function exported by @linkdlab/funcnodes_react_flow and can also carry properties):

  • window.FuncNodes.FuncnodesPyodideWorker — the JS worker class
  • window.FuncNodes.FuncnodesPyodide(...) — helper to mount the UI with a Pyodide worker

Recommended: FuncnodesPyodide(...)

This is the recommended API when using the prebuilt browser bundle:

<div id="root" style="height: 100vh"></div>
<script type="module" src="./funcnodes_pyodide_react_flow.es.js"></script>
<link rel="stylesheet" href="./funcnodes_pyodide_react_flow.css" />
<script type="module">
  window.FuncNodes.FuncnodesPyodide("root", {
    useWorkerManager: false,
    debug: true,
    // pyodide_url: "https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.mjs",
    // packages: ["https://example.com/your.whl"],
    // restore_worker_state_on_load: true,
  });
</script>

Advanced: construct a FuncnodesPyodideWorker yourself

This gives you direct access to the worker instance (for example to call save_worker_state()).

<div id="root" style="height: 100vh"></div>
<script type="module" src="./funcnodes_pyodide_react_flow.es.js"></script>
<link rel="stylesheet" href="./funcnodes_pyodide_react_flow.css" />
<script type="module">
  const worker = new window.FuncNodes.FuncnodesPyodideWorker({
    uuid: "root",
    shared_worker: false,
  });

  window.FuncNodes("root", {
    useWorkerManager: false,
    worker,
  });
</script>

Configuration knobs

FuncnodesPyodideWorker accepts (among others):

  • uuid: logical worker id (used to route messages)
  • shared_worker: true to use a SharedWorker, false for a dedicated Worker
  • pyodide_url: URL to pyodide.mjs (defaults to the jsDelivr CDN)
  • packages: additional Python packages to install via micropip before starting the worker
  • worker_url / worker: provide your own Worker/SharedWorker instance or URL instead of using the inline worker bundles
  • debug: enable more verbose console logs during boot

Where this is used in the FuncNodes ecosystem

FuncNodes’ documentation site can embed live graphs that run fully in-browser using this package.


Limitations / gotchas

  • Network required by default: the default setup fetches Pyodide and Python wheels at runtime (PyPI/CDNs).
  • Package compatibility: micropip can only install packages that are compatible with Pyodide (pure Python wheels or Pyodide-provided packages). Many native extensions won’t work.
  • Concurrency constraints: Pyodide does not provide CPython-style multiprocessing, and browser threading constraints apply. Heavy CPU work can freeze the worker.
  • File system semantics: Pyodide’s filesystem is virtual/in-memory unless you explicitly mount persistent storage; file-based logging is disabled by funcnodes_pyodide.patch.
  • Interrupt support is best-effort: the WebWorker tries to use SharedArrayBuffer for interrupts, but this requires cross-origin isolation headers (COOP/COEP) and isn’t available everywhere.

Development: using local Python changes in the browser

By default, the Pyodide worker installs funcnodes-pyodide from PyPI via micropip. For local development you typically want to install a wheel built from your working tree instead.

  1. Build a wheel:
cd funcnodes_pyodide
uv build --wheel
  1. Copy the wheel into the React dev server public/ folder (keep the original filename, don’t rename it):
mkdir -p src/react/public/pywheels
cp dist/*.whl src/react/public/pywheels/
  1. Point packages at the served wheel URL:
const wheelUrl = `${
  window.location.origin
}/pywheels/funcnodes_pyodide-<version>-py3-none-any.whl?t=${Date.now()}`;
window.FuncNodes.FuncnodesPyodide("root", { packages: [wheelUrl] });

Notes:

  • micropip downloads via http(s); a plain /pywheels/... path may be interpreted as a non-remote URL depending on where it’s constructed.
  • This repo’s JS worker code normalizes common relative/absolute paths to absolute URLs before sending them to the worker.

Development (building + tests)

Python (package + tests)

git clone https://github.com/Linkdlab/funcnodes_pyodide
cd funcnodes_pyodide
UV_CACHE_DIR=.cache/uv uv sync --group dev
FUNCNODES_CONFIG_DIR=.funcnodes uv run pytest

JS/TS (worker + UI bundle)

cd funcnodes_pyodide/src/react
yarn install
yarn watch
yarn test
yarn build

yarn build writes a production browser bundle into src/funcnodes_pyodide/static/ (see vite.browser.config.js), which is what python -m funcnodes_pyodide serves.


License

  • Python package funcnodes-pyodide: AGPL-3.0
  • JS package @linkdlab/funcnodes_pyodide_react_flow: MIT

Metadata

Release files for funcnodes-pyodide 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for funcnodes-pyodide 2.0.0
File Size Uploaded
funcnodes_pyodide-2.0.0.tar.gz 7.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for funcnodes-pyodide 2.0.0
File Interpreter ABI Platform
funcnodes_pyodide-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.2 kB

Release files / funcnodes_pyodide-2.0.0.tar.gz

Download URL funcnodes_pyodide-2.0.0.tar.gz
Size 7.3 kB
Tags Source
SHA-256 checksum
How to use checksums
3276d22442fa2dca612191e1678cbaa7be5bbdb87a1d17c70a3ccb09f87f6385
BLAKE2b-256 checksum
How to use checksums
a7130888e050ff87addf158c16975ed297fe73eafc15aa96d33a0aaeec59682f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 7, 2026.

Transparency log

Release files / funcnodes_pyodide-2.0.0-py3-none-any.whl

Download URL funcnodes_pyodide-2.0.0-py3-none-any.whl
Size 6.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
632b811f7a7f5fb8dd35d7e032698b7e6e5a2065035528d306792352df94ed2d
BLAKE2b-256 checksum
How to use checksums
eab481373bbbb76c2ab7bd9cbc0b1bd21838355f2ee8dde8fbaedbb5555b2611
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

0.1.11

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page