Vite + Streamlit: How to develop custom components
The way to develop new streamlit component sue Vanilla Java Script with vite
--
For deveoping custom streamlit component the official guide show how to made with react and it si also abit old configuration. There is that new guide that explain how to use vanilla javascript with vite and use the vite cli that is a very beatufull way to start a node project.
In this guide we will see step by step how to to create the custom streamlit component to the deploy on pypi repo or gitlab one.
Prerequirements
We need to setup python3.10 and node 18.x on the computer before working.
I will use pip and venv for python and npm for nodejs.
Overview of Folder structure
Firs of all the folder structure will be created in the same way:
/repofolder
component_name/
frontend/
vite project...
__init__.py
pypi_readme.md
MANIFEST.in
build.py
Create Frontend
Create component folder and put the frontend code
mkdir component_name
cd component_name
npm init vite@latest frontend --template vanilla
Create vite.config.js
export default {
base: './'
}
Replace The main.js
import { Streamlit } from "streamlit-component-lib"
const span = document.body.appendChild(document.createElement("span"))
const textNode = span.appendChild(document.createTextNode(""))
const button = span.appendChild(document.createElement("button"))
button.textContent = "Click Me!"
let numClicks = 0
let isFocused = false
button.onclick = function() {
numClicks += 1
Streamlit.setComponentValue(numClicks)
}
button.onfocus = function() { isFocused = true }
button.onblur = function() { isFocused = false }
function onRender(event) {
const data = event.detail
if (data.theme) {
const borderStyling = `1px solid var(${
isFocused ? "--primary-color" : "gray"
})`
button.style.border = borderStyling
button.style.outline = borderStyling
}
button.disabled = data.disabled
let name = data.args["name"]
textNode.textContent = `Hello, ${name}! ` + String.fromCharCode(160)
Streamlit.setFrameHeight()
}
Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRender)
Streamlit.setComponentReady()
Streamlit.setFrameHeight()
And run frontend:
cd component_name/frontend
npm install
npm i streamlit-component-lib
npm run dev
Python code
Now you can create inside the component_name folder the __init__.py
import os
import streamlit.components.v1 as components
_RELEASE = False
if not _RELEASE:
_component_func = components.declare_component(
"vite_vanilla_component",
url="http://localhost:5173", # vite dev server port
)
else:
parent_dir = os.path.dirname(os.path.abspath(__file__))
build_dir = os.path.join(parent_dir, "frontend/dist")
_component_func = components.declare_component("vite_vanilla_component", path=build_dir)
def my_component(name, key=None):
component_value = _component_func(name=name, key=key, default=0)
return component_value
if not _RELEASE:
import streamlit as st
st.subheader("Component Test")
num_clicks = my_component(name = "NameViteVanilla")
st.markdown("You've clicked %s times!" % int(num_clicks))
You can create venv install libs and run the server
python3.10 -m venv venv
source venv/bin/activate #or source venv/bin/activate.fish for fish shell
pip install streamlit
streamlit run component_name/__ini__.py
Now you are ready do develop new custom streamlit plugin.
Configure For build
To build a python libs we need a Setup.py
import setuptools
import os
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'component_name/pypi_readme.md'), 'r') as f:
long_des = f.read()
setuptools.setup(
name="component-name",
version="0.0.1",
author="Name Surname",
author_email="mail94@mail.it",
description="This library is a streamlit app for...",
long_description=long_des,
long_description_content_type="text/markdown",
url="https://siteurl...",
keywords = ['some', 'key', 'word'],
project_urls={
'Source': 'https://githuburl...',
},
packages=setuptools.find_packages(),
include_package_data=True,
classifiers=[],
python_requires=">=3.6",
install_requires=[
# By definition, a Custom Component depends on Streamlit.
# If your component has other Python dependencies, list
# them here.
"streamlit >= 0.63",
],
)
And a readme for the pypi description in component_name/pypi_readme.md:
# Component Name
This component is...
To install:
```
pip install component_name
```
Example to use:
```
import component_name
component_name...
```
Now you can login in pypi and configure the ~/.pypirc file
[pypi]
repository=https://upload.pypi.org/legacy/
username = __token__
password = <token>
Now you can use twine for build frontend:
cd component_name/frontend
# clean rm -rf dist
npm run build
Specify MANIFEST.in for the files to include in the lib
recursive-include component_name/frontend/dist *
include component_name/pypi_readme.md
Change on __init__.py
_RELEASE = True
(remember to change the version on setup.py)
Build python app
# clean rm -rf dist
python setup.py sdist
Install twine check and upload
pip install twine
twine check dist/*
twine upload dist/*
Now you have your lib on pypi!
Conclusions
To see furthermore things you can create automatic building pipeline for deploy. An example of an app maded as described here is streamlit_seqviz to see one deployed lib.
So enjoy publishing your own custom plugin and contribute to open source!