# Spiderpup
A lightweight web framework with reactive components, written in Perl and JavaScript. Author components in YAML or single-file `.pup` format.
## Features
- **Declarative components** - Define UI with YAML or single-file `.pup` syntax
- **Reactive data binding** - Computed properties with automatic updates
- **Shorthand syntax** - `$var` for getters/setters, `@click` for events, implicit `this`
- **LESS compiler** - Variables, nesting, mixins, color functions, math (via CSS::LESSp)
- **Component composition** - Imports, slots, broadcast/receive, event bubbling
- **SPA routing** - Client-side navigation with route parameters
- **Transitions** - Animated conditional rendering (fade, slide)
- **Developer experience** - Error overlays, HTML caching, base path support
## Architecture
Spiderpup uses a two-part architecture:
1. **pupserver** - A Perl HTTP server that:
- Loads YAML and `.pup` page definitions
- Compiles LESS to CSS
- Transforms shorthand syntax (`$var`, `@click`, implicit `this`)
- Parses HTML templates into JSON structures
- Generates JavaScript class definitions
- Caches compiled HTML for performance
- Serves static files (JS, CSS, raw YAML)
2. **www/webroot/js/spiderpup.js** - A client-side JavaScript runtime that:
- Provides the `Recipe` base class for components
- Handles reactive rendering and updates
- Manages component lifecycle (mount/destroy)
- Implements control flow (`if`/`elseif`/`else`, `for` loops)
- Supports slots for component composition
- Provides broadcast/receive messaging between components
- Handles event bubbling via `emit`/`on`
## Getting Started
### Running the Server
```bash
pupserver
```
The server runs on `http://localhost:5000` by default.
### Project Structure
```
spiderpup/
├── bin/
│ └── pupserver # Perl web server
├── lib/
│ └── Yote/Spiderpup/ # Server-side modules
│ ├── SFC.pm # Single-file component (.pup) parser
│ └── Transform.pm # Expression transformer
└── www/ # Web root directory
├── webroot/ # Static assets (servable by any webserver)
│ ├── js/ # JavaScript
│ │ └── spiderpup.js # Client-side runtime
│ ├── css/ # CSS stylesheets
│ └── *.html # Compiled page files
├── pages/ # Page definitions (YAML or .pup)
│ ├── index.yaml # Served at /
│ ├── about.yaml # Served at /about
│ └── mydir/ # Subdirectory
│ └── index.yaml # Served at /mydir
└── recipes/ # Reusable components
├── card.yaml # Imported as /recipes/card
├── clicker.pup # .pup format also works
└── ...
```
### URL Routing
URLs map to pages as follows:
| URL | Page File |
|-----|-----------|
| `/` | `www/pages/index.yaml` (or `index.pup`) |
| `/about` | `www/pages/about.yaml` (or `about.pup`) |
| `/mydir` | `www/pages/mydir/index.yaml` (or `index.pup`) |
| `/mydir/dashboard` | `www/pages/mydir/dashboard.yaml` (or `dashboard.pup`) |
Both `.yaml` and `.pup` files are supported. When both exist, `.yaml` takes precedence.
Recipes in `www/recipes/` are not directly accessible via URL. They are only available for import by pages and other recipes.
## Single-File Components (.pup)
As an alternative to YAML, you can author pages and recipes using the `.pup` single-file component format. This uses `
```
### Block Reference
| Block | Maps to | Notes |
|-------|---------|-------|
| `
```
Comments (`//` and `/* */`) and trailing commas are supported.
### Sub-Recipes
Define sub-recipes using `recipe="name"` on script and template blocks:
```html
My Component
```
### YAML vs .pup
Both formats produce identical compiled output. Choose based on preference:
| | YAML | .pup |
|---|------|------|
| Syntax | Indentation-based | Block-based (`` tags (files loaded separately)
- **`include-js`**: Reads file contents and embeds them inline in a `