So it’s a bit “out there” but the JupyterLab notebook is currently able to be completely “hosted” on a static web page using Pyodide kernels using web assembly. This is Python running directly within the user’s browser. No application server needed:
JupyterLite also has a really easy way to bundle up notebooks and python environments all within a nice reproducible archive.
I can see this model being absolutely awesome for Streamlit. Imagine being able to share a local version of a Streamlit app just by sending someone an archive that opens up the web browser and all of the Python runs within the user’s browser, without needing any Python installed. Self hosting Streamlit would be multiple orders of magnitude easier, one could host a Streamlit app with GitHub pages.
Anyway, here’s my proposal, support a Pyodide backend for Streamlit allowing Streamlit apps to run completely within the browser
This idea also crossed my mind and actually I recall multiple Creators have toyed with the idea: @whitphx@asehmi if you want to pop in the conversation with your experiences.
tornado install with micropip still is experimental
from memory, Streamlit runs python code from ReportContext in a thread, which I don’t know how WASM manages yet since its threading model is supposedly in proposal mode.
This WebSocket connection access /stream path defined above. From this point, the frontend and the server communicates via this WebSocket connection and the frontend is rendered dynamically.
ReportSession next instantiates its child objects and the call chain would be like ReportSession → ScriptRunner → ReportThread
What we have to do to turn Streamlit into frontend Pyodide runtime
Run the server-side code on WebWorker with Pyodide
This code will be called from the frontend SPA. So the booting process would be kind of “reversed” - frontend is loaded first, the server-side is loaded next from the frontend.
Replace the WebSocket connection with messaging on the WebWorker
It would not be much difficult as both are async so they are mostly interchangeable, I think.
Other paths like health check would be the same.
Implementation details
To replace the WebSocket connection,
On the server-side, server.py will be re-written.
Tornado will be omitted.
New async-based server will be implemented. It will communicate with JS code running on the WebWorker through Pyodide API.
pyolite-kernel package (Jupyter Lite’s module) is a good reference.
For such rewrite, I think the Streamlit repository have to be forked
In the case of Jupyter, the server and frontend are decoupled and the connection between them is highly abstracted. This is the reason why Jupyter Lite can be developed independently from the Jupyter and can import Jupyter core into its Pyodide runtime.
Surely not forked, instead just have the required preparatory refactoring rework undergone within the main repository first achieving the required decoupling. I think its quite important to keep this ecosystem/community tightly knit and not split out into forks.
Even if that decoupling work takes ~6 months worth of pull requests, for the long term maintainability of something like this that investment is worth it.
Another benefit I should add for the Streamlit company is that the costs for running the Streamlit cloud hosting could be significantly reduced when Python is running client side instead of on Streamlit servers. Also, in cases where the data being processed is sensitive, having that data never leave the client’s machine is quite beneficial.
@SimonBiggs
That’s right.
I didn’t want to refer to the project fork.
I wanted to say just about technical issue that some fixes are needed on the core and the development must be tightly coupled with the core development, which is different from Jupyter Lite. The fork here simply means “forking a branch in the main repo” unlike Jupyter Lite, which is a separate repo independent from the core.
As a separate discussion, I’m not sure if it can be merged into the main stream - the core design/development is not community-driven, but the core development team of the company does.
Of course the forked development can be merged into the main branch, but maybe not. It must be discussed with the core dev team.
It’s a project management/design decision and out of scope I wanted to write about in the post.
The advantages you wrote is true and such information is important to discuss with the core dev team, I think.
If I add something,
I have nothing technical to add to the conversation, just to also say I would very much appreciate this feature and I think it could be transformative to Streamlit as a whole
I made my first progress: Stlite playground
(On this page, ~50MB resources will be loaded including the Pyodide runtime and some Python packages)
On this sample page you can see that Streamlit is running on the browser. There is no server-side Python; it’s an SPA hosted on GitHub Pages. And you can see the logs on the dev tool console.
I set up a code editor on this playground app, so you can try to edit and save the code and run it.
As this sample is built as a PWA, it works in an offline environment after the first loading and caching, and it also can be installed to your local environment. I think this is one major possibility of the browser-based Streamlit - it works as a desktop/smartphone app (loading runtime is still slow though).
Note that it’s just a first example at the POC stage, where only a subset of Streamlit functionality is working and there are many things to implement and improve.
For example, components such as st.table or st.line_chart that are using PyArrow, PyDeck or PyZMQ (or maybe others) are not working [1].
Custom components are also not supported.
I’m currently trying to build a distributable package or some other ways to reuse this library so that developers can use this on their web pages, such as npm package, PyScript-like package that is usable via script tag, or Jupyter Lite-like iframe embedding.
Technically, these libraries have native code e.g. C-extensions that have to be compiled with Emscripten for Pyodide runtime, which is kind of tough. Supporting these components is one major task. ↩︎
Technically, I did “fork” the streamlit main repo: Comparing streamlit:develop...whitphx:stlite · streamlit/streamlit · GitHub
because the original Streamlit cannot run on Pyodide as it uses some features that Pyodide/WASM runtime do not support, such as threading. I had to replace them with Pyodide-compatibe modules, for example, threading → asyncio, but also took care of keeping the original code as much as possible so that it will be easier to merge the upstream changes into the forked repo.
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.