# Views
_Path: en/framework/views_
## Table of Contents
- Views
## Content
# Views
The `wippy/views` module provides a virtual page and component system with template rendering, resource management, and environment variable mapping. Pages can be backed by Jet templates or external components (SPAs, micro-frontends).
## Setup
Add the module to your project:
```bash
wippy add wippy/views
wippy install
```
Declare the dependency:
```yaml
version: "1.0"
namespace: app
entries:
- name: dep.views
kind: ns.dependency
component: wippy/views
version: "*"
parameters:
- name: api_router
value: app:api.public
- name: api_url_env
value: PUBLIC_API_URL
```
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `api_router` | yes | — | HTTP router for view API endpoints |
| `api_url_env` | no | `PUBLIC_API_URL` | Env var containing the public API URL |
## Template Pages
Template pages render server-side using Jet templates:
```yaml
entries:
- name: contact_page
kind: template.jet
meta:
type: view.page
name: contact
title: Contact Us
icon: mail
order: 5
group: main
group_icon: layout-grid
group_order: 1
announced: true
secure: false
data:
set: app.templates:default
data_func: app:contact_data
resources:
- contact_styles
```
### Page Metadata
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `meta.type` | string | — | Must be `view.page` |
| `meta.name` | string | entry name | Page identifier |
| `meta.title` | string | — | Display title |
| `meta.icon` | string | — | Icon identifier |
| `meta.order` | number | `9999` | Sort order within group |
| `meta.group` | string | — | Group category |
| `meta.group_icon` | string | — | Group icon |
| `meta.group_order` | number | `9999` | Group sort order |
| `meta.group_placement` | string | `"default"` | Placement: `"default"`, `"sidebar"` |
| `meta.secure` | boolean | `false` | Requires authentication |
| `meta.public` | boolean | `false` | Publicly accessible |
| `meta.announced` | boolean | `= public` | Show in navigation |
| `meta.inline` | boolean | `false` | Hidden from UI |
| `meta.content_type` | string | `text/html` | Response MIME type |
| `meta.parent` | string | — | Parent page ID |
### Template Data
| Field | Description |
|-------|-------------|
| `data.set` | Template set registry ID |
| `data.data_func` | Function ID that returns page data |
| `data.resources` | Array of resource registry IDs |
The `data_func` receives `{ params, query }` and returns a table that becomes the `data` context in the template.
### Rendering Pipeline
1. Load page from registry
2. Check access (security)
3. Call `data_func` if defined
4. Collect resources: globals + template set resources + page-specific resources
5. Load environment variables
6. Render Jet template with context: `{ data, resources, query_params, route_params, env }`
## Component Pages
Component pages point to external applications (SPAs, micro-frontends):
```yaml
entries:
- name: dashboard
kind: registry.entry
meta:
type: view.page
name: dashboard
title: Dashboard
icon: chart-bar
url: https://cdn.example.com/dashboard/
secure: true
announced: true
data:
proxy:
enabled: true
css:
prime_vue: true
theme_config: true
tailwind_config: true
```
The API returns a component descriptor with the base URL and proxy configuration. The frontend renders the component in an iframe or inline.
### Component Fields
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `meta.url` | string | — | Public URL of the component |
| `meta.entry_point` | string | `index.html` (pages), `index.js` (components) | Entry file |
### Proxy Configuration
The proxy controls what CSS and behavior is injected into the component:
| Option | Default | Description |
|--------|---------|-------------|
| `proxy.enabled` | `true` | Enable proxy wrapper |
| `proxy.css.fonts` | `true` | Inject font styles |
| `proxy.css.theme_config` | `true` | Inject theme variables |
| `proxy.css.iframe` | `true` | Iframe-specific styles |
| `proxy.css.prime_vue` | `false` | PrimeVue component styles |
| `proxy.css.markdown` | `false` | Markdown rendering styles |
| `proxy.css.custom_css` | `false` | Custom CSS |
| `proxy.css.custom_variables` | `false` | Custom CSS variables |
| `proxy.tailwind_config` | `false` | Inject Tailwind config |
| `proxy.resize_observer` | `true` | Auto-resize iframe |
| `proxy.prevent_link_clicks` | `true` | Intercept link navigation |
| `proxy.iconify_icons` | `false` | Load Iconify icon set |
## View Components
Standalone components that are not pages (no navigation entry):
```yaml
entries:
- name: widget
kind: registry.entry
meta:
type: view.component
name: chat-widget
title: Chat Widget
url: https://cdn.example.com/chat-widget/
data:
proxy:
enabled: true
```
Components use `meta.type: view.component` instead of `view.page`. They default to `index.js` as entry point.
## Resources
Resources are CSS, JS, and font files associated with pages:
```yaml
entries:
- name: global_styles
kind: registry.entry
meta:
type: view.resource
name: Global Styles
resource_type: style
global: true
order: 1
url: https://cdn.example.com/global.css
- name: app_script
kind: registry.entry
meta:
type: view.resource
name: App Script
resource_type: script
template_set: app.templates:default
order: 10
url: https://cdn.example.com/app.js
defer: true
```
### Resource Fields
| Field | Type | Description |
|-------|------|-------------|
| `meta.type` | string | Must be `view.resource` |
| `meta.resource_type` | string | `"style"`, `"script"`, `"font"` |
| `meta.order` | number | Sort order within type |
| `meta.global` | boolean | Applied to all pages |
| `meta.template_set` | string | Specific to a template set |
| `meta.url` | string | Resource URL |
| `meta.integrity` | string | SRI hash |
| `meta.crossorigin` | string | `"anonymous"` or `"use-credentials"` |
| `meta.media` | string | CSS media query |
| `meta.defer` | boolean | Deferred script loading |
| `meta.async` | boolean | Async script loading |
### Resource Collection
Resources are collected in three layers, merged in order:
1. **Global resources** — `global: true`, applied to all pages
2. **Template set resources** — matched by `template_set` ID
3. **Page resources** — listed in `data.resources` array
Within each layer, resources are grouped by `resource_type` and sorted by `order`.
## Environment Variable Mapping
The env loader maps environment variables to template context keys through a priority-based system.
### Defining Mappings
```yaml
entries:
- name: app_env
kind: registry.entry
meta:
type: view.env_mapping
priority: 20
data:
mappings:
api_endpoint: API_BASE_URL
app_title: APP_NAME
debug_mode: DEBUG_ENABLED
```
Each mapping entry associates context keys (used in templates as `env.api_endpoint`) with environment variable names.
### Priority System
| Range | Category | Description |
|-------|----------|-------------|
| 0–9 | Framework defaults | Built-in framework mappings |
| 10–19 | System overrides | System-level configuration |
| 20–29 | Application mappings | Application-specific mappings |
| 30–100 | Environment overrides | Runtime overrides |
Higher priority wins when multiple mappings define the same context key.
### Using in Templates
Resolved environment values are available in the `env` context object:
```html
```
## HTTP API Endpoints
The views module registers these endpoints on the configured router:
| Method | Path | Description |
|--------|------|-------------|
| GET | `/pages/list` | List accessible, announced pages |
| GET | `/components/list` | List view components |
| GET | `/pages/content/{id}` | Render page or return component descriptor |
| GET | `/pages/public/{id}` | Get component base URL |
### Render Response
For template pages, returns rendered HTML with the page's `content_type`.
For component pages, returns a descriptor:
```json
{
"name": "dashboard",
"version": "1.0.0",
"specification": "wippy-component-1.0",
"title": "Dashboard",
"baseUrl": "https://cdn.example.com/dashboard/",
"wippy": {
"type": "page",
"path": "index.html",
"proxy": {
"enabled": true,
"injections": {
"css": { "fonts": true, "themeConfig": true, "iframe": true },
"tailwindConfig": false,
"resizeObserver": true,
"preventLinkClicks": true
}
}
}
}
```
## Access Control
Pages with `secure: true` require authentication. The page registry checks `security.can("view", "page:")` against the current actor and scope.
Non-secure pages are always accessible. The `announced` flag controls visibility in navigation listings without affecting access.
## ID Qualification
Relative IDs in page definitions are qualified with the entry's namespace:
```yaml
# In namespace "app"
data:
data_func: my_data_func # resolves to app:my_data_func
set: templates:default # stays as templates:default (already qualified)
resources:
- page_styles # resolves to app:page_styles
```
## See Also
- [Facade](facade.md) - Frontend iframe facade and navigation sidebar
- [Template](../system/template.md) - Jet template engine
- [Security](../system/security.md) - Security actors and access control
- [Environment](../system/env.md) - Environment variable storage
- [Framework Overview](overview.md) - Framework module usage
## Navigation
Previous: Relay (framework/relay)
Next: Facade (framework/facade)