Development Workflow
Development Server
bash
pnpm devRuns Vite dev server with:
- Hot module replacement
- Fast refresh
- Source maps
- Port 5173
Component Development
Location
Components organized by purpose:
src/components/
├── layout/ # AppShell, Navbar
├── ui/ # Button, Card, Badge
├── Alert.js
├── BusinessCard.js
├── CategoryFilter.js
├── PostcodeSelect.js
└── ...Creating Components
Use VanJS functional components:
javascript
import van from 'vanjs-core';
const { div, button } = van.tags;
export function MyComponent({ title }) {
const count = van.state(0);
return div(
{ class: 'my-component' },
button(
{
onclick: () => count.val++,
class: 'btn btn-primary'
},
() => `Count: ${count.val}`
)
);
}Styling
Use Tailwind v4 utility classes:
javascript
div({ class: 'flex items-center gap-4 p-4 rounded-lg bg-background' })shadcn/ui design tokens available via CSS variables.
State Management
VanJS reactive state:
javascript
const state = van.state(initialValue);
state.val = newValue; // Update
const current = state.val; // ReadDerived state:
javascript
van.derive(() => {
// Runs when dependencies change
console.log(state.val);
});Routing
Hash-based routing in src/lib/router.js:
javascript
import { navigate } from './lib/router.js';
// Navigate programmatically
navigate('/business/1234567890');
// Link with hash
a({ href: '#/docs' }, 'Docs')Data Loading
Indices (Startup)
javascript
import { loadAllIndices } from './lib/dataLoader.js';
await loadAllIndices();
// Loads: postcode_index, category_index, classificationsProgressive Loading
javascript
import { loadPostcode } from './lib/postcodeLoader.js';
const businesses = await loadPostcode('06234');
// Returns: Array of businesses with _shard metadataDetail View
javascript
import { loadBusinessDetails } from './lib/dataLoader.js';
const details = await loadBusinessDetails(business);
// Uses business._shard to fetch shard directlyTesting
Run tests:
bash
pnpm testWatch mode:
bash
pnpm test:watchTest structure using Vitest:
javascript
import { describe, it, expect } from 'vitest';
describe('MyComponent', () => {
it('renders correctly', () => {
const el = MyComponent({ title: 'Test' });
expect(el).toBeDefined();
});
});Building
Production build:
bash
pnpm buildOutput: dist/
Preview:
bash
pnpm previewCode Style
- Immutability: Always create new objects
- Small functions: <50 lines
- Clear naming: Descriptive, no abbreviations
- Error handling: Explicit try/catch
- Comments: Only for "why", not "what"
Common Tasks
Add a new page
- Create
src/pages/MyPage.js - Add route in
src/lib/router.js - Add navigation link in
src/components/layout/Navbar.js
Add a classification system
- Generate JSON in
bizcat/orprdcat/ - Copy to
public/data/ - Update
dataLoader.loadCategoryMetadata()
Update styles
Edit src/index.css for global styles or use Tailwind utilities inline.
Debugging
Enable debug logging:
javascript
console.log('[dataLoader.js] Loading postcode:', postcode);Check network requests in DevTools for JSONL loading patterns.
OpenBSD Notes
Platform-specific scripts in scripts/:
install-tailwind-openbsd.sh- Patches lightningcss and @tailwindcss/oxideinstall-rolldown-openbsd.sh- Patches rolldown binding
Run after every pnpm install.