📚 StoneJS Developer Guide

Complete reference for building modern web applications with the StoneJS Framework

🛣️ Routing & Pages

File-Based Routing

StoneJS uses file-based routing. The file structure in pages/ directly maps to URLs:

File Path URL
pages/index.html / or /index.html
pages/about.html /about.html
pages/blog/index.html /blog/ or /blog/index.html
pages/blog/post.html /blog/post.html
pages/admin/users.html /admin/users.html

Dynamic Routing with Dhandlers

For dynamic routes, API endpoints, or custom routing logic, use dhandlers:

// pages/blog/dhandler module.exports = async (context) => { const { req, res, db } = context; // Extract path after /blog/ const path = req.path.replace('/blog/', ''); // Handle different routes if (path === '' || path === 'index.html') { // List all blog posts const posts = await db.query('SELECT * FROM posts ORDER BY created_at DESC'); return res.render('blog/list', { posts }); } // Match /blog/post-slug const post = await db.query('SELECT * FROM posts WHERE slug = $1', [path]); if (post.length > 0) { return res.render('blog/single', { post: post[0] }); } // 404 return res.status(404).send('Post not found'); };

Route Parameters

Access route parameters, query strings, and request data via $req:

Property Example URL/Request Access Method
Query parameters /users.html?id=123&role=admin $req.query.id"123"
POST body (JSON) {"name": "Alice", "email": "[email protected]"} $req.body.name"Alice"
URL path /blog/posts.html $req.path"/blog/posts.html"
HTTP method GET, POST, PUT, DELETE $req.method"GET"
Headers Authorization: Bearer token $req.headers.authorization
Cookies theme=dark $req.cookies.theme"dark"

Example Usage

<%%js> // URL: /users.html?id=123&role=admin const userId = $req.query.id; // "123" const userRole = $req.query.role; // "admin" // POST body parameters const name = $req.body.name; const email = $req.body.email; // Check HTTP method if ($req.method === 'POST') { // Handle form submission }

Autohandlers (Layouts)

Autohandlers wrap pages with shared HTML structure:

<!-- pages/autohandler (root layout) --> <!DOCTYPE html> <html> <head> <title><%= $context.get('pageTitle') || 'My Site' %></title> </head> <body> <header> <!-- Site header --> </header> <main> <%- await next() <!-- Child content injected here --> </main> <footer> <!-- Site footer --> </footer> </body> </html>

Nested Autohandlers

Autohandlers can be nested for section-specific layouts:

pages/ ├── autohandler # Root layout (all pages) ├── index.html └── admin/ ├── autohandler # Admin layout (only admin pages) └── dashboard.html

The admin/dashboard.html page will be wrapped by BOTH autohandlers:

  1. pages/autohandler (outer)
  2. pages/admin/autohandler (inner)
  3. pages/admin/dashboard.html (content)

Pro Tip: Use autohandlers for authentication checks, authorization, and shared layouts!

Templates & Components → Autohandler Demos Dhandler Demos

Need more help?

View All Demos Getting Started GitHub Repository