@uniweb/runtime 0.16.0 → 0.17.1
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 +115 -43
- package/dist/ssr.js.map +1 -1
- package/package.json +3 -3
- package/src/background-shared.js +72 -0
- package/src/collect-records.js +99 -0
- package/src/components/Background.jsx +4 -39
- package/src/default-fetcher.js +124 -52
- package/src/isolate-api.js +48 -1
- package/src/prefetch.js +7 -7
- package/src/ssr-renderer.js +2 -32
- package/src/ssr.js +8 -1
package/src/prefetch.js
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
* compute that itself: resolve the configs, issue the requests, unwrap the responses in the
|
|
11
11
|
* shape the datastore expects — a copy of the runtime's logic, in another repo, drifting
|
|
12
12
|
* (the records envelope went silently unread that way on 2026-09-02). [Diego, 2026-09-03]:
|
|
13
|
-
* *the backend sets
|
|
13
|
+
* *the backend sets the records service; the fetch comes from the runtime.* The host now calls
|
|
14
14
|
* this and carries no copy. Hosting agreed to exactly that shape the same day.
|
|
15
15
|
*
|
|
16
16
|
* ⛔ Contract with the host, deliberately small:
|
|
17
17
|
* - `content` the render payload (`site-content.json` / `__DATA__`), config included —
|
|
18
|
-
* `config.
|
|
18
|
+
* `config.services` and `config.base` are read from it.
|
|
19
19
|
* - `route` the page to prefetch for; a `[slug]` template resolves through the same
|
|
20
20
|
* matcher the SPA uses, so `/blog/post-1` finds `/blog/:slug`.
|
|
21
21
|
* - `fetch` how to dispatch a request. The runtime composes the address; the host
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
* is a different cache decision (hosting, 2026-09-03).
|
|
47
47
|
*
|
|
48
48
|
* It resolves nothing the host owns and models no host route layout: every address is
|
|
49
|
-
* `{base}/…` from the payload, or the
|
|
50
|
-
* `config.records
|
|
49
|
+
* `{base}/…` from the payload, or the records service the host itself
|
|
50
|
+
* published at `config.services.records`.
|
|
51
51
|
*/
|
|
52
52
|
import { resolveFetchConfigs } from '@uniweb/core/fetch-config'
|
|
53
53
|
import { deriveCacheKey } from '@uniweb/core/datastore'
|
|
@@ -118,7 +118,7 @@ export function resolvePageFetchConfigs(content, route, { locale = null } = {})
|
|
|
118
118
|
locale,
|
|
119
119
|
defaultLocale: resolveDefaultLocale(content?.config) ?? null,
|
|
120
120
|
queries: content?.config?.queries ?? null,
|
|
121
|
-
|
|
121
|
+
services: content?.config?.services ?? null,
|
|
122
122
|
variables: binding?.variables ?? null,
|
|
123
123
|
}
|
|
124
124
|
const out = new Map()
|
|
@@ -163,7 +163,7 @@ export function resolvePageFetchConfigs(content, route, { locale = null } = {})
|
|
|
163
163
|
* @param {Object[]} configs resolved configs (from `resolvePageFetchConfigs` or the host's own
|
|
164
164
|
* call to `resolveFetchConfigs`)
|
|
165
165
|
* @param {Object} opts
|
|
166
|
-
* @param {Object} opts.content the payload — `config.base`, `config.
|
|
166
|
+
* @param {Object} opts.content the payload — `config.base`, `config.services`
|
|
167
167
|
* @param {Function} [opts.fetch] the transport; defaults to the global `fetch`
|
|
168
168
|
* @param {boolean} [opts.dev]
|
|
169
169
|
* @returns {Promise<Array<{ config: Object, outcome: 'fetched'|'failed'|'skipped', data: any, error?: string }>>}
|
|
@@ -178,7 +178,7 @@ export async function executeFetchConfigs(configs, { content, fetch = null, dev
|
|
|
178
178
|
fetch,
|
|
179
179
|
})
|
|
180
180
|
const ctx = { website: null }
|
|
181
|
-
// Dispatched together, not one after another:
|
|
181
|
+
// Dispatched together, not one after another: the records service batches the
|
|
182
182
|
// requests issued in one tick into one POST, and a page's configs are
|
|
183
183
|
// independent of each other. Order is preserved in the result.
|
|
184
184
|
return Promise.all((configs || []).filter(Boolean).map(async (config) => {
|
package/src/ssr-renderer.js
CHANGED
|
@@ -18,6 +18,7 @@ import React from 'react'
|
|
|
18
18
|
import { renderToString } from 'react-dom/server'
|
|
19
19
|
import { createUniweb, resolveDefaultLocale } from '@uniweb/core'
|
|
20
20
|
import { sectionDomId } from '@uniweb/core/section-id'
|
|
21
|
+
import { siteUrl, withOpacity } from './background-shared.js'
|
|
21
22
|
import { routePatternToRegex } from '@uniweb/core/route-match'
|
|
22
23
|
import { DEFAULT_ICON_BASE, iconUrl } from '@uniweb/core/icon-corpus'
|
|
23
24
|
import { buildSectionOverrides, FONT_LINKS_MARKER } from '@uniweb/theming'
|
|
@@ -86,37 +87,6 @@ export function getWrapperProps(block) {
|
|
|
86
87
|
return { id: sectionDomId(block), style, className, background }
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
/**
|
|
90
|
-
* Convert hex/rgb color to rgba with opacity.
|
|
91
|
-
* Mirrors withOpacity() in Background.jsx.
|
|
92
|
-
*/
|
|
93
|
-
function withOpacity(color, opacity) {
|
|
94
|
-
if (color.startsWith('#')) {
|
|
95
|
-
const r = parseInt(color.slice(1, 3), 16)
|
|
96
|
-
const g = parseInt(color.slice(3, 5), 16)
|
|
97
|
-
const b = parseInt(color.slice(5, 7), 16)
|
|
98
|
-
return `rgba(${r}, ${g}, ${b}, ${opacity})`
|
|
99
|
-
}
|
|
100
|
-
if (color.startsWith('rgb')) {
|
|
101
|
-
const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/)
|
|
102
|
-
if (match) {
|
|
103
|
-
return `rgba(${match[1]}, ${match[2]}, ${match[3]}, ${opacity})`
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return color
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Resolve a URL against the site's base path.
|
|
111
|
-
* Mirrors resolveUrl() in Background.jsx.
|
|
112
|
-
*/
|
|
113
|
-
function resolveUrl(url) {
|
|
114
|
-
if (!url || !url.startsWith('/')) return url
|
|
115
|
-
const basePath = globalThis.uniweb?.activeWebsite?.basePath || ''
|
|
116
|
-
if (!basePath) return url
|
|
117
|
-
if (url.startsWith(basePath + '/') || url === basePath) return url
|
|
118
|
-
return basePath + url
|
|
119
|
-
}
|
|
120
90
|
|
|
121
91
|
/**
|
|
122
92
|
* Render a background element for SSR.
|
|
@@ -189,7 +159,7 @@ export function renderBackground(background) {
|
|
|
189
159
|
style: {
|
|
190
160
|
position: 'absolute',
|
|
191
161
|
inset: '0',
|
|
192
|
-
backgroundImage: `url(${
|
|
162
|
+
backgroundImage: `url(${siteUrl(img.src)})`,
|
|
193
163
|
backgroundPosition: img.position || 'center',
|
|
194
164
|
backgroundSize: img.size || 'cover',
|
|
195
165
|
backgroundRepeat: 'no-repeat',
|
package/src/ssr.js
CHANGED
|
@@ -58,7 +58,7 @@ export {
|
|
|
58
58
|
|
|
59
59
|
// Server-side prefetch — the runtime executing a page's fetches for a host, so an isolate
|
|
60
60
|
// receives `fetchedData` computed by our fetcher and the host carries no copy of it.
|
|
61
|
-
// [Diego, 2026-09-03]: the backend sets
|
|
61
|
+
// [Diego, 2026-09-03]: the backend sets the records service; the fetch comes from the runtime.
|
|
62
62
|
export {
|
|
63
63
|
findPageForRoute,
|
|
64
64
|
resolvePageFetchConfigs,
|
|
@@ -72,6 +72,13 @@ export {
|
|
|
72
72
|
// what it deliberately leaves to the host.
|
|
73
73
|
export { createPageRenderer, prefetchAndHydrate } from './page-renderer.js'
|
|
74
74
|
|
|
75
|
+
// The whole corpus, rather than one page — for a host that indexes a site or
|
|
76
|
+
// derives something over every record its queries return. It asks through the
|
|
77
|
+
// same client and the same composition a page render uses, which is the point:
|
|
78
|
+
// an index that composed its own questions could offer a result whose page then
|
|
79
|
+
// renders empty. The host supplies only the transport.
|
|
80
|
+
export { collectSiteRecords } from './collect-records.js'
|
|
81
|
+
|
|
75
82
|
// Appearance. injectPageContent() already emits this for every prerendered
|
|
76
83
|
// page; exported for lanes that assemble a shell without a per-page render.
|
|
77
84
|
export { renderAppearanceBootScript } from './appearance.js'
|