wilco 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wilco-0.1.2/.claude/settings.local.json +58 -0
- wilco-0.1.2/.gitignore +5 -0
- wilco-0.1.2/CHANGELOG.md +41 -0
- wilco-0.1.2/CLAUDE.md +146 -0
- wilco-0.1.2/Makefile +55 -0
- wilco-0.1.2/PKG-INFO +185 -0
- wilco-0.1.2/Procfile +2 -0
- wilco-0.1.2/README.md +151 -0
- wilco-0.1.2/docs/django.rst +412 -0
- wilco-0.1.2/docs/fastapi.rst +241 -0
- wilco-0.1.2/docs/internals/standalone.rst +352 -0
- wilco-0.1.2/docs/javascripts.rst +250 -0
- wilco-0.1.2/docs/specs/components.rst +659 -0
- wilco-0.1.2/examples/django-project/.gitignore +9 -0
- wilco-0.1.2/examples/django-project/.python-version +1 -0
- wilco-0.1.2/examples/django-project/Makefile +43 -0
- wilco-0.1.2/examples/django-project/README.md +55 -0
- wilco-0.1.2/examples/django-project/db.sqlite3 +0 -0
- wilco-0.1.2/examples/django-project/ecommerce/__init__.py +0 -0
- wilco-0.1.2/examples/django-project/ecommerce/asgi.py +16 -0
- wilco-0.1.2/examples/django-project/ecommerce/settings.py +148 -0
- wilco-0.1.2/examples/django-project/ecommerce/urls.py +20 -0
- wilco-0.1.2/examples/django-project/ecommerce/wsgi.py +16 -0
- wilco-0.1.2/examples/django-project/fixtures/sample_products.json +68 -0
- wilco-0.1.2/examples/django-project/manage.py +22 -0
- wilco-0.1.2/examples/django-project/media/products/cartridge.jpg +0 -0
- wilco-0.1.2/examples/django-project/media/products/coin.jpg +0 -0
- wilco-0.1.2/examples/django-project/media/products/giftcard.jpg +0 -0
- wilco-0.1.2/examples/django-project/media/products/knife.jpg +0 -0
- wilco-0.1.2/examples/django-project/media/products/mop.jpg +0 -0
- wilco-0.1.2/examples/django-project/media/products/teeshirt.jpg +0 -0
- wilco-0.1.2/examples/django-project/pyproject.toml +15 -0
- wilco-0.1.2/examples/django-project/static/android-chrome-192x192.png +0 -0
- wilco-0.1.2/examples/django-project/static/android-chrome-512x512.png +0 -0
- wilco-0.1.2/examples/django-project/static/apple-touch-icon.png +0 -0
- wilco-0.1.2/examples/django-project/static/css/admin.css +9 -0
- wilco-0.1.2/examples/django-project/static/favicon-16x16.png +0 -0
- wilco-0.1.2/examples/django-project/static/favicon-32x32.png +0 -0
- wilco-0.1.2/examples/django-project/static/favicon.ico +0 -0
- wilco-0.1.2/examples/django-project/static/site.webmanifest +1 -0
- wilco-0.1.2/examples/django-project/store/__init__.py +0 -0
- wilco-0.1.2/examples/django-project/store/admin.py +88 -0
- wilco-0.1.2/examples/django-project/store/apps.py +5 -0
- wilco-0.1.2/examples/django-project/store/components/__init__.py +1 -0
- wilco-0.1.2/examples/django-project/store/components/product/Product.styles.ts +115 -0
- wilco-0.1.2/examples/django-project/store/components/product/Product.tsx +72 -0
- wilco-0.1.2/examples/django-project/store/components/product/__init__.py +1 -0
- wilco-0.1.2/examples/django-project/store/components/product/index.tsx +1 -0
- wilco-0.1.2/examples/django-project/store/components/product/schema.json +35 -0
- wilco-0.1.2/examples/django-project/store/components/product_list/ProductList.styles.ts +38 -0
- wilco-0.1.2/examples/django-project/store/components/product_list/ProductList.tsx +37 -0
- wilco-0.1.2/examples/django-project/store/components/product_list/__init__.py +0 -0
- wilco-0.1.2/examples/django-project/store/components/product_list/index.tsx +1 -0
- wilco-0.1.2/examples/django-project/store/components/product_list/schema.json +43 -0
- wilco-0.1.2/examples/django-project/store/components/product_preview/ProductPreview.styles.ts +57 -0
- wilco-0.1.2/examples/django-project/store/components/product_preview/ProductPreview.tsx +44 -0
- wilco-0.1.2/examples/django-project/store/components/product_preview/__init__.py +0 -0
- wilco-0.1.2/examples/django-project/store/components/product_preview/index.tsx +1 -0
- wilco-0.1.2/examples/django-project/store/components/product_preview/schema.json +26 -0
- wilco-0.1.2/examples/django-project/store/migrations/0001_initial.py +32 -0
- wilco-0.1.2/examples/django-project/store/migrations/0002_alter_product_image_url.py +22 -0
- wilco-0.1.2/examples/django-project/store/migrations/0003_remove_product_image_url_product_image.py +22 -0
- wilco-0.1.2/examples/django-project/store/migrations/__init__.py +0 -0
- wilco-0.1.2/examples/django-project/store/models.py +12 -0
- wilco-0.1.2/examples/django-project/store/tests.py +3 -0
- wilco-0.1.2/examples/django-project/store/urls.py +10 -0
- wilco-0.1.2/examples/django-project/store/views.py +49 -0
- wilco-0.1.2/examples/django-project/templates/base.html +154 -0
- wilco-0.1.2/examples/django-project/templates/store/product_detail.html +9 -0
- wilco-0.1.2/examples/django-project/templates/store/product_list.html +7 -0
- wilco-0.1.2/examples/django-project/uv.lock +731 -0
- wilco-0.1.2/pyproject.toml +74 -0
- wilco-0.1.2/src/wilco/__init__.py +15 -0
- wilco-0.1.2/src/wilco/__main__.py +57 -0
- wilco-0.1.2/src/wilco/bridges/__init__.py +5 -0
- wilco-0.1.2/src/wilco/bridges/django/__init__.py +53 -0
- wilco-0.1.2/src/wilco/bridges/django/admin.py +163 -0
- wilco-0.1.2/src/wilco/bridges/django/apps.py +11 -0
- wilco-0.1.2/src/wilco/bridges/django/static/wilco/live-loader.js +311 -0
- wilco-0.1.2/src/wilco/bridges/django/static/wilco/loader.js +71 -0
- wilco-0.1.2/src/wilco/bridges/django/templatetags/__init__.py +1 -0
- wilco-0.1.2/src/wilco/bridges/django/templatetags/wilco_tags.py +65 -0
- wilco-0.1.2/src/wilco/bridges/django/urls.py +22 -0
- wilco-0.1.2/src/wilco/bridges/django/views.py +183 -0
- wilco-0.1.2/src/wilco/bridges/django/widgets.py +134 -0
- wilco-0.1.2/src/wilco/bridges/fastapi.py +73 -0
- wilco-0.1.2/src/wilco/bundler.py +326 -0
- wilco-0.1.2/src/wilco/examples/__init__.py +1 -0
- wilco-0.1.2/src/wilco/examples/carousel/Carousel.tsx +101 -0
- wilco-0.1.2/src/wilco/examples/carousel/NavButton.tsx +31 -0
- wilco-0.1.2/src/wilco/examples/carousel/__init__.py +1 -0
- wilco-0.1.2/src/wilco/examples/carousel/index.tsx +1 -0
- wilco-0.1.2/src/wilco/examples/carousel/schema.json +37 -0
- wilco-0.1.2/src/wilco/examples/counter/Counter.tsx +23 -0
- wilco-0.1.2/src/wilco/examples/counter/__init__.py +1 -0
- wilco-0.1.2/src/wilco/examples/counter/index.tsx +1 -0
- wilco-0.1.2/src/wilco/examples/counter/schema.json +21 -0
- wilco-0.1.2/src/wilco/examples/crasher/Crasher.tsx +22 -0
- wilco-0.1.2/src/wilco/examples/crasher/__init__.py +1 -0
- wilco-0.1.2/src/wilco/examples/crasher/index.tsx +1 -0
- wilco-0.1.2/src/wilco/examples/crasher/schema.json +20 -0
- wilco-0.1.2/src/wilco/examples/image/Image.tsx +37 -0
- wilco-0.1.2/src/wilco/examples/image/__init__.py +1 -0
- wilco-0.1.2/src/wilco/examples/image/index.tsx +1 -0
- wilco-0.1.2/src/wilco/examples/image/schema.json +47 -0
- wilco-0.1.2/src/wilco/registry.py +148 -0
- wilco-0.1.2/src/wilcojs/react/.gitignore +24 -0
- wilco-0.1.2/src/wilcojs/react/biome.json +21 -0
- wilco-0.1.2/src/wilcojs/react/index.html +12 -0
- wilco-0.1.2/src/wilcojs/react/package.json +40 -0
- wilco-0.1.2/src/wilcojs/react/pnpm-lock.yaml +2195 -0
- wilco-0.1.2/src/wilcojs/react/src/App.tsx +315 -0
- wilco-0.1.2/src/wilcojs/react/src/api/bundles.test.tsx +180 -0
- wilco-0.1.2/src/wilcojs/react/src/api/bundles.ts +80 -0
- wilco-0.1.2/src/wilcojs/react/src/components/PropsEditor.test.tsx +302 -0
- wilco-0.1.2/src/wilcojs/react/src/components/PropsEditor.tsx +179 -0
- wilco-0.1.2/src/wilcojs/react/src/components/StackTrace.test.tsx +166 -0
- wilco-0.1.2/src/wilcojs/react/src/components/StackTrace.tsx +276 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/ServerComponent.tsx +38 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/sourceMapRegistry.ts +150 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/standalone.ts +348 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/useComponent.test.ts +157 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/useComponent.ts +115 -0
- wilco-0.1.2/src/wilcojs/react/src/loader/wilco.ts +6 -0
- wilco-0.1.2/src/wilcojs/react/src/main.tsx +15 -0
- wilco-0.1.2/src/wilcojs/react/src/style.css +897 -0
- wilco-0.1.2/src/wilcojs/react/src/test/setup.ts +23 -0
- wilco-0.1.2/src/wilcojs/react/tsconfig.json +28 -0
- wilco-0.1.2/src/wilcojs/react/vite.config.ts +29 -0
- wilco-0.1.2/tests/conftest.py +154 -0
- wilco-0.1.2/tests/test_bridges_django.py +628 -0
- wilco-0.1.2/tests/test_bridges_fastapi.py +329 -0
- wilco-0.1.2/tests/test_bundler.py +406 -0
- wilco-0.1.2/tests/test_init.py +29 -0
- wilco-0.1.2/tests/test_registry.py +468 -0
- wilco-0.1.2/uv.lock +1539 -0
- wilco-0.1.2/wilco.jpg +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(pnpm install:*)",
|
|
5
|
+
"Bash(pnpm add:*)",
|
|
6
|
+
"Bash(uv sync:*)",
|
|
7
|
+
"Bash(uv run python:*)",
|
|
8
|
+
"Bash(ls:*)",
|
|
9
|
+
"Bash(pnpm typecheck:*)",
|
|
10
|
+
"Bash(curl:*)",
|
|
11
|
+
"Bash(pnpm dev)",
|
|
12
|
+
"Bash(pkill:*)",
|
|
13
|
+
"WebSearch",
|
|
14
|
+
"Bash(make start:*)",
|
|
15
|
+
"mcp__chrome-devtools__list_pages",
|
|
16
|
+
"mcp__chrome-devtools__navigate_page",
|
|
17
|
+
"mcp__chrome-devtools__take_snapshot",
|
|
18
|
+
"mcp__chrome-devtools__click",
|
|
19
|
+
"mcp__chrome-devtools__list_console_messages",
|
|
20
|
+
"mcp__chrome-devtools__get_console_message",
|
|
21
|
+
"mcp__chrome-devtools__list_network_requests",
|
|
22
|
+
"mcp__chrome-devtools__get_network_request",
|
|
23
|
+
"mcp__chrome-devtools__evaluate_script",
|
|
24
|
+
"mcp__chrome-devtools__take_screenshot",
|
|
25
|
+
"WebFetch(domain:pypi.org)",
|
|
26
|
+
"WebFetch(domain:github.com)",
|
|
27
|
+
"WebFetch(domain:www.npmjs.com)",
|
|
28
|
+
"WebFetch(domain:esbuild.github.io)",
|
|
29
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
30
|
+
"Bash(uv run pytest:*)",
|
|
31
|
+
"Bash(tree:*)",
|
|
32
|
+
"Bash(find:*)",
|
|
33
|
+
"Bash(mkdir:*)",
|
|
34
|
+
"Bash(python3:*)",
|
|
35
|
+
"mcp__chrome-devtools__wait_for",
|
|
36
|
+
"mcp__chrome-devtools__resize_page",
|
|
37
|
+
"Bash(make test:*)",
|
|
38
|
+
"Bash(make wheel:*)",
|
|
39
|
+
"Bash(uv init:*)",
|
|
40
|
+
"Bash(uv run:*)",
|
|
41
|
+
"WebFetch(domain:unfoldadmin.com)",
|
|
42
|
+
"mcp__chrome-devtools__new_page",
|
|
43
|
+
"mcp__chrome-devtools__fill_form",
|
|
44
|
+
"Bash(pnpm test:run:*)",
|
|
45
|
+
"Bash(pnpm build:loader:*)",
|
|
46
|
+
"mcp__chrome-devtools__fill",
|
|
47
|
+
"Bash(make format:*)",
|
|
48
|
+
"Bash(make format-frontend:*)",
|
|
49
|
+
"Bash(make test-frontend:*)",
|
|
50
|
+
"mcp__chrome-devtools__upload_file",
|
|
51
|
+
"Bash(cat:*)",
|
|
52
|
+
"Bash(uv build:*)",
|
|
53
|
+
"Bash(unzip:*)",
|
|
54
|
+
"Bash(uv lock:*)",
|
|
55
|
+
"Bash(uv pip install:*)"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
wilco-0.1.2/.gitignore
ADDED
wilco-0.1.2/CHANGELOG.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Django Admin Live Preview**: New `LivePreviewAdminMixin` enables real-time component preview in Django admin forms. The preview updates automatically when form fields lose focus, showing validation errors or the updated component.
|
|
13
|
+
- **Standalone Loader**: Self-contained JavaScript loader (`loader.js`) for rendering wilco components in server-rendered pages without a full React app. Includes React, transforms ESM bundles at runtime, and manages component lifecycle.
|
|
14
|
+
- **Live Loader Extension**: Additional `live-loader.js` script that adds live preview functionality to the standalone loader, with debounced validation and error display.
|
|
15
|
+
- **Django Template Tags**: `{% wilco_component %}` and `{% wilco_loader_script %}` template tags for embedding components in Django templates.
|
|
16
|
+
- **Component Widget**: `WilcoComponentWidget` class for rendering components in Django admin readonly fields.
|
|
17
|
+
- **Multi-source Registry**: `ComponentRegistry.add_source()` now supports multiple component directories with optional prefixes.
|
|
18
|
+
- **Django App Autodiscovery**: Automatically discovers components from `components/` directories in Django apps, prefixed with the app label (e.g., `store:product`).
|
|
19
|
+
- **Bundle Caching**: Django bridge caches bundles in memory with file mtime invalidation.
|
|
20
|
+
- **Product Component Modes**: Example product component now supports `list` and `detail` display modes.
|
|
21
|
+
- **Product List Component**: New `product_list` component for displaying grids of products.
|
|
22
|
+
- **Product Preview Component**: New `product_preview` component showing both list and detail modes for admin preview.
|
|
23
|
+
- **Goober CSS-in-JS**: Integrated goober (~1KB) for styled-components-like styling with design tokens.
|
|
24
|
+
- **useComponent Hook**: Standalone loader now supports `useComponent()` for dynamic component loading with React Suspense.
|
|
25
|
+
- **Client-side Image Preview**: Live preview supports blob URLs for previewing uploaded images before form submission.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **Barrel Pattern**: Example components now use barrel pattern with separate implementation and style files.
|
|
30
|
+
- **Component Composition**: ProductList and ProductPreview now use `useComponent("store:product")` instead of inline implementations.
|
|
31
|
+
|
|
32
|
+
- **Bundle Hash**: Metadata endpoint now includes content hash for cache busting.
|
|
33
|
+
- **Cache Headers**: Bundle responses use `immutable` cache directive for better CDN support.
|
|
34
|
+
- **Product Model**: Example Django project now uses `ImageField` instead of URL field for product images.
|
|
35
|
+
|
|
36
|
+
### Documentation
|
|
37
|
+
|
|
38
|
+
- Added FastAPI integration guide (`docs/fastapi.rst`)
|
|
39
|
+
- Added Django integration guide (`docs/django.rst`)
|
|
40
|
+
- Added standalone loader internals documentation (`docs/internals/standalone.rst`)
|
|
41
|
+
- Added JavaScript architecture overview (`docs/javascripts.rst`)
|
wilco-0.1.2/CLAUDE.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**wilco** is a proof-of-concept framework that enables Python backends to serve isolated React/TypeScript components to a Vite-based frontend. Components are defined in the Python codebase alongside their TypeScript implementations, then dynamically bundled with esbuild and loaded by the frontend at runtime.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
wilco/
|
|
13
|
+
├── pyproject.toml # Python package config
|
|
14
|
+
├── uv.lock
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── wilco/ # Python package
|
|
17
|
+
│ │ ├── __init__.py
|
|
18
|
+
│ │ ├── __main__.py # Development server entry point
|
|
19
|
+
│ │ ├── registry.py # Component discovery
|
|
20
|
+
│ │ ├── bundler.py # esbuild integration
|
|
21
|
+
│ │ ├── bridges/
|
|
22
|
+
│ │ │ ├── __init__.py
|
|
23
|
+
│ │ │ └── fastapi.py # Mountable FastAPI router
|
|
24
|
+
│ │ └── examples/ # Example components
|
|
25
|
+
│ └── wilcojs/ # JavaScript/TypeScript packages
|
|
26
|
+
│ └── react/ # React frontend app
|
|
27
|
+
│ ├── package.json
|
|
28
|
+
│ ├── index.html
|
|
29
|
+
│ ├── src/
|
|
30
|
+
│ │ ├── App.tsx
|
|
31
|
+
│ │ ├── api/
|
|
32
|
+
│ │ │ └── bundles.ts
|
|
33
|
+
│ │ └── loader/
|
|
34
|
+
│ │ ├── ServerComponent.tsx
|
|
35
|
+
│ │ ├── useComponent.ts
|
|
36
|
+
│ │ └── wilco.ts
|
|
37
|
+
│ ├── tsconfig.json
|
|
38
|
+
│ └── vite.config.ts
|
|
39
|
+
├── tests/ # Python tests
|
|
40
|
+
└── docs/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Key Concepts
|
|
44
|
+
|
|
45
|
+
- **Co-located components**: Each component has a Python package with `__init__.py`, `index.tsx` (React implementation), and optional `schema.json` (metadata/props)
|
|
46
|
+
- **Dynamic bundling**: Backend uses esbuild (from frontend's node_modules) to bundle TypeScript components on-demand
|
|
47
|
+
- **Runtime loading**: Frontend transforms ESM imports to use `window.__MODULES__`, then executes bundled code via `new Function()`
|
|
48
|
+
- **Bridge pattern**: The `wilco.bridges.fastapi` module provides a mountable router factory for easy integration
|
|
49
|
+
|
|
50
|
+
### API Endpoints
|
|
51
|
+
|
|
52
|
+
- `GET /api/bundles` - List available bundles (names only)
|
|
53
|
+
- `GET /api/bundles/{name}.js` - Get bundled JavaScript for a component
|
|
54
|
+
- `GET /api/bundles/{name}/metadata` - Get component metadata (title, description, props)
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
58
|
+
### Backend (Python/uv)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Install dependencies
|
|
62
|
+
uv sync
|
|
63
|
+
|
|
64
|
+
# Run development server (port 8000)
|
|
65
|
+
uv run python -m wilco
|
|
66
|
+
|
|
67
|
+
# Run tests
|
|
68
|
+
uv run pytest
|
|
69
|
+
uv run pytest tests/test_file.py -k "test_name"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Frontend (Vite/pnpm)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cd src/wilcojs/react
|
|
76
|
+
|
|
77
|
+
# Install dependencies
|
|
78
|
+
pnpm install
|
|
79
|
+
|
|
80
|
+
# Run development server (port 5173, proxies /api to backend)
|
|
81
|
+
pnpm dev
|
|
82
|
+
|
|
83
|
+
# Type checking
|
|
84
|
+
pnpm typecheck
|
|
85
|
+
|
|
86
|
+
# Build for production
|
|
87
|
+
pnpm build
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Running the POC
|
|
91
|
+
|
|
92
|
+
**Option 1: Using Procfile (recommended)**
|
|
93
|
+
```bash
|
|
94
|
+
# Install a process manager (honcho, foreman, or overmind)
|
|
95
|
+
pip install honcho # or: brew install overmind
|
|
96
|
+
|
|
97
|
+
# Start both services
|
|
98
|
+
honcho start # or: overmind start
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Option 2: Manual**
|
|
102
|
+
```bash
|
|
103
|
+
# Terminal 1
|
|
104
|
+
uv run python -m wilco
|
|
105
|
+
|
|
106
|
+
# Terminal 2
|
|
107
|
+
cd src/wilcojs/react && pnpm dev
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Open http://localhost:5173
|
|
111
|
+
|
|
112
|
+
### Hot Reloading
|
|
113
|
+
|
|
114
|
+
- **Backend**: uvicorn runs with `reload=True`, auto-reloads on Python file changes
|
|
115
|
+
- **Frontend**: Vite provides HMR (Hot Module Replacement) for instant updates
|
|
116
|
+
|
|
117
|
+
## Adding New Components
|
|
118
|
+
|
|
119
|
+
1. Create a component package: `src/wilco/examples/<name>/` (or your own components directory)
|
|
120
|
+
2. Add `__init__.py` (can be empty)
|
|
121
|
+
3. Add `index.tsx` with a default export React component
|
|
122
|
+
4. Optionally add `schema.json` with title, description, and props schema
|
|
123
|
+
5. Component will be auto-discovered and available at `/api/bundles/<name>.js`
|
|
124
|
+
|
|
125
|
+
## Using the Bridge Pattern
|
|
126
|
+
|
|
127
|
+
The `wilco.bridges.fastapi` module provides a `create_router()` factory for integrating with any FastAPI app:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from fastapi import FastAPI
|
|
131
|
+
from wilco import ComponentRegistry
|
|
132
|
+
from wilco.bridges.fastapi import create_router
|
|
133
|
+
|
|
134
|
+
app = FastAPI()
|
|
135
|
+
registry = ComponentRegistry(Path("./my_components"))
|
|
136
|
+
app.include_router(create_router(registry), prefix="/api")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Frontend State Management
|
|
140
|
+
|
|
141
|
+
Uses `@tanstack/react-query` for server state:
|
|
142
|
+
- `useBundles()` - Fetch list of available bundles
|
|
143
|
+
- `useBundleMetadata(name)` - Fetch metadata for a specific bundle
|
|
144
|
+
- `useBundleCode(name)` - Fetch bundled JavaScript code
|
|
145
|
+
|
|
146
|
+
Hooks are defined in `src/wilcojs/react/src/api/bundles.ts`.
|
wilco-0.1.2/Makefile
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.PHONY: start test test-backend test-frontend install clean wheel format format-python format-frontend build-loader publish publish-test
|
|
2
|
+
|
|
3
|
+
# Start development servers (default target)
|
|
4
|
+
start:
|
|
5
|
+
overmind start
|
|
6
|
+
|
|
7
|
+
# Build the standalone loader (compiles TypeScript to JavaScript)
|
|
8
|
+
build-loader:
|
|
9
|
+
cd src/wilcojs/react && pnpm build:loader
|
|
10
|
+
|
|
11
|
+
# Build Python wheel (includes pre-built JavaScript assets)
|
|
12
|
+
wheel: build-loader
|
|
13
|
+
uv build
|
|
14
|
+
|
|
15
|
+
# Publish to PyPI
|
|
16
|
+
publish: wheel
|
|
17
|
+
uv run twine upload dist/*
|
|
18
|
+
|
|
19
|
+
# Publish to TestPyPI (for testing before production release)
|
|
20
|
+
publish-test: wheel
|
|
21
|
+
uv run twine upload --repository testpypi dist/*
|
|
22
|
+
|
|
23
|
+
# Run all tests
|
|
24
|
+
test: test-backend test-frontend
|
|
25
|
+
|
|
26
|
+
# Run backend tests (Python/pytest)
|
|
27
|
+
test-backend:
|
|
28
|
+
uv run pytest
|
|
29
|
+
|
|
30
|
+
# Run frontend tests (TypeScript typecheck + Vitest)
|
|
31
|
+
test-frontend:
|
|
32
|
+
cd src/wilcojs/react && pnpm typecheck && pnpm test:run
|
|
33
|
+
|
|
34
|
+
# Install all dependencies
|
|
35
|
+
install:
|
|
36
|
+
uv sync
|
|
37
|
+
cd src/wilcojs/react && pnpm install
|
|
38
|
+
|
|
39
|
+
# Clean build artifacts
|
|
40
|
+
clean:
|
|
41
|
+
rm -rf .pytest_cache
|
|
42
|
+
rm -rf dist
|
|
43
|
+
rm -rf src/wilcojs/react/dist
|
|
44
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
45
|
+
|
|
46
|
+
# Format all code
|
|
47
|
+
format: format-python format-frontend
|
|
48
|
+
|
|
49
|
+
# Format Python files with ruff (4 spaces, 120 chars)
|
|
50
|
+
format-python:
|
|
51
|
+
uv run ruff format src tests
|
|
52
|
+
|
|
53
|
+
# Format frontend files with biome
|
|
54
|
+
format-frontend:
|
|
55
|
+
cd src/wilcojs/react && pnpm exec biome format --write .
|
wilco-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wilco
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Serve React components from Python backends
|
|
5
|
+
Project-URL: Homepage, https://github.com/user/wilco
|
|
6
|
+
Project-URL: Documentation, https://github.com/user/wilco#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/user/wilco
|
|
8
|
+
Project-URL: Issues, https://github.com/user/wilco/issues
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: components,django,esbuild,fastapi,react,typescript
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Framework :: Django
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: fastapi>=0.115.0
|
|
24
|
+
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: django>=4.2.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: twine>=6.0.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# wilco
|
|
36
|
+
|
|
37
|
+
**Server-defined React components for Python backends.**
|
|
38
|
+
|
|
39
|
+
Wilco lets you define React components alongside your Python code and serve them dynamically to any frontend. Components are bundled on-demand with esbuild and loaded at runtime—no build step required for your component library.
|
|
40
|
+
|
|
41
|
+
## Why wilco?
|
|
42
|
+
|
|
43
|
+
- **Co-locate components with backend logic**: Keep your UI components next to the Python code that powers them
|
|
44
|
+
- **No frontend build pipeline**: Components are bundled on-the-fly when requested
|
|
45
|
+
- **Full source map support**: Debug your TypeScript directly in browser devtools
|
|
46
|
+
- **Component composition**: Components can dynamically load other components
|
|
47
|
+
- **Framework agnostic**: Mount the API router in any FastAPI (or compatible) app
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install wilco
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Create a component
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
my_components/
|
|
61
|
+
└── greeting/
|
|
62
|
+
├── __init__.py
|
|
63
|
+
├── index.tsx
|
|
64
|
+
└── schema.json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// index.tsx
|
|
69
|
+
interface GreetingProps {
|
|
70
|
+
name: string;
|
|
71
|
+
formal?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default function Greeting({ name, formal = false }: GreetingProps) {
|
|
75
|
+
const message = formal ? `Good day, ${name}.` : `Hey ${name}!`;
|
|
76
|
+
return <p>{message}</p>;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"title": "Greeting",
|
|
83
|
+
"description": "A friendly greeting component",
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"name": { "type": "string" },
|
|
87
|
+
"formal": { "type": "boolean", "default": false }
|
|
88
|
+
},
|
|
89
|
+
"required": ["name"]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Mount the API
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
from fastapi import FastAPI
|
|
98
|
+
from wilco import ComponentRegistry
|
|
99
|
+
from wilco.bridges.fastapi import create_router
|
|
100
|
+
|
|
101
|
+
app = FastAPI()
|
|
102
|
+
registry = ComponentRegistry(Path("./my_components"))
|
|
103
|
+
app.include_router(create_router(registry), prefix="/api")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Load components in React
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { useComponent } from '@wilcojs/react';
|
|
110
|
+
|
|
111
|
+
function App() {
|
|
112
|
+
const Greeting = useComponent('greeting');
|
|
113
|
+
return <Greeting name="World" />;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## API Endpoints
|
|
118
|
+
|
|
119
|
+
| Endpoint | Description |
|
|
120
|
+
|----------|-------------|
|
|
121
|
+
| `GET /api/bundles` | List available components |
|
|
122
|
+
| `GET /api/bundles/{name}.js` | Get bundled JavaScript |
|
|
123
|
+
| `GET /api/bundles/{name}/metadata` | Get component metadata |
|
|
124
|
+
|
|
125
|
+
## Component Structure
|
|
126
|
+
|
|
127
|
+
Each component is a Python package with:
|
|
128
|
+
|
|
129
|
+
| File | Required | Description |
|
|
130
|
+
|------|----------|-------------|
|
|
131
|
+
| `__init__.py` | Yes | Package marker |
|
|
132
|
+
| `index.tsx` | Yes | React component (default export) |
|
|
133
|
+
| `schema.json` | No | Props schema and metadata |
|
|
134
|
+
|
|
135
|
+
Components can include additional `.tsx` files—they're all bundled together.
|
|
136
|
+
|
|
137
|
+
## Component Composition
|
|
138
|
+
|
|
139
|
+
Components can load other components dynamically:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { useComponent } from '@wilcojs/react';
|
|
143
|
+
|
|
144
|
+
export default function Dashboard() {
|
|
145
|
+
const Chart = useComponent('chart');
|
|
146
|
+
const Table = useComponent('table');
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
<Chart data={...} />
|
|
151
|
+
<Table rows={...} />
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Development Server
|
|
158
|
+
|
|
159
|
+
Run the built-in development server to preview components:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv run python -m wilco
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Then start the frontend:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cd src/wilcojs/react && pnpm dev
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Open http://localhost:5173 to browse and test your components.
|
|
172
|
+
|
|
173
|
+
## Requirements
|
|
174
|
+
|
|
175
|
+
- Python 3.10+
|
|
176
|
+
- Node.js (for esbuild bundling)
|
|
177
|
+
- React 18+ on the frontend
|
|
178
|
+
|
|
179
|
+
## About the Name
|
|
180
|
+
|
|
181
|
+
Named after **Roger Wilco**, the janitor-turned-hero from Sierra's *Space Quest* series. Roger stumbles into saving the galaxy while just trying to do his job. Like its namesake, this framework gets the job done despite the chaos—bridging Python backends with React frontends through dynamic bundling magic.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT
|
wilco-0.1.2/Procfile
ADDED
wilco-0.1.2/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# wilco
|
|
2
|
+
|
|
3
|
+
**Server-defined React components for Python backends.**
|
|
4
|
+
|
|
5
|
+
Wilco lets you define React components alongside your Python code and serve them dynamically to any frontend. Components are bundled on-demand with esbuild and loaded at runtime—no build step required for your component library.
|
|
6
|
+
|
|
7
|
+
## Why wilco?
|
|
8
|
+
|
|
9
|
+
- **Co-locate components with backend logic**: Keep your UI components next to the Python code that powers them
|
|
10
|
+
- **No frontend build pipeline**: Components are bundled on-the-fly when requested
|
|
11
|
+
- **Full source map support**: Debug your TypeScript directly in browser devtools
|
|
12
|
+
- **Component composition**: Components can dynamically load other components
|
|
13
|
+
- **Framework agnostic**: Mount the API router in any FastAPI (or compatible) app
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install wilco
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Create a component
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
my_components/
|
|
27
|
+
└── greeting/
|
|
28
|
+
├── __init__.py
|
|
29
|
+
├── index.tsx
|
|
30
|
+
└── schema.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// index.tsx
|
|
35
|
+
interface GreetingProps {
|
|
36
|
+
name: string;
|
|
37
|
+
formal?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default function Greeting({ name, formal = false }: GreetingProps) {
|
|
41
|
+
const message = formal ? `Good day, ${name}.` : `Hey ${name}!`;
|
|
42
|
+
return <p>{message}</p>;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"title": "Greeting",
|
|
49
|
+
"description": "A friendly greeting component",
|
|
50
|
+
"type": "object",
|
|
51
|
+
"properties": {
|
|
52
|
+
"name": { "type": "string" },
|
|
53
|
+
"formal": { "type": "boolean", "default": false }
|
|
54
|
+
},
|
|
55
|
+
"required": ["name"]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Mount the API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from pathlib import Path
|
|
63
|
+
from fastapi import FastAPI
|
|
64
|
+
from wilco import ComponentRegistry
|
|
65
|
+
from wilco.bridges.fastapi import create_router
|
|
66
|
+
|
|
67
|
+
app = FastAPI()
|
|
68
|
+
registry = ComponentRegistry(Path("./my_components"))
|
|
69
|
+
app.include_router(create_router(registry), prefix="/api")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Load components in React
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useComponent } from '@wilcojs/react';
|
|
76
|
+
|
|
77
|
+
function App() {
|
|
78
|
+
const Greeting = useComponent('greeting');
|
|
79
|
+
return <Greeting name="World" />;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API Endpoints
|
|
84
|
+
|
|
85
|
+
| Endpoint | Description |
|
|
86
|
+
|----------|-------------|
|
|
87
|
+
| `GET /api/bundles` | List available components |
|
|
88
|
+
| `GET /api/bundles/{name}.js` | Get bundled JavaScript |
|
|
89
|
+
| `GET /api/bundles/{name}/metadata` | Get component metadata |
|
|
90
|
+
|
|
91
|
+
## Component Structure
|
|
92
|
+
|
|
93
|
+
Each component is a Python package with:
|
|
94
|
+
|
|
95
|
+
| File | Required | Description |
|
|
96
|
+
|------|----------|-------------|
|
|
97
|
+
| `__init__.py` | Yes | Package marker |
|
|
98
|
+
| `index.tsx` | Yes | React component (default export) |
|
|
99
|
+
| `schema.json` | No | Props schema and metadata |
|
|
100
|
+
|
|
101
|
+
Components can include additional `.tsx` files—they're all bundled together.
|
|
102
|
+
|
|
103
|
+
## Component Composition
|
|
104
|
+
|
|
105
|
+
Components can load other components dynamically:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { useComponent } from '@wilcojs/react';
|
|
109
|
+
|
|
110
|
+
export default function Dashboard() {
|
|
111
|
+
const Chart = useComponent('chart');
|
|
112
|
+
const Table = useComponent('table');
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<div>
|
|
116
|
+
<Chart data={...} />
|
|
117
|
+
<Table rows={...} />
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Development Server
|
|
124
|
+
|
|
125
|
+
Run the built-in development server to preview components:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
uv run python -m wilco
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Then start the frontend:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
cd src/wilcojs/react && pnpm dev
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Open http://localhost:5173 to browse and test your components.
|
|
138
|
+
|
|
139
|
+
## Requirements
|
|
140
|
+
|
|
141
|
+
- Python 3.10+
|
|
142
|
+
- Node.js (for esbuild bundling)
|
|
143
|
+
- React 18+ on the frontend
|
|
144
|
+
|
|
145
|
+
## About the Name
|
|
146
|
+
|
|
147
|
+
Named after **Roger Wilco**, the janitor-turned-hero from Sierra's *Space Quest* series. Roger stumbles into saving the galaxy while just trying to do his job. Like its namesake, this framework gets the job done despite the chaos—bridging Python backends with React frontends through dynamic bundling magic.
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|