@sigx/ssg 0.3.2 β 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +358 -358
- package/dist/build-DP9zez3B.js.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/dev.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin-EIAzPLvE.js.map +1 -1
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +99 -0
- package/dist/plugin.js.map +1 -0
- package/dist/virtual-entries-CH-0HuqJ.js.map +1 -1
- package/package.json +23 -13
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -2357
- package/dist/cli.js.map +0 -7
package/README.md
CHANGED
|
@@ -1,358 +1,358 @@
|
|
|
1
|
-
# @sigx/ssg
|
|
2
|
-
|
|
3
|
-
Static Site Generator for SignalX with file-based routing, MDX support, and pluggable themes.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- π **File-based routing** - Pages in `src/pages/` become routes automatically
|
|
8
|
-
- π **Layout system** - Wrap pages with reusable layouts
|
|
9
|
-
- π **MDX support** - Write content with Markdown and SignalX components
|
|
10
|
-
- π¨ **Pluggable themes** - Install theme packages or create your own
|
|
11
|
-
- **Vite HMR** - Instant updates during development
|
|
12
|
-
- β‘ **Fast builds** - Parallel rendering with streaming
|
|
13
|
-
- π **Zero-config mode** - Works out of the box with sensible defaults
|
|
14
|
-
- πΊοΈ **Sitemap generation** - Automatic sitemap.xml and robots.txt
|
|
15
|
-
- π οΈ **CLI tools** - `ssg dev`, `ssg build`, and `ssg preview` commands
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install @sigx/ssg sigx @sigx/router vite
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Quick Start
|
|
24
|
-
|
|
25
|
-
### Zero-config mode
|
|
26
|
-
|
|
27
|
-
The simplest way to get started - just create pages and run:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
# Create a page
|
|
31
|
-
mkdir -p src/pages
|
|
32
|
-
echo 'export default () => <h1>Hello World</h1>' > src/pages/index.tsx
|
|
33
|
-
|
|
34
|
-
# Start development
|
|
35
|
-
npx ssg dev
|
|
36
|
-
|
|
37
|
-
# Build for production
|
|
38
|
-
npx ssg build
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### With configuration
|
|
42
|
-
|
|
43
|
-
Create `ssg.config.ts`:
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
// ssg.config.ts
|
|
47
|
-
import { defineSSGConfig } from '@sigx/ssg';
|
|
48
|
-
|
|
49
|
-
export default defineSSGConfig({
|
|
50
|
-
site: {
|
|
51
|
-
title: 'My Site',
|
|
52
|
-
description: 'Built with SignalX SSG',
|
|
53
|
-
url: 'https://example.com',
|
|
54
|
-
fonts: ['Inter:wght@400;500;600;700'],
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### With custom Vite config (optional)
|
|
60
|
-
|
|
61
|
-
```ts
|
|
62
|
-
// vite.config.ts
|
|
63
|
-
import { defineConfig } from 'vite';
|
|
64
|
-
import { sigxPlugin } from '@sigx/vite';
|
|
65
|
-
import { ssgPlugin } from '@sigx/ssg/vite';
|
|
66
|
-
|
|
67
|
-
export default defineConfig({
|
|
68
|
-
plugins: [
|
|
69
|
-
sigxPlugin(),
|
|
70
|
-
ssgPlugin(),
|
|
71
|
-
],
|
|
72
|
-
});
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Create pages
|
|
76
|
-
|
|
77
|
-
```tsx
|
|
78
|
-
// src/pages/index.tsx
|
|
79
|
-
import { component } from 'sigx';
|
|
80
|
-
|
|
81
|
-
export default component(() => {
|
|
82
|
-
return () => (
|
|
83
|
-
<div>
|
|
84
|
-
<h1>Welcome to my site!</h1>
|
|
85
|
-
</div>
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 4. Build
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
npx ssg build
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## File-based Routing
|
|
97
|
-
|
|
98
|
-
Pages in `src/pages/` are automatically converted to routes:
|
|
99
|
-
|
|
100
|
-
| File | Route |
|
|
101
|
-
|------|-------|
|
|
102
|
-
| `src/pages/index.tsx` | `/` |
|
|
103
|
-
| `src/pages/about.tsx` | `/about` |
|
|
104
|
-
| `src/pages/blog/index.tsx` | `/blog` |
|
|
105
|
-
| `src/pages/blog/[slug].tsx` | `/blog/:slug` |
|
|
106
|
-
| `src/pages/docs/[...path].tsx` | `/docs/*path` |
|
|
107
|
-
|
|
108
|
-
### Dynamic Routes
|
|
109
|
-
|
|
110
|
-
For dynamic routes, export a `getStaticPaths` function:
|
|
111
|
-
|
|
112
|
-
```tsx
|
|
113
|
-
// src/pages/blog/[slug].tsx
|
|
114
|
-
import { component } from 'sigx';
|
|
115
|
-
|
|
116
|
-
export async function getStaticPaths() {
|
|
117
|
-
// Fetch your data from any source
|
|
118
|
-
const posts = await fetchBlogPosts();
|
|
119
|
-
return posts.map(post => ({
|
|
120
|
-
params: { slug: post.slug },
|
|
121
|
-
props: { post },
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export default component(({ props }) => {
|
|
126
|
-
return () => (
|
|
127
|
-
<article>
|
|
128
|
-
<h1>{props.post.data.title}</h1>
|
|
129
|
-
</article>
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Layouts
|
|
135
|
-
|
|
136
|
-
Create layouts in `src/layouts/`:
|
|
137
|
-
|
|
138
|
-
```tsx
|
|
139
|
-
// src/layouts/default.tsx
|
|
140
|
-
import { component } from 'sigx';
|
|
141
|
-
|
|
142
|
-
export default component(({ slots, props }) => {
|
|
143
|
-
return () => (
|
|
144
|
-
<div class="layout">
|
|
145
|
-
<header>
|
|
146
|
-
<nav>My Site</nav>
|
|
147
|
-
</header>
|
|
148
|
-
<main>
|
|
149
|
-
{slots.default()}
|
|
150
|
-
</main>
|
|
151
|
-
<footer>Β© 2024</footer>
|
|
152
|
-
</div>
|
|
153
|
-
);
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Specify layout in frontmatter or export:
|
|
158
|
-
|
|
159
|
-
```mdx
|
|
160
|
-
---
|
|
161
|
-
title: My Page
|
|
162
|
-
layout: docs
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
# Content here
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Or in TSX:
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
export const layout = 'docs';
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## MDX
|
|
175
|
-
|
|
176
|
-
Write content with MDX:
|
|
177
|
-
|
|
178
|
-
```mdx
|
|
179
|
-
---
|
|
180
|
-
title: Hello World
|
|
181
|
-
date: 2024-01-01
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
# {frontmatter.title}
|
|
185
|
-
|
|
186
|
-
This is **markdown** with SignalX components!
|
|
187
|
-
|
|
188
|
-
<Counter initial={5} />
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Themes
|
|
192
|
-
|
|
193
|
-
Install a theme package:
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
npm install @sigx/ssg-theme-daisyui
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
Configure in ssg.config.ts:
|
|
200
|
-
|
|
201
|
-
```ts
|
|
202
|
-
export default defineSSGConfig({
|
|
203
|
-
theme: '@sigx/ssg-theme-daisyui',
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
Themes provide:
|
|
208
|
-
- Pre-built layouts (default, docs, blog, etc.)
|
|
209
|
-
- UI components
|
|
210
|
-
- CSS styles
|
|
211
|
-
|
|
212
|
-
## Hydration
|
|
213
|
-
|
|
214
|
-
SSG pages are pre-rendered at build time as static HTML. Interactive components are "hydrated" on the client side to become reactive.
|
|
215
|
-
|
|
216
|
-
### Islands Architecture
|
|
217
|
-
|
|
218
|
-
SignalX SSG supports selective hydration through **islands architecture**. Each interactive component can specify when it should be hydrated using client directives:
|
|
219
|
-
|
|
220
|
-
```tsx
|
|
221
|
-
import { Counter } from './components/Counter';
|
|
222
|
-
|
|
223
|
-
export default component(() => {
|
|
224
|
-
return () => (
|
|
225
|
-
<div>
|
|
226
|
-
{/* Static content - no JS needed */}
|
|
227
|
-
<h1>Welcome to my site</h1>
|
|
228
|
-
|
|
229
|
-
{/* Interactive islands with different hydration strategies */}
|
|
230
|
-
<Counter client:load />
|
|
231
|
-
<LazyWidget client:idle />
|
|
232
|
-
<OffscreenChart client:visible />
|
|
233
|
-
<MobileMenu client:media="(max-width: 768px)" />
|
|
234
|
-
<BrowserOnlyWidget client:only />
|
|
235
|
-
</div>
|
|
236
|
-
);
|
|
237
|
-
});
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Hydration Strategies
|
|
241
|
-
|
|
242
|
-
| Directive | When it Hydrates | Use Case |
|
|
243
|
-
|-----------|------------------|----------|
|
|
244
|
-
| `client:load` | Immediately on page load | Critical interactive elements |
|
|
245
|
-
| `client:idle` | When browser is idle (`requestIdleCallback`) | Non-critical interactivity |
|
|
246
|
-
| `client:visible` | When scrolled into viewport (`IntersectionObserver`) | Below-the-fold components |
|
|
247
|
-
| `client:media="query"` | When media query matches | Mobile-only components |
|
|
248
|
-
| `client:only` | Not SSR'd, renders only on client | Browser API dependencies |
|
|
249
|
-
|
|
250
|
-
### Example: Interactive Counter
|
|
251
|
-
|
|
252
|
-
```tsx
|
|
253
|
-
// src/components/Counter.tsx
|
|
254
|
-
import { component, signal } from 'sigx';
|
|
255
|
-
|
|
256
|
-
export const Counter = component(() => {
|
|
257
|
-
const count = signal(0);
|
|
258
|
-
|
|
259
|
-
return () => (
|
|
260
|
-
<div class="counter">
|
|
261
|
-
<button onClick={() => count.value--}>-</button>
|
|
262
|
-
<span>{count.value}</span>
|
|
263
|
-
<button onClick={() => count.value++}>+</button>
|
|
264
|
-
</div>
|
|
265
|
-
);
|
|
266
|
-
}, { name: 'Counter' });
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
```tsx
|
|
270
|
-
// src/pages/index.tsx
|
|
271
|
-
import { Counter } from '../components/Counter';
|
|
272
|
-
|
|
273
|
-
export default component(() => {
|
|
274
|
-
return () => (
|
|
275
|
-
<main>
|
|
276
|
-
<h1>Counter Demo</h1>
|
|
277
|
-
<Counter client:load />
|
|
278
|
-
</main>
|
|
279
|
-
);
|
|
280
|
-
});
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### How It Works
|
|
284
|
-
|
|
285
|
-
1. **Build time**: Pages are rendered to static HTML with component markers
|
|
286
|
-
2. **Page load**: Browser receives pre-rendered HTML (fast First Contentful Paint)
|
|
287
|
-
3. **Hydration**: JavaScript attaches event handlers and reactivity to existing DOM
|
|
288
|
-
4. **Interactivity**: Components become fully interactive without re-rendering
|
|
289
|
-
|
|
290
|
-
### Benefits
|
|
291
|
-
|
|
292
|
-
- **Fast initial load** - HTML is ready immediately, no JavaScript blocking
|
|
293
|
-
- **SEO friendly** - Search engines see full content
|
|
294
|
-
- **Progressive enhancement** - Content is visible before JS loads
|
|
295
|
-
- **Reduced JavaScript** - Only hydrate what needs to be interactive
|
|
296
|
-
- **Fine-grained control** - Choose when each component becomes interactive
|
|
297
|
-
|
|
298
|
-
## Configuration
|
|
299
|
-
|
|
300
|
-
Full configuration options:
|
|
301
|
-
|
|
302
|
-
```ts
|
|
303
|
-
defineSSGConfig({
|
|
304
|
-
// Directories
|
|
305
|
-
pages: 'src/pages',
|
|
306
|
-
layouts: 'src/layouts',
|
|
307
|
-
content: 'src/content',
|
|
308
|
-
outDir: 'dist',
|
|
309
|
-
|
|
310
|
-
// Site metadata
|
|
311
|
-
site: {
|
|
312
|
-
title: 'My Site',
|
|
313
|
-
description: 'Site description',
|
|
314
|
-
url: 'https://example.com',
|
|
315
|
-
lang: 'en',
|
|
316
|
-
favicon: '/favicon.ico',
|
|
317
|
-
fonts: ['Inter:wght@400;500;600;700'],
|
|
318
|
-
ogImage: 'https://example.com/og.png',
|
|
319
|
-
twitter: 'myhandle',
|
|
320
|
-
themeColor: '#000000',
|
|
321
|
-
},
|
|
322
|
-
|
|
323
|
-
// Theme
|
|
324
|
-
theme: '@sigx/ssg-theme-daisyui',
|
|
325
|
-
defaultLayout: 'default',
|
|
326
|
-
|
|
327
|
-
// Markdown options
|
|
328
|
-
markdown: {
|
|
329
|
-
shiki: {
|
|
330
|
-
light: 'github-light',
|
|
331
|
-
dark: 'github-dark',
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
});
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
## CLI
|
|
338
|
-
|
|
339
|
-
```bash
|
|
340
|
-
# Start development server
|
|
341
|
-
npx ssg dev
|
|
342
|
-
|
|
343
|
-
# Build static site (generates sitemap.xml and robots.txt)
|
|
344
|
-
npx ssg build
|
|
345
|
-
|
|
346
|
-
# Preview production build
|
|
347
|
-
npx ssg preview
|
|
348
|
-
|
|
349
|
-
# With custom config
|
|
350
|
-
npx ssg build --config=./my-config.ts
|
|
351
|
-
|
|
352
|
-
# With options
|
|
353
|
-
npx ssg dev --port=3000 --open
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
## License
|
|
357
|
-
|
|
358
|
-
MIT
|
|
1
|
+
# @sigx/ssg
|
|
2
|
+
|
|
3
|
+
Static Site Generator for SignalX with file-based routing, MDX support, and pluggable themes.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- π **File-based routing** - Pages in `src/pages/` become routes automatically
|
|
8
|
+
- π **Layout system** - Wrap pages with reusable layouts
|
|
9
|
+
- π **MDX support** - Write content with Markdown and SignalX components
|
|
10
|
+
- π¨ **Pluggable themes** - Install theme packages or create your own
|
|
11
|
+
- **Vite HMR** - Instant updates during development
|
|
12
|
+
- β‘ **Fast builds** - Parallel rendering with streaming
|
|
13
|
+
- π **Zero-config mode** - Works out of the box with sensible defaults
|
|
14
|
+
- πΊοΈ **Sitemap generation** - Automatic sitemap.xml and robots.txt
|
|
15
|
+
- π οΈ **CLI tools** - `ssg dev`, `ssg build`, and `ssg preview` commands
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @sigx/ssg sigx @sigx/router vite
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Zero-config mode
|
|
26
|
+
|
|
27
|
+
The simplest way to get started - just create pages and run:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Create a page
|
|
31
|
+
mkdir -p src/pages
|
|
32
|
+
echo 'export default () => <h1>Hello World</h1>' > src/pages/index.tsx
|
|
33
|
+
|
|
34
|
+
# Start development
|
|
35
|
+
npx ssg dev
|
|
36
|
+
|
|
37
|
+
# Build for production
|
|
38
|
+
npx ssg build
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### With configuration
|
|
42
|
+
|
|
43
|
+
Create `ssg.config.ts`:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// ssg.config.ts
|
|
47
|
+
import { defineSSGConfig } from '@sigx/ssg';
|
|
48
|
+
|
|
49
|
+
export default defineSSGConfig({
|
|
50
|
+
site: {
|
|
51
|
+
title: 'My Site',
|
|
52
|
+
description: 'Built with SignalX SSG',
|
|
53
|
+
url: 'https://example.com',
|
|
54
|
+
fonts: ['Inter:wght@400;500;600;700'],
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### With custom Vite config (optional)
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// vite.config.ts
|
|
63
|
+
import { defineConfig } from 'vite';
|
|
64
|
+
import { sigxPlugin } from '@sigx/vite';
|
|
65
|
+
import { ssgPlugin } from '@sigx/ssg/vite';
|
|
66
|
+
|
|
67
|
+
export default defineConfig({
|
|
68
|
+
plugins: [
|
|
69
|
+
sigxPlugin(),
|
|
70
|
+
ssgPlugin(),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Create pages
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
// src/pages/index.tsx
|
|
79
|
+
import { component } from 'sigx';
|
|
80
|
+
|
|
81
|
+
export default component(() => {
|
|
82
|
+
return () => (
|
|
83
|
+
<div>
|
|
84
|
+
<h1>Welcome to my site!</h1>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. Build
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx ssg build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## File-based Routing
|
|
97
|
+
|
|
98
|
+
Pages in `src/pages/` are automatically converted to routes:
|
|
99
|
+
|
|
100
|
+
| File | Route |
|
|
101
|
+
|------|-------|
|
|
102
|
+
| `src/pages/index.tsx` | `/` |
|
|
103
|
+
| `src/pages/about.tsx` | `/about` |
|
|
104
|
+
| `src/pages/blog/index.tsx` | `/blog` |
|
|
105
|
+
| `src/pages/blog/[slug].tsx` | `/blog/:slug` |
|
|
106
|
+
| `src/pages/docs/[...path].tsx` | `/docs/*path` |
|
|
107
|
+
|
|
108
|
+
### Dynamic Routes
|
|
109
|
+
|
|
110
|
+
For dynamic routes, export a `getStaticPaths` function:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
// src/pages/blog/[slug].tsx
|
|
114
|
+
import { component } from 'sigx';
|
|
115
|
+
|
|
116
|
+
export async function getStaticPaths() {
|
|
117
|
+
// Fetch your data from any source
|
|
118
|
+
const posts = await fetchBlogPosts();
|
|
119
|
+
return posts.map(post => ({
|
|
120
|
+
params: { slug: post.slug },
|
|
121
|
+
props: { post },
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default component(({ props }) => {
|
|
126
|
+
return () => (
|
|
127
|
+
<article>
|
|
128
|
+
<h1>{props.post.data.title}</h1>
|
|
129
|
+
</article>
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Layouts
|
|
135
|
+
|
|
136
|
+
Create layouts in `src/layouts/`:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// src/layouts/default.tsx
|
|
140
|
+
import { component } from 'sigx';
|
|
141
|
+
|
|
142
|
+
export default component(({ slots, props }) => {
|
|
143
|
+
return () => (
|
|
144
|
+
<div class="layout">
|
|
145
|
+
<header>
|
|
146
|
+
<nav>My Site</nav>
|
|
147
|
+
</header>
|
|
148
|
+
<main>
|
|
149
|
+
{slots.default()}
|
|
150
|
+
</main>
|
|
151
|
+
<footer>Β© 2024</footer>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Specify layout in frontmatter or export:
|
|
158
|
+
|
|
159
|
+
```mdx
|
|
160
|
+
---
|
|
161
|
+
title: My Page
|
|
162
|
+
layout: docs
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
# Content here
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Or in TSX:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
export const layout = 'docs';
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## MDX
|
|
175
|
+
|
|
176
|
+
Write content with MDX:
|
|
177
|
+
|
|
178
|
+
```mdx
|
|
179
|
+
---
|
|
180
|
+
title: Hello World
|
|
181
|
+
date: 2024-01-01
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
# {frontmatter.title}
|
|
185
|
+
|
|
186
|
+
This is **markdown** with SignalX components!
|
|
187
|
+
|
|
188
|
+
<Counter initial={5} />
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Themes
|
|
192
|
+
|
|
193
|
+
Install a theme package:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm install @sigx/ssg-theme-daisyui
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Configure in ssg.config.ts:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
export default defineSSGConfig({
|
|
203
|
+
theme: '@sigx/ssg-theme-daisyui',
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Themes provide:
|
|
208
|
+
- Pre-built layouts (default, docs, blog, etc.)
|
|
209
|
+
- UI components
|
|
210
|
+
- CSS styles
|
|
211
|
+
|
|
212
|
+
## Hydration
|
|
213
|
+
|
|
214
|
+
SSG pages are pre-rendered at build time as static HTML. Interactive components are "hydrated" on the client side to become reactive.
|
|
215
|
+
|
|
216
|
+
### Islands Architecture
|
|
217
|
+
|
|
218
|
+
SignalX SSG supports selective hydration through **islands architecture**. Each interactive component can specify when it should be hydrated using client directives:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { Counter } from './components/Counter';
|
|
222
|
+
|
|
223
|
+
export default component(() => {
|
|
224
|
+
return () => (
|
|
225
|
+
<div>
|
|
226
|
+
{/* Static content - no JS needed */}
|
|
227
|
+
<h1>Welcome to my site</h1>
|
|
228
|
+
|
|
229
|
+
{/* Interactive islands with different hydration strategies */}
|
|
230
|
+
<Counter client:load />
|
|
231
|
+
<LazyWidget client:idle />
|
|
232
|
+
<OffscreenChart client:visible />
|
|
233
|
+
<MobileMenu client:media="(max-width: 768px)" />
|
|
234
|
+
<BrowserOnlyWidget client:only />
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Hydration Strategies
|
|
241
|
+
|
|
242
|
+
| Directive | When it Hydrates | Use Case |
|
|
243
|
+
|-----------|------------------|----------|
|
|
244
|
+
| `client:load` | Immediately on page load | Critical interactive elements |
|
|
245
|
+
| `client:idle` | When browser is idle (`requestIdleCallback`) | Non-critical interactivity |
|
|
246
|
+
| `client:visible` | When scrolled into viewport (`IntersectionObserver`) | Below-the-fold components |
|
|
247
|
+
| `client:media="query"` | When media query matches | Mobile-only components |
|
|
248
|
+
| `client:only` | Not SSR'd, renders only on client | Browser API dependencies |
|
|
249
|
+
|
|
250
|
+
### Example: Interactive Counter
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
// src/components/Counter.tsx
|
|
254
|
+
import { component, signal } from 'sigx';
|
|
255
|
+
|
|
256
|
+
export const Counter = component(() => {
|
|
257
|
+
const count = signal(0);
|
|
258
|
+
|
|
259
|
+
return () => (
|
|
260
|
+
<div class="counter">
|
|
261
|
+
<button onClick={() => count.value--}>-</button>
|
|
262
|
+
<span>{count.value}</span>
|
|
263
|
+
<button onClick={() => count.value++}>+</button>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}, { name: 'Counter' });
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
// src/pages/index.tsx
|
|
271
|
+
import { Counter } from '../components/Counter';
|
|
272
|
+
|
|
273
|
+
export default component(() => {
|
|
274
|
+
return () => (
|
|
275
|
+
<main>
|
|
276
|
+
<h1>Counter Demo</h1>
|
|
277
|
+
<Counter client:load />
|
|
278
|
+
</main>
|
|
279
|
+
);
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### How It Works
|
|
284
|
+
|
|
285
|
+
1. **Build time**: Pages are rendered to static HTML with component markers
|
|
286
|
+
2. **Page load**: Browser receives pre-rendered HTML (fast First Contentful Paint)
|
|
287
|
+
3. **Hydration**: JavaScript attaches event handlers and reactivity to existing DOM
|
|
288
|
+
4. **Interactivity**: Components become fully interactive without re-rendering
|
|
289
|
+
|
|
290
|
+
### Benefits
|
|
291
|
+
|
|
292
|
+
- **Fast initial load** - HTML is ready immediately, no JavaScript blocking
|
|
293
|
+
- **SEO friendly** - Search engines see full content
|
|
294
|
+
- **Progressive enhancement** - Content is visible before JS loads
|
|
295
|
+
- **Reduced JavaScript** - Only hydrate what needs to be interactive
|
|
296
|
+
- **Fine-grained control** - Choose when each component becomes interactive
|
|
297
|
+
|
|
298
|
+
## Configuration
|
|
299
|
+
|
|
300
|
+
Full configuration options:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
defineSSGConfig({
|
|
304
|
+
// Directories
|
|
305
|
+
pages: 'src/pages',
|
|
306
|
+
layouts: 'src/layouts',
|
|
307
|
+
content: 'src/content',
|
|
308
|
+
outDir: 'dist',
|
|
309
|
+
|
|
310
|
+
// Site metadata
|
|
311
|
+
site: {
|
|
312
|
+
title: 'My Site',
|
|
313
|
+
description: 'Site description',
|
|
314
|
+
url: 'https://example.com',
|
|
315
|
+
lang: 'en',
|
|
316
|
+
favicon: '/favicon.ico',
|
|
317
|
+
fonts: ['Inter:wght@400;500;600;700'],
|
|
318
|
+
ogImage: 'https://example.com/og.png',
|
|
319
|
+
twitter: 'myhandle',
|
|
320
|
+
themeColor: '#000000',
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
// Theme
|
|
324
|
+
theme: '@sigx/ssg-theme-daisyui',
|
|
325
|
+
defaultLayout: 'default',
|
|
326
|
+
|
|
327
|
+
// Markdown options
|
|
328
|
+
markdown: {
|
|
329
|
+
shiki: {
|
|
330
|
+
light: 'github-light',
|
|
331
|
+
dark: 'github-dark',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## CLI
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# Start development server
|
|
341
|
+
npx ssg dev
|
|
342
|
+
|
|
343
|
+
# Build static site (generates sitemap.xml and robots.txt)
|
|
344
|
+
npx ssg build
|
|
345
|
+
|
|
346
|
+
# Preview production build
|
|
347
|
+
npx ssg preview
|
|
348
|
+
|
|
349
|
+
# With custom config
|
|
350
|
+
npx ssg build --config=./my-config.ts
|
|
351
|
+
|
|
352
|
+
# With options
|
|
353
|
+
npx ssg dev --port=3000 --open
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## License
|
|
357
|
+
|
|
358
|
+
MIT
|