@uniweb/runtime 1.1.15 → 1.1.17
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 +12 -8
- package/dist/ssr.js.map +1 -1
- package/package.json +4 -4
- package/src/foundation-loader.js +5 -3
- package/src/isolate-api.js +12 -3
- package/src/setup.js +7 -1
- package/src/ssr-renderer.js +10 -15
- package/src/ssr.js +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "Minimal runtime for loading Uniweb foundations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -36,15 +36,15 @@
|
|
|
36
36
|
"node": ">=22.12"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@uniweb/
|
|
40
|
-
"@uniweb/
|
|
39
|
+
"@uniweb/core": "~1.4.2",
|
|
40
|
+
"@uniweb/theming": "~1.2.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@vitejs/plugin-react": "^4.5.2",
|
|
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.
|
|
47
|
+
"@uniweb/build": "1.8.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": "^19.0.0",
|
package/src/foundation-loader.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* with CSS loading in parallel.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { foundationCssUrl } from '@uniweb/core/page-shell'
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Resolve a foundation/extension URL so that absolute-path forms
|
|
10
12
|
* (`/_module/...`) anchor to the document's origin, not to the importing
|
|
@@ -75,11 +77,11 @@ export async function loadFoundationCSS(url) {
|
|
|
75
77
|
*/
|
|
76
78
|
export async function loadFoundation(source) {
|
|
77
79
|
const rawUrl = typeof source === 'string' ? source : source.url
|
|
78
|
-
// Auto-derive CSS URL from JS URL by convention
|
|
80
|
+
// Auto-derive CSS URL from JS URL by the one convention, entry.js → assets/style.css
|
|
81
|
+
// (`foundationCssUrl`, which a page's shell links the primary's stylesheet by too).
|
|
79
82
|
// Pre-Phase-5 foundations were named foundation.js + assets/foundation.css;
|
|
80
83
|
// those keep working when an explicit `cssUrl` is passed in `source`.
|
|
81
|
-
const rawCssUrl = typeof source === 'object' ? source.cssUrl
|
|
82
|
-
: rawUrl.replace(/[^/]+\.js$/, 'assets/style.css')
|
|
84
|
+
const rawCssUrl = typeof source === 'object' ? source.cssUrl : foundationCssUrl(rawUrl)
|
|
83
85
|
|
|
84
86
|
// Phase 5: when the runtime is loaded from a different host than the
|
|
85
87
|
// document (e.g. runtime served from cdn.uniweb.app, page on
|
package/src/isolate-api.js
CHANGED
|
@@ -42,11 +42,14 @@
|
|
|
42
42
|
* at publish time and never hand-edited.
|
|
43
43
|
*
|
|
44
44
|
* ⚠️ **The tempting fix is the dangerous one.** Stamping the current version
|
|
45
|
-
* (`0.16.0`) would satisfy every check and be **false**: backend reads
|
|
46
|
-
* `minUsable` from the channel index and
|
|
47
|
-
* so a floor of 0.16.0 would promise an export that 0.16.0 does not contain —
|
|
45
|
+
* (`0.16.0`) would satisfy every check and be **false**: a backend reads
|
|
46
|
+
* `minUsable` from the channel index and publishes no site at a runtime below
|
|
47
|
+
* it, so a floor of 0.16.0 would promise an export that 0.16.0 does not contain —
|
|
48
48
|
* and a host at the floor is entitled to skip feature detection. That is a
|
|
49
49
|
* guarantee broken in the one direction the floor exists to prevent.
|
|
50
|
+
* ⛔ *This said a backend "refuses to serve a site below it" until 2026-10-24.*
|
|
51
|
+
* The floor bounds what is published next. A site already pinned below it is
|
|
52
|
+
* served as it is, until it is republished.
|
|
50
53
|
*
|
|
51
54
|
* ⇒ **`UNRELEASED` says the true thing: this export exists in the tree and in no
|
|
52
55
|
* published version.** It is stamped like any other name, so nothing rides out
|
|
@@ -119,6 +122,12 @@ export const ISOLATE_API = Object.freeze({
|
|
|
119
122
|
RESOLUTION_STATUS: '0.28.6',
|
|
120
123
|
// a redirect the host answers itself, with the visitor's query and fragment on it
|
|
121
124
|
carryQuery: '1.0.1',
|
|
125
|
+
// the `__DATA__` element a host writes into a page's shell, and the escaping it uses
|
|
126
|
+
dataScript: '1.1.16',
|
|
127
|
+
jsonForScript: '1.1.16',
|
|
128
|
+
// the page's whole shell, and the foundation stylesheet convention it links by
|
|
129
|
+
pageShell: '1.1.16',
|
|
130
|
+
foundationCssUrl: '1.1.16',
|
|
122
131
|
})
|
|
123
132
|
|
|
124
133
|
/**
|
package/src/setup.js
CHANGED
|
@@ -355,10 +355,16 @@ export async function decodeData() {
|
|
|
355
355
|
const raw = el.textContent
|
|
356
356
|
|
|
357
357
|
// Plain JSON (uncompressed)
|
|
358
|
+
// ⛔ A payload that is there and does not parse is said as such: the boot then finds no
|
|
359
|
+
// configuration, and "No site configuration found" alone sent a reader looking for a payload
|
|
360
|
+
// that was present. Measured 2026-10-23: a host escaped `<!--` as `<\!--`, which JSON has no
|
|
361
|
+
// escape for, and every page stayed its server render with nothing naming the cause. JSON
|
|
362
|
+
// inside a <script> escapes `<` as `<` (`build/src/prerender.js`).
|
|
358
363
|
if (el.type === 'application/json') {
|
|
359
364
|
try {
|
|
360
365
|
return JSON.parse(raw)
|
|
361
|
-
} catch {
|
|
366
|
+
} catch (err) {
|
|
367
|
+
console.error(`[Runtime] __DATA__ is not valid JSON, so the site cannot start: ${err.message}`)
|
|
362
368
|
return null
|
|
363
369
|
}
|
|
364
370
|
}
|
package/src/ssr-renderer.js
CHANGED
|
@@ -35,6 +35,7 @@ import { layoutStickiness, sectionStickyProps, sectionScrollMargin, zoneProps }
|
|
|
35
35
|
import { DefaultLayout } from './default-layout.js'
|
|
36
36
|
import { renderAppearanceBootScript } from './appearance.js'
|
|
37
37
|
import { documentTitle } from './document-title.js'
|
|
38
|
+
import { escapeHtml } from '@uniweb/core/page-shell'
|
|
38
39
|
|
|
39
40
|
// Re-export L2 helpers so the public `@uniweb/runtime/ssr` surface
|
|
40
41
|
// carries everything an SSR consumer needs from one entry point.
|
|
@@ -546,9 +547,12 @@ export async function prefetchIcons(siteContent, uniweb, onProgress = () => {})
|
|
|
546
547
|
)
|
|
547
548
|
|
|
548
549
|
const succeeded = results.filter(r => r.status === 'fulfilled').length
|
|
549
|
-
const
|
|
550
|
-
if (
|
|
551
|
-
|
|
550
|
+
const failedRefs = icons.filter((_, i) => results[i].status === 'rejected')
|
|
551
|
+
if (failedRefs.length > 0) {
|
|
552
|
+
// Named, so an author can fix the reference. ⛔ Until 2026-10-24 this said only "(1 failed)",
|
|
553
|
+
// and a missing icon on a live page took a search through every reference to find.
|
|
554
|
+
const shown = failedRefs.slice(0, 10).join(', ') + (failedRefs.length > 10 ? ', …' : '')
|
|
555
|
+
const msg = `Fetched ${succeeded}/${icons.length} icons (${failedRefs.length} failed: ${shown})`
|
|
552
556
|
console.warn(`[prerender] ${msg}`)
|
|
553
557
|
onProgress(` ${msg}`)
|
|
554
558
|
}
|
|
@@ -655,18 +659,9 @@ export function renderPage(page, website) {
|
|
|
655
659
|
// HTML injection
|
|
656
660
|
// ============================================================================
|
|
657
661
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
export function escapeHtml(str) {
|
|
662
|
-
if (!str) return ''
|
|
663
|
-
return String(str)
|
|
664
|
-
.replace(/&/g, '&')
|
|
665
|
-
.replace(/</g, '<')
|
|
666
|
-
.replace(/>/g, '>')
|
|
667
|
-
.replace(/"/g, '"')
|
|
668
|
-
.replace(/'/g, ''')
|
|
669
|
-
}
|
|
662
|
+
// Escape HTML special characters — the one implementation, which a page's shell writes with too
|
|
663
|
+
// (`@uniweb/core/page-shell`). Still exported from here, as it has been since 0.6.14.
|
|
664
|
+
export { escapeHtml }
|
|
670
665
|
|
|
671
666
|
/**
|
|
672
667
|
* Inject prerendered content into an HTML shell.
|
package/src/ssr.js
CHANGED
|
@@ -100,3 +100,20 @@ export { collectSiteRecords } from './collect-records.js'
|
|
|
100
100
|
// Appearance. injectPageContent() already emits this for every prerendered
|
|
101
101
|
// page; exported for lanes that assemble a shell without a per-page render.
|
|
102
102
|
export { renderAppearanceBootScript } from './appearance.js'
|
|
103
|
+
|
|
104
|
+
// ⭐ THE `__DATA__` ELEMENT A HOST WRITES INTO A PAGE'S SHELL — the boot payload as JSON a
|
|
105
|
+
// `<script>` cannot end or misparse (every `<` as `<`), carrying only the served page's
|
|
106
|
+
// sections when the content names where the others are (`config.pageHashes`). The rule a static
|
|
107
|
+
// build writes its own page data by (`@uniweb/core/data-script`). ⛔ A host wrote `__DATA__` with
|
|
108
|
+
// its own escaping until 2026-10-23, escaping `<!--` as `<\!--` — a JavaScript-string escape that
|
|
109
|
+
// is invalid JSON — and no page of the site it served could start (`decodeData`).
|
|
110
|
+
// `jsonForScript` is the escaping alone, for any other JSON a host writes into a `<script>`.
|
|
111
|
+
export { dataScript, jsonForScript } from '@uniweb/core/data-script'
|
|
112
|
+
|
|
113
|
+
// ⭐ THE PAGE'S SHELL — the whole HTML a page starts as, from what only the host holds (its
|
|
114
|
+
// addresses, the runtime's manifest, the content it read): the head, an empty `#root`, and
|
|
115
|
+
// `__DATA__`. Page assembly is framework's [Diego, 2026-10-23]. In an isolate it is the `shell`
|
|
116
|
+
// `createPageRenderer` renders into, versioned with the runtime; a host links the same function
|
|
117
|
+
// (`@uniweb/core/page-shell`) for a page it serves without rendering. `foundationCssUrl` is the
|
|
118
|
+
// one convention for a foundation's stylesheet, which the loader and the shell both follow.
|
|
119
|
+
export { pageShell, foundationCssUrl } from '@uniweb/core/page-shell'
|