@riebeckite/honox 0.0.31 → 0.0.33
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/index.js +534 -134
- package/dist/server.js +6 -0
- package/dist/src/asset_entries.d.ts +2 -1
- package/dist/src/client_module.d.ts +1 -1
- package/dist/src/content_assets.d.ts +1 -1
- package/dist/src/content_watch.d.ts +2 -1
- package/dist/src/endpoints.d.ts +1 -1
- package/dist/src/ssg/output_cache.d.ts +2 -2
- package/dist/src/ssg/types.d.ts +3 -2
- package/dist/src/ui/primitives.d.ts +36 -18
- package/dist/src/ui/primitives.js +229 -2
- package/dist/src/vite_runner.d.ts +3 -2
- package/package.json +10 -8
- package/style.css +249 -0
package/dist/index.js
CHANGED
|
@@ -293,20 +293,17 @@ import {
|
|
|
293
293
|
// src/content_assets.ts
|
|
294
294
|
import fs5 from "node:fs/promises";
|
|
295
295
|
import path7 from "node:path";
|
|
296
|
-
import {
|
|
297
|
-
|
|
298
|
-
isImagePath as isImagePath2,
|
|
299
|
-
normalizeContentPath as normalizeContentPath2
|
|
300
|
-
} from "@riebeckite/core";
|
|
296
|
+
import { isImagePath as isImagePath2, normalizeContentPath as normalizeContentPath2 } from "@riebeckite/core";
|
|
297
|
+
import { isIgnoredContentPath as isIgnoredContentPath2 } from "@riebeckite/node";
|
|
301
298
|
|
|
302
299
|
// src/content_watch.ts
|
|
303
300
|
import path6 from "node:path";
|
|
304
301
|
import {
|
|
305
302
|
isAttachmentPath,
|
|
306
|
-
isIgnoredContentPath,
|
|
307
303
|
isImagePath,
|
|
308
304
|
normalizeContentPath
|
|
309
305
|
} from "@riebeckite/core";
|
|
306
|
+
import { isIgnoredContentPath } from "@riebeckite/node";
|
|
310
307
|
|
|
311
308
|
// src/runtime_modules.ts
|
|
312
309
|
var riebeckiteConfigModuleId = "virtual:riebeckite/config";
|
|
@@ -355,11 +352,15 @@ export const config = resolveHonoxConfig(
|
|
|
355
352
|
}
|
|
356
353
|
function createContentModule() {
|
|
357
354
|
return `import { ContentManager } from "@riebeckite/core";
|
|
355
|
+
import { FileSystemContentSource } from "@riebeckite/node";
|
|
358
356
|
import { config } from ${JSON.stringify(riebeckiteConfigModuleId)};
|
|
359
357
|
|
|
360
358
|
export const content = new ContentManager(
|
|
361
|
-
config.content.
|
|
362
|
-
|
|
359
|
+
config.content.source ?? new FileSystemContentSource(
|
|
360
|
+
config.content.directory,
|
|
361
|
+
config.content.exclude,
|
|
362
|
+
),
|
|
363
|
+
[],
|
|
363
364
|
{ config, plugins: config.plugins },
|
|
364
365
|
);
|
|
365
366
|
`;
|
|
@@ -996,7 +997,7 @@ async function writeSsgOutputMetrics(metrics) {
|
|
|
996
997
|
}
|
|
997
998
|
|
|
998
999
|
// src/ssg/output_cache.ts
|
|
999
|
-
var
|
|
1000
|
+
var outputCacheValidationConcurrency = 12;
|
|
1000
1001
|
function decideOutputCacheRejection(decision) {
|
|
1001
1002
|
if (!decision.changeSetPresent) return "change-set-unavailable";
|
|
1002
1003
|
if (decision.changeSetRequiresFullRegeneration)
|
|
@@ -1112,7 +1113,6 @@ async function saveOutputCache(path11, state, outputDirectory, timingsMs) {
|
|
|
1112
1113
|
const entriesPath = outputCacheEntriesPath(path11);
|
|
1113
1114
|
const temporaryPath = `${path11}.${randomUUID2()}.tmp`;
|
|
1114
1115
|
try {
|
|
1115
|
-
await waitForFaultInjection("metadata-save-start");
|
|
1116
1116
|
const outputs = await measure(
|
|
1117
1117
|
timingsMs,
|
|
1118
1118
|
"outputCacheEntriesWrite",
|
|
@@ -1140,7 +1140,6 @@ async function saveOutputCache(path11, state, outputDirectory, timingsMs) {
|
|
|
1140
1140
|
"outputCacheRename",
|
|
1141
1141
|
() => replaceFile(temporaryPath, path11)
|
|
1142
1142
|
);
|
|
1143
|
-
await waitForFaultInjection("metadata-committed");
|
|
1144
1143
|
const checksum = createHash3("sha256").update(serialized).digest("hex");
|
|
1145
1144
|
if (state.finalOutputInventory && state.configFile) {
|
|
1146
1145
|
await saveFastPathCache(
|
|
@@ -1167,7 +1166,7 @@ function isOutputCacheState(value) {
|
|
|
1167
1166
|
}
|
|
1168
1167
|
function isOutputInventory(value) {
|
|
1169
1168
|
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.entries(value).every(
|
|
1170
|
-
([
|
|
1169
|
+
([outputPath2, checksum]) => isSafeLogicalOutputPath(outputPath2) && isChecksum(checksum)
|
|
1171
1170
|
);
|
|
1172
1171
|
}
|
|
1173
1172
|
function isOutputCacheEntries(value) {
|
|
@@ -1175,7 +1174,7 @@ function isOutputCacheEntries(value) {
|
|
|
1175
1174
|
return false;
|
|
1176
1175
|
}
|
|
1177
1176
|
return Object.entries(value).every(
|
|
1178
|
-
([
|
|
1177
|
+
([outputPath2, entry]) => isSafeLogicalOutputPath(outputPath2) && typeof entry === "object" && entry !== null && typeof entry.cachePath === "string" && entry.cachePath === outputCacheEntryName(outputPath2) && isChecksum(entry.checksum)
|
|
1179
1178
|
);
|
|
1180
1179
|
}
|
|
1181
1180
|
function outputCacheEntriesPath(outputCachePath) {
|
|
@@ -1184,31 +1183,30 @@ function outputCacheEntriesPath(outputCachePath) {
|
|
|
1184
1183
|
async function saveOutputCacheEntries(directory, outputDirectory, outputs, finalOutputInventory, timingsMs) {
|
|
1185
1184
|
await ensureOutputCacheEntriesDirectory(directory);
|
|
1186
1185
|
const entries = {};
|
|
1187
|
-
for (const
|
|
1188
|
-
assertSafeLogicalOutputPath(
|
|
1189
|
-
const existing = outputs[
|
|
1186
|
+
for (const outputPath2 of Object.keys(outputs).sort()) {
|
|
1187
|
+
assertSafeLogicalOutputPath(outputPath2);
|
|
1188
|
+
const existing = outputs[outputPath2];
|
|
1190
1189
|
if (existing.cachePath && existing.checksum) {
|
|
1191
|
-
if (existing.cachePath !== outputCacheEntryName(
|
|
1192
|
-
throw new Error(`Invalid SSG output cache entry: ${
|
|
1190
|
+
if (existing.cachePath !== outputCacheEntryName(outputPath2) || !isChecksum(existing.checksum)) {
|
|
1191
|
+
throw new Error(`Invalid SSG output cache entry: ${outputPath2}`);
|
|
1193
1192
|
}
|
|
1194
|
-
entries[
|
|
1193
|
+
entries[outputPath2] = existing;
|
|
1195
1194
|
continue;
|
|
1196
1195
|
}
|
|
1197
|
-
const source = resolveOutputCacheFile(outputDirectory,
|
|
1198
|
-
const cachePath = outputCacheEntryName(
|
|
1196
|
+
const source = resolveOutputCacheFile(outputDirectory, outputPath2);
|
|
1197
|
+
const cachePath = outputCacheEntryName(outputPath2);
|
|
1199
1198
|
const destination = join3(directory, cachePath);
|
|
1200
|
-
await waitForFaultInjection("entry-create-start");
|
|
1201
1199
|
await replaceOutputCacheEntry(source, destination, timingsMs);
|
|
1202
|
-
const checksum = finalOutputInventory?.[
|
|
1200
|
+
const checksum = finalOutputInventory?.[outputPath2];
|
|
1203
1201
|
if (!checksum) {
|
|
1204
1202
|
const cachedChecksum = await checksumFile(destination);
|
|
1205
1203
|
if (!cachedChecksum) {
|
|
1206
|
-
throw new Error(`Could not checksum cached output: ${
|
|
1204
|
+
throw new Error(`Could not checksum cached output: ${outputPath2}`);
|
|
1207
1205
|
}
|
|
1208
|
-
entries[
|
|
1206
|
+
entries[outputPath2] = { cachePath, checksum: cachedChecksum };
|
|
1209
1207
|
continue;
|
|
1210
1208
|
}
|
|
1211
|
-
entries[
|
|
1209
|
+
entries[outputPath2] = { cachePath, checksum };
|
|
1212
1210
|
}
|
|
1213
1211
|
return entries;
|
|
1214
1212
|
}
|
|
@@ -1216,20 +1214,43 @@ async function validateOutputCacheEntries(outputCachePath, entries, timingsMs) {
|
|
|
1216
1214
|
try {
|
|
1217
1215
|
const directory = outputCacheEntriesPath(outputCachePath);
|
|
1218
1216
|
if (!await isSafeOutputCacheEntriesDirectory(directory)) return false;
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1217
|
+
const entriesToValidate = Object.entries(entries);
|
|
1218
|
+
let nextEntryIndex = 0;
|
|
1219
|
+
let valid = true;
|
|
1220
|
+
const validateEntry = async () => {
|
|
1221
|
+
while (valid) {
|
|
1222
|
+
const next = entriesToValidate[nextEntryIndex++];
|
|
1223
|
+
if (!next) return;
|
|
1224
|
+
const [outputPath2, entry] = next;
|
|
1225
|
+
if (!isSafeLogicalOutputPath(outputPath2) || entry.cachePath !== outputCacheEntryName(outputPath2) || !isChecksum(entry.checksum)) {
|
|
1226
|
+
valid = false;
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const path11 = resolveOutputCacheFile(directory, entry.cachePath);
|
|
1230
|
+
if (!await isRegularFile(path11)) {
|
|
1231
|
+
valid = false;
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
if (await measure(
|
|
1235
|
+
timingsMs,
|
|
1236
|
+
"outputCacheEntryChecksum",
|
|
1237
|
+
() => checksumFile(path11)
|
|
1238
|
+
) !== entry.checksum)
|
|
1239
|
+
valid = false;
|
|
1222
1240
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1241
|
+
};
|
|
1242
|
+
await Promise.all(
|
|
1243
|
+
Array.from(
|
|
1244
|
+
{
|
|
1245
|
+
length: Math.min(
|
|
1246
|
+
outputCacheValidationConcurrency,
|
|
1247
|
+
entriesToValidate.length
|
|
1248
|
+
)
|
|
1249
|
+
},
|
|
1250
|
+
validateEntry
|
|
1251
|
+
)
|
|
1252
|
+
);
|
|
1253
|
+
return valid;
|
|
1233
1254
|
} catch {
|
|
1234
1255
|
return false;
|
|
1235
1256
|
}
|
|
@@ -1263,7 +1284,6 @@ async function saveFastPathCache(path11, state, timingsMs) {
|
|
|
1263
1284
|
}
|
|
1264
1285
|
const temporaryPath = `${path11}.${randomUUID2()}.tmp`;
|
|
1265
1286
|
try {
|
|
1266
|
-
await waitForFaultInjection("sidecar-save-start");
|
|
1267
1287
|
await measure(
|
|
1268
1288
|
timingsMs,
|
|
1269
1289
|
"sidecarWrite",
|
|
@@ -1275,7 +1295,6 @@ async function saveFastPathCache(path11, state, timingsMs) {
|
|
|
1275
1295
|
"sidecarRename",
|
|
1276
1296
|
() => replaceFile(temporaryPath, path11)
|
|
1277
1297
|
);
|
|
1278
|
-
await waitForFaultInjection("sidecar-committed");
|
|
1279
1298
|
} catch (error) {
|
|
1280
1299
|
await rm2(temporaryPath, { force: true }).catch(() => void 0);
|
|
1281
1300
|
throw error;
|
|
@@ -1358,8 +1377,8 @@ function assertSafeLogicalOutputPath(path11) {
|
|
|
1358
1377
|
throw new Error(`Invalid SSG output path: ${path11}`);
|
|
1359
1378
|
}
|
|
1360
1379
|
}
|
|
1361
|
-
function outputCacheEntryName(
|
|
1362
|
-
return createHash3("sha256").update(
|
|
1380
|
+
function outputCacheEntryName(outputPath2) {
|
|
1381
|
+
return createHash3("sha256").update(outputPath2).digest("hex");
|
|
1363
1382
|
}
|
|
1364
1383
|
function isChecksum(value) {
|
|
1365
1384
|
return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
|
|
@@ -1407,19 +1426,16 @@ async function replaceOutputCacheEntry(source, destination, timingsMs) {
|
|
|
1407
1426
|
"outputCacheEntryWrite",
|
|
1408
1427
|
() => writeFile2(temporaryPath, new Uint8Array())
|
|
1409
1428
|
);
|
|
1410
|
-
await waitForFaultInjection("entry-body-write");
|
|
1411
1429
|
await measure(
|
|
1412
1430
|
timingsMs,
|
|
1413
1431
|
"outputCacheEntryCopy",
|
|
1414
1432
|
() => copyFile(source, temporaryPath)
|
|
1415
1433
|
);
|
|
1416
|
-
await waitForFaultInjection("entry-rename-before");
|
|
1417
1434
|
await measure(
|
|
1418
1435
|
timingsMs,
|
|
1419
1436
|
"outputCacheEntryRename",
|
|
1420
1437
|
() => replaceFile(temporaryPath, destination)
|
|
1421
1438
|
);
|
|
1422
|
-
await waitForFaultInjection("entry-committed");
|
|
1423
1439
|
} catch (error) {
|
|
1424
1440
|
await rm2(temporaryPath, { force: true }).catch(() => void 0);
|
|
1425
1441
|
throw error;
|
|
@@ -1428,7 +1444,6 @@ async function replaceOutputCacheEntry(source, destination, timingsMs) {
|
|
|
1428
1444
|
async function collectUnreferencedOutputCacheEntries(directory, outputs, timingsMs) {
|
|
1429
1445
|
try {
|
|
1430
1446
|
if (!await isSafeOutputCacheEntriesDirectory(directory)) return;
|
|
1431
|
-
await waitForFaultInjection("gc-start");
|
|
1432
1447
|
const referenced = new Set(
|
|
1433
1448
|
Object.values(outputs).map((entry) => entry.cachePath)
|
|
1434
1449
|
);
|
|
@@ -1443,7 +1458,6 @@ async function collectUnreferencedOutputCacheEntries(directory, outputs, timings
|
|
|
1443
1458
|
}
|
|
1444
1459
|
const path11 = join3(directory, entry.name);
|
|
1445
1460
|
if (await isRegularFile(path11)) {
|
|
1446
|
-
await waitForFaultInjection("gc-entry-delete");
|
|
1447
1461
|
await measure(
|
|
1448
1462
|
timingsMs,
|
|
1449
1463
|
"outputCacheGcDelete",
|
|
@@ -1455,25 +1469,6 @@ async function collectUnreferencedOutputCacheEntries(directory, outputs, timings
|
|
|
1455
1469
|
return;
|
|
1456
1470
|
}
|
|
1457
1471
|
}
|
|
1458
|
-
async function waitForFaultInjection(point) {
|
|
1459
|
-
if (process.env.NODE_ENV !== "test" || process.env.RIEBECKITE_SSG_FAULT_INJECTION !== "1" || process.env.RIEBECKITE_SSG_FAULT_POINT !== point) {
|
|
1460
|
-
return;
|
|
1461
|
-
}
|
|
1462
|
-
const occurrence = Number.parseInt(
|
|
1463
|
-
process.env.RIEBECKITE_SSG_FAULT_OCCURRENCE ?? "1",
|
|
1464
|
-
10
|
|
1465
|
-
);
|
|
1466
|
-
const count = (faultInjectionCounts.get(point) ?? 0) + 1;
|
|
1467
|
-
faultInjectionCounts.set(point, count);
|
|
1468
|
-
if (!Number.isSafeInteger(occurrence) || occurrence < 1 || count !== occurrence)
|
|
1469
|
-
return;
|
|
1470
|
-
const signalFile = process.env.RIEBECKITE_SSG_FAULT_SIGNAL_FILE;
|
|
1471
|
-
if (!signalFile) return;
|
|
1472
|
-
await writeFile2(signalFile, `${point}
|
|
1473
|
-
`, "utf8");
|
|
1474
|
-
await new Promise(() => {
|
|
1475
|
-
});
|
|
1476
|
-
}
|
|
1477
1472
|
|
|
1478
1473
|
// src/ssg_plugin.ts
|
|
1479
1474
|
var defaultEntry = "./src/index.tsx";
|
|
@@ -1543,8 +1538,17 @@ function riebeckiteSsg(options = {}) {
|
|
|
1543
1538
|
...config.resolve,
|
|
1544
1539
|
builtins: [...config.resolve.builtins, /^node:/]
|
|
1545
1540
|
},
|
|
1546
|
-
plugins: [
|
|
1541
|
+
plugins: [
|
|
1542
|
+
{
|
|
1543
|
+
name: "riebeckite-ssg-package-resolution",
|
|
1544
|
+
enforce: "post",
|
|
1545
|
+
configResolved(runtimeConfig) {
|
|
1546
|
+
runtimeConfig.resolve.alias = [];
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
],
|
|
1547
1550
|
build: { ssr: true },
|
|
1551
|
+
oxc: { jsx: { runtime: "automatic", importSource: "hono/jsx" } },
|
|
1548
1552
|
environments: {
|
|
1549
1553
|
ssr: { resolve: { noExternal: [/^honox(?:\/.*)?$/] } }
|
|
1550
1554
|
},
|
|
@@ -1595,7 +1599,7 @@ function riebeckiteSsg(options = {}) {
|
|
|
1595
1599
|
);
|
|
1596
1600
|
viteClientAssetPaths = [
|
|
1597
1601
|
.../* @__PURE__ */ new Set([...viteClientAssetPaths, ...Object.keys(bundle)])
|
|
1598
|
-
].filter((
|
|
1602
|
+
].filter((outputPath2) => !siteOwnedOutputPaths.has(outputPath2)).sort();
|
|
1599
1603
|
const siteOutputCollisions = findBuildOutputSiteCollisions(
|
|
1600
1604
|
Object.keys(bundle),
|
|
1601
1605
|
siteOwnedOutputPaths
|
|
@@ -1924,14 +1928,12 @@ function riebeckiteSsg(options = {}) {
|
|
|
1924
1928
|
"publicFingerprint",
|
|
1925
1929
|
() => fingerprintDirectory(resolve2(publicDir))
|
|
1926
1930
|
) : void 0;
|
|
1927
|
-
await waitForFaultInjection("build-state-before");
|
|
1928
1931
|
await saveOutputCache(
|
|
1929
1932
|
outputCache.path,
|
|
1930
1933
|
outputCache.state,
|
|
1931
1934
|
outputCache.outDir,
|
|
1932
1935
|
outputCache.timingsMs
|
|
1933
1936
|
);
|
|
1934
|
-
await waitForFaultInjection("build-state-committed");
|
|
1935
1937
|
} catch (error) {
|
|
1936
1938
|
this.warn(
|
|
1937
1939
|
`SSG output cache could not be saved; the next build regenerates every output. ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2091,55 +2093,160 @@ function riebeckiteClientModule(getConfig) {
|
|
|
2091
2093
|
}
|
|
2092
2094
|
function createClientModule(config, development) {
|
|
2093
2095
|
const imports = [];
|
|
2094
|
-
const
|
|
2096
|
+
const appInitializers = [];
|
|
2097
|
+
const pageInitializers = [];
|
|
2098
|
+
imports.push('import { ClientLifecycle } from "@riebeckite/core/client";');
|
|
2099
|
+
if (config.spa !== void 0) {
|
|
2100
|
+
imports.push('import { createClient } from "honox/client";');
|
|
2101
|
+
imports.push('import { startSpaNavigation } from "@riebeckite/spa";');
|
|
2102
|
+
}
|
|
2095
2103
|
if (development) {
|
|
2096
2104
|
imports.push(
|
|
2097
2105
|
'import { initDevelopmentInspector } from "virtual:riebeckite/development-inspector";'
|
|
2098
2106
|
);
|
|
2099
|
-
|
|
2107
|
+
appInitializers.push("initDevelopmentInspector()");
|
|
2100
2108
|
}
|
|
2101
2109
|
for (const [index, entry] of config.plugins.flatMap((plugin) => plugin.clientEntries ?? []).entries()) {
|
|
2102
2110
|
const localName = `pluginClientInitializer${index}`;
|
|
2103
2111
|
const importTarget = entry.exportName ? `{ ${entry.exportName} as ${localName} }` : localName;
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2112
|
+
if (entry.presenceSelector === void 0) {
|
|
2113
|
+
imports.push(
|
|
2114
|
+
`import ${importTarget} from ${JSON.stringify(entry.moduleSpecifier)};`
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2107
2117
|
const publicConfig = entry.publicConfig;
|
|
2108
|
-
const
|
|
2118
|
+
const serializedConfig = publicConfig === void 0 ? "undefined" : serializePublicClientConfig(publicConfig);
|
|
2119
|
+
const initializer = entry.initializerArguments === "context" ? `${localName}(context)` : entry.initializerArguments === "root" ? `${localName}(context.root)` : `${localName}(context.config)`;
|
|
2120
|
+
const initializers = entry.scope === "app" ? appInitializers : pageInitializers;
|
|
2121
|
+
if (entry.presenceSelector === void 0) {
|
|
2122
|
+
initializers.push(
|
|
2123
|
+
`mountPluginClientInitializer(${JSON.stringify(entry.scope ?? "page")}, ${JSON.stringify(entry.moduleSpecifier)}, root, ${serializedConfig}, (context) => ${initializer})`
|
|
2124
|
+
);
|
|
2125
|
+
continue;
|
|
2126
|
+
}
|
|
2127
|
+
const dynamicInitializer = entry.initializerArguments === "context" ? `initializer(context)` : entry.initializerArguments === "root" ? `initializer(context.root)` : `initializer(context.config)`;
|
|
2109
2128
|
initializers.push(
|
|
2110
|
-
`
|
|
2129
|
+
`mountConditionalPluginClientInitializer(${JSON.stringify(entry.scope ?? "page")}, ${JSON.stringify(entry.moduleSpecifier)}, root, ${serializedConfig}, ${JSON.stringify(entry.presenceSelector)}, async () => { const { ${entry.exportName ?? "default"}: initializer } = await import(${JSON.stringify(entry.moduleSpecifier)}); return (context) => ${dynamicInitializer}; })`
|
|
2111
2130
|
);
|
|
2112
2131
|
}
|
|
2113
2132
|
return `${imports.join("\n")}
|
|
2114
2133
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2134
|
+
const lifecycle = new ClientLifecycle();
|
|
2135
|
+
let stopSpaNavigation;
|
|
2136
|
+
|
|
2137
|
+
function mountPluginClientInitializer(scope, name, root, config, initialize) {
|
|
2138
|
+
void lifecycle.mount({ scope, name, root, config, initialize });
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
function mountConditionalPluginClientInitializer(scope, name, root, config, presenceSelector, load) {
|
|
2142
|
+
if (!root.querySelector(presenceSelector)) return;
|
|
2143
|
+
void load().then((initialize) => {
|
|
2144
|
+
if ("isConnected" in root && !root.isConnected) return;
|
|
2145
|
+
void lifecycle.mount({ scope, name, root, config, initialize });
|
|
2146
|
+
}, (error) => console.error("[riebeckite] Client initializer module failed: " + name, error));
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
function mountAppClientInitializers(root) {
|
|
2150
|
+
${appInitializers.map((initializer) => ` ${initializer};`).join("\n")}
|
|
2124
2151
|
}
|
|
2125
2152
|
|
|
2126
|
-
function
|
|
2127
|
-
|
|
2153
|
+
function mountPageClientInitializers(root) {
|
|
2154
|
+
${pageInitializers.map((initializer) => ` ${initializer};`).join("\n")}
|
|
2128
2155
|
}
|
|
2129
2156
|
|
|
2130
2157
|
export function initRiebeckiteClient() {
|
|
2131
|
-
|
|
2158
|
+
mountAppClientInitializers(document);
|
|
2159
|
+
mountPageClientInitializers(document.querySelector("#main-content") ?? document);
|
|
2160
|
+
${config.spa === void 0 ? "" : ` stopSpaNavigation ??= startSpaNavigation({
|
|
2161
|
+
...${serializePublicClientConfig(config.spa)},
|
|
2162
|
+
onBeforePageCommit: () => lifecycle.unmount("page"),
|
|
2163
|
+
onPageCommit: async ({ root, signal }) => {
|
|
2164
|
+
if (signal.aborted) return;
|
|
2165
|
+
await createClient();
|
|
2166
|
+
if (signal.aborted || !root.isConnected) return;
|
|
2167
|
+
mountPageClientInitializers(root);
|
|
2168
|
+
},
|
|
2169
|
+
});`}
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
export async function remountRiebeckitePage(root) {
|
|
2173
|
+
await lifecycle.unmount("page");
|
|
2174
|
+
mountPageClientInitializers(root);
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
export async function disposeRiebeckiteClient() {
|
|
2178
|
+
stopSpaNavigation?.();
|
|
2179
|
+
stopSpaNavigation = undefined;
|
|
2180
|
+
await lifecycle.dispose();
|
|
2132
2181
|
}
|
|
2133
2182
|
`;
|
|
2134
2183
|
}
|
|
2135
2184
|
|
|
2136
2185
|
// src/development_inspector.ts
|
|
2137
|
-
import {
|
|
2186
|
+
import {
|
|
2187
|
+
buildOutputPlan as buildOutputPlan2,
|
|
2188
|
+
ContentManager
|
|
2189
|
+
} from "@riebeckite/core";
|
|
2190
|
+
import {
|
|
2191
|
+
collectDevelopmentDiagnostics,
|
|
2192
|
+
diagnoseOutputPlan,
|
|
2193
|
+
sortDevelopmentDiagnostics
|
|
2194
|
+
} from "@riebeckite/diagnostics";
|
|
2195
|
+
import { FileSystemContentSource } from "@riebeckite/node";
|
|
2138
2196
|
var clientModuleId2 = "virtual:riebeckite/development-inspector";
|
|
2139
2197
|
var resolvedClientModuleId2 = `\0${clientModuleId2}`;
|
|
2140
|
-
var
|
|
2198
|
+
var reportPath = "/__riebeckite/inspector/report";
|
|
2199
|
+
var outputPath = "/__riebeckite/inspector/output";
|
|
2200
|
+
var listedOutputLimit = 20;
|
|
2141
2201
|
function riebeckiteDevelopmentInspector(getApplication) {
|
|
2142
2202
|
let revision = 0;
|
|
2203
|
+
let inspection = null;
|
|
2204
|
+
const inspectApplication = (application, currentRevision) => {
|
|
2205
|
+
if (inspection?.revision === currentRevision && inspection.application === application) {
|
|
2206
|
+
return inspection;
|
|
2207
|
+
}
|
|
2208
|
+
if (inspection) {
|
|
2209
|
+
const previous = inspection;
|
|
2210
|
+
const disposePrevious = () => {
|
|
2211
|
+
void previous.dispose().catch(() => {
|
|
2212
|
+
});
|
|
2213
|
+
};
|
|
2214
|
+
void Promise.allSettled([previous.report, previous.output]).then(
|
|
2215
|
+
disposePrevious
|
|
2216
|
+
);
|
|
2217
|
+
inspection = null;
|
|
2218
|
+
}
|
|
2219
|
+
const content = createInspectionContent(application);
|
|
2220
|
+
let disposed = false;
|
|
2221
|
+
const dispose = async () => {
|
|
2222
|
+
if (disposed) return;
|
|
2223
|
+
disposed = true;
|
|
2224
|
+
await content.dispose();
|
|
2225
|
+
};
|
|
2226
|
+
const report = collectDevelopmentDiagnostics({
|
|
2227
|
+
config: application.config,
|
|
2228
|
+
content,
|
|
2229
|
+
revision: currentRevision,
|
|
2230
|
+
includeOutput: false
|
|
2231
|
+
});
|
|
2232
|
+
const output = report.then(
|
|
2233
|
+
() => inspectContentOutputs(content),
|
|
2234
|
+
() => inspectContentOutputs(content)
|
|
2235
|
+
);
|
|
2236
|
+
const entry = {
|
|
2237
|
+
application,
|
|
2238
|
+
revision: currentRevision,
|
|
2239
|
+
report,
|
|
2240
|
+
output,
|
|
2241
|
+
dispose
|
|
2242
|
+
};
|
|
2243
|
+
inspection = entry;
|
|
2244
|
+
void report.catch(() => {
|
|
2245
|
+
if (inspection === entry) inspection = null;
|
|
2246
|
+
void output.then(dispose, dispose);
|
|
2247
|
+
});
|
|
2248
|
+
return entry;
|
|
2249
|
+
};
|
|
2143
2250
|
return {
|
|
2144
2251
|
name: "riebeckite-development-inspector",
|
|
2145
2252
|
apply: "serve",
|
|
@@ -2151,7 +2258,7 @@ function riebeckiteDevelopmentInspector(getApplication) {
|
|
|
2151
2258
|
return id === resolvedClientModuleId2 ? inspectorClientModule() : null;
|
|
2152
2259
|
},
|
|
2153
2260
|
configureServer(server) {
|
|
2154
|
-
const
|
|
2261
|
+
const reportMiddleware = async (request, response) => {
|
|
2155
2262
|
if (!isLocalRequest(request.headers.host, server)) {
|
|
2156
2263
|
response.statusCode = 403;
|
|
2157
2264
|
response.end();
|
|
@@ -2159,25 +2266,16 @@ function riebeckiteDevelopmentInspector(getApplication) {
|
|
|
2159
2266
|
}
|
|
2160
2267
|
try {
|
|
2161
2268
|
const application = getApplication();
|
|
2162
|
-
const report = await
|
|
2163
|
-
config: application.config,
|
|
2164
|
-
revision
|
|
2165
|
-
});
|
|
2269
|
+
const report = await inspectApplication(application, revision).report;
|
|
2166
2270
|
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
2167
2271
|
response.setHeader("cache-control", "no-store");
|
|
2168
|
-
const currentPage = currentPageFromRequest(request.url);
|
|
2169
2272
|
response.end(
|
|
2170
2273
|
JSON.stringify({
|
|
2171
2274
|
...report,
|
|
2172
2275
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2173
|
-
currentPage,
|
|
2276
|
+
currentPage: currentPageFromRequest(request.url),
|
|
2174
2277
|
theme: application.config.theme.name,
|
|
2175
|
-
plugins: application.config.plugins.map((plugin) => plugin.name)
|
|
2176
|
-
capabilities: {
|
|
2177
|
-
dependencies: "unavailable",
|
|
2178
|
-
output: "unavailable",
|
|
2179
|
-
pageMetadata: "unavailable"
|
|
2180
|
-
}
|
|
2278
|
+
plugins: application.config.plugins.map((plugin) => plugin.name)
|
|
2181
2279
|
})
|
|
2182
2280
|
);
|
|
2183
2281
|
} catch {
|
|
@@ -2186,8 +2284,39 @@ function riebeckiteDevelopmentInspector(getApplication) {
|
|
|
2186
2284
|
response.end(JSON.stringify({ code: "INSPECTOR_REPORT_FAILED" }));
|
|
2187
2285
|
}
|
|
2188
2286
|
};
|
|
2189
|
-
|
|
2190
|
-
|
|
2287
|
+
const outputMiddleware = async (request, response) => {
|
|
2288
|
+
if (!isLocalRequest(request.headers.host, server)) {
|
|
2289
|
+
response.statusCode = 403;
|
|
2290
|
+
response.end();
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2293
|
+
try {
|
|
2294
|
+
const application = getApplication();
|
|
2295
|
+
const entry = inspectApplication(application, revision);
|
|
2296
|
+
const result = await entry.output;
|
|
2297
|
+
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
2298
|
+
response.setHeader("cache-control", "no-store");
|
|
2299
|
+
response.end(
|
|
2300
|
+
JSON.stringify({
|
|
2301
|
+
version: 1,
|
|
2302
|
+
revision: entry.revision,
|
|
2303
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2304
|
+
...result,
|
|
2305
|
+
diagnostics: sortDevelopmentDiagnostics(result.diagnostics)
|
|
2306
|
+
})
|
|
2307
|
+
);
|
|
2308
|
+
} catch {
|
|
2309
|
+
response.statusCode = 500;
|
|
2310
|
+
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
2311
|
+
response.end(JSON.stringify({ code: "INSPECTOR_OUTPUT_FAILED" }));
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2314
|
+
server.middlewares.use(reportPath, reportMiddleware);
|
|
2315
|
+
server.middlewares.use(outputPath, outputMiddleware);
|
|
2316
|
+
return () => {
|
|
2317
|
+
prioritizeMiddleware(server, outputMiddleware, outputPath);
|
|
2318
|
+
prioritizeMiddleware(server, reportMiddleware, reportPath);
|
|
2319
|
+
};
|
|
2191
2320
|
},
|
|
2192
2321
|
handleHotUpdate({ server }) {
|
|
2193
2322
|
revision += 1;
|
|
@@ -2195,16 +2324,142 @@ function riebeckiteDevelopmentInspector(getApplication) {
|
|
|
2195
2324
|
}
|
|
2196
2325
|
};
|
|
2197
2326
|
}
|
|
2327
|
+
function createInspectionContent(application) {
|
|
2328
|
+
const { config, contentRoot } = application;
|
|
2329
|
+
return new ContentManager(
|
|
2330
|
+
config.content.source ?? new FileSystemContentSource(contentRoot, config.content.exclude),
|
|
2331
|
+
config.content.exclude,
|
|
2332
|
+
{ config, commitBuildState: false }
|
|
2333
|
+
);
|
|
2334
|
+
}
|
|
2335
|
+
async function inspectContentOutputs(content) {
|
|
2336
|
+
try {
|
|
2337
|
+
const changes = await content.getOutputChangeSet();
|
|
2338
|
+
const plan = buildOutputPlan2({
|
|
2339
|
+
inventory: [...changes.affected, ...changes.unchanged],
|
|
2340
|
+
removed: changes.removed,
|
|
2341
|
+
affectedPaths: new Set(changes.affected.map((output) => output.path)),
|
|
2342
|
+
cacheAvailable: changes.unchanged.length > 0
|
|
2343
|
+
});
|
|
2344
|
+
return {
|
|
2345
|
+
output: inspectOutput(changes, plan),
|
|
2346
|
+
dependencies: inspectDependencies(changes),
|
|
2347
|
+
diagnostics: diagnoseOutputPlan(plan)
|
|
2348
|
+
};
|
|
2349
|
+
} catch {
|
|
2350
|
+
return {
|
|
2351
|
+
output: {
|
|
2352
|
+
status: "unavailable",
|
|
2353
|
+
reason: "output inspection failed"
|
|
2354
|
+
},
|
|
2355
|
+
dependencies: {
|
|
2356
|
+
status: "unavailable",
|
|
2357
|
+
reason: "dependency inspection failed"
|
|
2358
|
+
},
|
|
2359
|
+
diagnostics: []
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
function inspectOutput(changes, plan) {
|
|
2364
|
+
return {
|
|
2365
|
+
status: "available",
|
|
2366
|
+
candidateOutputCount: changes.candidateOutputCount,
|
|
2367
|
+
affectedOutputCount: changes.affectedOutputCount,
|
|
2368
|
+
unchangedOutputCount: changes.unchangedOutputCount,
|
|
2369
|
+
removedOutputCount: changes.removedOutputCount,
|
|
2370
|
+
fullRegenerationRequired: changes.fullRegenerationRequired,
|
|
2371
|
+
conflicts: plan.conflicts.map((conflict) => ({
|
|
2372
|
+
path: conflict.path,
|
|
2373
|
+
owners: conflict.owners
|
|
2374
|
+
})),
|
|
2375
|
+
affected: changes.affected.slice(0, listedOutputLimit).map(listOutput),
|
|
2376
|
+
hiddenAffectedCount: Math.max(
|
|
2377
|
+
0,
|
|
2378
|
+
changes.affected.length - listedOutputLimit
|
|
2379
|
+
),
|
|
2380
|
+
removed: changes.removed.slice(0, listedOutputLimit).map(listOutput),
|
|
2381
|
+
hiddenRemovedCount: Math.max(0, changes.removed.length - listedOutputLimit)
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
function inspectDependencies(changes) {
|
|
2385
|
+
const outputs = [...changes.affected, ...changes.unchanged];
|
|
2386
|
+
const kinds = /* @__PURE__ */ new Map();
|
|
2387
|
+
const listed = [];
|
|
2388
|
+
let dependencyCount = 0;
|
|
2389
|
+
let dependentOutputCount = 0;
|
|
2390
|
+
let unknownOutputCount = 0;
|
|
2391
|
+
let hiddenOutputCount = 0;
|
|
2392
|
+
for (const output of outputs) {
|
|
2393
|
+
for (const dependency of output.dependencies) {
|
|
2394
|
+
dependencyCount += 1;
|
|
2395
|
+
kinds.set(dependency.type, (kinds.get(dependency.type) ?? 0) + 1);
|
|
2396
|
+
}
|
|
2397
|
+
if (output.dependencies.some(({ type }) => type === "unknown")) {
|
|
2398
|
+
unknownOutputCount += 1;
|
|
2399
|
+
}
|
|
2400
|
+
if (output.dependencies.length === 0) continue;
|
|
2401
|
+
dependentOutputCount += 1;
|
|
2402
|
+
if (listed.length < listedOutputLimit) {
|
|
2403
|
+
listed.push({
|
|
2404
|
+
path: output.path,
|
|
2405
|
+
dependencies: output.dependencies.map(dependencyLabel)
|
|
2406
|
+
});
|
|
2407
|
+
} else {
|
|
2408
|
+
hiddenOutputCount += 1;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
return {
|
|
2412
|
+
status: "available",
|
|
2413
|
+
outputCount: outputs.length,
|
|
2414
|
+
dependentOutputCount,
|
|
2415
|
+
dependencyCount,
|
|
2416
|
+
unknownOutputCount,
|
|
2417
|
+
kinds: [...kinds.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([kind, count]) => ({ kind, count })),
|
|
2418
|
+
outputs: listed,
|
|
2419
|
+
hiddenOutputCount
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
function listOutput(output) {
|
|
2423
|
+
return {
|
|
2424
|
+
path: output.path,
|
|
2425
|
+
kind: output.kind,
|
|
2426
|
+
producer: output.producer
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
function dependencyLabel(dependency) {
|
|
2430
|
+
switch (dependency.type) {
|
|
2431
|
+
case "content":
|
|
2432
|
+
return `content:${dependency.slug}`;
|
|
2433
|
+
case "tag":
|
|
2434
|
+
return `tag:${dependency.tag}`;
|
|
2435
|
+
case "folder":
|
|
2436
|
+
return `folder:${dependency.folder}`;
|
|
2437
|
+
case "file":
|
|
2438
|
+
return `file:${dependency.path}`;
|
|
2439
|
+
case "public-location":
|
|
2440
|
+
return `public-location:${dependency.pathname}`;
|
|
2441
|
+
case "projection":
|
|
2442
|
+
return `projection:${dependency.projection}`;
|
|
2443
|
+
case "external":
|
|
2444
|
+
return `external:${dependency.id}`;
|
|
2445
|
+
case "content-query":
|
|
2446
|
+
return `content-query:${dependency.properties.join(",")}${dependency.unknown ? "?" : ""}`;
|
|
2447
|
+
case "global":
|
|
2448
|
+
return "global";
|
|
2449
|
+
case "unknown":
|
|
2450
|
+
return "unknown";
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2198
2453
|
function currentPageFromRequest(url) {
|
|
2199
|
-
const value = new URL(url ??
|
|
2454
|
+
const value = new URL(url ?? reportPath, "http://localhost").searchParams.get(
|
|
2200
2455
|
"path"
|
|
2201
2456
|
);
|
|
2202
|
-
return value
|
|
2457
|
+
return value?.startsWith("/") && !value.startsWith("//") ? value : "/";
|
|
2203
2458
|
}
|
|
2204
|
-
function prioritizeMiddleware(server, middleware) {
|
|
2459
|
+
function prioritizeMiddleware(server, middleware, path11) {
|
|
2205
2460
|
const stack = server.middlewares.stack;
|
|
2206
2461
|
const index = stack?.findIndex(
|
|
2207
|
-
(layer) => layer.handle === middleware || layer.route ===
|
|
2462
|
+
(layer) => layer.handle === middleware || layer.route === path11
|
|
2208
2463
|
) ?? -1;
|
|
2209
2464
|
if (index > 0 && stack) stack.unshift(...stack.splice(index, 1));
|
|
2210
2465
|
}
|
|
@@ -2218,7 +2473,8 @@ function isLocalRequest(host, server) {
|
|
|
2218
2473
|
}
|
|
2219
2474
|
function inspectorClientModule() {
|
|
2220
2475
|
return `
|
|
2221
|
-
const
|
|
2476
|
+
const reportEndpoint = ${JSON.stringify(reportPath)};
|
|
2477
|
+
const outputEndpoint = ${JSON.stringify(outputPath)};
|
|
2222
2478
|
const panelId = "riebeckite-development-inspector";
|
|
2223
2479
|
|
|
2224
2480
|
export function initDevelopmentInspector() {
|
|
@@ -2228,23 +2484,57 @@ export function initDevelopmentInspector() {
|
|
|
2228
2484
|
let generation = 0;
|
|
2229
2485
|
let report;
|
|
2230
2486
|
let activeTab = 0;
|
|
2487
|
+
let refreshing = false;
|
|
2488
|
+
let pendingRefresh = false;
|
|
2489
|
+
let loadingTimer;
|
|
2231
2490
|
const tabs = ["Overview", "Diagnostics", "Dependencies", "Plugins", "Output"];
|
|
2232
2491
|
const refresh = async () => {
|
|
2233
2492
|
if (!panel?.isConnected) return;
|
|
2493
|
+
if (refreshing) {
|
|
2494
|
+
pendingRefresh = true;
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
refreshing = true;
|
|
2234
2498
|
controller?.abort();
|
|
2235
2499
|
controller = new AbortController();
|
|
2236
2500
|
const current = ++generation;
|
|
2237
2501
|
try {
|
|
2238
|
-
const response = await fetch(
|
|
2502
|
+
const response = await fetch(reportEndpoint + "?path=" + encodeURIComponent(location.pathname), { cache: "no-store", signal: controller.signal });
|
|
2239
2503
|
if (!response.ok) throw new Error("Inspector report is unavailable.");
|
|
2240
2504
|
const next = await response.json();
|
|
2241
2505
|
if (current !== generation || !panel?.isConnected) return;
|
|
2242
2506
|
report = next;
|
|
2243
2507
|
render();
|
|
2508
|
+
void loadOutput(current);
|
|
2244
2509
|
} catch (error) {
|
|
2245
2510
|
if (error.name === "AbortError" || current !== generation) return;
|
|
2246
|
-
|
|
2247
|
-
|
|
2511
|
+
clearInterval(loadingTimer);
|
|
2512
|
+
renderFailure(panel.shadowRoot, error instanceof Error ? error.message : String(error));
|
|
2513
|
+
panel.shadowRoot.querySelector("[data-close]").addEventListener("click", close);
|
|
2514
|
+
} finally {
|
|
2515
|
+
refreshing = false;
|
|
2516
|
+
if (pendingRefresh) {
|
|
2517
|
+
pendingRefresh = false;
|
|
2518
|
+
void refresh();
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
};
|
|
2522
|
+
const loadOutput = async (current) => {
|
|
2523
|
+
try {
|
|
2524
|
+
const response = await fetch(outputEndpoint, { cache: "no-store", signal: controller.signal });
|
|
2525
|
+
if (!response.ok) throw new Error("Inspector output is unavailable.");
|
|
2526
|
+
const next = await response.json();
|
|
2527
|
+
if (current !== generation || !panel?.isConnected) return;
|
|
2528
|
+
report.output = next.output;
|
|
2529
|
+
report.dependencies = next.dependencies;
|
|
2530
|
+
report.diagnostics = report.diagnostics.concat(next.diagnostics);
|
|
2531
|
+
report.summary = summarize(report.diagnostics);
|
|
2532
|
+
render();
|
|
2533
|
+
} catch (error) {
|
|
2534
|
+
if (error.name === "AbortError" || current !== generation) return;
|
|
2535
|
+
report.output = { status: "unavailable", reason: "output inspection failed" };
|
|
2536
|
+
report.dependencies = { status: "unavailable", reason: "dependency inspection failed" };
|
|
2537
|
+
render();
|
|
2248
2538
|
}
|
|
2249
2539
|
};
|
|
2250
2540
|
const open = () => {
|
|
@@ -2252,16 +2542,30 @@ export function initDevelopmentInspector() {
|
|
|
2252
2542
|
panel = document.createElement("div");
|
|
2253
2543
|
panel.id = panelId;
|
|
2254
2544
|
panel.attachShadow({ mode: "open" });
|
|
2255
|
-
document.body.append(panel);
|
|
2256
2545
|
}
|
|
2257
|
-
|
|
2546
|
+
if (!panel.isConnected) document.body.append(panel);
|
|
2547
|
+
showLoading();
|
|
2548
|
+
void refresh();
|
|
2258
2549
|
};
|
|
2259
2550
|
const close = () => {
|
|
2260
2551
|
generation += 1;
|
|
2552
|
+
pendingRefresh = false;
|
|
2261
2553
|
controller?.abort();
|
|
2554
|
+
clearInterval(loadingTimer);
|
|
2262
2555
|
panel?.remove();
|
|
2263
2556
|
launcher?.focus();
|
|
2264
2557
|
};
|
|
2558
|
+
const showLoading = () => {
|
|
2559
|
+
if (!panel) return;
|
|
2560
|
+
clearInterval(loadingTimer);
|
|
2561
|
+
panel.shadowRoot.innerHTML = '<style>' + styles + '</style><section role="dialog" aria-modal="false" aria-labelledby="rb-loading-title"><header><strong id="rb-loading-title">Riebeckite Inspector</strong><button type="button" data-close aria-label="Close inspector">Close</button></header><p class="status" aria-live="polite">Loading inspector report…</p></section>';
|
|
2562
|
+
const status = panel.shadowRoot.querySelector(".status");
|
|
2563
|
+
const started = Date.now();
|
|
2564
|
+
loadingTimer = setInterval(() => {
|
|
2565
|
+
if (status?.isConnected) status.textContent = 'Loading inspector report… ' + Math.round((Date.now() - started) / 1000) + 's';
|
|
2566
|
+
}, 1000);
|
|
2567
|
+
panel.shadowRoot.querySelector("[data-close]").addEventListener("click", close);
|
|
2568
|
+
};
|
|
2265
2569
|
launcher = document.createElement("button");
|
|
2266
2570
|
launcher.type = "button";
|
|
2267
2571
|
launcher.textContent = "Inspector";
|
|
@@ -2282,8 +2586,9 @@ export function initDevelopmentInspector() {
|
|
|
2282
2586
|
import.meta.hot?.on("riebeckite:inspector", refresh);
|
|
2283
2587
|
|
|
2284
2588
|
function render() {
|
|
2589
|
+
clearInterval(loadingTimer);
|
|
2285
2590
|
const root = panel.shadowRoot;
|
|
2286
|
-
root.innerHTML = '<style>' + styles + '</style><section role="dialog" aria-modal="false" aria-labelledby="rb-title" tabindex="-1"><header><div><strong id="rb-title">Riebeckite Inspector</strong><p>Ctrl+Alt+R</p></div><button type="button" data-close aria-label="Close inspector">Close</button></header><div class="summary"><b>' + report.summary.errors + '</b> errors <b>' + report.summary.warnings + '</b> warnings <b>' + report.summary.info + '</b> info</div><div role="tablist" aria-label="Inspector sections">' + tabs.map((tab, index) => '<button id="rb-tab-' + index + '" role="tab" aria-controls="rb-panel-' + index + '" aria-selected="' + (index === activeTab) + '" tabindex="' + (index === activeTab ? 0 : -1) + '" data-tab="' + index + '">' + tab + '</button>').join("") + '</div><div id="rb-panel-' + activeTab + '" role="tabpanel" aria-labelledby="rb-tab-' + activeTab + '" tabindex="0">' + panelContent() + '</div><p class="status" aria-live="polite">Inspector report updated</p></section>';
|
|
2591
|
+
root.innerHTML = '<style>' + styles + '</style><section role="dialog" aria-modal="false" aria-labelledby="rb-title" tabindex="-1"><header><div><strong id="rb-title">Riebeckite Inspector</strong><p>Ctrl+Alt+R</p></div><button type="button" data-close aria-label="Close inspector">Close</button></header><div class="summary"><b>' + report.summary.errors + '</b> errors <b>' + report.summary.warnings + '</b> warnings <b>' + report.summary.info + '</b> info</div><div role="tablist" aria-label="Inspector sections">' + tabs.map((tab, index) => '<button id="rb-tab-' + index + '" role="tab" aria-controls="rb-panel-' + index + '" aria-selected="' + (index === activeTab) + '" tabindex="' + (index === activeTab ? 0 : -1) + '" data-tab="' + index + '">' + tab + '</button>').join("") + '</div><div id="rb-panel-' + activeTab + '" role="tabpanel" aria-labelledby="rb-tab-' + activeTab + '" tabindex="0">' + panelContent() + '</div><p class="status" aria-live="polite">' + (report.output ? "Inspector report updated" : "Inspector report updated · loading output plan…") + '</p></section>';
|
|
2287
2592
|
root.querySelector("[data-close]").addEventListener("click", close);
|
|
2288
2593
|
root.querySelectorAll("[data-tab]").forEach((button) => button.addEventListener("click", () => { activeTab = Number(button.dataset.tab); render(); }));
|
|
2289
2594
|
root.querySelector("[role=tablist]").addEventListener("keydown", (event) => {
|
|
@@ -2298,20 +2603,78 @@ export function initDevelopmentInspector() {
|
|
|
2298
2603
|
function panelContent() {
|
|
2299
2604
|
if (activeTab === 0) return '<dl><dt>Page</dt><dd>' + escapeHtml(report.currentPage) + '</dd><dt>Theme</dt><dd>' + escapeHtml(report.theme) + '</dd><dt>Revision</dt><dd>' + escapeHtml(report.revision) + '</dd></dl>';
|
|
2300
2605
|
if (activeTab === 1) return diagnosticList(report.diagnostics);
|
|
2301
|
-
if (activeTab === 2) return
|
|
2606
|
+
if (activeTab === 2) return dependencyReport(report.dependencies);
|
|
2302
2607
|
if (activeTab === 3) return '<ul>' + (report.plugins.map((plugin) => '<li>' + escapeHtml(plugin) + '</li>').join("") || "<li>No plugins configured.</li>") + '</ul>';
|
|
2303
|
-
return
|
|
2608
|
+
return outputReport(report.output);
|
|
2304
2609
|
}
|
|
2305
2610
|
}
|
|
2306
2611
|
|
|
2612
|
+
function summarize(diagnostics) {
|
|
2613
|
+
return {
|
|
2614
|
+
errors: diagnostics.filter((diagnostic) => diagnostic.severity === "error").length,
|
|
2615
|
+
warnings: diagnostics.filter((diagnostic) => diagnostic.severity === "warning").length,
|
|
2616
|
+
info: diagnostics.filter((diagnostic) => diagnostic.severity === "info").length,
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2307
2620
|
function diagnosticList(diagnostics) {
|
|
2308
2621
|
return '<ul>' + (diagnostics.map((diagnostic) =>
|
|
2309
2622
|
'<li data-severity="' + escapeHtml(diagnostic.severity) + '"><b>' + escapeHtml(diagnostic.code) + '</b> ' + escapeHtml(diagnostic.message) + location(diagnostic) + '</li>'
|
|
2310
2623
|
).join("") || "<li>No diagnostic findings.</li>") + '</ul>';
|
|
2311
2624
|
}
|
|
2312
2625
|
|
|
2626
|
+
function outputReport(output) {
|
|
2627
|
+
if (!output) return '<p class="status" aria-live="polite">Loading output plan…</p>';
|
|
2628
|
+
if (output.status !== "available") return unavailable("Output", output.reason);
|
|
2629
|
+
return '<dl>' +
|
|
2630
|
+
'<dt>Candidate</dt><dd>' + output.candidateOutputCount + '</dd>' +
|
|
2631
|
+
'<dt>Affected</dt><dd>' + output.affectedOutputCount + '</dd>' +
|
|
2632
|
+
'<dt>Unchanged</dt><dd>' + output.unchangedOutputCount + '</dd>' +
|
|
2633
|
+
'<dt>Removed</dt><dd>' + output.removedOutputCount + '</dd>' +
|
|
2634
|
+
'<dt>Full regeneration</dt><dd>' + (output.fullRegenerationRequired ? "required" : "not required") + '</dd>' +
|
|
2635
|
+
'<dt>Owner conflicts</dt><dd>' + output.conflicts.length + '</dd>' +
|
|
2636
|
+
'</dl>' +
|
|
2637
|
+
listedOutputs("Affected outputs", output.affected, output.hiddenAffectedCount) +
|
|
2638
|
+
listedOutputs("Removed outputs", output.removed, output.hiddenRemovedCount) +
|
|
2639
|
+
conflictList(output.conflicts);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
function listedOutputs(title, outputs, hiddenCount) {
|
|
2643
|
+
if (outputs.length === 0) return "";
|
|
2644
|
+
return '<h3>' + escapeHtml(title) + '</h3><ul>' + outputs.map((output) =>
|
|
2645
|
+
'<li><code>' + escapeHtml(output.path) + '</code> <small>' + escapeHtml(output.kind) + ' · ' + escapeHtml(output.producer) + '</small></li>'
|
|
2646
|
+
).join("") + '</ul>' + (hiddenCount > 0 ? '<p class="more">' + hiddenCount + ' more not shown.</p>' : "");
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
function conflictList(conflicts) {
|
|
2650
|
+
if (conflicts.length === 0) return "";
|
|
2651
|
+
return '<h3>Owner conflicts</h3><ul>' + conflicts.map((conflict) =>
|
|
2652
|
+
'<li><code>' + escapeHtml(conflict.path) + '</code> <small>' + escapeHtml(conflict.owners.join(", ")) + '</small></li>'
|
|
2653
|
+
).join("") + '</ul>';
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
function dependencyReport(dependencies) {
|
|
2657
|
+
if (!dependencies) return '<p class="status" aria-live="polite">Loading dependencies…</p>';
|
|
2658
|
+
if (dependencies.status !== "available") return unavailable("Dependencies", dependencies.reason);
|
|
2659
|
+
return '<dl>' +
|
|
2660
|
+
'<dt>Outputs</dt><dd>' + dependencies.outputCount + '</dd>' +
|
|
2661
|
+
'<dt>With dependencies</dt><dd>' + dependencies.dependentOutputCount + '</dd>' +
|
|
2662
|
+
'<dt>Dependencies</dt><dd>' + dependencies.dependencyCount + '</dd>' +
|
|
2663
|
+
'<dt>Unknown outputs</dt><dd>' + dependencies.unknownOutputCount + '</dd>' +
|
|
2664
|
+
'</dl>' +
|
|
2665
|
+
(dependencies.kinds.length === 0 ? "<p>No output dependencies.</p>" :
|
|
2666
|
+
'<h3>Kinds</h3><ul>' + dependencies.kinds.map((kind) =>
|
|
2667
|
+
'<li>' + escapeHtml(kind.kind) + ' <small>' + kind.count + '</small></li>'
|
|
2668
|
+
).join("") + '</ul>') +
|
|
2669
|
+
(dependencies.outputs.length === 0 ? "" :
|
|
2670
|
+
'<h3>Outputs</h3><ul>' + dependencies.outputs.map((output) =>
|
|
2671
|
+
'<li><code>' + escapeHtml(output.path) + '</code><br><small>' + escapeHtml(output.dependencies.join(", ")) + '</small></li>'
|
|
2672
|
+
).join("") + '</ul>') +
|
|
2673
|
+
(dependencies.hiddenOutputCount > 0 ? '<p class="more">' + dependencies.hiddenOutputCount + ' more outputs not shown.</p>' : "");
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2313
2676
|
function unavailable(subject, capability) {
|
|
2314
|
-
return '<p class="partial">' + escapeHtml(subject) + ': ' + escapeHtml(capability) + '
|
|
2677
|
+
return '<p class="partial">' + escapeHtml(subject) + ' unavailable: ' + escapeHtml(capability) + '.</p>';
|
|
2315
2678
|
}
|
|
2316
2679
|
|
|
2317
2680
|
function renderFailure(root, message) {
|
|
@@ -2327,7 +2690,7 @@ function escapeHtml(value) {
|
|
|
2327
2690
|
return String(value).replace(/[&<>"]/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[character]);
|
|
2328
2691
|
}
|
|
2329
2692
|
|
|
2330
|
-
const styles = ':host{all:initial}section{position:fixed;right:16px;bottom:56px;z-index:2147483647;width:min(540px,calc(100vw - 32px));max-height:70vh;overflow:auto;background:#171717;color:#f4f4f4;border:1px solid #555;padding:16px;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;box-shadow:0 8px 24px #0006}header{display:flex;justify-content:space-between;gap:16px;border-bottom:1px solid #555;padding-bottom:8px}header p,.status,small{color:#b8b8b8;margin:2px 0}.summary{margin:12px 0}button{border:1px solid #666;background:#242424;color:#fff;padding:6px 8px;cursor:pointer}button[aria-selected="true"]{border-color:#e2c57b;color:#ffe08a}.partial{color:#e2c57b}ul{margin:12px 0;padding-left:20px}li{margin:8px 0}li[data-severity="error"]{color:#ff9797}li[data-severity="warning"]{color:#ffe08a}dl{display:grid;grid-template-columns:max-content 1fr;gap:8px 16px}dt{color:#b8b8b8}.failure{color:#ff9797}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}@media(max-width:560px){section{right:8px;bottom:52px;width:calc(100vw - 32px);max-height:75vh}}';
|
|
2693
|
+
const styles = ':host{all:initial}section{position:fixed;right:16px;bottom:56px;z-index:2147483647;width:min(540px,calc(100vw - 32px));max-height:70vh;overflow:auto;background:#171717;color:#f4f4f4;border:1px solid #555;padding:16px;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;box-shadow:0 8px 24px #0006}header{display:flex;justify-content:space-between;gap:16px;border-bottom:1px solid #555;padding-bottom:8px}header p,.status,small{color:#b8b8b8;margin:2px 0}.summary{margin:12px 0}button{border:1px solid #666;background:#242424;color:#fff;padding:6px 8px;cursor:pointer}button[aria-selected="true"]{border-color:#e2c57b;color:#ffe08a}.partial{color:#e2c57b}.more{color:#b8b8b8;margin:4px 0}h3{color:#b8b8b8;font-size:12px;margin:12px 0 4px;text-transform:uppercase}ul{margin:12px 0;padding-left:20px}li{margin:8px 0}li[data-severity="error"]{color:#ff9797}li[data-severity="warning"]{color:#ffe08a}dl{display:grid;grid-template-columns:max-content 1fr;gap:8px 16px}dt{color:#b8b8b8}.failure{color:#ff9797}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}@media(max-width:560px){section{right:8px;bottom:52px;width:calc(100vw - 32px);max-height:75vh}}';
|
|
2331
2694
|
`;
|
|
2332
2695
|
}
|
|
2333
2696
|
|
|
@@ -2340,6 +2703,14 @@ var viteConfigFileNames = [
|
|
|
2340
2703
|
"vite.config.js",
|
|
2341
2704
|
"vite.config.mjs"
|
|
2342
2705
|
];
|
|
2706
|
+
var ignoredApplicationRootDirectoryNames = /* @__PURE__ */ new Set([
|
|
2707
|
+
".git",
|
|
2708
|
+
".riebeckite",
|
|
2709
|
+
"node_modules",
|
|
2710
|
+
"test",
|
|
2711
|
+
"tests",
|
|
2712
|
+
"templates"
|
|
2713
|
+
]);
|
|
2343
2714
|
async function resolveHonoxApplicationRoot(configRoot, startDirectory) {
|
|
2344
2715
|
const roots = await findViteApplicationRoots(configRoot, startDirectory);
|
|
2345
2716
|
if (roots.length === 1) return roots[0];
|
|
@@ -2402,12 +2773,24 @@ async function startHonoxDevServer(options) {
|
|
|
2402
2773
|
});
|
|
2403
2774
|
}
|
|
2404
2775
|
await server.listen(options.server?.port);
|
|
2405
|
-
|
|
2776
|
+
const urls = [
|
|
2406
2777
|
...server.resolvedUrls?.local ?? [],
|
|
2407
2778
|
...server.resolvedUrls?.network ?? []
|
|
2408
|
-
]
|
|
2409
|
-
server
|
|
2410
|
-
|
|
2779
|
+
];
|
|
2780
|
+
const shutdown = waitForShutdown(server);
|
|
2781
|
+
try {
|
|
2782
|
+
server.printUrls();
|
|
2783
|
+
await options.onServerReady?.(urls);
|
|
2784
|
+
} catch (error) {
|
|
2785
|
+
shutdown.dispose();
|
|
2786
|
+
if (shutdown.isClosing()) {
|
|
2787
|
+
await shutdown.promise;
|
|
2788
|
+
return;
|
|
2789
|
+
}
|
|
2790
|
+
await server.close();
|
|
2791
|
+
throw error;
|
|
2792
|
+
}
|
|
2793
|
+
await shutdown.promise;
|
|
2411
2794
|
});
|
|
2412
2795
|
}
|
|
2413
2796
|
async function buildHonoxApplication(options) {
|
|
@@ -2438,14 +2821,28 @@ async function withWorkingDirectory(root, task) {
|
|
|
2438
2821
|
async function runTraced(tracer, name, buildTask) {
|
|
2439
2822
|
return tracer ? await tracer.span(name, {}, buildTask) : await buildTask();
|
|
2440
2823
|
}
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2824
|
+
function waitForShutdown(server) {
|
|
2825
|
+
let resolve3 = () => {
|
|
2826
|
+
};
|
|
2827
|
+
let closing = false;
|
|
2828
|
+
const close = () => {
|
|
2829
|
+
if (closing) return;
|
|
2830
|
+
closing = true;
|
|
2831
|
+
void server.close().finally(resolve3);
|
|
2832
|
+
};
|
|
2833
|
+
const promise = new Promise((resolvePromise) => {
|
|
2834
|
+
resolve3 = resolvePromise;
|
|
2448
2835
|
});
|
|
2836
|
+
process.once("SIGINT", close);
|
|
2837
|
+
process.once("SIGTERM", close);
|
|
2838
|
+
return {
|
|
2839
|
+
promise,
|
|
2840
|
+
isClosing: () => closing,
|
|
2841
|
+
dispose: () => {
|
|
2842
|
+
process.removeListener("SIGINT", close);
|
|
2843
|
+
process.removeListener("SIGTERM", close);
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2449
2846
|
}
|
|
2450
2847
|
async function findViteApplicationRoots(root, startDirectory) {
|
|
2451
2848
|
const applicationRoot = startDirectory ? await findViteApplicationRootFrom(startDirectory, root) : void 0;
|
|
@@ -2458,7 +2855,7 @@ async function findViteApplicationRoots(root, startDirectory) {
|
|
|
2458
2855
|
if (await hasViteConfig(directory)) applicationRoots.push(directory);
|
|
2459
2856
|
const entries = await fs7.readdir(directory, { withFileTypes: true });
|
|
2460
2857
|
for (const entry of entries) {
|
|
2461
|
-
if (!entry.isDirectory() ||
|
|
2858
|
+
if (!entry.isDirectory() || ignoredApplicationRootDirectoryNames.has(entry.name)) {
|
|
2462
2859
|
continue;
|
|
2463
2860
|
}
|
|
2464
2861
|
directories.push(path9.join(directory, entry.name));
|
|
@@ -2541,6 +2938,9 @@ function riebeckite(options = {}, onApplicationResolved) {
|
|
|
2541
2938
|
define: {
|
|
2542
2939
|
"process.env.RIEBECKITE_APP_ROOT": JSON.stringify(appRoot)
|
|
2543
2940
|
},
|
|
2941
|
+
oxc: {
|
|
2942
|
+
jsx: { runtime: "automatic", importSource: "hono/jsx" }
|
|
2943
|
+
},
|
|
2544
2944
|
server: {
|
|
2545
2945
|
watch: {
|
|
2546
2946
|
ignored: ["**/.riebeckite/**"]
|