@uniweb/runtime 1.5.5 → 1.5.6
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/dist/ssr.js +41 -13
- package/dist/ssr.js.map +1 -1
- package/package.json +3 -3
- package/src/page-renderer.js +12 -6
- package/src/section-records.js +56 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.6",
|
|
4
4
|
"description": "Minimal runtime for loading Uniweb foundations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node": ">=22.12"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@uniweb/core": "~1.6.
|
|
39
|
+
"@uniweb/core": "~1.6.11",
|
|
40
40
|
"@uniweb/theming": "~1.3.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"esbuild": "^0.21.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.27.0 || ^0.28.0",
|
|
45
45
|
"vite": "^7.3.1",
|
|
46
46
|
"vitest": "^4.1.7",
|
|
47
|
-
"@uniweb/build": "1.20.
|
|
47
|
+
"@uniweb/build": "1.20.4"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": "^19.0.0",
|
package/src/page-renderer.js
CHANGED
|
@@ -82,13 +82,15 @@ export function createPageRenderer({ website, shell }) {
|
|
|
82
82
|
* parametric pages made from them (`Website#forgetData`), and files these, all in this
|
|
83
83
|
* synchronous call, so a Website reused across requests renders each against its own and
|
|
84
84
|
* no other request runs in between. Absent, the render reads whatever the store holds.
|
|
85
|
-
* @param {boolean} [options.sectionData] - also say
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
85
|
+
* @param {boolean} [options.sectionData] - also say what the page's Markdown carries:
|
|
86
|
+
* `sections`, the records each section showed, and on a record page `record`, its own record as
|
|
87
|
+
* this render read it. Hand both to `renderPageMarkdown(page, { record, sections })`
|
|
88
|
+
* (`@uniweb/projections`). Read from the store this render read, after its HTML
|
|
89
|
+
* (`section-records.js`), so a render that does not ask does no more work than before.
|
|
89
90
|
* @returns {{ outcome: 'rendered'|'notFound'|'failed', html: string|null,
|
|
90
91
|
* page: Object|null, error: {type: string, message: string}|null,
|
|
91
|
-
* sections?: Array<{ id: string, data: Object }
|
|
92
|
+
* sections?: Array<{ id: string, data: Object }>, record?: Object|null }} `sections` when asked,
|
|
93
|
+
* on a page with `html`; `record` beside it on a record page, null when its route names none
|
|
92
94
|
* `notFound` means the URL names nothing, and `html` says whether there is a page to
|
|
93
95
|
* send for it. Send `html` with your not-found status when it is set, and the shell
|
|
94
96
|
* when it is not:
|
|
@@ -189,7 +191,11 @@ export function createPageRenderer({ website, shell }) {
|
|
|
189
191
|
})
|
|
190
192
|
const rendered = { outcome: missing ? 'notFound' : 'rendered', html, page, error: null }
|
|
191
193
|
// In this same synchronous call, so the store holds this page's answers and no other request's.
|
|
192
|
-
if (sectionData)
|
|
194
|
+
if (sectionData) {
|
|
195
|
+
const shown = sectionRecords(page)
|
|
196
|
+
rendered.sections = shown.sections
|
|
197
|
+
if (shown.record !== undefined) rendered.record = shown.record
|
|
198
|
+
}
|
|
193
199
|
return rendered
|
|
194
200
|
}
|
|
195
201
|
|
package/src/section-records.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* - **Left out:** a key the section holds as a tagged block in its own content (` ```yaml:tag `, or
|
|
25
25
|
* a concept block), which the page's Markdown already shows as it was written; a record page's
|
|
26
26
|
* own record (a key whose fetch uses this page's record, `current: only`), which its Markdown
|
|
27
|
-
* writes once, as the page's
|
|
27
|
+
* writes once, as the page's, from `record` (`pageRecordOf`); and a key with no value, `null` —
|
|
28
28
|
* nothing fills it, or its fetch failed, never ran or is still out.
|
|
29
29
|
* - **Whose:** each body section and its child sections, under its own id, and the insets in a
|
|
30
30
|
* section, under the id of the section they sit in, since a page's Markdown has no place of their
|
|
@@ -34,32 +34,67 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import { sectionDomId } from '@uniweb/core/section-id'
|
|
36
36
|
import { declaredKeys } from '@uniweb/core/data-keys'
|
|
37
|
-
import { blockFillsOf, blockRouteQuery, fillIsPageRecord } from '@uniweb/core/page-data'
|
|
37
|
+
import { blockFillsOf, blockRouteQuery, fillIsPageRecord, heldPageRecord } from '@uniweb/core/page-data'
|
|
38
38
|
import { getComponentMeta, receivedData } from './prepare-props.js'
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* The records each of a page's sections showed,
|
|
41
|
+
* The records each of a page's sections showed, and a record page's own record, read after the
|
|
42
|
+
* page's render: what its Markdown carries (`renderPageMarkdown(page, { record, sections })`).
|
|
42
43
|
*
|
|
43
44
|
* @param {Object} page - the Page just rendered, its Website the one `globalThis.uniweb` names
|
|
44
|
-
* @returns {Array<{ id: string, data: Object }
|
|
45
|
-
*
|
|
45
|
+
* @returns {{ sections: Array<{ id: string, data: Object }>, record: Object|null|undefined }}
|
|
46
|
+
* `sections` in page order, one entry per section, child section or inset that showed any, `id`
|
|
47
|
+
* the section's DOM id (`sectionDomId`) and `data` its records by name. `record` a record page's
|
|
48
|
+
* own (`pageRecordOf`): null when its route names none, undefined off a record page
|
|
46
49
|
*/
|
|
47
50
|
export function sectionRecords(page) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
const sections = []
|
|
52
|
+
// The page's own record as its sections received it, which `sections` leaves out.
|
|
53
|
+
const shown = []
|
|
54
|
+
for (const block of page?.getBodyBlocks?.() ?? []) visit(block, sectionDomId(block), sections, shown)
|
|
55
|
+
return { sections, record: pageRecordOf(page, shown) }
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
function visit(block, id,
|
|
58
|
+
function visit(block, id, sections, shown) {
|
|
54
59
|
if (!block) return
|
|
55
|
-
const data = recordsOf(block)
|
|
56
|
-
if (data)
|
|
57
|
-
for (const inset of block.insets || []) visit(inset, id,
|
|
58
|
-
for (const child of block.childBlocks || []) visit(child, sectionDomId(child),
|
|
60
|
+
const data = recordsOf(block, shown)
|
|
61
|
+
if (data) sections.push({ id, data })
|
|
62
|
+
for (const inset of block.insets || []) visit(inset, id, sections, shown)
|
|
63
|
+
for (const child of block.childBlocks || []) visit(child, sectionDomId(child), sections, shown)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* ⭐ A RECORD PAGE'S OWN RECORD, AS ITS RENDER READ IT — the most of it the page held, so its
|
|
68
|
+
* Markdown carries what its sections drew: whole when a section received it whole, or when the
|
|
69
|
+
* record index holds it whole; else as a section received it; else the answer the page's own
|
|
70
|
+
* question got (`heldPageRecord`, `@uniweb/core/page-data`), which names the page and says whether
|
|
71
|
+
* it exists.
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} page
|
|
74
|
+
* @param {Array<{ value: *, whole: boolean }>} shown
|
|
75
|
+
* @returns {Object|null|undefined}
|
|
76
|
+
*/
|
|
77
|
+
function pageRecordOf(page, shown) {
|
|
78
|
+
if (!page?.dynamicContext) return undefined
|
|
79
|
+
const one = (value) => (Array.isArray(value) ? (value[0] ?? null) : value)
|
|
80
|
+
const whole = shown.find((s) => s.whole && one(s.value))
|
|
81
|
+
if (whole) return one(whole.value)
|
|
82
|
+
const website = page.website
|
|
83
|
+
const fetcher = website?.fetcher
|
|
84
|
+
const own = heldPageRecord(page, {
|
|
85
|
+
website,
|
|
86
|
+
peek: (request) => fetcher?.peek?.(request, { website, page, block: null }),
|
|
87
|
+
peekRecord: (id) => fetcher?.peekRecord?.(id),
|
|
88
|
+
})
|
|
89
|
+
const seen = shown.map((s) => one(s.value)).find(Boolean) ?? null
|
|
90
|
+
const id = (own ?? seen)?.$uuid
|
|
91
|
+
const held = typeof id === 'string' && id ? fetcher?.peekRecord?.(id) : null
|
|
92
|
+
if (held?.whole === true && held.record) return held.record
|
|
93
|
+
return seen ?? own
|
|
59
94
|
}
|
|
60
95
|
|
|
61
96
|
/** One block's records by name, or null when it showed none. */
|
|
62
|
-
function recordsOf(block) {
|
|
97
|
+
function recordsOf(block, shown) {
|
|
63
98
|
// A type the foundation doesn't have renders as an error box, and its render asks for no data.
|
|
64
99
|
if (!globalThis.uniweb?.getComponent?.(block.type)) return null
|
|
65
100
|
const meta = getComponentMeta(block.type)
|
|
@@ -89,8 +124,13 @@ function recordsOf(block) {
|
|
|
89
124
|
route = blockRouteQuery(block)
|
|
90
125
|
fills = blockFillsOf(block, meta, route)
|
|
91
126
|
}
|
|
92
|
-
const
|
|
93
|
-
|
|
127
|
+
const fill = fills.get(key)
|
|
128
|
+
const cfg = fill?.cfg
|
|
129
|
+
if (!cfg?.as) continue
|
|
130
|
+
if (fillIsPageRecord(block, cfg, route)) {
|
|
131
|
+
shown.push({ value, whole: fill.whole === true })
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
94
134
|
name = cfg.as
|
|
95
135
|
}
|
|
96
136
|
if (Object.hasOwn(out, name) && !sameValue(out[name], value)) name = key
|