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