Skip to main content

CLI scaffold tool for pywebview + Vue3 desktop apps

Project description

wv-cli

A command-line scaffold tool for building pywebview (Python backend) + Vue 3 / React (frontend) desktop apps.

Requirements

  • Python ≥ 3.9
  • uv — Python package manager
  • Node.js / npm — for the frontend
  • pnpm (optional) — alternative package manager
  • Inno Setup 6 (Windows only, required for --publish)

Installation

pip install wv-cli

Or install from source with uv:

git clone https://github.com/yourname/wv-cli
cd wv-cli
uv pip install -e .

Quick Start

Create a new project

# Interactive — creates ./my-app/
wv create

# In the current directory
wv create .

# Explicit directory
wv create path/to/my-app

You will be prompted for:

Prompt Default
Project name directory name
Window title project name
Version 1.0.0
Author (empty)
Package manager npm (auto-detected)
Frontend template Vue 3 + TypeScript
SQLite database No

Available frontend templates:

  • Vue 3 + TypeScript (vue-ts)
  • Vue 3 + JavaScript (vue)
  • React + TypeScript (react-ts)
  • React + JavaScript (react)

SQLite Database Support: When enabled, the project will include:

  • SQLAlchemy ORM with a sample User model
  • Database utilities for session management
  • Example API methods (create_user, get_users, delete_user)
  • backend/data/ directory for the SQLite database file

After answering, the CLI will:

  1. Scaffold the full directory structure
  2. Initialize the frontend with create-vite
  3. Initialize the backend with uv

Run in development mode

cd my-app
wv run

Builds the frontend, then launches the pywebview window loading frontend/dist.

Production build

wv build

Builds the frontend and runs PyInstaller to produce build/dist/<project-name>/.

Build + Windows installer

wv build --publish

Runs the full build, then calls Inno Setup to produce build/publish/<project-name>-<version>-setup.exe.

Configure the Inno Setup path in wv.toml if needed:

[build]
inno_setup_path = "C:/Program Files (x86)/Inno Setup 6/ISCC.exe"

Generated Project Structure

my-app/
├── icon/
│   ├── favicon.ico
│   └── logo.png
├── frontend/          ← Vue 3 or React (Vite)
│   └── dist/          ← built by wv run / wv build
├── backend/
│   ├── .venv/         ← uv virtual environment
│   ├── data/          ← SQLite database files (if enabled)
│   └── src/
│       ├── main.py
│       ├── config.py
│       ├── bridge/
│       │   ├── __init__.py
│       │   └── api.py
│       └── db/        ← Database module (if SQLite enabled)
│           ├── __init__.py
│           ├── models.py
│           └── utils.py
├── build/
│   ├── my-app.spec    ← PyInstaller config
│   ├── my-app.iss     ← Inno Setup config
│   └── publish/       ← installer output
└── wv.toml

Frontend Router Note

When using Vue Router or React Router, ensure you use HashHistory mode for file:// protocol compatibility after packaging:

  • Vue: Use createWebHashHistory instead of createWebHistory
  • React: Use createHashHistory instead of createBrowserHistory

The CLI will remind you about this after wv create, wv run, and wv build.

wv.toml Reference

[project]
name = "my-app"
version = "1.0.0"
window_title = "My App"
author = ""

[build]
inno_setup_path = "C:/Program Files (x86)/Inno Setup 6/ISCC.exe"

Extending the JS Bridge

Edit backend/src/bridge/api.py:

class Api:
    def greet(self, name: str) -> str:
        return f"Hello, {name}!"

    def read_file(self, path: str) -> str:
        with open(path) as f:
            return f.read()

Call from Vue:

const result = await window.pywebview.api.greet('World')

Database Usage (SQLite)

When you enable SQLite support during project creation, the following database API methods are available:

# backend/src/bridge/api.py
class Api:
    def create_user(self, name: str, email: str = "") -> dict:
        """Create a new user."""
        ...

    def get_users(self) -> list:
        """Get all users."""
        ...

    def delete_user(self, user_id: int) -> bool:
        """Delete a user by ID."""
        ...

Call from frontend:

// Create a user
const newUser = await window.pywebview.api.create_user('John', 'john@example.com')

// Get all users
const users = await window.pywebview.api.get_users()

// Delete a user
const success = await window.pywebview.api.delete_user(1)

Customizing Database Models

Edit backend/src/db/models.py to add your own models:

from sqlalchemy import Column, Integer, String
from db.models import Base

class Task(Base):
    __tablename__ = "tasks"

    id = Column(Integer, primary_key=True)
    title = Column(String(200), nullable=False)
    completed = Column(Integer, default=0)

Then regenerate the database by deleting backend/data/app.db and restarting the app.

Migrating Existing Projects to wv-cli

If you have an existing pywebview + Vue/React project and want to use wv-cli for development and building, follow this guide to make minimal changes.

🚀 Quick Migration with AI

Copy the prompt below and paste it to your AI assistant (ChatGPT, Claude, etc.) to get automated help with migration:

I want to migrate my existing pywebview desktop app to use wv-cli for development and building.

My project structure:
- Frontend: [Vue 3 / React] located at [frontend/]
- Backend: Python with pywebview located at [backend/ or src/]
- Current entry point: [main.py or app.py]

Please help me:
1. Create a wv.toml configuration file
2. Adjust the project structure to match wv-cli conventions
3. Update the backend entry point to work with wv-cli
4. Ensure the JS Bridge API is properly exposed
5. Configure PyInstaller spec for building

Requirements:
- Minimize changes to existing code
- Keep the existing frontend code as-is
- Preserve the current JS Bridge API structure

Manual Migration Steps

1. Create wv.toml

Add this configuration file to your project root:

[project]
name = "your-app-name"
version = "1.0.0"
window_title = "Your App Title"
author = "Your Name"
package_manager = "npm"  # or "pnpm"

[build]
inno_setup_path = "C:/Program Files (x86)/Inno Setup 6/ISCC.exe"

2. Adjust Project Structure

wv-cli expects this structure:

your-project/
├── wv.toml              # Add this
├── icon/
│   ├── favicon.ico      # App icon
│   └── logo.png
├── frontend/            # Your existing frontend
│   ├── src/
│   ├── dist/            # Build output
│   └── package.json
├── backend/             # Your existing backend
│   ├── src/
│   │   ├── main.py      # Entry point
│   │   ├── config.py    # Create this
│   │   └── bridge/
│   │       ├── __init__.py
│   │       └── api.py    # Your JS Bridge API
│   └── .venv/           # uv virtual environment
└── build/
    ├── your-app.spec    # PyInstaller config
    └── publish/         # Installer output

3. Create backend/src/config.py

# Development mode: load index.html directly from frontend/dist
HTML_PATH_DEV = '../../frontend/dist/index.html'

# Packaged mode: PyInstaller bundles frontend/dist contents into _f_dist
HTML_PATH_APP = '_f_dist/index.html'

# Window title (injected from wv.toml at project creation time)
WINDOW_TITLE = "Your App Title"

4. Update Backend Entry Point

Modify your main.py to use the config:

import sys
import os
import webview
from config import WINDOW_TITLE, HTML_PATH_DEV, HTML_PATH_APP

def get_html_path() -> str:
    """Resolve the correct HTML path depending on the runtime environment."""
    if getattr(sys, 'frozen', False):
        # PyInstaller packaged environment
        base = sys._MEIPASS
        return os.path.join(base, HTML_PATH_APP)
    else:
        # Development environment
        base = os.path.dirname(os.path.abspath(__file__))
        return os.path.join(base, HTML_PATH_DEV)

def main():
    from bridge.api import Api
    api = Api()
    window = webview.create_window(
        WINDOW_TITLE,
        url=get_html_path(),
        js_api=api,
    )
    webview.start()

if __name__ == '__main__':
    main()

5. Ensure JS Bridge API is in bridge/api.py

Move your existing API class to this location:

class Api:
    """Your existing JS Bridge API methods."""

    def your_existing_method(self, arg):
        # Your implementation
        pass

6. Initialize uv Environment

cd backend
uv init --no-workspace --vcs none
uv venv
uv add pywebview pyinstaller
# If using SQLite:
# uv add sqlalchemy alembic

7. Build and Run

# Development mode
wv run

# Production build
wv build

# Build with installer
wv build --publish

Important Notes

  • Frontend Router: If using Vue Router or React Router, ensure you use HashHistory mode
  • Static Assets: Make sure your frontend build outputs to frontend/dist/
  • PyInstaller: The spec file in build/ should bundle frontend/dist into _f_dist

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wv_cli-0.1.3.tar.gz (429.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wv_cli-0.1.3-py3-none-any.whl (426.4 kB view details)

Uploaded Python 3

File details

Details for the file wv_cli-0.1.3.tar.gz.

File metadata

  • Download URL: wv_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 429.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wv_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 b2e75bf35671bf259e3f5946a0015e42fd4768024f70a7c84fbca775be0edb25
MD5 f6f8a451ba199911e5b3af1551dc881f
BLAKE2b-256 b0960c1bc5f2a85359e6a05f517997f7443e124e0775400ee27207c6552b45e0

See more details on using hashes here.

File details

Details for the file wv_cli-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: wv_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 426.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for wv_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3be2febbb5fb01ff7fcc9c71abadd0015765cc827f695576c6c24836a5a3835b
MD5 2a99f03fa05eceb7750a9f75e7ec7de0
BLAKE2b-256 c29e326ca4c3a757b3fcc5ac7337d52bae5a0fbe85fdac392215af85cebdfca4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page