Embed React app in your Python Package
Steps to embed a React app within a python package. The compiled React build can be then shipped within the python package distributable and served as a static site.
First step is to create the python package using cookie cutter and your code. Then create a react project, in my case I am using vite based template along with tailwind CSS and some basic scaffolding. The location of react source code doesn’t matter, it can be within the same project directory or in a different repository.
I used these steps to embed the server into my application getsome
https://github.com/ranuzz/getsome, you can refer to the source code for more details.
Create a folder in the python package root directory. Keep it empty, there is not even a need for __init__.py
file.
cd getsome
mkdir ui
change the output directory of vite
build
export default defineConfig({
build: {
outDir: "../../getsome/ui",
emptyOutDir: true,
},
});
The production build files will now be kept within the package directory. Add a handy make
command in the Makefile
to make this process easier.
ui:
cd ui/src && npm install && npm run build
Update the Manifest.in
to include all the folders in the React build files.
include getsome/ui/*
include getsome/ui/assets/*
Before creating a build for the python package, make sure to run ui build as well and get the latest files.
make ui
make dist
when you install the distribution you will get the files in the package installed location. Next, step is to move the files in users directory and create the server script
def setup_server():
# create a dir for static site files
server_www_files = os.path.join(app_home, 'www')
os.makedirs(server_www_files, exist_ok=True)
# copy the files from package ui folder
distutils.dir_util.copy_tree(os.path.join(os.path.dirname(__file__), 'ui'), server_www_files)
# call this routine from the package init file
Add a module www
in the package to write the server code.
# This folder is pointing to the www folder created earlier
app = Flask(__name__, static_folders)
# Handle all custom urls first
@app.route('/getsome')
def getsomeUrl():
return 'Custom URL'
# Then Serve React App
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve(path):
if path != "" and os.path.exists(app.static_folder + '/' + path):
return send_from_directory(app.static_folder, path)
else:
return send_from_directory(app.static_folder, 'index.html')
Add the module as package script
entry_points={
'console_scripts': [
'getsome-server=getsome.www.server:main'
],
},
Run the server
# getsome-server