svelte-python-desktop Svelte Themes

Svelte Python Desktop

A modern desktop application template combining pywebview (Python) with SvelteKit (TypeScript). Build native desktop apps with a Python backend and a reactive Svelte frontend.

Svelte Python Desktop

A modern desktop application template combining pywebview (Python) with SvelteKit (TypeScript). Build native desktop apps with a Python backend and a reactive Svelte frontend.

Features

  • Python Backend: Full access to Python ecosystem, system APIs, and native capabilities
  • SvelteKit Frontend: Modern, reactive UI with TypeScript support and Svelte 5 runes
  • Type-Safe Communication: Fully typed API layer between Python and JavaScript
  • Hot Reload: Both Python (via Jurigged) and frontend (via Vite HMR) hot reload during development
  • Cross-Platform: Works on macOS, Windows, and Linux

Tech Stack

Layer Technology
Backend Python 3.12+, pywebview 5.0+
Frontend SvelteKit 2, Svelte 5, TypeScript
Tooling uv, Vite, ESLint, Prettier, Ruff, mypy

Quick Start

Prerequisites

Installation

# Clone the repository
git clone https://github.com/yourusername/svelte-python-desktop.git
cd svelte-python-desktop

# Install Python dependencies
uv sync

# Install frontend dependencies
cd frontend && npm install && cd ..

Development

Start the app with hot reload enabled for both Python and frontend:

uv run python -m jurigged -v scripts/dev.py

This command:

  1. Starts the Vite dev server (frontend hot reload)
  2. Launches pywebview pointing to localhost:5173
  3. Watches Python files for changes (via Jurigged)

Production Build

# Build the frontend
cd frontend && npm run build && cd ..

# Run the production app
uv run python -m backend.main

Project Structure

svelte-python-desktop/
├── backend/                 # Python backend
│   ├── __init__.py
│   ├── main.py              # App entry point, window configuration
│   └── api.py               # API methods exposed to JavaScript
├── frontend/                # SvelteKit frontend
│   ├── src/
│   │   ├── lib/
│   │   │   ├── api.ts       # Type-safe wrapper for Python API
│   │   │   └── types.ts     # TypeScript interfaces for API responses
│   │   └── routes/
│   │       └── +page.svelte # Main page component
│   ├── static/              # Static assets (favicon, images)
│   └── package.json
├── scripts/
│   └── dev.py               # Development server script
└── pyproject.toml           # Python project configuration

How It Works

Python to JavaScript Communication

The Python Api class in backend/api.py exposes methods to JavaScript:

# backend/api.py
class Api:
    def greet(self, name: str) -> dict[str, Any]:
        return {"message": f"Hello, {name}!"}

    def get_app_info(self) -> dict[str, Any]:
        return {"name": "My App", "version": "1.0.0"}

JavaScript to Python Calls

Call Python methods from Svelte using the typed wrapper in frontend/src/lib/api.ts:

// frontend/src/lib/api.ts
import { greet, getAppInfo } from '$lib/api';

// Call Python backend
const result = await greet('World');
console.log(result.message); // "Hello, World!"

const info = await getAppInfo();
console.log(info.version); // "1.0.0"

Type Safety

Define TypeScript interfaces that match your Python return types:

// frontend/src/lib/types.ts
export interface GreetResponse {
  message: string;
}

export interface AppInfoResponse {
  name: string;
  version: string;
}

Adding New API Methods

  1. Add the Python method in backend/api.py:
def calculate(self, a: int, b: int) -> dict[str, Any]:
    return {"result": a + b}
  1. Add the TypeScript interface in frontend/src/lib/types.ts:
export interface CalculateResponse {
  result: number;
}
  1. Add the typed wrapper in frontend/src/lib/api.ts:
export async function calculate(a: number, b: number): Promise<CalculateResponse> {
  return getApi().calculate(a, b);
}
  1. Use it in your Svelte component:
<script lang="ts">
  import { calculate } from '$lib/api';

  async function handleCalculate() {
    const result = await calculate(5, 3);
    console.log(result.result); // 8
  }
</script>

Configuration

Window Settings

Configure the desktop window in backend/main.py:

webview.create_window(
    title="My App",           # Window title
    url=url,                  # Frontend URL
    js_api=api,               # Python API instance
    width=1280,               # Initial width
    height=720,               # Initial height
    min_size=(800, 600),      # Minimum window size
    resizable=True,           # Allow resizing
    frameless=False,          # Show window frame
    easy_drag=False,          # Easy window dragging
    fullscreen=False,         # Start in fullscreen
    on_top=False,             # Always on top
)

SvelteKit Configuration

The frontend uses @sveltejs/adapter-static for static site generation, configured in frontend/svelte.config.js. This generates static HTML/JS/CSS files that pywebview serves directly.

Code Quality

Linting and Formatting

# Python
uv run ruff check backend/           # Lint
uv run ruff format backend/          # Format
uv run mypy backend/                 # Type check

# Frontend
cd frontend
npm run lint                         # ESLint
npm run format                       # Prettier
npm run check                        # Svelte + TypeScript check

Pre-commit (Optional)

Add pre-commit hooks for automatic code quality checks:

uv add --dev pre-commit
uv run pre-commit install

Packaging for Distribution

Create standalone executables that users can run without installing Python or Node.js.

Prerequisites

First, build the frontend:

cd frontend && npm run build && cd ..

PyInstaller (All Platforms)

PyInstaller creates a single executable or folder containing your app and all dependencies.

# Install PyInstaller
uv add --dev pyinstaller

macOS (.app bundle)

uv run pyinstaller \
    --name "Svelte Python Desktop" \
    --windowed \
    --onedir \
    --add-data "frontend/build:frontend/build" \
    --icon "assets/icon.icns" \
    --osx-bundle-identifier "com.yourcompany.svelte-python-desktop" \
    backend/main.py

The .app bundle will be in dist/Svelte Python Desktop.app.

Windows (.exe)

uv run pyinstaller ^
    --name "Svelte Python Desktop" ^
    --windowed ^
    --onefile ^
    --add-data "frontend/build;frontend/build" ^
    --icon "assets/icon.ico" ^
    backend/main.py

Note: On Windows, use ; instead of : for --add-data separator.

Linux (AppImage or binary)

uv run pyinstaller \
    --name "svelte-python-desktop" \
    --windowed \
    --onefile \
    --add-data "frontend/build:frontend/build" \
    backend/main.py

For AppImage packaging, use appimage-builder with the PyInstaller output.

For reproducible builds, create a build.spec file:

# build.spec
from PyInstaller.utils.hooks import collect_data_files
import sys

block_cipher = None

# Platform-specific settings
if sys.platform == 'darwin':
    icon = 'assets/icon.icns'
    separator = ':'
elif sys.platform == 'win32':
    icon = 'assets/icon.ico'
    separator = ';'
else:
    icon = None
    separator = ':'

a = Analysis(
    ['backend/main.py'],
    pathex=[],
    binaries=[],
    datas=[(f'frontend/build{separator}frontend/build')],
    hiddenimports=['webview'],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='Svelte Python Desktop',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,
    icon=icon,
)

coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='Svelte Python Desktop',
)

# macOS app bundle
if sys.platform == 'darwin':
    app = BUNDLE(
        coll,
        name='Svelte Python Desktop.app',
        icon=icon,
        bundle_identifier='com.yourcompany.svelte-python-desktop',
        info_plist={
            'CFBundleShortVersionString': '0.1.0',
            'CFBundleVersion': '0.1.0',
            'NSHighResolutionCapable': True,
        },
    )

Build using the spec file:

uv run pyinstaller build.spec

py2app (macOS Native)

py2app creates native macOS .app bundles with better system integration.

uv add --dev py2app

Create setup.py:

# setup.py
from setuptools import setup

APP = ['backend/main.py']
DATA_FILES = [('frontend/build', ['frontend/build'])]
OPTIONS = {
    'argv_emulation': False,
    'iconfile': 'assets/icon.icns',
    'plist': {
        'CFBundleName': 'Svelte Python Desktop',
        'CFBundleDisplayName': 'Svelte Python Desktop',
        'CFBundleIdentifier': 'com.yourcompany.svelte-python-desktop',
        'CFBundleVersion': '0.1.0',
        'CFBundleShortVersionString': '0.1.0',
        'NSHighResolutionCapable': True,
    },
    'packages': ['backend', 'webview'],
}

setup(
    name='Svelte Python Desktop',
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

Build the app:

# Development build (faster, for testing)
uv run python setup.py py2app -A

# Production build (standalone)
uv run python setup.py py2app

Creating App Icons

You'll need icons in different formats for each platform:

Platform Format Sizes
macOS .icns 16, 32, 64, 128, 256, 512, 1024px
Windows .ico 16, 32, 48, 256px
Linux .png 256px or 512px

Generate icons from SVG

# Install imagemagick
brew install imagemagick  # macOS
sudo apt install imagemagick  # Linux

# Create assets directory
mkdir -p assets

# Generate PNG from SVG
convert -background none frontend/static/favicon.svg -resize 1024x1024 assets/icon.png

# Generate ICO for Windows
convert assets/icon.png -define icon:auto-resize=256,128,64,48,32,16 assets/icon.ico

# Generate ICNS for macOS (requires iconutil on macOS)
mkdir -p assets/icon.iconset
for size in 16 32 64 128 256 512; do
    convert assets/icon.png -resize ${size}x${size} assets/icon.iconset/icon_${size}x${size}.png
    convert assets/icon.png -resize $((size*2))x$((size*2)) assets/icon.iconset/icon_${size}x${size}@2x.png
done
iconutil -c icns assets/icon.iconset -o assets/icon.icns
rm -rf assets/icon.iconset

Code Signing

macOS

Sign your app for distribution outside the Mac App Store:

# Sign the app
codesign --force --deep --sign "Developer ID Application: Your Name (TEAM_ID)" \
    "dist/Svelte Python Desktop.app"

# Notarize with Apple
xcrun notarytool submit "dist/Svelte Python Desktop.app" \
    --apple-id "[email protected]" \
    --team-id "TEAM_ID" \
    --password "app-specific-password" \
    --wait

# Staple the notarization ticket
xcrun stapler staple "dist/Svelte Python Desktop.app"

Windows

Sign your executable with a code signing certificate:

signtool sign /f certificate.pfx /p password /tr http://timestamp.digicert.com /td sha256 /fd sha256 "dist\Svelte Python Desktop.exe"

Creating Installers

macOS DMG

# Install create-dmg
brew install create-dmg

# Create DMG
create-dmg \
    --volname "Svelte Python Desktop" \
    --window-size 600 400 \
    --icon-size 100 \
    --icon "Svelte Python Desktop.app" 150 200 \
    --app-drop-link 450 200 \
    "dist/Svelte Python Desktop.dmg" \
    "dist/Svelte Python Desktop.app"

Windows Installer (NSIS)

Install NSIS and create an installer script:

; installer.nsi
!include "MUI2.nsh"

Name "Svelte Python Desktop"
OutFile "dist\SveltePythonDesktop-Setup.exe"
InstallDir "$PROGRAMFILES\Svelte Python Desktop"

!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"

Section "Install"
    SetOutPath "$INSTDIR"
    File /r "dist\Svelte Python Desktop\*.*"
    CreateShortcut "$DESKTOP\Svelte Python Desktop.lnk" "$INSTDIR\Svelte Python Desktop.exe"
    CreateDirectory "$SMPROGRAMS\Svelte Python Desktop"
    CreateShortcut "$SMPROGRAMS\Svelte Python Desktop\Svelte Python Desktop.lnk" "$INSTDIR\Svelte Python Desktop.exe"
SectionEnd

Section "Uninstall"
    RMDir /r "$INSTDIR"
    Delete "$DESKTOP\Svelte Python Desktop.lnk"
    RMDir /r "$SMPROGRAMS\Svelte Python Desktop"
SectionEnd

Build the installer:

makensis installer.nsi

Linux DEB/RPM

Use fpm to create packages:

# Install fpm
gem install fpm

# Create DEB package
fpm -s dir -t deb \
    -n svelte-python-desktop \
    -v 0.1.0 \
    --description "Desktop app with Svelte and Python" \
    --license MIT \
    dist/svelte-python-desktop=/usr/local/bin/

# Create RPM package
fpm -s dir -t rpm \
    -n svelte-python-desktop \
    -v 0.1.0 \
    dist/svelte-python-desktop=/usr/local/bin/

CI/CD with GitHub Actions

Automate builds for all platforms:

# .github/workflows/build.yml
name: Build

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      matrix:
        os: [macos-latest, windows-latest, ubuntu-latest]
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install uv
        uses: astral-sh/setup-uv@v4

      - name: Install dependencies
        run: |
          uv sync
          cd frontend && npm ci && npm run build && cd ..

      - name: Build executable
        run: |
          uv add --dev pyinstaller
          uv run pyinstaller build.spec

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-${{ matrix.os }}
          path: dist/

Troubleshooting

pywebview not detected in browser

This is expected when opening localhost:5173 directly in a browser. The Python backend is only available when running through pywebview. Use the development command to start the full app.

Hot reload not working (Python)

Make sure you're using Jurigged:

uv run python -m jurigged -v scripts/dev.py

Window not appearing (macOS)

On macOS, you may need to grant accessibility permissions. Also ensure you have a compatible WebKit version installed.

Frontend build errors

Clear the build cache and reinstall:

cd frontend
rm -rf node_modules .svelte-kit build
npm install
npm run build

Resources

License

MIT License - feel free to use this template for your own projects.

Top categories

Loading Svelte Themes