@uniweb/runtime 1.4.3 → 1.4.4
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 +63 -22
- package/dist/ssr.js.map +1 -1
- package/package.json +1 -1
- package/src/load-page-data.js +11 -5
- package/src/page-icons.js +111 -38
package/dist/ssr.js
CHANGED
|
@@ -1220,6 +1220,12 @@ function parseIconReference(ref) {
|
|
|
1220
1220
|
const library = ref.slice(0, dash);
|
|
1221
1221
|
return ICON_FAMILY_MAP[library] ? { library, name: ref.slice(dash + 1) } : null;
|
|
1222
1222
|
}
|
|
1223
|
+
const ICON_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1224
|
+
function iconValue(value) {
|
|
1225
|
+
if (value.length > 64) return null;
|
|
1226
|
+
const ref = parseIconReference(value);
|
|
1227
|
+
return ref && ICON_FAMILY_MAP[ref.library.toLowerCase()] && ICON_NAME.test(ref.name) ? ref : null;
|
|
1228
|
+
}
|
|
1223
1229
|
function visit(node, found) {
|
|
1224
1230
|
if (!node || typeof node !== "object") return;
|
|
1225
1231
|
if (node.type === "image" && node.attrs?.role === "icon") found.push(node.attrs);
|
|
@@ -1229,9 +1235,18 @@ function visit(node, found) {
|
|
|
1229
1235
|
}
|
|
1230
1236
|
if (Array.isArray(node.content)) for (const child of node.content) visit(child, found);
|
|
1231
1237
|
}
|
|
1232
|
-
function
|
|
1233
|
-
|
|
1234
|
-
|
|
1238
|
+
function visitValue(value, found, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1239
|
+
if (typeof value === "string") {
|
|
1240
|
+
const ref = iconValue(value);
|
|
1241
|
+
if (ref) found.push(ref);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
1245
|
+
seen.add(value);
|
|
1246
|
+
if (value.type === "image" && value.attrs?.role === "icon") found.push(value.attrs);
|
|
1247
|
+
for (const child of Array.isArray(value) ? value : Object.values(value)) visitValue(child, found, seen);
|
|
1248
|
+
}
|
|
1249
|
+
function addressed(named) {
|
|
1235
1250
|
const icons = /* @__PURE__ */ new Map();
|
|
1236
1251
|
for (const { library, name } of named) {
|
|
1237
1252
|
const family = ICON_FAMILY_MAP[String(library).toLowerCase()];
|
|
@@ -1239,27 +1254,51 @@ function pageIcons(blocks) {
|
|
|
1239
1254
|
}
|
|
1240
1255
|
return icons;
|
|
1241
1256
|
}
|
|
1242
|
-
|
|
1257
|
+
function pageIcons(blocks) {
|
|
1258
|
+
const named = [];
|
|
1259
|
+
for (const block of blocks) visit(block.rawContent?.doc ?? block.rawContent, named);
|
|
1260
|
+
for (const block of blocks) {
|
|
1261
|
+
visitValue(block.properties, named);
|
|
1262
|
+
visitValue(getComponentMeta(block.type)?.defaults, named);
|
|
1263
|
+
visitValue(block.heldData, named);
|
|
1264
|
+
}
|
|
1265
|
+
return addressed(named);
|
|
1266
|
+
}
|
|
1267
|
+
function dataIcons(values) {
|
|
1268
|
+
const named = [];
|
|
1269
|
+
visitValue(values, named);
|
|
1270
|
+
return addressed(named);
|
|
1271
|
+
}
|
|
1272
|
+
function iconRequests({ website, fetch: fetch2, cache }) {
|
|
1243
1273
|
const config = website.config?.icons;
|
|
1244
|
-
if (config?.cdn === false) return;
|
|
1245
1274
|
const base = config?.base || DEFAULT_ICON_BASE;
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
if (
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1275
|
+
const asked = /* @__PURE__ */ new Set();
|
|
1276
|
+
return async function ask(icons) {
|
|
1277
|
+
if (config?.cdn === false) return;
|
|
1278
|
+
const wanted = [];
|
|
1279
|
+
for (const [key, address] of icons) {
|
|
1280
|
+
if (asked.size === MAX_ICON_REQUESTS) break;
|
|
1281
|
+
if (cache.has(key) || asked.has(key)) continue;
|
|
1282
|
+
asked.add(key);
|
|
1283
|
+
wanted.push([key, address]);
|
|
1255
1284
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1285
|
+
if (wanted.length === 0) return;
|
|
1286
|
+
const all = Promise.all(wanted.map(async ([key, { family, name }]) => {
|
|
1287
|
+
try {
|
|
1288
|
+
const response = await fetch2(iconUrl(family, name, base), { method: "GET" });
|
|
1289
|
+
if (!response.ok) return;
|
|
1290
|
+
const svg = await response.text();
|
|
1291
|
+
if (/<svg[\s>]/i.test(svg)) cache.set(key, svg);
|
|
1292
|
+
} catch {
|
|
1293
|
+
}
|
|
1294
|
+
}));
|
|
1295
|
+
let timer;
|
|
1296
|
+
const waited = new Promise((resolve) => {
|
|
1297
|
+
timer = setTimeout(resolve, ICON_WAIT_MS);
|
|
1298
|
+
});
|
|
1299
|
+
await Promise.race([all, waited]);
|
|
1300
|
+
clearTimeout(timer);
|
|
1301
|
+
};
|
|
1263
1302
|
}
|
|
1264
1303
|
function whileReadingIcons(uniweb, read, draw) {
|
|
1265
1304
|
const cache = uniweb?.iconCache;
|
|
@@ -1328,13 +1367,15 @@ async function loadPageData({ website, route, fetch: fetch2, dev = false, locale
|
|
|
1328
1367
|
};
|
|
1329
1368
|
const store = website.entityStore;
|
|
1330
1369
|
const blocks = blocksOf(page);
|
|
1370
|
+
const askIcons = icons && iconCache ? iconRequests({ website, fetch: fetch2, cache: iconCache }) : null;
|
|
1331
1371
|
await Promise.all([
|
|
1332
1372
|
// The page's own record: asked whether or not a section declares the route key, because the
|
|
1333
1373
|
// page names itself from it and a URL naming no record is a 404.
|
|
1334
1374
|
store.fetchPageRecord(page, { dispatcher: recording }),
|
|
1335
1375
|
...blocks.map((block) => store.fetch(block, getComponentMeta(block.type), { dispatcher: recording })),
|
|
1336
|
-
|
|
1376
|
+
askIcons?.(pageIcons(blocks))
|
|
1337
1377
|
]);
|
|
1378
|
+
if (askIcons) await askIcons(dataIcons([...entries.values()].map((entry) => entry.data)));
|
|
1338
1379
|
return [...entries.values()];
|
|
1339
1380
|
}
|
|
1340
1381
|
function createPageRenderer({ website, shell }) {
|