@sigx/ssg
v0.1.6
Published
Static Site Generator for SignalX with file-based routing, MDX support, and pluggable themes
Maintainers
Readme
@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, andssg previewcommands
Installation
npm install @sigx/ssg sigx @sigx/router viteQuick Start
Zero-config mode
The simplest way to get started - just create pages and run:
# 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 buildWith configuration
Create ssg.config.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)
// 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
// src/pages/index.tsx
import { component } from 'sigx';
export default component(() => {
return () => (
<div>
<h1>Welcome to my site!</h1>
</div>
);
});4. Build
npx ssg buildFile-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:
// 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/:
// 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:
---
title: My Page
layout: docs
---
# Content hereOr in TSX:
export const layout = 'docs';MDX
Write content with MDX:
---
title: Hello World
date: 2024-01-01
---
# {frontmatter.title}
This is **markdown** with SignalX components!
<Counter initial={5} />Themes
Install a theme package:
npm install @sigx/ssg-theme-daisyuiConfigure in ssg.config.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:
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
// 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' });// 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
- Build time: Pages are rendered to static HTML with component markers
- Page load: Browser receives pre-rendered HTML (fast First Contentful Paint)
- Hydration: JavaScript attaches event handlers and reactivity to existing DOM
- 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:
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
# 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 --openLicense
MIT
