Skip to content

Development Workflow ​

Development Server ​

bash
pnpm dev

Runs 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;  // Read

Derived 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, classifications

Progressive Loading ​

javascript
import { loadPostcode } from './lib/postcodeLoader.js';

const businesses = await loadPostcode('06234');
// Returns: Array of businesses with _shard metadata

Detail View ​

javascript
import { loadBusinessDetails } from './lib/dataLoader.js';

const details = await loadBusinessDetails(business);
// Uses business._shard to fetch shard directly

Testing ​

Run tests:

bash
pnpm test

Watch mode:

bash
pnpm test:watch

Test 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 build

Output: dist/

Preview:

bash
pnpm preview

Code 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 ​

  1. Create src/pages/MyPage.js
  2. Add route in src/lib/router.js
  3. Add navigation link in src/components/layout/Navbar.js

Add a classification system ​

  1. Generate JSON in bizcat/ or prdcat/
  2. Copy to public/data/
  3. 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/oxide
  • install-rolldown-openbsd.sh - Patches rolldown binding

Run after every pnpm install.

Korean Business Directory System