Large Apps
Building something big on Manifest — a product with many screens, sign-in, lots of data? Here's how to set it up so it stays fast and easy to change.
Organize Your Code
Once your scripts grow past a few hundred lines, split them into small files that import each other. Browsers do this natively with JavaScript modules, so there's still no build step. An import map gives your folder a short name.
This demo is built exactly that way. Every name here is a stand-in: call the folder, the files and the prefix whatever you like.
<script type="importmap">
{ "imports": { "@js/": "/js/" } }
</script>
<script src="https://cdn.jsdelivr.net/npm/mnfst@latest/lib/manifest.min.js"></script>
<script type="module" src="/js/main.js"></script>
Register components and stores in an alpine:init listener. Import each file by a single URL: the same file at a different URL, such as with ?v=2, loads a second copy with its own state.
Share Code with Your Server
If a server, such as a Cloudflare Worker, checks the same things as the page, put those rules in one file that both import. The page and the server then can't disagree, and a change is one edit.
export const maxTitle = 80
export function checkTitle(title) {
if (!title.trim()) return 'required'
if (title.length > maxTitle) return 'too-long'
}
Everything the page loads is public, so keep secrets in server code only.
Load Large Tables
An Appwrite table shows its first 25 rows unless you ask for more. Set paging on the data source and Manifest loads pages as people scroll, keeping each one live. Filter on the server with $query, and save with $update: the change shows at once and rolls back if it fails.
<div x-virtual class="h-[480px] overflow-auto" @virtual-end="$x.tasks.$more()">
<template x-for="task in $x.tasks" :key="task.$id">
<label>
<input type="checkbox" :checked="task.done" @change="$x.tasks.$update(task.$id, { done: $el.checked })">
<span x-text="task.title"></span>
</label>
</template>
</div>
manifest.json {
"data": {
"tasks": { "appwriteTableId": "tasks", "paging": { "mode": "window", "size": 100 } }
}
}
See large tables for every option.
Catch Mistakes Early
A misspelt name often fails only when someone clicks. mnfst-types reads your scripts, without changing them, and points at the mistake first.
npx mnfst-types
npx mnfst-types --tsc
The first command writes manifest.d.ts, the types for Manifest itself; run it again when your data sources change. The second checks:
js/cart-summary.js(1,10): error TS2724: '"@js/money.js"' has no exported member named 'formatPrise'. Did you mean 'formatPrice'?
It checks the scripts your page loads and everything they import. See type checks.
Test Like a User
List the few things people must always be able to do, like signing in or adding an item, and let mnfst-test do them in a real browser (it uses puppeteer). It saves a screenshot wherever you call snap and fails when one changes. Install it with npm install -D mnfst-test puppeteer.
journeys.mjs export default {
root: '.',
journeys: [{
name: 'add an item',
async steps(j) {
await j.page.click('button')
await j.snap('added')
}
}]
}
npx mnfst-test journeys journeys.mjs
See golden journeys.
Article does not exist
There is no documentation at this path.