Search
PocketPages Logo

PocketPages

npm create pocketpages

No-Build Multi-Page Apps for PocketBase

<!-- pb_hooks/pages/index.ejs -->
<%= `Hello, PocketPages!` %>
http://localhost:8090
Hello, PocketPages!

Why PocketPages is Better

Zero compilation, zero bundling, zero build steps. Just write code and deploy - frontend and backend.

Zero Build Steps

No compilation anywhere. Write HTMX, Alpine.js, or VanJS and see changes instantly.

Server-Side Rendered

Pages render on the server using PocketBase JSVM. Fast, SEO-friendly, and reliable.

PocketBase Native

Built specifically for PocketBase JSVM (Goja). Access your data, auth, and APIs directly.

Why Multi-Page Apps Matter

While SPAs dominate the conversation, MPAs offer proven benefits for most web applications. PocketPages brings this architecture to PocketBase's powerful backend.

✓ MPA Advantages

  • Instant Page Loads: Server renders HTML, browser shows content immediately
  • SEO by Default: Search engines get fully rendered HTML
  • Progressive Enhancement: Works without JavaScript, enhanced with it
  • Simpler Mental Model: Each URL = one page, like the web was designed
  • Zero Compilation: No build steps anywhere - frontend or backend
pb_hooks/pages/users/[id].ejs
// Server-side data loading in PocketBase JSVM
const userId = $request.pathParam('id')
const user = $app.dao().findRecordById('users', userId)

// Template renders with live data
<%= user.name %> joined <%= formatDate(user.created) %>

PocketBase JSVM Integration

Direct access to your database, authentication, and APIs server-side.

Perfect for No-Build Frontend

Drop in your favorite no-build frontend library and start building. No webpack configs, no bundlers, no compile steps.

htmx

High power tools for HTML

Alpine.js

Minimal framework for HTML

Datastar

Reactive UI with data binding

VanJS

Ultra-lightweight reactive UI

Vanilla JS

Pure JavaScript, no dependencies

HTMX + PocketPages
<%- include('header.ejs') %>

<div hx-get="/api/todos" 
     hx-trigger="load"
     hx-target="#todo-list">
  Loading todos...
</div>

<div id="todo-list"></div>
Alpine.js + PocketPages
<div x-data="{ todos: <%= JSON.stringify(todos) %> }">
  <template x-for="todo in todos">
    <div x-text="todo.title"
         :class="{ 'completed': todo.done }">
    </div>
  </template>
</div>
Datastar + PocketPages
<input type="text" 
       name="message" 
       data-bind-message />

<button data-on-click="@get('/api/chat')">
  Send
</button>

<div id="chat-box">
  <% for (const msg of store('messages')||[]) { %>
    <div><%= msg.message %></div>
  <% } %>
</div>