npm package: @sigx/ssg
Description: Static Site Generator for SignalX with file-based routing, MDX support, and pluggable themes
Author: Andreas Ekdahl
Latest version: 0.2.4

# @sigx/ssg

Static Site Generator for SignalX with file-based routing, MDX support, and pluggable themes.

## Features

- 🗂 **File-based routing** - Pages in `src/pages/` become routes automatically
- 📑 **Layout system** - Wrap pages with reusable layouts
- 📝 **MDX support** - Write content with Markdown and SignalX components
- 🎨 **Pluggable themes** - Install theme packages or create your own
-  **Vite HMR** - Instant updates during development
- ⚡ **Fast builds** - Parallel rendering with streaming
- 🚀 **Zero-config mode** - Works out of the box with sensible defaults
- 🗺️ **Sitemap generation** - Automatic sitemap.xml and robots.txt
- 🛠️ **CLI tools** - `ssg dev`, `ssg build`, and `ssg preview` commands

## Installation

```bash
npm install @sigx/ssg sigx @sigx/router vite
```

## Quick Start

### Zero-config mode

The simplest way to get started - just create pages and run:

```bash
# Create a page
mkdir -p src/pages
echo 'export default () => <h1>Hello World</h1>' > src/pages/index.tsx

# Start development
npx ssg dev

# Build for production
npx ssg build
```

### With configuration

Create `ssg.config.ts`:

```ts
// ssg.config.ts
import { defineSSGConfig } from '@sigx/ssg';

export default defineSSGConfig({
    site: {
        title: 'My Site',
        description: 'Built with SignalX SSG',
        url: 'https://example.com',
        fonts: ['Inter:wght@400;500;600;700'],
    },
});
```

### With custom Vite config (optional)

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import { sigxPlugin } from '@sigx/vite';
import { ssgPlugin } from '@sigx/ssg/vite';

export default defineConfig({
    plugins: [
        sigxPlugin(),
        ssgPlugin(),
    ],
});
```

### Create pages

```tsx
// src/pages/index.tsx
import { component } from 'sigx';

export default component(() => {
    return () => (
        <div>
            <h1>Welcome to my site!</h1>
        </div>
    );
});
```

### 4. Build

```bash
npx ssg build
```

## File-based Routing

Pages in `src/pages/` are automatically converted to routes:

| File | Route |
|------|-------|
| `src/pages/index.tsx` | `/` |
| `src/pages/about.tsx` | `/about` |
| `src/pages/blog/index.tsx` | `/blog` |
| `src/pages/blog/[slug].tsx` | `/blog/:slug` |
| `src/pages/docs/[...path].tsx` | `/docs/*path` |

### Dynamic Routes

For dynamic routes, export a `getStaticPaths` function:

```tsx
// src/pages/blog/[slug].tsx
import { component } from 'sigx';

export async function getStaticPaths() {
    // Fetch your data from any source
    const posts = await fetchBlogPosts();
    return posts.map(post => ({
        params: { slug: post.slug },
        props: { post },
    }));
}

export default component(({ props }) => {
    return () => (
        <article>
            <h1>{props.post.data.title}</h1>
        </article>
    );
});
```

## Layouts

Create layouts in `src/layouts/`:

```tsx
// src/layouts/default.tsx
import { component } from 'sigx';

export default component(({ slots, props }) => {
    return () => (
        <div class="layout">
            <header>
                <nav>My Site</nav>
            </header>
            <main>
                {slots.default()}
            </main>
            <footer>© 2024</footer>
        </div>
    );
});
```

Specify layout in frontmatter or export:

```mdx
---
title: My Page
layout: docs
---

# Content here
```

Or in TSX:

```tsx
export const layout = 'docs';
```

## MDX

Write content with MDX:

```mdx
---
title: Hello World
date: 2024-01-01
---

# {frontmatter.title}

This is **markdown** with SignalX components!

<Counter initial={5} />
```

## Themes

Install a theme package:

```bash
npm install @sigx/ssg-theme-daisyui
```

Configure in ssg.config.ts:

```ts
export default defineSSGConfig({
    theme: '@sigx/ssg-theme-daisyui',
});
```

Themes provide:
- Pre-built layouts (default, docs, blog, etc.)
- UI components
- CSS styles

## Hydration

SSG pages are pre-rendered at build time as static HTML. Interactive components are "hydrated" on the client side to become reactive.

### Islands Architecture

SignalX SSG supports selective hydration through **islands architecture**. Each interactive component can specify when it should be hydrated using client directives:

```tsx
import { Counter } from './components/Counter';

export default component(() => {
    return () => (
        <div>
            {/* Static content - no JS needed */}
            <h1>Welcome to my site</h1>
            
            {/* Interactive islands with different hydration strategies */}
            <Counter client:load />
            <LazyWidget client:idle />
            <OffscreenChart client:visible />
            <MobileMenu client:media="(max-width: 768px)" />
            <BrowserOnlyWidget client:only />
        </div>
    );
});
```

### Hydration Strategies

| Directive | When it Hydrates | Use Case |
|-----------|------------------|----------|
| `client:load` | Immediately on page load | Critical interactive elements |
| `client:idle` | When browser is idle (`requestIdleCallback`) | Non-critical interactivity |
| `client:visible` | When scrolled into viewport (`IntersectionObserver`) | Below-the-fold components |
| `client:media="query"` | When media query matches | Mobile-only components |
| `client:only` | Not SSR'd, renders only on client | Browser API dependencies |

### Example: Interactive Counter

```tsx
// src/components/Counter.tsx
import { component, signal } from 'sigx';

export const Counter = component(() => {
    const count = signal(0);
    
    return () => (
        <div class="counter">
            <button onClick={() => count.value--}>-</button>
            <span>{count.value}</span>
            <button onClick={() => count.value++}>+</button>
        </div>
    );
}, { name: 'Counter' });
```

```tsx
// src/pages/index.tsx
import { Counter } from '../components/Counter';

export default component(() => {
    return () => (
        <main>
            <h1>Counter Demo</h1>
            <Counter client:load />
        </main>
    );
});
```

### How It Works

1. **Build time**: Pages are rendered to static HTML with component markers
2. **Page load**: Browser receives pre-rendered HTML (fast First Contentful Paint)
3. **Hydration**: JavaScript attaches event handlers and reactivity to existing DOM
4. **Interactivity**: Components become fully interactive without re-rendering

### Benefits

- **Fast initial load** - HTML is ready immediately, no JavaScript blocking
- **SEO friendly** - Search engines see full content
- **Progressive enhancement** - Content is visible before JS loads
- **Reduced JavaScript** - Only hydrate what needs to be interactive
- **Fine-grained control** - Choose when each component becomes interactive

## Configuration

Full configuration options:

```ts
defineSSGConfig({
    // Directories
    pages: 'src/pages',
    layouts: 'src/layouts',
    content: 'src/content',
    outDir: 'dist',

    // Site metadata
    site: {
        title: 'My Site',
        description: 'Site description',
        url: 'https://example.com',
        lang: 'en',
        favicon: '/favicon.ico',
        fonts: ['Inter:wght@400;500;600;700'],
        ogImage: 'https://example.com/og.png',
        twitter: 'myhandle',
        themeColor: '#000000',
    },

    // Theme
    theme: '@sigx/ssg-theme-daisyui',
    defaultLayout: 'default',

    // Markdown options
    markdown: {
        shiki: {
            light: 'github-light',
            dark: 'github-dark',
        },
    },
});
```

## CLI

```bash
# Start development server
npx ssg dev

# Build static site (generates sitemap.xml and robots.txt)
npx ssg build

# Preview production build
npx ssg preview

# With custom config
npx ssg build --config=./my-config.ts

# With options
npx ssg dev --port=3000 --open
```

## License

MIT