@jasonshimmy/vite-plugin-cer-app 0.20.0 → 0.20.2
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/CHANGELOG.md +9 -0
- package/README.md +1 -0
- package/commits.txt +2 -2
- package/dist/plugin/content/parser.d.ts.map +1 -1
- package/dist/plugin/content/parser.js +63 -0
- package/dist/plugin/content/parser.js.map +1 -1
- package/dist/plugin/dev-server.d.ts.map +1 -1
- package/dist/plugin/dev-server.js +5 -2
- package/dist/plugin/dev-server.js.map +1 -1
- package/dist/types/page.d.ts +2 -1
- package/dist/types/page.d.ts.map +1 -1
- package/docs/content.md +17 -0
- package/docs/data-loading.md +47 -20
- package/e2e/cypress/e2e/content.cy.ts +67 -4
- package/e2e/cypress/e2e/error-boundary.cy.ts +20 -0
- package/e2e/kitchen-sink/app/pages/content-fallback.ts +36 -0
- package/e2e/kitchen-sink/app/pages/loader-response-error-test.ts +13 -0
- package/e2e/kitchen-sink/content/blog/no-frontmatter.md +7 -0
- package/package.json +2 -2
- package/src/__tests__/plugin/content/parser.test.ts +143 -1
- package/src/__tests__/plugin/dev-server.test.ts +96 -2
- package/src/__tests__/plugin/entry-server-template.test.ts +7 -0
- package/src/plugin/content/parser.ts +67 -0
- package/src/plugin/dev-server.ts +5 -2
- package/src/types/page.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
|
+
## [v0.20.2] - 2026-04-11
|
|
5
|
+
|
|
6
|
+
- fix: correct loader error handling and improve data fetching in SSR/SSG modes (d225a99)
|
|
7
|
+
- docs: add Content Layer section to README for Markdown/JSON support (376a990)
|
|
8
|
+
|
|
9
|
+
## [v0.20.1] - 2026-04-11
|
|
10
|
+
|
|
11
|
+
- fix(content): add fallback title and description extraction from Markdown body (9bab321)
|
|
12
|
+
|
|
4
13
|
## [v0.20.0] - 2026-04-11
|
|
5
14
|
|
|
6
15
|
- feat(content): implement file-based content layer with Markdown/JSON support (#1) (c6ef0f7)
|
package/README.md
CHANGED
|
@@ -220,6 +220,7 @@ component('page-about', () => {
|
|
|
220
220
|
| [Layouts](docs/layouts.md) | Layout system and `<slot>` composition |
|
|
221
221
|
| [Components](docs/components.md) | Auto-registered custom elements |
|
|
222
222
|
| [Composables](docs/composables.md) | Auto-imported composables |
|
|
223
|
+
| [Content Layer](docs/content.md) | File-based Markdown/JSON content with `queryContent()` and `useContentSearch()` |
|
|
223
224
|
| [Plugins](docs/plugins.md) | App plugin system and DI |
|
|
224
225
|
| [Middleware](docs/middleware.md) | Route guards and server middleware |
|
|
225
226
|
| [Server API Routes](docs/server-api.md) | HTTP handlers in `server/api/` |
|
package/commits.txt
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
-
|
|
2
|
-
-
|
|
1
|
+
- fix: correct loader error handling and improve data fetching in SSR/SSG modes (d225a99)
|
|
2
|
+
- docs: add Content Layer section to README for Markdown/JSON support (376a990)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/plugin/content/parser.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/plugin/content/parser.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AA6N/C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,GACjB,WAAW,CAGb;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAGtB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAI5D"}
|
|
@@ -40,6 +40,60 @@ function extractHeadings(tokens) {
|
|
|
40
40
|
walk(tokens);
|
|
41
41
|
return headings;
|
|
42
42
|
}
|
|
43
|
+
// ─── Fallback title / description extraction ─────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Converts a list of inline marked tokens to plain text by recursing into
|
|
46
|
+
* formatted tokens (strong, em, link, etc.) and collecting their leaf text.
|
|
47
|
+
* Used to derive readable fallback values from body content.
|
|
48
|
+
*/
|
|
49
|
+
function inlineToPlainText(tokens) {
|
|
50
|
+
let result = '';
|
|
51
|
+
for (const t of tokens) {
|
|
52
|
+
const children = t.tokens;
|
|
53
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
54
|
+
result += inlineToPlainText(children);
|
|
55
|
+
}
|
|
56
|
+
else if (t.type === 'br') {
|
|
57
|
+
result += ' ';
|
|
58
|
+
}
|
|
59
|
+
else if ('text' in t && typeof t.text === 'string') {
|
|
60
|
+
result += t.text;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
const DESCRIPTION_MAX_LEN = 160;
|
|
66
|
+
/**
|
|
67
|
+
* Scans the top-level token list for a fallback `title` (first depth-1 heading)
|
|
68
|
+
* and `description` (first paragraph). Both are `undefined` when no matching
|
|
69
|
+
* token is found.
|
|
70
|
+
*
|
|
71
|
+
* These are applied only when the corresponding frontmatter field is absent, so
|
|
72
|
+
* frontmatter always wins.
|
|
73
|
+
*/
|
|
74
|
+
function extractFallbacks(tokens) {
|
|
75
|
+
let title;
|
|
76
|
+
let description;
|
|
77
|
+
for (const token of tokens) {
|
|
78
|
+
if (title === undefined && token.type === 'heading' && token.depth === 1) {
|
|
79
|
+
const text = inlineToPlainText(token.tokens ?? []).trim();
|
|
80
|
+
if (text)
|
|
81
|
+
title = text;
|
|
82
|
+
}
|
|
83
|
+
if (description === undefined && token.type === 'paragraph') {
|
|
84
|
+
const text = inlineToPlainText(token.tokens ?? []).trim();
|
|
85
|
+
if (text) {
|
|
86
|
+
description =
|
|
87
|
+
text.length > DESCRIPTION_MAX_LEN
|
|
88
|
+
? text.slice(0, DESCRIPTION_MAX_LEN).trimEnd() + '…'
|
|
89
|
+
: text;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (title !== undefined && description !== undefined)
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return { title, description };
|
|
96
|
+
}
|
|
43
97
|
// ─── Custom renderer: add id to heading tags ─────────────────────────────────
|
|
44
98
|
const renderer = new marked.Renderer();
|
|
45
99
|
renderer.heading = function ({ tokens, depth }) {
|
|
@@ -105,6 +159,9 @@ function parseContentFileFromRaw(file, contentDir, raw) {
|
|
|
105
159
|
const excerpt = excerptSource !== null
|
|
106
160
|
? marked.parse(excerptSource, { renderer })
|
|
107
161
|
: undefined;
|
|
162
|
+
// Derive fallback title / description from body tokens when frontmatter
|
|
163
|
+
// does not provide them. Frontmatter always wins — these only fill gaps.
|
|
164
|
+
const fallbacks = extractFallbacks(tokens);
|
|
108
165
|
const item = {
|
|
109
166
|
...frontmatter,
|
|
110
167
|
_path,
|
|
@@ -113,6 +170,12 @@ function parseContentFileFromRaw(file, contentDir, raw) {
|
|
|
113
170
|
body,
|
|
114
171
|
toc,
|
|
115
172
|
};
|
|
173
|
+
if (item.title === undefined && fallbacks.title !== undefined) {
|
|
174
|
+
item.title = fallbacks.title;
|
|
175
|
+
}
|
|
176
|
+
if (item.description === undefined && fallbacks.description !== undefined) {
|
|
177
|
+
item.description = fallbacks.description;
|
|
178
|
+
}
|
|
116
179
|
if (excerpt !== undefined) {
|
|
117
180
|
item.excerpt = excerpt;
|
|
118
181
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/plugin/content/parser.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/plugin/content/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/plugin/dev-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAKzC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;IAC1E,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAA;IAC9D,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAA;IACtD,WAAW,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;IACjG,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,OAAO,oBAAoB,EAAE,oBAAoB,CAAA;KAAE,CAAA;IAC9G,IAAI,EAAE,OAAO,oBAAoB,EAAE,UAAU,GAAG,IAAI,CAAA;IACpD,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,uBAAuB,GAAG,WAAW,CAAA;KAAE,GAAG,IAAI,CAAA;CACtH;AA0GD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,iBAAiB,GACxB,IAAI,
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/plugin/dev-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAKzC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;IAC1E,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAA;IAC9D,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAA;IACtD,WAAW,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;IACjG,aAAa,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,OAAO,oBAAoB,EAAE,oBAAoB,CAAA;KAAE,CAAA;IAC9G,IAAI,EAAE,OAAO,oBAAoB,EAAE,UAAU,GAAG,IAAI,CAAA;IACpD,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,uBAAuB,GAAG,WAAW,CAAA;KAAE,GAAG,IAAI,CAAA;CACtH;AA0GD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,iBAAiB,GACxB,IAAI,CA8KN"}
|
|
@@ -186,8 +186,11 @@ export function configureCerDevServer(server, config) {
|
|
|
186
186
|
catch {
|
|
187
187
|
// virtual:cer-server-api not yet ready or empty — continue
|
|
188
188
|
}
|
|
189
|
-
// 3. SSR mode: intercept HTML requests
|
|
190
|
-
|
|
189
|
+
// 3. SSR/SSG mode: intercept HTML requests and server-render them.
|
|
190
|
+
// Both 'ssr' and 'ssg' modes run loaders on the server so usePageData()
|
|
191
|
+
// returns real data during dev — matching production behaviour.
|
|
192
|
+
// 'spa' mode never runs server loaders, so it falls through to the client bundle.
|
|
193
|
+
if (config.mode === 'ssr' || config.mode === 'ssg') {
|
|
191
194
|
const acceptsHtml = (req.headers['accept'] ?? '').includes('text/html') ||
|
|
192
195
|
url === '/' ||
|
|
193
196
|
(!url.includes('.') && !url.startsWith('/api/'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.js","sourceRoot":"","sources":["../../src/plugin/dev-server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dev-server.js","sourceRoot":"","sources":["../../src/plugin/dev-server.ts"],"names":[],"mappings":"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"}
|
package/dist/types/page.d.ts
CHANGED
|
@@ -83,7 +83,8 @@ export interface PageMeta {
|
|
|
83
83
|
export interface PageLoaderContext<P extends Record<string, string> = Record<string, string>> {
|
|
84
84
|
params: P;
|
|
85
85
|
query: Record<string, string>;
|
|
86
|
-
|
|
86
|
+
/** Present during SSR/SSG server render. Absent (`undefined`) during client-side navigation. */
|
|
87
|
+
req?: IncomingMessage;
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
89
90
|
* Server-side data loader for a page. Export as `export const loader` (or `export async function loader`)
|
package/dist/types/page.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/types/page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;AAElE,qHAAqH;AACrH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,GAAG,eAAe,EAAE,CAAA;IAC5D;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,wGAAwG;IACxG,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,GAAG,CAAC,EAAE,aAAa,CAAA;IACnB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC7B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAC1F,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,GAAG,EAAE,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/types/page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;AAElE,qHAAqH;AACrH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,GAAG,eAAe,EAAE,CAAA;IAC5D;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,wGAAwG;IACxG,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,GAAG,CAAC,EAAE,aAAa,CAAA;IACnB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC7B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAC1F,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,gGAAgG;IAChG,GAAG,CAAC,EAAE,eAAe,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,UAAU,CACpB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACzD,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACzB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA"}
|
package/docs/content.md
CHANGED
|
@@ -131,6 +131,23 @@ Recognized frontmatter keys:
|
|
|
131
131
|
|
|
132
132
|
Any additional frontmatter keys are stored verbatim in the `ContentMeta` / `ContentItem` object.
|
|
133
133
|
|
|
134
|
+
### Automatic title and description
|
|
135
|
+
|
|
136
|
+
When `title` or `description` are absent from frontmatter, the parser derives them from the body:
|
|
137
|
+
|
|
138
|
+
- **`title`** — plain text of the first depth-1 heading (`# …`). Only `h1` is considered; `h2`–`h6` are ignored.
|
|
139
|
+
- **`description`** — plain text of the first paragraph, truncated to 160 characters (with `…` appended). Inline formatting is stripped.
|
|
140
|
+
|
|
141
|
+
Frontmatter values always win — these fallbacks only fill the gaps. JSON files do not receive fallbacks (they have no Markdown body to parse from).
|
|
142
|
+
|
|
143
|
+
```md
|
|
144
|
+
# Hello World
|
|
145
|
+
|
|
146
|
+
This becomes the description because no description key is in frontmatter.
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Results in `title: 'Hello World'` and `description: 'This becomes the description because no description key is in frontmatter.'`.
|
|
150
|
+
|
|
134
151
|
### Date-prefixed filenames
|
|
135
152
|
|
|
136
153
|
Filenames starting with `YYYY-MM-DD-` have the date prefix stripped when computing the content path:
|
package/docs/data-loading.md
CHANGED
|
@@ -11,12 +11,12 @@ Each page can export a `loader` function that runs on the server before the page
|
|
|
11
11
|
import type { PageLoader } from '@jasonshimmy/vite-plugin-cer-app/types'
|
|
12
12
|
|
|
13
13
|
component('page-blog-slug', () => {
|
|
14
|
-
const
|
|
14
|
+
const data = usePageData<{ title: string; body: string }>()
|
|
15
15
|
|
|
16
16
|
return html`
|
|
17
17
|
<article>
|
|
18
|
-
<h1>${
|
|
19
|
-
<div>${
|
|
18
|
+
<h1>${data?.title ?? ''}</h1>
|
|
19
|
+
<div>${data?.body ?? ''}</div>
|
|
20
20
|
</article>
|
|
21
21
|
`
|
|
22
22
|
})
|
|
@@ -27,7 +27,7 @@ export const loader: PageLoader = async ({ params }) => {
|
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The object returned by `loader` is
|
|
30
|
+
The object returned by `loader` is made available via `usePageData()` in the page component. Primitive values (strings, numbers, booleans) are also forwarded as HTML element attributes so `useProps()` can read them.
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
@@ -36,13 +36,13 @@ The object returned by `loader` is serialized and passed as props to the page co
|
|
|
36
36
|
```ts
|
|
37
37
|
type PageLoader<
|
|
38
38
|
Params extends Record<string, string> = Record<string, string>,
|
|
39
|
-
Data
|
|
40
|
-
> = (ctx: PageLoaderContext<Params>) => Promise<Data>
|
|
39
|
+
Data = Record<string, unknown>,
|
|
40
|
+
> = (ctx: PageLoaderContext<Params>) => Promise<Data> | Data
|
|
41
41
|
|
|
42
42
|
interface PageLoaderContext<P extends Record<string, string>> {
|
|
43
43
|
params: P // URL path parameters
|
|
44
44
|
query: Record<string, string> // Parsed query string
|
|
45
|
-
req
|
|
45
|
+
req?: IncomingMessage // Raw Node.js request (present during SSR/SSG server render; absent during client-side navigation)
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -66,7 +66,7 @@ interface PageLoaderContext<P extends Record<string, string>> {
|
|
|
66
66
|
|
|
67
67
|
1. Browser receives the full HTML — content is immediately visible via Declarative Shadow DOM before any JS runs
|
|
68
68
|
2. Client JS boots; `usePageData()` reads `window.__CER_DATA__` and returns the hydrated values
|
|
69
|
-
3. After the initial `router.replace()` in `.cer/app.ts` completes, `.cer/app.ts`
|
|
69
|
+
3. After the initial `router.replace()` in `.cer/app.ts` completes, `.cer/app.ts` clears the loader data from `globalThis` so subsequent client-side navigations trigger a fresh fetch instead of reusing stale server data
|
|
70
70
|
4. Components that received SSR data skip their `useOnConnected` fetch — no duplicate request
|
|
71
71
|
|
|
72
72
|
---
|
|
@@ -106,18 +106,22 @@ export const loader = async ({ params }: { params: { id: string } }) => {
|
|
|
106
106
|
|
|
107
107
|
## Accessing loader data in components
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
Use `usePageData()` to read loader data — it receives everything the loader returned (primitives and complex objects alike) and works in all modes: SSR, SSG, and client-side navigation.
|
|
110
110
|
|
|
111
111
|
```ts
|
|
112
112
|
component('page-user', () => {
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
113
|
+
const ssrData = usePageData<{ user: { id: string; name: string; email: string } }>()
|
|
114
|
+
const user = ref(ssrData?.user ?? { id: '', name: '', email: '' })
|
|
115
|
+
|
|
116
|
+
useOnConnected(async () => {
|
|
117
|
+
if (ssrData) return // already hydrated
|
|
118
|
+
const { data } = await useFetch(`/api/users/${user.value.id}`)
|
|
119
|
+
if (data) user.value = data
|
|
116
120
|
})
|
|
117
121
|
|
|
118
122
|
return html`
|
|
119
|
-
<h1>Hello, ${
|
|
120
|
-
<p>${
|
|
123
|
+
<h1>Hello, ${user.value.name}</h1>
|
|
124
|
+
<p>${user.value.email}</p>
|
|
121
125
|
`
|
|
122
126
|
})
|
|
123
127
|
|
|
@@ -127,6 +131,27 @@ export const loader: PageLoader<{ id: string }> = async ({ params }) => {
|
|
|
127
131
|
}
|
|
128
132
|
```
|
|
129
133
|
|
|
134
|
+
`useProps()` is an alternative for **primitive values only** (strings, numbers, booleans). It reads element HTML attributes rather than the loader payload directly, which means it also picks up attributes passed by parent components in the component tree — but it cannot receive arrays or objects.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
component('page-profile', () => {
|
|
138
|
+
// Works for primitives only — use usePageData() if you need objects or arrays
|
|
139
|
+
const props = useProps<{ username: string; bio: string }>({ username: '', bio: '' })
|
|
140
|
+
|
|
141
|
+
return html`
|
|
142
|
+
<h1>${props.username}</h1>
|
|
143
|
+
<p>${props.bio}</p>
|
|
144
|
+
`
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
export const loader = async ({ params }: { params: { id: string } }) => {
|
|
148
|
+
const { data: user } = await useFetch(`/api/users/${params.id}`)
|
|
149
|
+
return { username: user?.name, bio: user?.bio } // primitives only
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
> **Rule of thumb:** reach for `usePageData()` first. Only prefer `useProps()` when you specifically need the element attribute binding model — for example, when the same component is also used as a child that receives attributes from a parent.
|
|
154
|
+
|
|
130
155
|
---
|
|
131
156
|
|
|
132
157
|
## SSG and loaders
|
|
@@ -153,6 +178,14 @@ export const loader: PageLoader<{ slug: string }> = async ({ params }) => {
|
|
|
153
178
|
|
|
154
179
|
---
|
|
155
180
|
|
|
181
|
+
## Dev server behavior
|
|
182
|
+
|
|
183
|
+
In `mode: 'ssr'` and `mode: 'ssg'`, the dev server runs the server entry module and calls your `loader` on every HTML request — matching production behaviour. Both `usePageData()` and `useProps()` receive real loader data during development.
|
|
184
|
+
|
|
185
|
+
In `mode: 'spa'`, no loaders run in the dev server. `usePageData()` always returns `null` and `useProps()` returns its defaults. Use `useOnConnected` to fetch data client-side in SPA mode.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
156
189
|
## Error handling in loaders
|
|
157
190
|
|
|
158
191
|
When a `loader` throws, the SSR error boundary intercepts it:
|
|
@@ -173,12 +206,6 @@ export const loader: PageLoader<{ id: string }> = async ({ params }) => {
|
|
|
173
206
|
}
|
|
174
207
|
```
|
|
175
208
|
|
|
176
|
-
You can also throw a standard `Response` — the framework reads its `.status` property:
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
throw new Response('Not Found', { status: 404 })
|
|
180
|
-
```
|
|
181
|
-
|
|
182
209
|
Unhandled errors without a `status` property default to HTTP 500.
|
|
183
210
|
|
|
184
211
|
---
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Content layer e2e tests — exercises queryContent() and useContentSearch().
|
|
3
3
|
*
|
|
4
4
|
* Pages under test:
|
|
5
|
-
* /content-index
|
|
6
|
-
* /content-blog
|
|
7
|
-
* /content-doc
|
|
8
|
-
* /content-search
|
|
5
|
+
* /content-index — queryContent().find() (all content)
|
|
6
|
+
* /content-blog — queryContent('/blog').find() (blog prefix, draft exclusion)
|
|
7
|
+
* /content-doc — queryContent('/docs/getting-started').first() (body + TOC)
|
|
8
|
+
* /content-search — useContentSearch() (MiniSearch, client-side)
|
|
9
|
+
* /content-fallback — title/description derived from body when frontmatter omits them
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
const mode = Cypress.env('mode') as 'spa' | 'ssr' | 'ssg'
|
|
@@ -226,3 +227,65 @@ describe('Content search — useContentSearch()', () => {
|
|
|
226
227
|
cy.get('[data-cy=content-search-result]').should('not.exist')
|
|
227
228
|
})
|
|
228
229
|
})
|
|
230
|
+
|
|
231
|
+
// ─── /content-fallback ────────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
describe('Content fallback — title and description derived from body', () => {
|
|
234
|
+
// blog/no-frontmatter.md has no frontmatter at all.
|
|
235
|
+
// Expected derived values:
|
|
236
|
+
// title → "Derived From Body" (first h1)
|
|
237
|
+
// description → "This description is…" (first paragraph, ≤160 chars)
|
|
238
|
+
|
|
239
|
+
if (mode !== 'spa') {
|
|
240
|
+
it('pre-renders the derived title in initial HTML (SSR/SSG)', () => {
|
|
241
|
+
cy.request('/content-fallback').then((response) => {
|
|
242
|
+
expect(response.body).to.include('Derived From Body')
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('pre-renders the derived description in initial HTML (SSR/SSG)', () => {
|
|
247
|
+
cy.request('/content-fallback').then((response) => {
|
|
248
|
+
expect(response.body).to.include('This description is derived from the first paragraph')
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
it('renders the derived title after hydration', () => {
|
|
254
|
+
cy.visit('/content-fallback')
|
|
255
|
+
cy.get('[data-cy=content-fallback-title]', { timeout: 8000 })
|
|
256
|
+
.should('contain', 'Derived From Body')
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('renders the derived description after hydration', () => {
|
|
260
|
+
cy.visit('/content-fallback')
|
|
261
|
+
cy.get('[data-cy=content-fallback-desc]', { timeout: 8000 })
|
|
262
|
+
.should('contain', 'This description is derived from the first paragraph')
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('document is found — fallback-missing element is absent', () => {
|
|
266
|
+
cy.visit('/content-fallback')
|
|
267
|
+
cy.get('[data-cy=content-fallback-heading]', { timeout: 8000 }).should('exist')
|
|
268
|
+
cy.get('[data-cy=content-fallback-missing]').should('not.exist')
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('derived item appears in queryContent find() results (content-index)', () => {
|
|
272
|
+
cy.visit('/content-index')
|
|
273
|
+
cy.get('[data-cy=content-item][data-path="/blog/no-frontmatter"]', { timeout: 8000 })
|
|
274
|
+
.should('exist')
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('derived title is shown in the content-index listing', () => {
|
|
278
|
+
cy.visit('/content-index')
|
|
279
|
+
cy.get('[data-cy=content-item][data-path="/blog/no-frontmatter"] [data-cy=content-item-title]', { timeout: 8000 })
|
|
280
|
+
.should('contain', 'Derived From Body')
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('derived item appears in search results when searching by derived title', () => {
|
|
284
|
+
cy.intercept('GET', '/_content/search-index.json').as('searchIndex')
|
|
285
|
+
cy.visit('/content-search')
|
|
286
|
+
cy.wait('@searchIndex')
|
|
287
|
+
setSearchQuery('Derived')
|
|
288
|
+
cy.get('[data-cy=content-search-result]', { timeout: 8000 })
|
|
289
|
+
.should('contain', 'Derived From Body')
|
|
290
|
+
})
|
|
291
|
+
})
|
|
@@ -65,4 +65,24 @@ if (mode === 'ssr') {
|
|
|
65
65
|
cy.get('[data-cy=error-retry]').should('exist')
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
|
+
|
|
69
|
+
describe('SSR error boundary — loader throws a Response object', () => {
|
|
70
|
+
it('reads the numeric .status from the thrown Response (405)', () => {
|
|
71
|
+
cy.request({ url: '/loader-response-error-test', failOnStatusCode: false }).then((response) => {
|
|
72
|
+
expect(response.status).to.eq(405)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('renders page-error element in the server response for a thrown Response', () => {
|
|
77
|
+
cy.request({ url: '/loader-response-error-test', failOnStatusCode: false }).then((response) => {
|
|
78
|
+
expect(response.body).to.include('page-error')
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('does not render the normal page heading when a Response is thrown', () => {
|
|
83
|
+
cy.request({ url: '/loader-response-error-test', failOnStatusCode: false }).then((response) => {
|
|
84
|
+
expect(response.body).not.to.include('loader-response-error-heading')
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
})
|
|
68
88
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content fallback page — exercises title/description derivation from body
|
|
3
|
+
* when frontmatter does not supply them.
|
|
4
|
+
*
|
|
5
|
+
* Fetches /blog/no-frontmatter (no frontmatter at all) and renders its
|
|
6
|
+
* derived title and description so Cypress can assert both in all modes.
|
|
7
|
+
*
|
|
8
|
+
* Route: /content-fallback
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
component('page-content-fallback', () => {
|
|
12
|
+
useHead({ title: 'Content Fallback — Kitchen Sink' })
|
|
13
|
+
|
|
14
|
+
const ssrData = usePageData<{ doc: ContentItem | null }>()
|
|
15
|
+
const doc = ref<ContentItem | null>(ssrData?.doc ?? null)
|
|
16
|
+
|
|
17
|
+
useOnConnected(async () => {
|
|
18
|
+
if (ssrData) return // already hydrated
|
|
19
|
+
doc.value = await queryContent('/blog/no-frontmatter').first()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return html`
|
|
23
|
+
<div>
|
|
24
|
+
<h1 data-cy="content-fallback-heading">Content Fallback</h1>
|
|
25
|
+
${doc.value ? html`
|
|
26
|
+
<p data-cy="content-fallback-title">${doc.value.title}</p>
|
|
27
|
+
<p data-cy="content-fallback-desc">${doc.value.description}</p>
|
|
28
|
+
` : html`<p data-cy="content-fallback-missing">Document not found.</p>`}
|
|
29
|
+
</div>
|
|
30
|
+
`
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const loader = async () => {
|
|
34
|
+
const doc = await queryContent('/blog/no-frontmatter').first()
|
|
35
|
+
return { doc }
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
component('page-loader-response-error-test', () => {
|
|
2
|
+
return html`
|
|
3
|
+
<div>
|
|
4
|
+
<h1 data-cy="loader-response-error-heading">Response Error Test</h1>
|
|
5
|
+
</div>
|
|
6
|
+
`
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
export async function loader() {
|
|
10
|
+
// Verify that throwing a Response-like object (which has a numeric .status property)
|
|
11
|
+
// causes the framework to use that status code for the HTTP response.
|
|
12
|
+
throw new Response('Method Not Allowed', { status: 405 })
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jasonshimmy/vite-plugin-cer-app",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "Nuxt-style meta-framework for @jasonshimmy/custom-elements-runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"eslint": "^10.2.0",
|
|
103
103
|
"happy-dom": "^20.8.9",
|
|
104
104
|
"jiti": "^2.6.1",
|
|
105
|
-
"start-server-and-test": "^3.0.
|
|
105
|
+
"start-server-and-test": "^3.0.2",
|
|
106
106
|
"typescript": "^5.9.3",
|
|
107
107
|
"typescript-eslint": "^8.58.1",
|
|
108
108
|
"vite": "^8.0.8",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll } from 'vitest'
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
2
|
import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs'
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { join } from 'pathe'
|
|
@@ -62,6 +62,62 @@ Just content, no more marker.
|
|
|
62
62
|
`)
|
|
63
63
|
|
|
64
64
|
writeFileSync(join(contentDir, 'data', 'products.json'), JSON.stringify([{ id: 1, name: 'Widget' }]))
|
|
65
|
+
|
|
66
|
+
// ── Fallback fixtures ────────────────────────────────────────────────────
|
|
67
|
+
// No frontmatter at all — title and description derived from body
|
|
68
|
+
writeFileSync(join(contentDir, 'no-frontmatter.md'), `# Derived Title
|
|
69
|
+
|
|
70
|
+
First paragraph for description.
|
|
71
|
+
|
|
72
|
+
Second paragraph.
|
|
73
|
+
`)
|
|
74
|
+
|
|
75
|
+
// Frontmatter title only — description derived from body
|
|
76
|
+
writeFileSync(join(contentDir, 'title-only.md'), `---
|
|
77
|
+
title: Explicit Title
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
Description will come from this paragraph.
|
|
81
|
+
`)
|
|
82
|
+
|
|
83
|
+
// Frontmatter description only — title derived from h1
|
|
84
|
+
writeFileSync(join(contentDir, 'desc-only.md'), `---
|
|
85
|
+
description: Explicit description
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
# Derived H1 Title
|
|
89
|
+
|
|
90
|
+
Some paragraph.
|
|
91
|
+
`)
|
|
92
|
+
|
|
93
|
+
// Both set in frontmatter — body values must NOT overwrite them
|
|
94
|
+
writeFileSync(join(contentDir, 'both-frontmatter.md'), `---
|
|
95
|
+
title: FM Title
|
|
96
|
+
description: FM Description
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
# Different H1
|
|
100
|
+
|
|
101
|
+
Different paragraph.
|
|
102
|
+
`)
|
|
103
|
+
|
|
104
|
+
// h1 with inline formatting — plain text only
|
|
105
|
+
writeFileSync(join(contentDir, 'formatted-h1.md'), `# Hello **World**
|
|
106
|
+
|
|
107
|
+
Some intro.
|
|
108
|
+
`)
|
|
109
|
+
|
|
110
|
+
// Long paragraph — description truncated to 160 chars + ellipsis
|
|
111
|
+
writeFileSync(join(contentDir, 'long-para.md'), `# Long
|
|
112
|
+
|
|
113
|
+
${'A'.repeat(200)}
|
|
114
|
+
`)
|
|
115
|
+
|
|
116
|
+
// No h1, only h2 — title fallback must remain undefined
|
|
117
|
+
writeFileSync(join(contentDir, 'no-h1.md'), `## Section Only
|
|
118
|
+
|
|
119
|
+
A paragraph here.
|
|
120
|
+
`)
|
|
65
121
|
})
|
|
66
122
|
|
|
67
123
|
function makeFile(filePath: string, ext: 'md' | 'json'): ContentFile {
|
|
@@ -237,3 +293,89 @@ describe('parseContentFile — date normalisation', () => {
|
|
|
237
293
|
expect(date < '2027-01-01').toBe(true)
|
|
238
294
|
})
|
|
239
295
|
})
|
|
296
|
+
|
|
297
|
+
// ─── Fallback title / description ────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
describe('parseContentFile — fallback title from h1', () => {
|
|
300
|
+
it('derives title from h1 when frontmatter title is absent', () => {
|
|
301
|
+
const item = parseContentFile(makeFile(join(contentDir, 'no-frontmatter.md'), 'md'), contentDir)
|
|
302
|
+
expect(item.title).toBe('Derived Title')
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('frontmatter title is not overwritten when present', () => {
|
|
306
|
+
const item = parseContentFile(makeFile(join(contentDir, 'title-only.md'), 'md'), contentDir)
|
|
307
|
+
expect(item.title).toBe('Explicit Title')
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('derives title from h1 when only description is in frontmatter', () => {
|
|
311
|
+
const item = parseContentFile(makeFile(join(contentDir, 'desc-only.md'), 'md'), contentDir)
|
|
312
|
+
expect(item.title).toBe('Derived H1 Title')
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('frontmatter title wins over h1 when both set', () => {
|
|
316
|
+
const item = parseContentFile(makeFile(join(contentDir, 'both-frontmatter.md'), 'md'), contentDir)
|
|
317
|
+
expect(item.title).toBe('FM Title')
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
it('strips inline formatting — title is plain text', () => {
|
|
321
|
+
const item = parseContentFile(makeFile(join(contentDir, 'formatted-h1.md'), 'md'), contentDir)
|
|
322
|
+
expect(item.title).toBe('Hello World')
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('does not derive title from h2 — must be h1 only', () => {
|
|
326
|
+
const item = parseContentFile(makeFile(join(contentDir, 'no-h1.md'), 'md'), contentDir)
|
|
327
|
+
expect(item.title).toBeUndefined()
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
describe('parseContentFile — fallback description from first paragraph', () => {
|
|
332
|
+
it('derives description from first paragraph when frontmatter description is absent', () => {
|
|
333
|
+
const item = parseContentFile(makeFile(join(contentDir, 'no-frontmatter.md'), 'md'), contentDir)
|
|
334
|
+
expect(item.description).toBe('First paragraph for description.')
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('frontmatter description is not overwritten when present', () => {
|
|
338
|
+
const item = parseContentFile(makeFile(join(contentDir, 'desc-only.md'), 'md'), contentDir)
|
|
339
|
+
expect(item.description).toBe('Explicit description')
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('derives description from first paragraph when only title is in frontmatter', () => {
|
|
343
|
+
const item = parseContentFile(makeFile(join(contentDir, 'title-only.md'), 'md'), contentDir)
|
|
344
|
+
expect(item.description).toBe('Description will come from this paragraph.')
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
it('frontmatter description wins when both set', () => {
|
|
348
|
+
const item = parseContentFile(makeFile(join(contentDir, 'both-frontmatter.md'), 'md'), contentDir)
|
|
349
|
+
expect(item.description).toBe('FM Description')
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('truncates long paragraphs to 160 chars with ellipsis', () => {
|
|
353
|
+
const item = parseContentFile(makeFile(join(contentDir, 'long-para.md'), 'md'), contentDir)
|
|
354
|
+
expect(typeof item.description).toBe('string')
|
|
355
|
+
expect((item.description as string).length).toBeLessThanOrEqual(164) // 160 + '…' (3 bytes)
|
|
356
|
+
expect(item.description as string).toMatch(/…$/)
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it('derived description is on ContentMeta (present in manifest)', async () => {
|
|
360
|
+
const { toContentMeta } = await import('../../../plugin/content/parser.js')
|
|
361
|
+
const item = parseContentFile(makeFile(join(contentDir, 'no-frontmatter.md'), 'md'), contentDir)
|
|
362
|
+
const meta = toContentMeta(item)
|
|
363
|
+
expect(meta.description).toBe('First paragraph for description.')
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
describe('parseContentFile — JSON fallback', () => {
|
|
368
|
+
it('does not apply title/description fallbacks to JSON files', () => {
|
|
369
|
+
// JSON files have no markdown body to extract from
|
|
370
|
+
const item = parseContentFile(
|
|
371
|
+
makeFile(join(contentDir, 'data', 'products.json'), 'json'),
|
|
372
|
+
contentDir,
|
|
373
|
+
)
|
|
374
|
+
expect(item.title).toBeUndefined()
|
|
375
|
+
expect(item.description).toBeUndefined()
|
|
376
|
+
})
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
afterAll(() => {
|
|
380
|
+
rmSync(tmpDir, { recursive: true, force: true })
|
|
381
|
+
})
|
|
@@ -450,6 +450,43 @@ describe('configureCerDevServer — SSR mode', () => {
|
|
|
450
450
|
expect(ssrHandler).toHaveBeenCalled()
|
|
451
451
|
})
|
|
452
452
|
|
|
453
|
+
it('invokes SSR handler for HTML requests in ssg mode', async () => {
|
|
454
|
+
const ssrHandler = vi.fn(async (req: any, res: any) => res.end('<html>SSG-DEV</html>'))
|
|
455
|
+
const { server, getMiddleware } = makeServer()
|
|
456
|
+
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
457
|
+
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
458
|
+
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
459
|
+
return { handler: ssrHandler }
|
|
460
|
+
})
|
|
461
|
+
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
462
|
+
const res = createRes()
|
|
463
|
+
await getMiddleware()(
|
|
464
|
+
createReq({ url: '/', headers: { accept: 'text/html' } }),
|
|
465
|
+
res,
|
|
466
|
+
vi.fn(),
|
|
467
|
+
)
|
|
468
|
+
expect(ssrHandler).toHaveBeenCalled()
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
it('does not invoke SSR handler in spa mode', async () => {
|
|
472
|
+
const ssrHandler = vi.fn()
|
|
473
|
+
const { server, getMiddleware } = makeServer()
|
|
474
|
+
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
475
|
+
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
476
|
+
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
477
|
+
return { handler: ssrHandler }
|
|
478
|
+
})
|
|
479
|
+
configureCerDevServer(server as any, makeConfig({ mode: 'spa' }))
|
|
480
|
+
const next = vi.fn()
|
|
481
|
+
await getMiddleware()(
|
|
482
|
+
createReq({ url: '/', headers: { accept: 'text/html' } }),
|
|
483
|
+
createRes(),
|
|
484
|
+
next,
|
|
485
|
+
)
|
|
486
|
+
expect(ssrHandler).not.toHaveBeenCalled()
|
|
487
|
+
expect(next).toHaveBeenCalled()
|
|
488
|
+
})
|
|
489
|
+
|
|
453
490
|
it('does not invoke SSR handler for non-HTML requests (e.g. assets)', async () => {
|
|
454
491
|
const ssrHandler = vi.fn()
|
|
455
492
|
const { server, getMiddleware } = makeServer()
|
|
@@ -469,6 +506,25 @@ describe('configureCerDevServer — SSR mode', () => {
|
|
|
469
506
|
expect(next).toHaveBeenCalled()
|
|
470
507
|
})
|
|
471
508
|
|
|
509
|
+
it('does not invoke SSR handler for non-HTML requests in ssg mode', async () => {
|
|
510
|
+
const ssrHandler = vi.fn()
|
|
511
|
+
const { server, getMiddleware } = makeServer()
|
|
512
|
+
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
513
|
+
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
514
|
+
if (path.includes('server-api')) return { apiRoutes: [] }
|
|
515
|
+
return { handler: ssrHandler }
|
|
516
|
+
})
|
|
517
|
+
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
518
|
+
const next = vi.fn()
|
|
519
|
+
await getMiddleware()(
|
|
520
|
+
createReq({ url: '/assets/main.js', headers: { accept: 'application/javascript' } }),
|
|
521
|
+
createRes(),
|
|
522
|
+
next,
|
|
523
|
+
)
|
|
524
|
+
expect(ssrHandler).not.toHaveBeenCalled()
|
|
525
|
+
expect(next).toHaveBeenCalled()
|
|
526
|
+
})
|
|
527
|
+
|
|
472
528
|
it('returns 500 and error text when SSR handler throws', async () => {
|
|
473
529
|
const { server, getMiddleware } = makeServer()
|
|
474
530
|
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
@@ -531,13 +587,14 @@ describe('configureCerDevServer — SSR mode', () => {
|
|
|
531
587
|
})
|
|
532
588
|
})
|
|
533
589
|
|
|
534
|
-
// ─── Per-route render mode (SSR mode)
|
|
590
|
+
// ─── Per-route render mode (SSR/SSG mode) ────────────────────────────────────
|
|
535
591
|
|
|
536
592
|
describe("configureCerDevServer — per-route render mode in SSR", () => {
|
|
537
593
|
/** Build a server where virtual:cer-routes returns the given routes array. */
|
|
538
594
|
function makeServerWithRoutes(
|
|
539
595
|
pageRoutes: Array<{ path: string; meta?: Record<string, unknown> }>,
|
|
540
596
|
ssrHandler = vi.fn(async (_req: any, res: any) => res.end('<html>SSR</html>')),
|
|
597
|
+
mode: 'ssr' | 'ssg' = 'ssr',
|
|
541
598
|
) {
|
|
542
599
|
const { server, getMiddleware } = makeServer()
|
|
543
600
|
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
@@ -546,7 +603,7 @@ describe("configureCerDevServer — per-route render mode in SSR", () => {
|
|
|
546
603
|
if (path.includes('cer-routes')) return { default: pageRoutes }
|
|
547
604
|
return { handler: ssrHandler }
|
|
548
605
|
})
|
|
549
|
-
configureCerDevServer(server as any, makeConfig({ mode
|
|
606
|
+
configureCerDevServer(server as any, makeConfig({ mode }))
|
|
550
607
|
return { middleware: getMiddleware(), ssrHandler }
|
|
551
608
|
}
|
|
552
609
|
|
|
@@ -564,6 +621,22 @@ describe("configureCerDevServer — per-route render mode in SSR", () => {
|
|
|
564
621
|
expect(ssrHandler).not.toHaveBeenCalled()
|
|
565
622
|
})
|
|
566
623
|
|
|
624
|
+
it("calls next() instead of SSR for a route with render: 'spa' in ssg mode", async () => {
|
|
625
|
+
const { middleware, ssrHandler } = makeServerWithRoutes(
|
|
626
|
+
[{ path: '/spa-page', meta: { render: 'spa' } }],
|
|
627
|
+
vi.fn(async (_req: any, res: any) => res.end('<html>SSG</html>')),
|
|
628
|
+
'ssg',
|
|
629
|
+
)
|
|
630
|
+
const next = vi.fn()
|
|
631
|
+
await middleware(
|
|
632
|
+
createReq({ url: '/spa-page', headers: { accept: 'text/html' } }),
|
|
633
|
+
createRes(),
|
|
634
|
+
next,
|
|
635
|
+
)
|
|
636
|
+
expect(next).toHaveBeenCalled()
|
|
637
|
+
expect(ssrHandler).not.toHaveBeenCalled()
|
|
638
|
+
})
|
|
639
|
+
|
|
567
640
|
it("proceeds to SSR for a route with render: 'server'", async () => {
|
|
568
641
|
const { middleware, ssrHandler } = makeServerWithRoutes([
|
|
569
642
|
{ path: '/server-page', meta: { render: 'server' } },
|
|
@@ -620,6 +693,27 @@ describe("configureCerDevServer — per-route render mode in SSR", () => {
|
|
|
620
693
|
)
|
|
621
694
|
expect(routesCalls).toHaveLength(0)
|
|
622
695
|
})
|
|
696
|
+
|
|
697
|
+
it("loads routes module in ssg mode to check per-route render mode", async () => {
|
|
698
|
+
const ssrHandler = vi.fn(async (_req: any, res: any) => res.end('<html>SSG</html>'))
|
|
699
|
+
const { server, getMiddleware } = makeServer()
|
|
700
|
+
server.ssrLoadModule.mockImplementation(async (path: string) => {
|
|
701
|
+
if (path.includes('server-middleware')) return { serverMiddleware: [] }
|
|
702
|
+
if (path.includes('server-api') || path.includes('cer-server-api')) return { apiRoutes: [] }
|
|
703
|
+
if (path.includes('cer-routes')) return { default: [] }
|
|
704
|
+
return { handler: ssrHandler }
|
|
705
|
+
})
|
|
706
|
+
configureCerDevServer(server as any, makeConfig({ mode: 'ssg' }))
|
|
707
|
+
await getMiddleware()(
|
|
708
|
+
createReq({ url: '/about', headers: { accept: 'text/html' } }),
|
|
709
|
+
createRes(),
|
|
710
|
+
vi.fn(),
|
|
711
|
+
)
|
|
712
|
+
const routesCalls = (server.ssrLoadModule as any).mock.calls.filter(
|
|
713
|
+
([p]: [string]) => p.includes('cer-routes'),
|
|
714
|
+
)
|
|
715
|
+
expect(routesCalls.length).toBeGreaterThan(0)
|
|
716
|
+
})
|
|
623
717
|
})
|
|
624
718
|
|
|
625
719
|
// ─── parseBody edge cases ─────────────────────────────────────────────────────
|
|
@@ -173,6 +173,13 @@ describe('entry-server-template (ENTRY_SERVER_TEMPLATE content)', () => {
|
|
|
173
173
|
expect(src).toContain('err.status')
|
|
174
174
|
})
|
|
175
175
|
|
|
176
|
+
it('guards err.status with typeof === "number" so Response-like thrown values work', () => {
|
|
177
|
+
// `new Response("...", { status: 404 })` has a numeric `.status` property.
|
|
178
|
+
// The typeof guard ensures that non-numeric status values (e.g. a string "404")
|
|
179
|
+
// do not pass through — only genuine numbers are accepted.
|
|
180
|
+
expect(src).toContain("typeof err.status === 'number'")
|
|
181
|
+
})
|
|
182
|
+
|
|
176
183
|
it('defaults to status 500 when thrown error has no .status', () => {
|
|
177
184
|
expect(src).toContain(': 500')
|
|
178
185
|
})
|
|
@@ -48,6 +48,62 @@ function extractHeadings(tokens: Token[]): ContentHeading[] {
|
|
|
48
48
|
return headings
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// ─── Fallback title / description extraction ─────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Converts a list of inline marked tokens to plain text by recursing into
|
|
55
|
+
* formatted tokens (strong, em, link, etc.) and collecting their leaf text.
|
|
56
|
+
* Used to derive readable fallback values from body content.
|
|
57
|
+
*/
|
|
58
|
+
function inlineToPlainText(tokens: Token[]): string {
|
|
59
|
+
let result = ''
|
|
60
|
+
for (const t of tokens) {
|
|
61
|
+
const children = (t as { tokens?: Token[] }).tokens
|
|
62
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
63
|
+
result += inlineToPlainText(children)
|
|
64
|
+
} else if (t.type === 'br') {
|
|
65
|
+
result += ' '
|
|
66
|
+
} else if ('text' in t && typeof (t as { text: string }).text === 'string') {
|
|
67
|
+
result += (t as { text: string }).text
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const DESCRIPTION_MAX_LEN = 160
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Scans the top-level token list for a fallback `title` (first depth-1 heading)
|
|
77
|
+
* and `description` (first paragraph). Both are `undefined` when no matching
|
|
78
|
+
* token is found.
|
|
79
|
+
*
|
|
80
|
+
* These are applied only when the corresponding frontmatter field is absent, so
|
|
81
|
+
* frontmatter always wins.
|
|
82
|
+
*/
|
|
83
|
+
function extractFallbacks(tokens: Token[]): { title?: string; description?: string } {
|
|
84
|
+
let title: string | undefined
|
|
85
|
+
let description: string | undefined
|
|
86
|
+
|
|
87
|
+
for (const token of tokens) {
|
|
88
|
+
if (title === undefined && token.type === 'heading' && token.depth === 1) {
|
|
89
|
+
const text = inlineToPlainText((token as { tokens: Token[] }).tokens ?? []).trim()
|
|
90
|
+
if (text) title = text
|
|
91
|
+
}
|
|
92
|
+
if (description === undefined && token.type === 'paragraph') {
|
|
93
|
+
const text = inlineToPlainText((token as { tokens: Token[] }).tokens ?? []).trim()
|
|
94
|
+
if (text) {
|
|
95
|
+
description =
|
|
96
|
+
text.length > DESCRIPTION_MAX_LEN
|
|
97
|
+
? text.slice(0, DESCRIPTION_MAX_LEN).trimEnd() + '…'
|
|
98
|
+
: text
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (title !== undefined && description !== undefined) break
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { title, description }
|
|
105
|
+
}
|
|
106
|
+
|
|
51
107
|
// ─── Custom renderer: add id to heading tags ─────────────────────────────────
|
|
52
108
|
|
|
53
109
|
const renderer = new marked.Renderer()
|
|
@@ -129,6 +185,10 @@ function parseContentFileFromRaw(
|
|
|
129
185
|
? (marked.parse(excerptSource, { renderer }) as string)
|
|
130
186
|
: undefined
|
|
131
187
|
|
|
188
|
+
// Derive fallback title / description from body tokens when frontmatter
|
|
189
|
+
// does not provide them. Frontmatter always wins — these only fill gaps.
|
|
190
|
+
const fallbacks = extractFallbacks(tokens)
|
|
191
|
+
|
|
132
192
|
const item: ContentItem = {
|
|
133
193
|
...frontmatter,
|
|
134
194
|
_path,
|
|
@@ -138,6 +198,13 @@ function parseContentFileFromRaw(
|
|
|
138
198
|
toc,
|
|
139
199
|
}
|
|
140
200
|
|
|
201
|
+
if (item.title === undefined && fallbacks.title !== undefined) {
|
|
202
|
+
item.title = fallbacks.title
|
|
203
|
+
}
|
|
204
|
+
if (item.description === undefined && fallbacks.description !== undefined) {
|
|
205
|
+
item.description = fallbacks.description
|
|
206
|
+
}
|
|
207
|
+
|
|
141
208
|
if (excerpt !== undefined) {
|
|
142
209
|
item.excerpt = excerpt
|
|
143
210
|
}
|
package/src/plugin/dev-server.ts
CHANGED
|
@@ -238,8 +238,11 @@ export function configureCerDevServer(
|
|
|
238
238
|
// virtual:cer-server-api not yet ready or empty — continue
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
// 3. SSR mode: intercept HTML requests
|
|
242
|
-
|
|
241
|
+
// 3. SSR/SSG mode: intercept HTML requests and server-render them.
|
|
242
|
+
// Both 'ssr' and 'ssg' modes run loaders on the server so usePageData()
|
|
243
|
+
// returns real data during dev — matching production behaviour.
|
|
244
|
+
// 'spa' mode never runs server loaders, so it falls through to the client bundle.
|
|
245
|
+
if (config.mode === 'ssr' || config.mode === 'ssg') {
|
|
243
246
|
const acceptsHtml =
|
|
244
247
|
(req.headers['accept'] ?? '').includes('text/html') ||
|
|
245
248
|
url === '/' ||
|
package/src/types/page.ts
CHANGED
|
@@ -88,7 +88,8 @@ export interface PageMeta {
|
|
|
88
88
|
export interface PageLoaderContext<P extends Record<string, string> = Record<string, string>> {
|
|
89
89
|
params: P
|
|
90
90
|
query: Record<string, string>
|
|
91
|
-
|
|
91
|
+
/** Present during SSR/SSG server render. Absent (`undefined`) during client-side navigation. */
|
|
92
|
+
req?: IncomingMessage
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
/**
|