@inglorious/ssx 1.4.2 → 1.4.3

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.
Files changed (2) hide show
  1. package/README.md +724 -724
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,724 +1,724 @@
1
- # @inglorious/ssx
2
-
3
- [![NPM version](https://img.shields.io/npm/v/@inglorious/ssx.svg)](https://www.npmjs.com/package/@inglorious/ssx)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
-
6
- **Static Site Xecution** - Build blazing-fast static sites with [@inglorious/web](https://www.npmjs.com/package/@inglorious/web), complete with server-side rendering, client-side hydration, and zero-config routing.
7
-
8
- SSX takes your entity-based web apps and generates optimized static HTML with full hydration support. Think Next.js SSG or Astro, but with the simplicity and predictability of Inglorious Web's entity architecture.
9
-
10
- ---
11
-
12
- ## Why SSX?
13
-
14
- ### ⚡️ Fast by Default
15
-
16
- - **Pre-rendered HTML** - Every page is built at compile time
17
- - **Instant load times** - No waiting for server responses
18
- - **CDN-ready** - Deploy anywhere static files are served
19
- - **Perfect Lighthouse scores** - SEO and performance out of the box
20
-
21
- ### 🎯 Simple Architecture
22
-
23
- - **No server required** - Pure static files
24
- - **No complex build configs** - Convention over configuration
25
- - **File-based routing** - Pages are just files in `src/pages/`
26
- - **Entity-based state** - Same familiar patterns from @inglorious/web
27
-
28
- ### 🔥 Modern DX
29
-
30
- - **Hot reload dev server** - See changes instantly
31
- - **Lazy-loaded routes** - Code splitting automatically
32
- - **lit-html hydration** - Interactive UI without the bloat
33
- - **TypeScript Ready** - Write your pages and entities in TypeScript.
34
- - **Image Optimization** - Automatic compression for static assets.
35
- - **Markdown Support** - Built-in support for `.md` pages with code highlighting and math.
36
-
37
- ### 🚀 Production Ready
38
-
39
- - **Automatic code splitting** - Per-page bundles
40
- - **Optimized builds** - Minified, tree-shaken output
41
- - **Source maps** - Debug production like development
42
- - **Error boundaries** - Graceful failure handling
43
-
44
- ---
45
-
46
- ## Quick Start
47
-
48
- ### Installation
49
-
50
- ```bash
51
- npm install @inglorious/ssx @inglorious/web
52
- ```
53
-
54
- ### Create Your First Site
55
-
56
- ```bash
57
- npx @inglorious/create-app my-site --template ssx-js
58
- cd my-site
59
- npm run dev
60
- ```
61
-
62
- Or manually:
63
-
64
- ### Create Your First Site (TypeScript)
65
-
66
- ```typescript
67
- // src/pages/index.ts
68
- import { html } from "@inglorious/web"
69
-
70
- // You can import API for type safety, though it's optional
71
- // import type { API } from "@inglorious/web"
72
-
73
- export const index = {
74
- render(/* entity: any, api: API */) {
75
- return html`
76
- <div>
77
- <h1>Welcome to SSX!</h1>
78
- <p>This page was pre-rendered at build time.</p>
79
- <nav>
80
- <a href="/about">About</a>
81
- </nav>
82
- </div>
83
- `
84
- },
85
- }
86
- ```
87
-
88
- ### Create Your First Site (JavaScript)
89
-
90
- ```javascript
91
- // src/pages/index.js
92
- import { html } from "@inglorious/web"
93
-
94
- export const index = {
95
- render() {
96
- return html`
97
- <div>
98
- <h1>Welcome to SSX!</h1>
99
- <p>This page was pre-rendered at build time.</p>
100
- <nav>
101
- <a href="/about">About</a>
102
- </nav>
103
- </div>
104
- `
105
- },
106
- }
107
-
108
- export const metadata = {
109
- title: "Home",
110
- meta: {
111
- description: "Welcome to our site",
112
- "og:image": "/og-image.png",
113
- },
114
- }
115
- ```
116
-
117
- ### Development
118
-
119
- ```bash
120
- npm run dev
121
- # → Dev server at http://localhost:3000
122
- ```
123
-
124
- ### Build
125
-
126
- ```bash
127
- npm run build
128
- # → Static site in dist/
129
- ```
130
-
131
- ### Deploy
132
-
133
- ```bash
134
- npm run preview
135
- # → Preview production build
136
- ```
137
-
138
- Deploy `dist/` to:
139
-
140
- - **Vercel** - Zero config
141
- - **Netlify** - Drop folder
142
- - **GitHub Pages** - Push and done
143
- - **Cloudflare Pages** - Instant edge
144
- - **Any CDN** - It's just files!
145
-
146
- ---
147
-
148
- ## Features
149
-
150
- ### 🗺️ Sitemap & RSS Generation
151
-
152
- SSX automatically generates `sitemap.xml` and `rss.xml` based on your pages. Configure them in `src/site.config.js`:
153
-
154
- ```javascript
155
- export default {
156
- // Basic metadata
157
- title: "My Awesome Site",
158
- meta: {
159
- description: "A site built with SSX",
160
- "og:type": "website",
161
- "og:site_name": "My Site",
162
- },
163
-
164
- // Sitemap configuration
165
- sitemap: {
166
- hostname: "https://myblog.com",
167
- filter: (page) => !["/admin", "/draft-*", "/test"].includes(page.pattern),
168
- defaults: {
169
- changefreq: "weekly",
170
- priority: 0.5,
171
- },
172
- },
173
-
174
- // RSS configuration
175
- rss: {
176
- title: "My Blog",
177
- description: "Latest posts from my blog",
178
- link: "https://myblog.com",
179
- feedPath: "/feed.xml",
180
- language: "en",
181
- copyright: "© 2026 My Blog",
182
- maxItems: 10,
183
- filter: (page) => page.path.startsWith("/posts/"),
184
- },
185
- }
186
- ```
187
-
188
- Pages with a `published` date in metadata are included in RSS feeds.
189
-
190
- ### 📁 File-Based Routing
191
-
192
- Your file structure defines your routes:
193
-
194
- ```
195
- src/pages/
196
- ├── index.js → /
197
- ├── about.js → /about
198
- ├── blog.js → /blog
199
- └── posts/
200
- └── _slug.js → /posts/:slug
201
- ```
202
-
203
- Dynamic routes use underscore prefix: `_id.js`, `_slug.js`, etc.
204
-
205
- ### ⚛️ Entity-Based State And Behavior
206
-
207
- ```javascript
208
- // src/pages/about.js
209
- import { html } from "@inglorious/web"
210
-
211
- export const about = {
212
- click(entity) {
213
- entity.name += "!"
214
- },
215
-
216
- render(entity, api) {
217
- return html`<h1>
218
- About
219
- <span @click=${() => api.notify(`#${entity.id}:click`)}
220
- >${entity.name}</span
221
- >
222
- </h1>`
223
- },
224
- }
225
- ```
226
-
227
- ```javascript
228
- // src/store/entities.js
229
- export const entities = {
230
- about: {
231
- type: "about",
232
- name: "Us",
233
- },
234
- }
235
- ```
236
-
237
- ### 🔄 Data Loading
238
-
239
- Load data at build time with the `load` export:
240
-
241
- ```javascript
242
- // src/pages/blog.js
243
- import { html } from "@inglorious/web"
244
-
245
- export const blog = {
246
- render(entity) {
247
- return html`
248
- <h1>Blog Posts</h1>
249
- <ul>
250
- ${entity.posts?.map(
251
- (post) => html`
252
- <li>
253
- <a href="/posts/${post.id}">${post.title}</a>
254
- </li>
255
- `,
256
- )}
257
- </ul>
258
- `
259
- },
260
- }
261
-
262
- // SSR: Load data during build
263
- export async function load(entity) {
264
- const response = await fetch("https://api.example.com/posts")
265
- entity.posts = await response.json()
266
- }
267
-
268
- export const title = "Blog"
269
- ```
270
-
271
- The `load` function runs on the server during build. Data is serialized into the HTML and available immediately on the client.
272
-
273
- ### 🎨 Dynamic Routes with `staticPaths`
274
-
275
- Generate multiple pages from data:
276
-
277
- ```javascript
278
- // src/pages/posts/_slug.js
279
- import { html } from "@inglorious/web"
280
-
281
- export const post = {
282
- render(entity) {
283
- return html`
284
- <article>
285
- <h1>${entity.post.title}</h1>
286
- <div>${entity.post.body}</div>
287
- </article>
288
- `
289
- },
290
- }
291
-
292
- // Load data for a specific post
293
- export async function load(entity, page) {
294
- const response = await fetch(
295
- `https://api.example.com/posts/${page.params.slug}`,
296
- )
297
- entity.post = await response.json()
298
- }
299
-
300
- // Tell SSX which pages to generate
301
- export async function staticPaths() {
302
- const response = await fetch(`https://api.example.com/posts`)
303
- const posts = await response.json()
304
-
305
- return posts.map((post) => ({
306
- params: { slug: post.slug },
307
- path: `/posts/${post.slug}`,
308
- }))
309
- }
310
-
311
- export const metadata = (entity) => ({
312
- title: entity.post.title ?? "Post",
313
- meta: {
314
- description: entity.post.excerpt,
315
- },
316
- })
317
- ```
318
-
319
- ### 📄 Page Metadata
320
-
321
- Export metadata for HTML `<head>`. The `metadata` export can be a plain object or a function:
322
-
323
- ```javascript
324
- export const index = {
325
- render() {
326
- return html`<h1>Home</h1>`
327
- },
328
- }
329
-
330
- // Static metadata
331
- export const metadata = {
332
- title: "My Site",
333
- meta: {
334
- description: "An awesome static site",
335
- "og:image": "/og-image.png",
336
- },
337
- }
338
-
339
- // Or dynamic metadata (uses entity data)
340
- export const metadata = (entity) => ({
341
- title: `${entity.user.name}'s Profile`,
342
- meta: {
343
- description: entity.user.bio,
344
- "og:image": entity.user.avatar,
345
- },
346
- })
347
- ```
348
-
349
- ### 🔥 Client-Side Hydration
350
-
351
- Pages hydrate automatically with lit-html. Interactivity works immediately:
352
-
353
- ```javascript
354
- export const counter = {
355
- click(entity) {
356
- entity.count++
357
- },
358
-
359
- render(entity, api) {
360
- return html`
361
- <div>
362
- <p>Count: ${entity.count}</p>
363
- <button @click=${() => api.notify(`#${entity.id}:click`)}>
364
- Increment
365
- </button>
366
- </div>
367
- `
368
- },
369
- }
370
- ```
371
-
372
- The HTML is pre-rendered on the server. When JavaScript loads, lit-html hydrates the existing DOM and wires up event handlers. No flash of unstyled content, no duplicate rendering.
373
-
374
- ### 🧭 Client-Side Navigation
375
-
376
- After hydration, navigation is instant:
377
-
378
- ```javascript
379
- // Links navigate without page reload
380
- ;<a href="/about">About</a> // Client-side routing
381
-
382
- // Programmatic navigation
383
- api.notify("navigate", "/posts")
384
-
385
- // With options
386
- api.notify("navigate", {
387
- to: "/posts/123",
388
- replace: true,
389
- })
390
- ```
391
-
392
- Routes are lazy-loaded on demand, keeping initial bundle size small.
393
-
394
- ### 🖼️ Image Optimization
395
-
396
- SSX includes built-in image optimization using `vite-plugin-image-optimizer`.
397
-
398
- - **Automatic compression** - PNG, JPEG, GIF, SVG, WebP, and AVIF are compressed at build time.
399
- - **Lossless & Lossy** - Configurable settings via `vite` config in `site.config.js`.
400
-
401
- ### 📝 Markdown Support
402
-
403
- SSX treats `.md` files as first-class pages. You can create `src/pages/post.md` and it will be rendered automatically.
404
-
405
- - **Frontmatter** - Metadata is exported as `metadata`.
406
- - **Code Highlighting** - Built-in syntax highlighting with `highlight.js`.
407
- - **Math Support** - LaTeX support via `katex` (use `$E=mc^2$` or `$$...$$`).
408
- - **Mermaid Diagrams** - Use `mermaid` code blocks (requires client-side mermaid.js).
409
-
410
- Configure the syntax highlighting theme in `site.config.js`:
411
-
412
- ```javascript
413
- export default {
414
- markdown: {
415
- theme: "monokai", // default: "github-dark"
416
- },
417
- }
418
- ```
419
-
420
- ```markdown
421
- ---
422
- title: My Post
423
- ---
424
-
425
- # Hello World
426
-
427
- This is a markdown page.
428
- ```
429
-
430
- ---
431
-
432
- ## CLI
433
-
434
- SSX provides a simple CLI for building and developing:
435
-
436
- ### `ssx build`
437
-
438
- Builds your static site:
439
-
440
- ```bash
441
- pnpm ssx build [options]
442
-
443
- Options:
444
- -c, --config <file> Config file (default: "site.config.js")
445
- -r, --root <dir> Source root directory (default: "src")
446
- -o, --out <dir> Output directory (default: "dist")
447
- -i, --incremental Enable incremental builds (default: true)
448
- -f, --force Force clean build, ignore cache
449
- ```
450
-
451
- ### `preview`
452
-
453
- Serves the built static site on port 3000 through the `serve` NPM package.
454
-
455
- ```bash
456
- pnpm preview
457
- ```
458
-
459
- ### `ssx dev`
460
-
461
- Starts the Vite development server on port 3000 with hot reload:
462
-
463
- ```bash
464
- pnpm ssx dev [options]
465
-
466
- Options:
467
- -c, --config <file> Config file (default: "site.config.js")
468
- -r, --root <dir> Source root directory (default: "src")
469
- -p, --port <port> Dev server port (default: 3000)
470
- ```
471
-
472
- ---
473
-
474
- ## Project Structure
475
-
476
- ```
477
- my-site/
478
- ├── src/
479
- │ ├── pages/ # File-based routes
480
- │ │ ├── index.js # Home page
481
- │ │ ├── about.js # About page
482
- │ │ └── posts/
483
- │ │ ├── index.js # /posts
484
- │ │ └── _id.js # /posts/:id
485
- │ ├── store/ # Store configuration
486
- │ │ └── entities.js # Entity definitions
487
- │ └── types/ # Custom entity types (optional)
488
- ├── dist/ # Build output
489
- ├── package.json
490
- └── site.config.js # Site configuration
491
- ```
492
-
493
- ---
494
-
495
- ## Comparison to Other Tools
496
-
497
- | Feature | SSX | Next.js (SSG) | Astro | Eleventy |
498
- | ------------------ | ----------- | ------------- | ------ | -------- |
499
- | Pre-rendered HTML | ✅ | ✅ | ✅ | ✅ |
500
- | Client hydration | ✅ lit-html | ✅ React | ✅ Any | ❌ |
501
- | Client routing | ✅ | ✅ | ✅ | ❌ |
502
- | Lazy loading | ✅ | ✅ | ✅ | ❌ |
503
- | Entity-based state | ✅ | ❌ | ❌ | ❌ |
504
- | Zero config | ✅ | ❌ | ❌ | ❌ |
505
- | Framework agnostic | ❌ | ❌ | ✅ | ✅ |
506
-
507
- SSX is perfect if you:
508
-
509
- - Want static site performance
510
- - Love entity-based architecture
511
- - Prefer convention over configuration
512
- - Need full client-side interactivity
513
- - Don't want React/Vue lock-in
514
-
515
- ---
516
-
517
- ## Advanced Usage
518
-
519
- ### Site Configuration
520
-
521
- Customize SSX behavior in `src/site.config.js`:
522
-
523
- ```javascript
524
- export default {
525
- // Basic metadata
526
- lang: "en",
527
- charset: "UTF-8",
528
- title: "My Awesome Site",
529
- meta: {
530
- description: "A site built with SSX",
531
- "og:type": "website",
532
- },
533
-
534
- // Global assets
535
- styles: ["./styles/reset.css", "./styles/theme.css"],
536
- scripts: ["./scripts/analytics.js"],
537
-
538
- // Build options
539
- basePath: "/",
540
- rootDir: "src",
541
- outDir: "dist",
542
- publicDir: "public",
543
- favicon: "/favicon.ico",
544
-
545
- // Router config
546
- router: {
547
- trailingSlash: false,
548
- scrollBehavior: "smooth",
549
- },
550
-
551
- // Vite config passthrough
552
- vite: {
553
- server: {
554
- port: 3000,
555
- open: true,
556
- },
557
- },
558
-
559
- // Build hooks
560
- hooks: {
561
- beforeBuild: async (config) => console.log("Starting build..."),
562
- afterBuild: async (result) => console.log(`Built ${result.pages} pages`),
563
- },
564
- }
565
- ```
566
-
567
- ### Environment Variables
568
-
569
- Use Vite's environment variables:
570
-
571
- ```javascript
572
- // Access in your code
573
- const apiUrl = import.meta.env.VITE_API_URL
574
-
575
- // .env file
576
- VITE_API_URL=https://api.example.com
577
- ```
578
-
579
- ### Custom 404 Page
580
-
581
- Create a fallback route:
582
-
583
- ```javascript
584
- // src/pages/404.js
585
- export const notFound = {
586
- render() {
587
- return html`
588
- <div>
589
- <h1>404 - Page Not Found</h1>
590
- <a href="/">Go Home</a>
591
- </div>
592
- `
593
- },
594
- }
595
-
596
- export const metadata = {
597
- title: "404",
598
- }
599
- ```
600
-
601
- Register it in your router:
602
-
603
- ```javascript
604
- // src/store/entities.js
605
- import { setRoutes } from "@inglorious/web/router"
606
-
607
- setRoutes({
608
- // ... other routes
609
- "*": "notFound", // Fallback
610
- })
611
- ```
612
-
613
- ### Incremental Builds
614
-
615
- SSX enables incremental builds by default. Only changed pages are rebuilt, dramatically speeding up your build process:
616
-
617
- ```bash
618
- ssx build
619
- # Only changed pages are rebuilt
620
-
621
- ssx build --force
622
- # Force a clean rebuild of all pages
623
- ```
624
-
625
- Incremental builds respect your page dependencies and invalidate cache when dependencies change.
626
-
627
- ---
628
-
629
- ## API Reference
630
-
631
- ### Build API
632
-
633
- ```javascript
634
- import { build } from "@inglorious/ssx/build"
635
-
636
- await build({
637
- rootDir: "src",
638
- outDir: "dist",
639
- configFile: "site.config.js",
640
- incremental: true,
641
- clean: false,
642
- })
643
- ```
644
-
645
- ### Dev Server API
646
-
647
- ```javascript
648
- import { dev } from "@inglorious/ssx/dev"
649
-
650
- await dev({
651
- rootDir: "src",
652
- port: 3000,
653
- configFile: "site.config.js",
654
- })
655
- ```
656
-
657
- ---
658
-
659
- <!-- ## Examples
660
-
661
- Check out these example projects:
662
-
663
- - **[Basic Blog](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-blog)** - Simple blog with posts
664
- - **[Documentation Site](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-docs)** - Multi-page docs
665
- - **[E-commerce](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-shop)** - Product catalog
666
- - **[Portfolio](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-portfolio)** - Personal portfolio
667
-
668
- --- -->
669
-
670
- ## Roadmap
671
-
672
- - [x] TypeScript support
673
- - [x] Image optimization
674
- - [ ] API routes (serverless functions)
675
- - [x] Markdown support
676
- - [ ] i18n helpers
677
-
678
- ---
679
-
680
- ## Philosophy
681
-
682
- SSX embraces the philosophy of [@inglorious/web](https://www.npmjs.com/package/@inglorious/web):
683
-
684
- - **Simplicity over cleverness** - Obvious beats clever
685
- - **Convention over configuration** - Sensible defaults
686
- - **Predictability over magic** - Explicit is better than implicit
687
- - **Standards over abstractions** - Use the platform
688
-
689
- Static site generation should be simple. SSX makes it simple.
690
-
691
- ---
692
-
693
- ## Contributing
694
-
695
- Contributions are welcome! Please read our [Contributing Guidelines](../../CONTRIBUTING.md) first.
696
-
697
- ---
698
-
699
- ## License
700
-
701
- **MIT License** - Free and open source
702
-
703
- Created by [Matteo Antony Mistretta](https://github.com/IngloriousCoderz)
704
-
705
- ---
706
-
707
- ## Related Packages
708
-
709
- - [@inglorious/web](https://www.npmjs.com/package/@inglorious/web) - Entity-based web framework
710
- - [@inglorious/store](https://www.npmjs.com/package/@inglorious/store) - State management
711
- - [@inglorious/engine](https://www.npmjs.com/package/@inglorious/engine) - Game engine
712
-
713
- ---
714
-
715
- ## Support
716
-
717
- - 📖 [Documentation](https://inglorious-engine.vercel.app)
718
- - 💬 [Discord Community](https://discord.gg/Byx85t2eFp)
719
- - 🐛 [Issue Tracker](https://github.com/IngloriousCoderz/inglorious-forge/issues)
720
- - 📧 [Email Support](mailto:antony.mistretta@gmail.com)
721
-
722
- ---
723
-
724
- **Build static sites the Inglorious way. Simple. Predictable. Fast.** 🚀
1
+ # @inglorious/ssx
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@inglorious/ssx.svg)](https://www.npmjs.com/package/@inglorious/ssx)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ **Static Site Xecution** - Build blazing-fast static sites with [@inglorious/web](https://www.npmjs.com/package/@inglorious/web), complete with server-side rendering, client-side hydration, and zero-config routing.
7
+
8
+ SSX takes your entity-based web apps and generates optimized static HTML with full hydration support. Think Next.js SSG or Astro, but with the simplicity and predictability of Inglorious Web's entity architecture.
9
+
10
+ ---
11
+
12
+ ## Why SSX?
13
+
14
+ ### ⚡️ Fast by Default
15
+
16
+ - **Pre-rendered HTML** - Every page is built at compile time
17
+ - **Instant load times** - No waiting for server responses
18
+ - **CDN-ready** - Deploy anywhere static files are served
19
+ - **Perfect Lighthouse scores** - SEO and performance out of the box
20
+
21
+ ### 🎯 Simple Architecture
22
+
23
+ - **No server required** - Pure static files
24
+ - **No complex build configs** - Convention over configuration
25
+ - **File-based routing** - Pages are just files in `src/pages/`
26
+ - **Entity-based state** - Same familiar patterns from @inglorious/web
27
+
28
+ ### 🔥 Modern DX
29
+
30
+ - **Hot reload dev server** - See changes instantly
31
+ - **Lazy-loaded routes** - Code splitting automatically
32
+ - **lit-html hydration** - Interactive UI without the bloat
33
+ - **TypeScript Ready** - Write your pages and entities in TypeScript.
34
+ - **Image Optimization** - Automatic compression for static assets.
35
+ - **Markdown Support** - Built-in support for `.md` pages with code highlighting and math.
36
+
37
+ ### 🚀 Production Ready
38
+
39
+ - **Automatic code splitting** - Per-page bundles
40
+ - **Optimized builds** - Minified, tree-shaken output
41
+ - **Source maps** - Debug production like development
42
+ - **Error boundaries** - Graceful failure handling
43
+
44
+ ---
45
+
46
+ ## Quick Start
47
+
48
+ ### Installation
49
+
50
+ ```bash
51
+ npm install @inglorious/ssx @inglorious/web
52
+ ```
53
+
54
+ ### Create Your First Site
55
+
56
+ ```bash
57
+ npx @inglorious/create-app my-site --template ssx-js
58
+ cd my-site
59
+ npm run dev
60
+ ```
61
+
62
+ Or manually:
63
+
64
+ ### Create Your First Site (TypeScript)
65
+
66
+ ```typescript
67
+ // src/pages/index.ts
68
+ import { html } from "@inglorious/web"
69
+
70
+ // You can import API for type safety, though it's optional
71
+ // import type { API } from "@inglorious/web"
72
+
73
+ export const index = {
74
+ render(/* entity: any, api: API */) {
75
+ return html`
76
+ <div>
77
+ <h1>Welcome to SSX!</h1>
78
+ <p>This page was pre-rendered at build time.</p>
79
+ <nav>
80
+ <a href="/about">About</a>
81
+ </nav>
82
+ </div>
83
+ `
84
+ },
85
+ }
86
+ ```
87
+
88
+ ### Create Your First Site (JavaScript)
89
+
90
+ ```javascript
91
+ // src/pages/index.js
92
+ import { html } from "@inglorious/web"
93
+
94
+ export const index = {
95
+ render() {
96
+ return html`
97
+ <div>
98
+ <h1>Welcome to SSX!</h1>
99
+ <p>This page was pre-rendered at build time.</p>
100
+ <nav>
101
+ <a href="/about">About</a>
102
+ </nav>
103
+ </div>
104
+ `
105
+ },
106
+ }
107
+
108
+ export const metadata = {
109
+ title: "Home",
110
+ meta: {
111
+ description: "Welcome to our site",
112
+ "og:image": "/og-image.png",
113
+ },
114
+ }
115
+ ```
116
+
117
+ ### Development
118
+
119
+ ```bash
120
+ npm run dev
121
+ # → Dev server at http://localhost:3000
122
+ ```
123
+
124
+ ### Build
125
+
126
+ ```bash
127
+ npm run build
128
+ # → Static site in dist/
129
+ ```
130
+
131
+ ### Deploy
132
+
133
+ ```bash
134
+ npm run preview
135
+ # → Preview production build
136
+ ```
137
+
138
+ Deploy `dist/` to:
139
+
140
+ - **Vercel** - Zero config
141
+ - **Netlify** - Drop folder
142
+ - **GitHub Pages** - Push and done
143
+ - **Cloudflare Pages** - Instant edge
144
+ - **Any CDN** - It's just files!
145
+
146
+ ---
147
+
148
+ ## Features
149
+
150
+ ### 🗺️ Sitemap & RSS Generation
151
+
152
+ SSX automatically generates `sitemap.xml` and `rss.xml` based on your pages. Configure them in `src/site.config.js`:
153
+
154
+ ```javascript
155
+ export default {
156
+ // Basic metadata
157
+ title: "My Awesome Site",
158
+ meta: {
159
+ description: "A site built with SSX",
160
+ "og:type": "website",
161
+ "og:site_name": "My Site",
162
+ },
163
+
164
+ // Sitemap configuration
165
+ sitemap: {
166
+ hostname: "https://myblog.com",
167
+ filter: (page) => !["/admin", "/draft-*", "/test"].includes(page.pattern),
168
+ defaults: {
169
+ changefreq: "weekly",
170
+ priority: 0.5,
171
+ },
172
+ },
173
+
174
+ // RSS configuration
175
+ rss: {
176
+ title: "My Blog",
177
+ description: "Latest posts from my blog",
178
+ link: "https://myblog.com",
179
+ feedPath: "/feed.xml",
180
+ language: "en",
181
+ copyright: "© 2026 My Blog",
182
+ maxItems: 10,
183
+ filter: (page) => page.path.startsWith("/posts/"),
184
+ },
185
+ }
186
+ ```
187
+
188
+ Pages with a `published` date in metadata are included in RSS feeds.
189
+
190
+ ### 📁 File-Based Routing
191
+
192
+ Your file structure defines your routes:
193
+
194
+ ```
195
+ src/pages/
196
+ ├── index.js → /
197
+ ├── about.js → /about
198
+ ├── blog.js → /blog
199
+ └── posts/
200
+ └── _slug.js → /posts/:slug
201
+ ```
202
+
203
+ Dynamic routes use underscore prefix: `_id.js`, `_slug.js`, etc.
204
+
205
+ ### ⚛️ Entity-Based State And Behavior
206
+
207
+ ```javascript
208
+ // src/pages/about.js
209
+ import { html } from "@inglorious/web"
210
+
211
+ export const about = {
212
+ click(entity) {
213
+ entity.name += "!"
214
+ },
215
+
216
+ render(entity, api) {
217
+ return html`<h1>
218
+ About
219
+ <span @click=${() => api.notify(`#${entity.id}:click`)}
220
+ >${entity.name}</span
221
+ >
222
+ </h1>`
223
+ },
224
+ }
225
+ ```
226
+
227
+ ```javascript
228
+ // src/store/entities.js
229
+ export const entities = {
230
+ about: {
231
+ type: "about",
232
+ name: "Us",
233
+ },
234
+ }
235
+ ```
236
+
237
+ ### 🔄 Data Loading
238
+
239
+ Load data at build time with the `load` export:
240
+
241
+ ```javascript
242
+ // src/pages/blog.js
243
+ import { html } from "@inglorious/web"
244
+
245
+ export const blog = {
246
+ render(entity) {
247
+ return html`
248
+ <h1>Blog Posts</h1>
249
+ <ul>
250
+ ${entity.posts?.map(
251
+ (post) => html`
252
+ <li>
253
+ <a href="/posts/${post.id}">${post.title}</a>
254
+ </li>
255
+ `,
256
+ )}
257
+ </ul>
258
+ `
259
+ },
260
+ }
261
+
262
+ // SSR: Load data during build
263
+ export async function load(entity) {
264
+ const response = await fetch("https://api.example.com/posts")
265
+ entity.posts = await response.json()
266
+ }
267
+
268
+ export const title = "Blog"
269
+ ```
270
+
271
+ The `load` function runs on the server during build. Data is serialized into the HTML and available immediately on the client.
272
+
273
+ ### 🎨 Dynamic Routes with `staticPaths`
274
+
275
+ Generate multiple pages from data:
276
+
277
+ ```javascript
278
+ // src/pages/posts/_slug.js
279
+ import { html } from "@inglorious/web"
280
+
281
+ export const post = {
282
+ render(entity) {
283
+ return html`
284
+ <article>
285
+ <h1>${entity.post.title}</h1>
286
+ <div>${entity.post.body}</div>
287
+ </article>
288
+ `
289
+ },
290
+ }
291
+
292
+ // Load data for a specific post
293
+ export async function load(entity, page) {
294
+ const response = await fetch(
295
+ `https://api.example.com/posts/${page.params.slug}`,
296
+ )
297
+ entity.post = await response.json()
298
+ }
299
+
300
+ // Tell SSX which pages to generate
301
+ export async function staticPaths() {
302
+ const response = await fetch(`https://api.example.com/posts`)
303
+ const posts = await response.json()
304
+
305
+ return posts.map((post) => ({
306
+ params: { slug: post.slug },
307
+ path: `/posts/${post.slug}`,
308
+ }))
309
+ }
310
+
311
+ export const metadata = (entity) => ({
312
+ title: entity.post.title ?? "Post",
313
+ meta: {
314
+ description: entity.post.excerpt,
315
+ },
316
+ })
317
+ ```
318
+
319
+ ### 📄 Page Metadata
320
+
321
+ Export metadata for HTML `<head>`. The `metadata` export can be a plain object or a function:
322
+
323
+ ```javascript
324
+ export const index = {
325
+ render() {
326
+ return html`<h1>Home</h1>`
327
+ },
328
+ }
329
+
330
+ // Static metadata
331
+ export const metadata = {
332
+ title: "My Site",
333
+ meta: {
334
+ description: "An awesome static site",
335
+ "og:image": "/og-image.png",
336
+ },
337
+ }
338
+
339
+ // Or dynamic metadata (uses entity data)
340
+ export const metadata = (entity) => ({
341
+ title: `${entity.user.name}'s Profile`,
342
+ meta: {
343
+ description: entity.user.bio,
344
+ "og:image": entity.user.avatar,
345
+ },
346
+ })
347
+ ```
348
+
349
+ ### 🔥 Client-Side Hydration
350
+
351
+ Pages hydrate automatically with lit-html. Interactivity works immediately:
352
+
353
+ ```javascript
354
+ export const counter = {
355
+ click(entity) {
356
+ entity.count++
357
+ },
358
+
359
+ render(entity, api) {
360
+ return html`
361
+ <div>
362
+ <p>Count: ${entity.count}</p>
363
+ <button @click=${() => api.notify(`#${entity.id}:click`)}>
364
+ Increment
365
+ </button>
366
+ </div>
367
+ `
368
+ },
369
+ }
370
+ ```
371
+
372
+ The HTML is pre-rendered on the server. When JavaScript loads, lit-html hydrates the existing DOM and wires up event handlers. No flash of unstyled content, no duplicate rendering.
373
+
374
+ ### 🧭 Client-Side Navigation
375
+
376
+ After hydration, navigation is instant:
377
+
378
+ ```javascript
379
+ // Links navigate without page reload
380
+ ;<a href="/about">About</a> // Client-side routing
381
+
382
+ // Programmatic navigation
383
+ api.notify("navigate", "/posts")
384
+
385
+ // With options
386
+ api.notify("navigate", {
387
+ to: "/posts/123",
388
+ replace: true,
389
+ })
390
+ ```
391
+
392
+ Routes are lazy-loaded on demand, keeping initial bundle size small.
393
+
394
+ ### 🖼️ Image Optimization
395
+
396
+ SSX includes built-in image optimization using `vite-plugin-image-optimizer`.
397
+
398
+ - **Automatic compression** - PNG, JPEG, GIF, SVG, WebP, and AVIF are compressed at build time.
399
+ - **Lossless & Lossy** - Configurable settings via `vite` config in `site.config.js`.
400
+
401
+ ### 📝 Markdown Support
402
+
403
+ SSX treats `.md` files as first-class pages. You can create `src/pages/post.md` and it will be rendered automatically.
404
+
405
+ - **Frontmatter** - Metadata is exported as `metadata`.
406
+ - **Code Highlighting** - Built-in syntax highlighting with `highlight.js`.
407
+ - **Math Support** - LaTeX support via `katex` (use `$E=mc^2$` or `$$...$$`).
408
+ - **Mermaid Diagrams** - Use `mermaid` code blocks (requires client-side mermaid.js).
409
+
410
+ Configure the syntax highlighting theme in `site.config.js`:
411
+
412
+ ```javascript
413
+ export default {
414
+ markdown: {
415
+ theme: "monokai", // default: "github-dark"
416
+ },
417
+ }
418
+ ```
419
+
420
+ ```markdown
421
+ ---
422
+ title: My Post
423
+ ---
424
+
425
+ # Hello World
426
+
427
+ This is a markdown page.
428
+ ```
429
+
430
+ ---
431
+
432
+ ## CLI
433
+
434
+ SSX provides a simple CLI for building and developing:
435
+
436
+ ### `ssx build`
437
+
438
+ Builds your static site:
439
+
440
+ ```bash
441
+ pnpm ssx build [options]
442
+
443
+ Options:
444
+ -c, --config <file> Config file (default: "site.config.js")
445
+ -r, --root <dir> Source root directory (default: "src")
446
+ -o, --out <dir> Output directory (default: "dist")
447
+ -i, --incremental Enable incremental builds (default: true)
448
+ -f, --force Force clean build, ignore cache
449
+ ```
450
+
451
+ ### `preview`
452
+
453
+ Serves the built static site on port 3000 through the `serve` NPM package.
454
+
455
+ ```bash
456
+ pnpm preview
457
+ ```
458
+
459
+ ### `ssx dev`
460
+
461
+ Starts the Vite development server on port 3000 with hot reload:
462
+
463
+ ```bash
464
+ pnpm ssx dev [options]
465
+
466
+ Options:
467
+ -c, --config <file> Config file (default: "site.config.js")
468
+ -r, --root <dir> Source root directory (default: "src")
469
+ -p, --port <port> Dev server port (default: 3000)
470
+ ```
471
+
472
+ ---
473
+
474
+ ## Project Structure
475
+
476
+ ```
477
+ my-site/
478
+ ├── src/
479
+ │ ├── pages/ # File-based routes
480
+ │ │ ├── index.js # Home page
481
+ │ │ ├── about.js # About page
482
+ │ │ └── posts/
483
+ │ │ ├── index.js # /posts
484
+ │ │ └── _id.js # /posts/:id
485
+ │ ├── store/ # Store configuration
486
+ │ │ └── entities.js # Entity definitions
487
+ │ └── types/ # Custom entity types (optional)
488
+ ├── dist/ # Build output
489
+ ├── package.json
490
+ └── site.config.js # Site configuration
491
+ ```
492
+
493
+ ---
494
+
495
+ ## Comparison to Other Tools
496
+
497
+ | Feature | SSX | Next.js (SSG) | Astro | Eleventy |
498
+ | ------------------ | ----------- | ------------- | ------ | -------- |
499
+ | Pre-rendered HTML | ✅ | ✅ | ✅ | ✅ |
500
+ | Client hydration | ✅ lit-html | ✅ React | ✅ Any | ❌ |
501
+ | Client routing | ✅ | ✅ | ✅ | ❌ |
502
+ | Lazy loading | ✅ | ✅ | ✅ | ❌ |
503
+ | Entity-based state | ✅ | ❌ | ❌ | ❌ |
504
+ | Zero config | ✅ | ❌ | ❌ | ❌ |
505
+ | Framework agnostic | ❌ | ❌ | ✅ | ✅ |
506
+
507
+ SSX is perfect if you:
508
+
509
+ - Want static site performance
510
+ - Love entity-based architecture
511
+ - Prefer convention over configuration
512
+ - Need full client-side interactivity
513
+ - Don't want React/Vue lock-in
514
+
515
+ ---
516
+
517
+ ## Advanced Usage
518
+
519
+ ### Site Configuration
520
+
521
+ Customize SSX behavior in `src/site.config.js`:
522
+
523
+ ```javascript
524
+ export default {
525
+ // Basic metadata
526
+ lang: "en",
527
+ charset: "UTF-8",
528
+ title: "My Awesome Site",
529
+ meta: {
530
+ description: "A site built with SSX",
531
+ "og:type": "website",
532
+ },
533
+
534
+ // Global assets
535
+ styles: ["./styles/reset.css", "./styles/theme.css"],
536
+ scripts: ["./scripts/analytics.js"],
537
+
538
+ // Build options
539
+ basePath: "/",
540
+ rootDir: "src",
541
+ outDir: "dist",
542
+ publicDir: "public",
543
+ favicon: "/favicon.ico",
544
+
545
+ // Router config
546
+ router: {
547
+ trailingSlash: false,
548
+ scrollBehavior: "smooth",
549
+ },
550
+
551
+ // Vite config passthrough
552
+ vite: {
553
+ server: {
554
+ port: 3000,
555
+ open: true,
556
+ },
557
+ },
558
+
559
+ // Build hooks
560
+ hooks: {
561
+ beforeBuild: async (config) => console.log("Starting build..."),
562
+ afterBuild: async (result) => console.log(`Built ${result.pages} pages`),
563
+ },
564
+ }
565
+ ```
566
+
567
+ ### Environment Variables
568
+
569
+ Use Vite's environment variables:
570
+
571
+ ```javascript
572
+ // Access in your code
573
+ const apiUrl = import.meta.env.VITE_API_URL
574
+
575
+ // .env file
576
+ VITE_API_URL=https://api.example.com
577
+ ```
578
+
579
+ ### Custom 404 Page
580
+
581
+ Create a fallback route:
582
+
583
+ ```javascript
584
+ // src/pages/404.js
585
+ export const notFound = {
586
+ render() {
587
+ return html`
588
+ <div>
589
+ <h1>404 - Page Not Found</h1>
590
+ <a href="/">Go Home</a>
591
+ </div>
592
+ `
593
+ },
594
+ }
595
+
596
+ export const metadata = {
597
+ title: "404",
598
+ }
599
+ ```
600
+
601
+ Register it in your router:
602
+
603
+ ```javascript
604
+ // src/store/entities.js
605
+ import { setRoutes } from "@inglorious/web/router"
606
+
607
+ setRoutes({
608
+ // ... other routes
609
+ "*": "notFound", // Fallback
610
+ })
611
+ ```
612
+
613
+ ### Incremental Builds
614
+
615
+ SSX enables incremental builds by default. Only changed pages are rebuilt, dramatically speeding up your build process:
616
+
617
+ ```bash
618
+ ssx build
619
+ # Only changed pages are rebuilt
620
+
621
+ ssx build --force
622
+ # Force a clean rebuild of all pages
623
+ ```
624
+
625
+ Incremental builds respect your page dependencies and invalidate cache when dependencies change.
626
+
627
+ ---
628
+
629
+ ## API Reference
630
+
631
+ ### Build API
632
+
633
+ ```javascript
634
+ import { build } from "@inglorious/ssx/build"
635
+
636
+ await build({
637
+ rootDir: "src",
638
+ outDir: "dist",
639
+ configFile: "site.config.js",
640
+ incremental: true,
641
+ clean: false,
642
+ })
643
+ ```
644
+
645
+ ### Dev Server API
646
+
647
+ ```javascript
648
+ import { dev } from "@inglorious/ssx/dev"
649
+
650
+ await dev({
651
+ rootDir: "src",
652
+ port: 3000,
653
+ configFile: "site.config.js",
654
+ })
655
+ ```
656
+
657
+ ---
658
+
659
+ <!-- ## Examples
660
+
661
+ Check out these example projects:
662
+
663
+ - **[Basic Blog](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-blog)** - Simple blog with posts
664
+ - **[Documentation Site](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-docs)** - Multi-page docs
665
+ - **[E-commerce](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-shop)** - Product catalog
666
+ - **[Portfolio](https://github.com/IngloriousCoderz/inglorious-forge/tree/main/examples/ssx-portfolio)** - Personal portfolio
667
+
668
+ --- -->
669
+
670
+ ## Roadmap
671
+
672
+ - [x] TypeScript support
673
+ - [x] Image optimization
674
+ - [ ] API routes (serverless functions)
675
+ - [x] Markdown support
676
+ - [ ] i18n helpers
677
+
678
+ ---
679
+
680
+ ## Philosophy
681
+
682
+ SSX embraces the philosophy of [@inglorious/web](https://www.npmjs.com/package/@inglorious/web):
683
+
684
+ - **Simplicity over cleverness** - Obvious beats clever
685
+ - **Convention over configuration** - Sensible defaults
686
+ - **Predictability over magic** - Explicit is better than implicit
687
+ - **Standards over abstractions** - Use the platform
688
+
689
+ Static site generation should be simple. SSX makes it simple.
690
+
691
+ ---
692
+
693
+ ## Contributing
694
+
695
+ Contributions are welcome! Please read our [Contributing Guidelines](../../CONTRIBUTING.md) first.
696
+
697
+ ---
698
+
699
+ ## License
700
+
701
+ **MIT License** - Free and open source
702
+
703
+ Created by [Matteo Antony Mistretta](https://github.com/IngloriousCoderz)
704
+
705
+ ---
706
+
707
+ ## Related Packages
708
+
709
+ - [@inglorious/web](https://www.npmjs.com/package/@inglorious/web) - Entity-based web framework
710
+ - [@inglorious/store](https://www.npmjs.com/package/@inglorious/store) - State management
711
+ - [@inglorious/engine](https://www.npmjs.com/package/@inglorious/engine) - Game engine
712
+
713
+ ---
714
+
715
+ ## Support
716
+
717
+ - 📖 [Documentation](https://inglorious-engine.vercel.app)
718
+ - 💬 [Discord Community](https://discord.gg/Byx85t2eFp)
719
+ - 🐛 [Issue Tracker](https://github.com/IngloriousCoderz/inglorious-forge/issues)
720
+ - 📧 [Email Support](mailto:antony.mistretta@gmail.com)
721
+
722
+ ---
723
+
724
+ **Build static sites the Inglorious way. Simple. Predictable. Fast.** 🚀