@uniweb/runtime 0.26.4 → 0.26.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 +67 -4
- package/dist/ssr.js.map +1 -1
- package/package.json +3 -3
- package/src/isolate-api.js +2 -0
- package/src/load-page-data.js +138 -0
- package/src/page-renderer.js +17 -5
- package/src/prefetch.js +11 -7
- package/src/ssr-renderer.js +13 -2
- package/src/ssr.js +12 -2
package/dist/ssr.js
CHANGED
|
@@ -9,8 +9,8 @@ import { DEFAULT_ICON_BASE, iconUrl } from "@uniweb/core/icon-corpus";
|
|
|
9
9
|
import { buildTheme, FONT_LINKS_MARKER, buildSectionOverrides } from "@uniweb/theming";
|
|
10
10
|
import "@uniweb/core/services";
|
|
11
11
|
import "@uniweb/core/tracker";
|
|
12
|
+
import DataStore, { deriveCacheKey as deriveCacheKey$1 } from "@uniweb/core/datastore";
|
|
12
13
|
import { pageRouteQuery, siteReaches, fetchEntries, resolveFetchConfigs, currentFor, othersView, routeSelection } from "@uniweb/core/fetch-config";
|
|
13
|
-
import { deriveCacheKey as deriveCacheKey$1 } from "@uniweb/core/datastore";
|
|
14
14
|
import { buildDetailConfig } from "@uniweb/core/detail-url";
|
|
15
15
|
import { resolveDefaultLocale as resolveDefaultLocale$1 } from "@uniweb/core/locale-config";
|
|
16
16
|
import { findLayoutEntry } from "@uniweb/core/layout-name";
|
|
@@ -668,8 +668,9 @@ function initPrerender(content, foundation, extensionsOrOptions, maybeOptions) {
|
|
|
668
668
|
const website = uniweb.activeWebsite;
|
|
669
669
|
uniweb.routingComponents = {
|
|
670
670
|
useLocation: () => {
|
|
671
|
-
const route = website?.activePage?.route || "";
|
|
672
|
-
|
|
671
|
+
const route = website?.activePage?.route || "/";
|
|
672
|
+
const pathname = route.startsWith("/") ? route : `/${route}`;
|
|
673
|
+
return { pathname, search: "", hash: "", state: null, key: "default" };
|
|
673
674
|
},
|
|
674
675
|
useParams: () => ({}),
|
|
675
676
|
useNavigate: () => () => {
|
|
@@ -1142,6 +1143,67 @@ function safeParseJSON(text) {
|
|
|
1142
1143
|
return void 0;
|
|
1143
1144
|
}
|
|
1144
1145
|
}
|
|
1146
|
+
function blocksOf(page) {
|
|
1147
|
+
const out = [];
|
|
1148
|
+
const walk = (list) => {
|
|
1149
|
+
for (const block of list || []) {
|
|
1150
|
+
if (!block) continue;
|
|
1151
|
+
out.push(block);
|
|
1152
|
+
walk(block.childBlocks);
|
|
1153
|
+
walk(block.insets);
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
walk(page.getBodyBlocks?.() ?? page.bodyBlocks);
|
|
1157
|
+
for (const area of Object.values(page.getLayoutAreas?.() ?? {})) walk(area);
|
|
1158
|
+
return out;
|
|
1159
|
+
}
|
|
1160
|
+
async function loadPageData({ website, route, fetch: fetch2, dev = false, locale = null, prerender = "always" }) {
|
|
1161
|
+
if (prerender !== "author" && prerender !== "always") {
|
|
1162
|
+
throw new Error(`loadPageData: prerender must be 'author' or 'always', got ${JSON.stringify(prerender)}`);
|
|
1163
|
+
}
|
|
1164
|
+
const active = website?.getActiveLocale?.() ?? null;
|
|
1165
|
+
if (locale && active && locale !== active) {
|
|
1166
|
+
throw new Error(
|
|
1167
|
+
`loadPageData: this Website renders ${JSON.stringify(active)} and the caller asked for ${JSON.stringify(locale)}. A Website is locale-sliced — build one per locale (\`initPrerenderForLocale\`) rather than asking this step for another language.`
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
const resolved = typeof route === "string" ? resolvePage(website, route) : route;
|
|
1171
|
+
if (!resolved) return [];
|
|
1172
|
+
const page = typeof resolved.getRenderableSelf === "function" ? resolved.getRenderableSelf() : resolved;
|
|
1173
|
+
if (typeof page.getBodyBlocks !== "function") {
|
|
1174
|
+
throw new Error("loadPageData: `route` must be a route or a Page from this Website — page data is not enough to say what its render reads.");
|
|
1175
|
+
}
|
|
1176
|
+
const dispatcher = website.dispatcherFor({
|
|
1177
|
+
dataStore: new DataStore(),
|
|
1178
|
+
defaultFetcher: createDefaultFetcher({ basePath: website.config?.base || "", dev, fetch: fetch2 })
|
|
1179
|
+
});
|
|
1180
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1181
|
+
const record = (request, entry) => {
|
|
1182
|
+
const key = deriveCacheKey$1(request);
|
|
1183
|
+
if (!entries.has(key)) entries.set(key, entry);
|
|
1184
|
+
};
|
|
1185
|
+
const recording = {
|
|
1186
|
+
peek: (request, ctx) => dispatcher.peek(request, ctx),
|
|
1187
|
+
peekRecord: (id) => dispatcher.peekRecord(id),
|
|
1188
|
+
dispatch: async (request, ctx) => {
|
|
1189
|
+
if (prerender === "author" && request?.prerender === false) {
|
|
1190
|
+
record(request, { config: request, outcome: "skipped", data: null });
|
|
1191
|
+
return { data: null };
|
|
1192
|
+
}
|
|
1193
|
+
const result = await dispatcher.dispatch(request, ctx);
|
|
1194
|
+
record(request, result?.error ? { config: request, outcome: "failed", data: null, error: result.error } : { config: request, outcome: "fetched", data: result?.data ?? null, ...result?.meta ? { meta: result.meta } : {} });
|
|
1195
|
+
return result;
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
const store = website.entityStore;
|
|
1199
|
+
await Promise.all([
|
|
1200
|
+
// The page's own record: asked whether or not a section declares the route key, because the
|
|
1201
|
+
// page names itself from it and a URL naming no record is a 404.
|
|
1202
|
+
store.fetchPageRecord(page, { dispatcher: recording }),
|
|
1203
|
+
...blocksOf(page).map((block) => store.fetch(block, getComponentMeta(block.type), { dispatcher: recording }))
|
|
1204
|
+
]);
|
|
1205
|
+
return [...entries.values()];
|
|
1206
|
+
}
|
|
1145
1207
|
function parentPageOf(page, pages) {
|
|
1146
1208
|
const byRoute = new Map(pages.filter((p) => p?.route).map((p) => [p.route, p]));
|
|
1147
1209
|
const route = parentRouteOf(page.route, { declared: page.parent ?? null, has: (r) => byRoute.has(r) });
|
|
@@ -1275,7 +1337,7 @@ async function prefetchAndHydrate({ website, content, route, locale = null, fetc
|
|
|
1275
1337
|
"prefetchAndHydrate: `fetch` must be a function. A transport does not survive a JSON-serialized isolate boundary — pass it as an RPC method argument. To use the ambient fetch deliberately, pass `fetch: globalThis.fetch`."
|
|
1276
1338
|
);
|
|
1277
1339
|
}
|
|
1278
|
-
const fetched = await
|
|
1340
|
+
const fetched = await loadPageData({ website, route, fetch: fetch2, dev, locale, prerender });
|
|
1279
1341
|
hydrateDataStore(website, fetched);
|
|
1280
1342
|
return fetched;
|
|
1281
1343
|
}
|
|
@@ -1328,6 +1390,7 @@ export {
|
|
|
1328
1390
|
initPrerender,
|
|
1329
1391
|
initPrerenderForLocale,
|
|
1330
1392
|
injectPageContent,
|
|
1393
|
+
loadPageData,
|
|
1331
1394
|
prefetchAndHydrate,
|
|
1332
1395
|
prefetchIcons,
|
|
1333
1396
|
prefetchPageData,
|