Server-Side-X. Xecution? Xperience? Who knows.
npm install @inglorious/ssx

Static Site Xecution - Build blazing-fast static sites with @inglorious/web, complete with server-side rendering, client-side hydration, and zero-config routing.
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.
---
- Pre-rendered HTML - Every page is built at compile time
- Instant load times - No waiting for server responses
- CDN-ready - Deploy anywhere static files are served
- Perfect Lighthouse scores - SEO and performance out of the box
- No server required - Pure static files
- No complex build configs - Convention over configuration
- File-based routing - Pages are just files in src/pages/
- Entity-based state - Same familiar patterns from @inglorious/web
- Hot reload dev server - See changes instantly
- Lazy-loaded routes - Code splitting automatically
- lit-html hydration - Interactive UI without the bloat
- TypeScript ready - Write your pages and entities in TypeScript
- Image optimization - Automatic compression for static assets
- Markdown support - Built-in support for .md pages with code highlighting and math
- Automatic code splitting - Per-page bundles
- Optimized builds - Minified, tree-shaken output
- Source maps - Debug production like development
- Error boundaries - Graceful failure handling
---
``bash`
npm install @inglorious/ssx @inglorious/web
`bash`
npx @inglorious/create-app my-site --template ssx-js
cd my-site
npm run dev
Or manually:
`typescript
// src/pages/index.ts
import { html } from "@inglorious/web"
// You can import API for type safety, though it's optional
// import type { API } from "@inglorious/web"
export const index = {
render(/ entity: any, api: API /) {
return html
This page was pre-rendered at build time.
},
}
`$3
`javascript
// src/pages/index.js
import { html } from "@inglorious/web"export const index = {
render() {
return html
This page was pre-rendered at build time.
},
}export const metadata = {
title: "Home",
meta: {
description: "Welcome to our site",
"og:image": "/og-image.png",
},
}
`$3
`bash
npm run dev
β Dev server at http://localhost:3000
`$3
`bash
npm run build
β Static site in dist/
`$3
`bash
npm run preview
β Preview production build
`Deploy
dist/ to:- Vercel - Zero config
- Netlify - Drop folder
- GitHub Pages - Push and done
- Cloudflare Pages - Instant edge
- Any CDN - It's just files!
---
Features
$3
SSX automatically generates
sitemap.xml and rss.xml based on your pages. Configure them in src/site.config.js:`javascript
export default {
// Basic metadata
title: "My Awesome Site",
meta: {
description: "A site built with SSX",
"og:type": "website",
"og:site_name": "My Site",
}, // Sitemap configuration
sitemap: {
hostname: "https://myblog.com",
filter: (page) => !["/admin", "/draft-*", "/test"].includes(page.pattern),
defaults: {
changefreq: "weekly",
priority: 0.5,
},
},
// RSS configuration
rss: {
title: "My Blog",
description: "Latest posts from my blog",
link: "https://myblog.com",
feedPath: "/feed.xml",
language: "en",
copyright: "Β© 2026 My Blog",
maxItems: 10,
filter: (page) => page.path.startsWith("/posts/"),
},
}
`Pages with a
published date in metadata are included in RSS feeds.$3
Your file structure defines your routes:
`
src/pages/
βββ index.js β /
βββ about.js β /about
βββ blog.js β /blog
βββ posts/
βββ _slug.js β /posts/:slug
`Dynamic routes use underscore prefix:
_id.js, _slug.js, etc.$3
`javascript
// src/pages/about.js
import { html } from "@inglorious/web"export const about = {
click(entity) {
entity.name += "!"
},
render(entity, api) {
return html
#${entity.id}:click)}
},
}
``javascript
// src/store/entities.js
export const entities = {
about: {
type: "about",
name: "Us",
},
}
`$3
Load data at build time with the
load export:`javascript
// src/pages/blog.js
import { html } from "@inglorious/web"export const blog = {
render(entity) {
return html
${post.title}
,
},
}// SSR: Load data during build
export async function load(entity) {
const response = await fetch("https://api.example.com/posts")
entity.posts = await response.json()
}
export const metadata = {
title: "Blog",
}
`The
load function runs on the server during build. Data is serialized into the HTML and available immediately on the client.$3
Generate multiple pages from data:
`javascript
// src/pages/posts/_slug.js
import { html } from "@inglorious/web"export const post = {
render(entity) {
return html
},
}// Load data for a specific post
export async function load(entity, page) {
const response = await fetch(
https://api.example.com/posts/${page.params.slug},
)
entity.post = await response.json()
}// Tell SSX which pages to generate
export async function staticPaths() {
const response = await fetch(
https://api.example.com/posts)
const posts = await response.json() return posts.map((post) => ({
params: { slug: post.slug },
path:
/posts/${post.slug},
}))
}export const metadata = (entity) => ({
title: entity.post?.title ?? "Post",
meta: {
description: entity.post?.excerpt,
},
})
`$3
Export metadata for HTML
. The metadata export can be a plain object or a function:`javascript
export const index = {
render() {
return html
},
}// Static metadata
export const metadata = {
title: "My Site",
meta: {
description: "An awesome static site",
"og:image": "/og-image.png",
},
}
// Or dynamic metadata (uses entity data)
export const metadata = (entity) => ({
title:
${entity.user.name}'s Profile,
meta: {
description: entity.user.bio,
"og:image": entity.user.avatar,
},
})
`$3
Pages hydrate automatically with lit-html. Interactivity works immediately:
`javascript
export const counter = {
click(entity) {
entity.count++
}, render(entity, api) {
return html
Count: ${entity.count}
},
}
`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.
$3
After hydration, navigation is instant:
`javascript
// Links navigate without page reload
;About // Client-side routing// Programmatic navigation
api.notify("navigate", "/posts")
// With options
api.notify("navigate", {
to: "/posts/123",
replace: true,
})
`Routes are lazy-loaded on demand, keeping initial bundle size small.
$3
SSX includes built-in image optimization using
vite-plugin-image-optimizer.- Automatic compression - PNG, JPEG, GIF, SVG, WebP, and AVIF are compressed at build time
- Lossless & lossy - Configurable settings via
vite config in site.config.js$3
SSX treats
.md files as first-class pages. You can create src/pages/post.md and it will be rendered automatically.- Frontmatter - Metadata is exported as
metadata
- Code highlighting - Built-in syntax highlighting with highlight.js
- Math support - LaTeX support via katex (use $E=mc^2$ or $$...$$)
- Mermaid diagrams - Use mermaid code blocks (requires client-side mermaid.js)Configure the syntax highlighting theme in
site.config.js:`javascript
export default {
markdown: {
theme: "monokai", // default: "github-dark"
},
}
`Example markdown file:
`markdown
---
title: My Post
---Hello World
This is a markdown page.
`---
CLI
SSX provides a simple CLI for building and developing:
$3
Builds your static site:
`bash
pnpm ssx build [options]Options:
-c, --config Config file (default: "site.config.js")
-r, --root Source root directory (default: "src")
-o, --out Output directory (default: "dist")
-i, --incremental Enable incremental builds (default: true)
-f, --force Force clean build, ignore cache
`$3
Starts the Vite development server on port 3000 with hot reload:
`bash
pnpm ssx dev [options]Options:
-c, --config Config file (default: "site.config.js")
-r, --root Source root directory (default: "src")
-p, --port Dev server port (default: 3000)
`$3
Serves the built static site on port 3000 through the
serve NPM package:`bash
pnpm preview
`---
Project Structure
`
my-site/
βββ src/
β βββ pages/ # File-based routes
β β βββ index.js # Home page
β β βββ about.js # About page
β β βββ posts/
β β βββ index.js # /posts
β β βββ _id.js # /posts/:id
β βββ store/ # Store configuration
β β βββ entities.js # Entity definitions
β βββ types/ # Custom entity types (optional)
βββ dist/ # Build output
βββ package.json
βββ site.config.js # Site configuration
`---
Comparison to Other Tools
| Feature | SSX | Next.js (SSG) | Astro | Eleventy |
| ------------------ | ----------- | ------------- | ------ | -------- |
| Pre-rendered HTML | β
| β
| β
| β
|
| Client hydration | β
lit-html | β
React | β
Any | β |
| Client routing | β
| β
| β
| β |
| Lazy loading | β
| β
| β
| β |
| Entity-based state | β
| β | β | β |
| Zero config | β
| β | β | β |
| Framework agnostic | β | β | β
| β
|
SSX is perfect if you:
- Want static site performance
- Love entity-based architecture
- Prefer convention over configuration
- Need full client-side interactivity
- Don't want React/Vue lock-in
---
Advanced Usage
$3
Customize SSX behavior in
src/site.config.js:`javascript
export default {
// Basic metadata
lang: "en",
charset: "UTF-8",
title: "My Awesome Site",
meta: {
description: "A site built with SSX",
"og:type": "website",
}, // Global assets
styles: ["./styles/reset.css", "./styles/theme.css"],
scripts: ["./scripts/analytics.js"],
// Build options
basePath: "/",
rootDir: "src",
outDir: "dist",
publicDir: "public",
favicon: "/favicon.ico",
// Router config
router: {
trailingSlash: false,
scrollBehavior: "smooth",
},
// Vite config passthrough
vite: {
server: {
port: 3000,
open: true,
},
},
// Build hooks
hooks: {
beforeBuild: async (config) => console.log("Starting build..."),
afterBuild: async (result) => console.log(
Built ${result.pages} pages),
},
}
`$3
Use Vite's environment variables:
`javascript
// Access in your code
const apiUrl = import.meta.env.VITE_API_URL// .env file
VITE_API_URL=https://api.example.com
`$3
Create a fallback route:
`javascript
// src/pages/404.js
export const notFound = {
render() {
return html
},
}export const metadata = {
title: "404",
}
`Register it in your router:
`javascript
// src/store/entities.js
import { setRoutes } from "@inglorious/web/router"setRoutes({
// ... other routes
"*": "notFound", // Fallback
})
`$3
SSX enables incremental builds by default. Only changed pages are rebuilt, dramatically speeding up your build process:
`bash
ssx build
Only changed pages are rebuilt
ssx build --force
Force a clean rebuild of all pages
`Incremental builds respect your page dependencies and invalidate the cache when dependencies change.
---
Component Compatibility
$3
- All Inglorious Web components (
table, list, select, form)
- Custom components using lit-html templates
- Plain HTML and CSS$3
- Third-party Web Components (Shoelace, Material Web, etc.)
- Will not appear in pre-rendered HTML
- Require client-side JavaScript to initialize
- Best used for client-only interactive features
- Consider using Inglorious Web components for SSG content
---
API Reference
$3
`javascript
import { build } from "@inglorious/ssx/build"await build({
rootDir: "src",
outDir: "dist",
configFile: "site.config.js",
incremental: true,
clean: false,
})
`$3
`javascript
import { dev } from "@inglorious/ssx/dev"await dev({
rootDir: "src",
port: 3000,
configFile: "site.config.js",
})
``---
- [x] TypeScript support
- [x] Image optimization
- [ ] API routes (serverless functions)
- [x] Markdown support
- [ ] i18n helpers
---
SSX embraces the philosophy of @inglorious/web:
- Simplicity over cleverness - Obvious beats clever
- Convention over configuration - Sensible defaults
- Predictability over magic - Explicit is better than implicit
- Standards over abstractions - Use the platform
Static site generation should be simple. SSX makes it simple.
---
Contributions are welcome! Please read our Contributing Guidelines first.
---
MIT License - Free and open source
Created by Matteo Antony Mistretta
---
- @inglorious/web - Entity-based web framework
- @inglorious/store - State management
- @inglorious/engine - Game engine
---
- π Documentation
- π¬ Discord Community
- π Issue Tracker
- π§ Email Support
---
Build static sites the Inglorious way. Simple. Predictable. Fast. π