create-viteframe
v1.0.1
Published
Create a new ViteFrame app — file-based routing, reactive state, dynamic components
Maintainers
Readme
create-viteframe
Scaffold a new ViteFrame app — a lightweight SPA framework built on Vite with file-based routing, reactive state, and dynamic HTML components. No external JS dependencies.
Quick start
npm create viteframe@latest my-app
cd my-app
npm install
npm run devOr with pnpm / yarn:
pnpm create viteframe my-app
yarn create viteframe my-appWhat you get
src/
├── core/
│ ├── router.js # File-based SPA router (~180 lines)
│ ├── state.js # Reactive state store (~100 lines)
│ └── components.js # Dynamic component loader (~120 lines)
├── pages/
│ ├── landing.page.html # → /
│ ├── about.page.html # → /about
│ ├── docs.page.html # → /docs
│ └── [id]post.page.html # → /post/:id
├── components/
│ ├── header.comp.html
│ └── toast.comp.html
├── styles/
│ └── main.css # Design tokens + utility classes
└── main.js # BootstrapAll framework code lives in your project — read it, modify it, own it.
Routing
File name determines the route. Drop files in src/pages/.
| File | Route |
| ------------------------- | ----------------- |
| landing.page.html | / |
| about.page.html | /about |
| [id]post.page.html | /post/:id |
| [id-slug]post.page.html | /post/:id/:slug |
| [lang-id]post.page.html | /post/:lang/:id |
Programmatic navigation
window.__vf.navigate("/about");
window.__vf.navigate("/post/42", { replace: true });State
Global state
Shared across all pages. Persists during navigation.
const { globalState } = window.__vf;
globalState.set("user", { name: "Alice" });
globalState.get("user");
globalState.subscribe("user", (val) => console.log(val));
// Bind value → DOM (auto-updates when state changes)
globalState.bind("user", el, (u) => u?.name ?? "Guest");
// Two-way bind: input ↔ state
globalState.bindInput("search", inputEl);
// Partial merge
globalState.merge("settings", { darkMode: true });Page state
Isolated to a single page visit. Created inside onMount, discarded on navigation.
export function onMount() {
const { createPageState } = window.__vf;
const state = createPageState({ count: 0, open: false });
state.update("count", (n) => n + 1);
state.bind("count", document.getElementById("counter"));
}Computed values
const { computed, globalState } = window.__vf
const fullName = computed(
['firstName', 'lastName'],
[globalState, globalState],
(first, last) => `${first} ${last}`
)
fullName.get() // 'Alice Smith'
fullName.subscribe(v => …) // fires when either dep changesComponents
Components are .comp.html files in src/components/. They support scoped <style> and <script> blocks.
Use in HTML
<!-- Simple -->
<component src="header"></component>
<!-- With props via data-* attributes -->
<component src="card" data-title="Hello" data-body="World"></component>Template syntax
<!-- src/components/card.comp.html -->
<div class="card">
<h3>{{title}}</h3>
<p>{{body}}</p>
</div>Mount from JavaScript
const { mountComponent } = window.__vf;
await mountComponent("#target", "card", { title: "Hello", body: "World" });Page lifecycle
Add <script data-lifecycle> to any page and export onMount:
<script data-lifecycle>
export function onMount({ params, query, globalState }) {
// params → route params e.g. { id: '42' }
// query → ?key=val e.g. { tab: 'info' }
// globalState → shared store
console.log("id:", params.id);
console.log("tab:", query.tab);
const { createPageState } = window.__vf;
const state = createPageState({ count: 0 });
}
</script>Navigation guards
In src/main.js:
router.beforeEach(({ pathname }) => {
if (pathname.startsWith("/admin") && !globalState.get("user")) {
router.navigate("/login");
return false; // cancel navigation
}
});Toast notifications
Include <component src="toast"> on a page, then anywhere:
window.toast("Saved!", "success"); // green
window.toast("Something broke", "error"); // red
window.toast("FYI", "info", 5000); // purple, 5sCSS design tokens
All colors, spacing, and radii are CSS variables in src/styles/main.css.
/* Override in your own CSS */
:root {
--accent: #your-color;
--radius: 12px;
}Dark/light theme is toggled by setting data-theme="light" on <html>:
window.__vf.globalState.set("theme", "light");License
MIT
