# Spiderpup A lightweight YAML-based web framework with reactive components, written in Perl and JavaScript. ## Features - **Declarative YAML components** - Define UI with simple YAML 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 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 │ └── 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) │ ├── 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 ├── button.yaml # Imported as /recipes/button └── ... ``` ### URL Routing URLs map to pages as follows: | URL | Page File | |-----|-----------| | `/` | `www/pages/index.yaml` | | `/about` | `www/pages/about.yaml` | | `/mydir` | `www/pages/mydir/index.yaml` | | `/mydir/dashboard` | `www/pages/mydir/dashboard.yaml` | Recipes in `www/recipes/` are not directly accessible via URL. They are only available for import by pages and other recipes. ## Page Definition (YAML) Each page is defined in a YAML file with the following fields: ### Basic Structure ```yaml title: My Page Title css: | button { background-color: blue; } less: | @primary: #333; div { color: @primary; &:hover { color: red; } } import: foo: /foo.yaml bar: /bar.yaml vars: count: 0 name: "World" methods: increment: () => { $count = $count + 1 } html: |

Hello, $name!

``` ### Fields Reference | Field | Description | |-------|-------------| | `title` | Page title (appears in browser tab) | | `css` | Raw CSS styles (scoped to the page) | | `less` | LESS styles (compiled to CSS, scoped to the page) | | `import` | Map of component namespaces to YAML file paths | | `vars` | Reactive variables with initial values | | `computed` | Derived values that auto-update when dependencies change | | `watch` | *(Planned)* Callbacks triggered when specific variables change | | `methods` | JavaScript functions available to the page | | `lifecycle` | Hooks for mount/destroy events (`onMount`, `onDestroy`) | | `routes` | SPA route definitions (path → component mapping) | | `initial_store` | Initialize global store values (see Global Store section) | | `import-css` | Array of external CSS file URLs to include via `` tags | | `import-js` | Array of external JS file URLs to include via `` tags (files loaded separately) - **`include-js`**: Reads file contents and embeds them inline in a `