@inglorious/ssx 1.4.3 → 1.5.0

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/README.md CHANGED
@@ -30,9 +30,9 @@ SSX takes your entity-based web apps and generates optimized static HTML with fu
30
30
  - **Hot reload dev server** - See changes instantly
31
31
  - **Lazy-loaded routes** - Code splitting automatically
32
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.
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
36
 
37
37
  ### 🚀 Production Ready
38
38
 
@@ -61,7 +61,7 @@ npm run dev
61
61
 
62
62
  Or manually:
63
63
 
64
- ### Create Your First Site (TypeScript)
64
+ ### TypeScript Example
65
65
 
66
66
  ```typescript
67
67
  // src/pages/index.ts
@@ -85,7 +85,7 @@ export const index = {
85
85
  }
86
86
  ```
87
87
 
88
- ### Create Your First Site (JavaScript)
88
+ ### JavaScript Example
89
89
 
90
90
  ```javascript
91
91
  // src/pages/index.js
@@ -195,14 +195,14 @@ Your file structure defines your routes:
195
195
  src/pages/
196
196
  ├── index.js → /
197
197
  ├── about.js → /about
198
- ├── blog.js → /blog
198
+ ├── blog.js → /blog
199
199
  └── posts/
200
- └── _slug.js → /posts/:slug
200
+ └── _slug.js → /posts/:slug
201
201
  ```
202
202
 
203
203
  Dynamic routes use underscore prefix: `_id.js`, `_slug.js`, etc.
204
204
 
205
- ### ⚛️ Entity-Based State And Behavior
205
+ ### ⚛️ Entity-Based State and Behavior
206
206
 
207
207
  ```javascript
208
208
  // src/pages/about.js
@@ -265,7 +265,9 @@ export async function load(entity) {
265
265
  entity.posts = await response.json()
266
266
  }
267
267
 
268
- export const title = "Blog"
268
+ export const metadata = {
269
+ title: "Blog",
270
+ }
269
271
  ```
270
272
 
271
273
  The `load` function runs on the server during build. Data is serialized into the HTML and available immediately on the client.
@@ -309,9 +311,9 @@ export async function staticPaths() {
309
311
  }
310
312
 
311
313
  export const metadata = (entity) => ({
312
- title: entity.post.title ?? "Post",
314
+ title: entity.post?.title ?? "Post",
313
315
  meta: {
314
- description: entity.post.excerpt,
316
+ description: entity.post?.excerpt,
315
317
  },
316
318
  })
317
319
  ```
@@ -395,17 +397,17 @@ Routes are lazy-loaded on demand, keeping initial bundle size small.
395
397
 
396
398
  SSX includes built-in image optimization using `vite-plugin-image-optimizer`.
397
399
 
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
+ - **Automatic compression** - PNG, JPEG, GIF, SVG, WebP, and AVIF are compressed at build time
401
+ - **Lossless & lossy** - Configurable settings via `vite` config in `site.config.js`
400
402
 
401
403
  ### 📝 Markdown Support
402
404
 
403
405
  SSX treats `.md` files as first-class pages. You can create `src/pages/post.md` and it will be rendered automatically.
404
406
 
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).
407
+ - **Frontmatter** - Metadata is exported as `metadata`
408
+ - **Code highlighting** - Built-in syntax highlighting with `highlight.js`
409
+ - **Math support** - LaTeX support via `katex` (use `$E=mc^2$` or `$$...$$`)
410
+ - **Mermaid diagrams** - Use `mermaid` code blocks (requires client-side mermaid.js)
409
411
 
410
412
  Configure the syntax highlighting theme in `site.config.js`:
411
413
 
@@ -417,6 +419,8 @@ export default {
417
419
  }
418
420
  ```
419
421
 
422
+ Example markdown file:
423
+
420
424
  ```markdown
421
425
  ---
422
426
  title: My Post
@@ -448,14 +452,6 @@ Options:
448
452
  -f, --force Force clean build, ignore cache
449
453
  ```
450
454
 
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
455
  ### `ssx dev`
460
456
 
461
457
  Starts the Vite development server on port 3000 with hot reload:
@@ -469,6 +465,14 @@ Options:
469
465
  -p, --port <port> Dev server port (default: 3000)
470
466
  ```
471
467
 
468
+ ### `preview`
469
+
470
+ Serves the built static site on port 3000 through the `serve` NPM package:
471
+
472
+ ```bash
473
+ pnpm preview
474
+ ```
475
+
472
476
  ---
473
477
 
474
478
  ## Project Structure
@@ -622,7 +626,25 @@ ssx build --force
622
626
  # Force a clean rebuild of all pages
623
627
  ```
624
628
 
625
- Incremental builds respect your page dependencies and invalidate cache when dependencies change.
629
+ Incremental builds respect your page dependencies and invalidate the cache when dependencies change.
630
+
631
+ ---
632
+
633
+ ## Component Compatibility
634
+
635
+ ### Fully Supported
636
+
637
+ - All Inglorious Web components (`table`, `list`, `select`, `form`)
638
+ - Custom components using lit-html templates
639
+ - Plain HTML and CSS
640
+
641
+ ### Limited Support
642
+
643
+ - Third-party Web Components (Shoelace, Material Web, etc.)
644
+ - Will not appear in pre-rendered HTML
645
+ - Require client-side JavaScript to initialize
646
+ - Best used for client-only interactive features
647
+ - Consider using Inglorious Web components for SSG content
626
648
 
627
649
  ---
628
650
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/ssx",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Server-Side-X. Xecution? Xperience? Who knows.",
5
5
  "author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
@@ -56,7 +56,7 @@
56
56
  "svgo": "^4.0.0",
57
57
  "vite": "^7.1.3",
58
58
  "vite-plugin-image-optimizer": "^2.0.3",
59
- "@inglorious/web": "4.0.5"
59
+ "@inglorious/web": "4.0.6"
60
60
  },
61
61
  "devDependencies": {
62
62
  "prettier": "^3.6.2",
@@ -5,6 +5,7 @@ const DEFAULT_OPTIONS = {
5
5
  lang: "en",
6
6
  charset: "UTF-8",
7
7
  title: "",
8
+ favicon: "",
8
9
  meta: {},
9
10
  styles: [],
10
11
  head: "",
@@ -26,17 +27,18 @@ export async function renderPage(store, page, entity, options = {}) {
26
27
 
27
28
  const getPageOption = createGetPageOption(store, module, entity)
28
29
 
29
- const lang = getPageOption("lang", DEFAULT_OPTIONS) ?? options.lang
30
- const charset = getPageOption("charset", DEFAULT_OPTIONS) ?? options.charset
31
- const title = getPageOption("title", DEFAULT_OPTIONS) ?? options.title
30
+ const lang = getPageOption("lang", DEFAULT_OPTIONS) || options.lang
31
+ const charset = getPageOption("charset", DEFAULT_OPTIONS) || options.charset
32
+ const title = getPageOption("title", DEFAULT_OPTIONS) || options.title
33
+ const favicon = getPageOption("favicon", DEFAULT_OPTIONS) || options.favicon
32
34
  const meta = { ...options.meta, ...getPageOption("meta", DEFAULT_OPTIONS) }
33
35
  const styles = [
34
- ...(options.styles ?? []),
36
+ ...(options.styles || []),
35
37
  ...getPageOption("styles", DEFAULT_OPTIONS),
36
38
  ]
37
- const head = getPageOption("head", DEFAULT_OPTIONS) ?? options.head
39
+ const head = getPageOption("head", DEFAULT_OPTIONS) || options.head
38
40
  const scripts = [
39
- ...(options.scripts ?? []),
41
+ ...(options.scripts || []),
40
42
  ...getPageOption("scripts", DEFAULT_OPTIONS),
41
43
  ]
42
44
 
@@ -45,6 +47,7 @@ export async function renderPage(store, page, entity, options = {}) {
45
47
  lang,
46
48
  charset,
47
49
  title,
50
+ favicon,
48
51
  meta,
49
52
  styles,
50
53
  head,
@@ -18,6 +18,7 @@ export function layout(body, options) {
18
18
  lang = "en",
19
19
  charset = "UTF-8",
20
20
  title = "",
21
+ favicon = "",
21
22
  meta = {},
22
23
  styles = [],
23
24
  head = "",
@@ -30,6 +31,7 @@ export function layout(body, options) {
30
31
  <head>
31
32
  <meta charset="${charset}" />
32
33
  <title>${title}</title>
34
+ <link rel="icon" type="image/x-icon" href="${favicon}">
33
35
  ${Object.entries(meta)
34
36
  .map(
35
37
  ([name, content]) => `<meta name="${name}" content="${content}">`,
@@ -97,7 +97,17 @@ describe("router", () => {
97
97
  const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
98
98
  const pages = await getPages(PAGES_DIR)
99
99
 
100
- expect(pages).toMatchSnapshot()
100
+ // Verify that we got some pages
101
+ expect(pages.length).toBeGreaterThan(0)
102
+
103
+ // Verify specific pages exist and have correct structure
104
+ const rootPage = pages.find((p) => p.pattern === "/")
105
+ expect(rootPage).toBeDefined()
106
+ expect(rootPage.filePath).toMatch(/pages[/\\]index\.js$/)
107
+
108
+ const aboutPage = pages.find((p) => p.pattern === "/about")
109
+ expect(aboutPage).toBeDefined()
110
+ expect(aboutPage.filePath).toMatch(/pages[/\\]about\.js$/)
101
111
 
102
112
  // Dynamic route without staticPaths should be skipped (and warn)
103
113
  const blogPage = pages.find((p) => p.path.includes("/api/"))