create-vanilla-spa
v1.1.0
Published
Scaffold a Single-Page Application (SPA) built with vanilla JavaScript.
Maintainers
Readme
create-vanilla-spa
Scaffold a Single-Page Application (SPA) built with vanilla JavaScript and Vite.
Quick Start
Scaffold a new project with:
npm create vanilla-spa@latest spa-project
cd spa-projectThis downloads the vanilla-spa template into spa-project. Then continue below to finish setup.
Leave off the directory name to scaffold into the current folder instead:
npm create vanilla-spa@latestGetting Started
npm install
npm run devOther available scripts, once inside the generated project:
npm run build # production build to dist/
npm run preview # preview the production build locallyProject Structure
index.html # HTML entry point, mounts #app
src/
main.js # Entry point - creates the SPA instance and registers routes
core/
spa.js # Router: route matching, history, link click handling
useState.js # Minimal reactive state helper (get, set, subscribe)
layouts/
default.js # Shared header/main/footer shell used by pages
pages/ # Route handlers - build a layout and mount components into it
components/ # UI pieces, one folder per component (main.js + component.module.css, event.js)
store/ # App-wide state created with useState
lib/ # Third-party client setup (e.g. axios)
styles/ # Global CSS
assets/ # Static assets bundled by Vite
public/ # Static assets served as-isRouting
Routes are registered in src/main.js:
app.add('/', HomePage)
app.add(/\/pages\/(?<id>\d+)/i, Page)A path can be a string (exact match) or a RegExp (supports named capture groups, passed to the page as params). defaultRoute in the SPA config handles unmatched paths (404). Internal link clicks are intercepted automatically and pushed through history.pushState, no full page reload.
State
useState returns a [get, set, subscribe] tuple, similar in spirit to a signal:
import { useState } from '../core/useState'
export const [count, setCount] = useState(0)Call subscribe(fn) to re-run fn whenever the value changes, useful for updating the DOM from a component without a virtual DOM diff.
