@riebeckite/honox 0.0.29 → 0.0.31

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 CHANGED
@@ -284,6 +284,7 @@ function isJavaScriptModule(filePath) {
284
284
  // src/ssg_plugin.ts
285
285
  import { rm as rm3 } from "node:fs/promises";
286
286
  import { join as join4, relative as relative3, resolve as resolve2 } from "node:path";
287
+ import { buildOutputPlan, compareOutputPlan } from "@riebeckite/core";
287
288
  import { defaultExtensionMap, redirectPlugin, toSSG } from "hono/ssg";
288
289
  import {
289
290
  createServer
@@ -728,6 +729,33 @@ async function discardClientBuildArtifacts(artifacts) {
728
729
  if (!artifacts) return;
729
730
  await rm(artifacts.stagingDirectory, { recursive: true, force: true });
730
731
  }
732
+ async function collectBuildOutputPaths(directory, relativeDirectory = "") {
733
+ const entries = await readdir(directory, { withFileTypes: true }).catch(
734
+ (error) => {
735
+ if (isMissingDirectoryError(error)) return void 0;
736
+ throw error;
737
+ }
738
+ );
739
+ if (!entries) return [];
740
+ const paths = [];
741
+ for (const entry of entries) {
742
+ const relativePath = join(relativeDirectory, entry.name).replaceAll(
743
+ "\\",
744
+ "/"
745
+ );
746
+ if (entry.isDirectory()) {
747
+ paths.push(
748
+ ...await collectBuildOutputPaths(
749
+ join(directory, entry.name),
750
+ relativePath
751
+ )
752
+ );
753
+ } else if (entry.isFile()) {
754
+ paths.push(relativePath);
755
+ }
756
+ }
757
+ return paths.sort();
758
+ }
731
759
  function collectClientAssetPaths(manifestSource) {
732
760
  let manifest;
733
761
  try {
@@ -1503,6 +1531,7 @@ function riebeckiteSsg(options = {}) {
1503
1531
  }
1504
1532
  const timingsMs = process.env.RIEBECKITE_SSG_METRICS_FILE ? {} : void 0;
1505
1533
  const outDir = resolve2(config.root, config.build.outDir);
1534
+ let viteClientAssetPaths = [];
1506
1535
  removeVirtualEntryChunk(bundle, resolvedVirtualId);
1507
1536
  const server = await measure(
1508
1537
  timingsMs,
@@ -1525,6 +1554,7 @@ function riebeckiteSsg(options = {}) {
1525
1554
  );
1526
1555
  try {
1527
1556
  await restoreClientBuildArtifacts(outDir, clientBuildArtifacts);
1557
+ viteClientAssetPaths = await collectBuildOutputPaths(outDir);
1528
1558
  logSsgDiagnostics(
1529
1559
  this,
1530
1560
  `SSR noExternal=${formatSsrNoExternal()} · client manifest ${clientBuildArtifacts ? "restored" : "not found"}`
@@ -1563,6 +1593,9 @@ function riebeckiteSsg(options = {}) {
1563
1593
  "siteOwnedOutputs",
1564
1594
  () => collectSiteOwnedOutputPaths(config.publicDir)
1565
1595
  );
1596
+ viteClientAssetPaths = [
1597
+ .../* @__PURE__ */ new Set([...viteClientAssetPaths, ...Object.keys(bundle)])
1598
+ ].filter((outputPath) => !siteOwnedOutputPaths.has(outputPath)).sort();
1566
1599
  const siteOutputCollisions = findBuildOutputSiteCollisions(
1567
1600
  Object.keys(bundle),
1568
1601
  siteOwnedOutputPaths
@@ -1588,6 +1621,12 @@ function riebeckiteSsg(options = {}) {
1588
1621
  const reusablePaths = new Set(
1589
1622
  canUseIncremental ? (outputChangeSet?.unchanged ?? []).map((output) => output.path) : []
1590
1623
  );
1624
+ const inventory = [
1625
+ ...outputChangeSet?.affected ?? [],
1626
+ ...outputChangeSet?.unchanged ?? []
1627
+ ];
1628
+ const inventoryPaths = new Set(inventory.map((output) => output.path));
1629
+ const honoStaticRoutePaths = /* @__PURE__ */ new Set();
1591
1630
  logSsgDiagnostics(
1592
1631
  this,
1593
1632
  `output cache ${canUseIncremental ? "hit" : `miss (${outputCacheRejectionReason})`} · ${reusablePaths.size} reusable outputs`
@@ -1631,6 +1670,19 @@ function riebeckiteSsg(options = {}) {
1631
1670
  manifestHookCacheMiss: 0,
1632
1671
  manifestHookDurationMs: 0,
1633
1672
  manifestHookPlugins: {},
1673
+ plannedOutputCount: 0,
1674
+ actualOutputCount: 0,
1675
+ matchedOutputCount: 0,
1676
+ missingInPlanCount: 0,
1677
+ missingInDistCount: 0,
1678
+ unknownOutputCount: 0,
1679
+ ownerConflictCount: 0,
1680
+ publicationViolationCount: 0,
1681
+ plannedGenerateOutputCount: 0,
1682
+ plannedReuseOutputCount: 0,
1683
+ plannedRemoveOutputCount: 0,
1684
+ plannedUnknownOutputCount: 0,
1685
+ outputPlanMemoryDeltaBytes: 0,
1634
1686
  outputCacheDecision,
1635
1687
  outputCacheRejectionReason: outputCacheRejectionReason ?? null,
1636
1688
  timingsMs: timingsMs ?? {}
@@ -1648,6 +1700,9 @@ function riebeckiteSsg(options = {}) {
1648
1700
  "\\",
1649
1701
  "/"
1650
1702
  );
1703
+ if (!inventoryPaths.has(fileName)) {
1704
+ honoStaticRoutePaths.add(fileName);
1705
+ }
1651
1706
  if (siteOwnedOutputPaths.has(fileName)) {
1652
1707
  shadowedOutputs.add(fileName);
1653
1708
  return;
@@ -1775,7 +1830,18 @@ function riebeckiteSsg(options = {}) {
1775
1830
  timingsMs,
1776
1831
  outDir,
1777
1832
  publicDir: config.publicDir,
1778
- configFile: config.configFile
1833
+ configFile: config.configFile,
1834
+ outputPlanInput: {
1835
+ inventory,
1836
+ affectedPaths: new Set(
1837
+ (outputChangeSet?.affected ?? []).map((output) => output.path)
1838
+ ),
1839
+ removed: outputChangeSet?.removed ?? [],
1840
+ cacheAvailable: canUseIncremental,
1841
+ honoStaticRoutePaths,
1842
+ viteClientAssetPaths: new Set(viteClientAssetPaths),
1843
+ sitePublicAssetPaths: siteOwnedOutputPaths
1844
+ }
1779
1845
  };
1780
1846
  this.info(
1781
1847
  `SSG outputs: ${metrics.renderedOutputCount} rendered · ${metrics.reusedOutputCount} reused · ${metrics.deletedOutputCount} removed`
@@ -1813,6 +1879,44 @@ function riebeckiteSsg(options = {}) {
1813
1879
  "outputInventory",
1814
1880
  () => fingerprintOutputDirectory(outputCache.outDir)
1815
1881
  );
1882
+ const finalOutputInventory = outputCache.state.finalOutputInventory;
1883
+ const outputPlanRssBefore = process.memoryUsage().rss;
1884
+ const outputPlan = measureSync(
1885
+ outputCache.timingsMs,
1886
+ "outputPlan",
1887
+ () => buildOutputPlan({
1888
+ ...outputCache.outputPlanInput
1889
+ })
1890
+ );
1891
+ const outputPlanComparison = measureSync(
1892
+ outputCache.timingsMs,
1893
+ "outputPlanComparison",
1894
+ () => compareOutputPlan(outputPlan, Object.keys(finalOutputInventory))
1895
+ );
1896
+ outputCache.metrics.plannedOutputCount = outputPlan.entries.length;
1897
+ outputCache.metrics.actualOutputCount = Object.keys(finalOutputInventory).length;
1898
+ outputCache.metrics.matchedOutputCount = outputPlanComparison.matched.length;
1899
+ outputCache.metrics.missingInPlanCount = outputPlanComparison.missingInPlan.length;
1900
+ outputCache.metrics.missingInDistCount = outputPlanComparison.missingInDist.length;
1901
+ outputCache.metrics.unknownOutputCount = outputPlanComparison.unknown.length;
1902
+ outputCache.metrics.ownerConflictCount = outputPlanComparison.ownerConflicts.length;
1903
+ outputCache.metrics.publicationViolationCount = outputPlanComparison.publicationViolations.length;
1904
+ outputCache.metrics.plannedGenerateOutputCount = outputPlan.entries.filter(
1905
+ (entry2) => entry2.action === "generate"
1906
+ ).length;
1907
+ outputCache.metrics.plannedReuseOutputCount = outputPlan.entries.filter(
1908
+ (entry2) => entry2.action === "reuse"
1909
+ ).length;
1910
+ outputCache.metrics.plannedRemoveOutputCount = outputPlan.entries.filter(
1911
+ (entry2) => entry2.action === "remove"
1912
+ ).length;
1913
+ outputCache.metrics.plannedUnknownOutputCount = outputPlan.entries.filter(
1914
+ (entry2) => entry2.action === "unknown"
1915
+ ).length;
1916
+ outputCache.metrics.outputPlanMemoryDeltaBytes = Math.max(
1917
+ 0,
1918
+ process.memoryUsage().rss - outputPlanRssBefore
1919
+ );
1816
1920
  const publicDir = outputCache.publicDir;
1817
1921
  outputCache.state.publicDirectory = publicDir ? resolve2(publicDir) : void 0;
1818
1922
  outputCache.state.publicFingerprint = publicDir ? await measure(
@@ -1965,27 +2069,35 @@ function isNotFoundError2(error) {
1965
2069
  }
1966
2070
 
1967
2071
  // src/client_module.ts
1968
- import {
1969
- serializePublicClientConfig
1970
- } from "@riebeckite/core";
2072
+ import { serializePublicClientConfig } from "@riebeckite/core";
1971
2073
  var clientModuleId = "virtual:riebeckite/client";
1972
2074
  var resolvedClientModuleId = `\0${clientModuleId}`;
1973
2075
  function riebeckiteClientModule(getConfig) {
2076
+ let development = false;
1974
2077
  return {
1975
2078
  name: "riebeckite-client-module",
2079
+ config(_config, environment) {
2080
+ development = environment.command === "serve";
2081
+ },
1976
2082
  resolveId(id) {
1977
2083
  if (id === clientModuleId) return resolvedClientModuleId;
1978
2084
  return null;
1979
2085
  },
1980
2086
  load(id) {
1981
2087
  if (id !== resolvedClientModuleId) return null;
1982
- return createClientModule(getConfig());
2088
+ return createClientModule(getConfig(), development);
1983
2089
  }
1984
2090
  };
1985
2091
  }
1986
- function createClientModule(config) {
2092
+ function createClientModule(config, development) {
1987
2093
  const imports = [];
1988
2094
  const initializers = [];
2095
+ if (development) {
2096
+ imports.push(
2097
+ 'import { initDevelopmentInspector } from "virtual:riebeckite/development-inspector";'
2098
+ );
2099
+ initializers.push("initDevelopmentInspector()");
2100
+ }
1989
2101
  for (const [index, entry] of config.plugins.flatMap((plugin) => plugin.clientEntries ?? []).entries()) {
1990
2102
  const localName = `pluginClientInitializer${index}`;
1991
2103
  const importTarget = entry.exportName ? `{ ${entry.exportName} as ${localName} }` : localName;
@@ -2021,6 +2133,204 @@ ${initializers.map((initializer) => ` ${initializer};`).join("\n")}
2021
2133
  `;
2022
2134
  }
2023
2135
 
2136
+ // src/development_inspector.ts
2137
+ import { collectDevelopmentDiagnostics } from "@riebeckite/diagnostics";
2138
+ var clientModuleId2 = "virtual:riebeckite/development-inspector";
2139
+ var resolvedClientModuleId2 = `\0${clientModuleId2}`;
2140
+ var endpointPath = "/__riebeckite/inspector/report";
2141
+ function riebeckiteDevelopmentInspector(getApplication) {
2142
+ let revision = 0;
2143
+ return {
2144
+ name: "riebeckite-development-inspector",
2145
+ apply: "serve",
2146
+ enforce: "pre",
2147
+ resolveId(id) {
2148
+ return id === clientModuleId2 ? resolvedClientModuleId2 : null;
2149
+ },
2150
+ load(id) {
2151
+ return id === resolvedClientModuleId2 ? inspectorClientModule() : null;
2152
+ },
2153
+ configureServer(server) {
2154
+ const middleware = async (request, response) => {
2155
+ if (!isLocalRequest(request.headers.host, server)) {
2156
+ response.statusCode = 403;
2157
+ response.end();
2158
+ return;
2159
+ }
2160
+ try {
2161
+ const application = getApplication();
2162
+ const report = await collectDevelopmentDiagnostics({
2163
+ config: application.config,
2164
+ revision
2165
+ });
2166
+ response.setHeader("content-type", "application/json; charset=utf-8");
2167
+ response.setHeader("cache-control", "no-store");
2168
+ const currentPage = currentPageFromRequest(request.url);
2169
+ response.end(
2170
+ JSON.stringify({
2171
+ ...report,
2172
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2173
+ currentPage,
2174
+ 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
+ }
2181
+ })
2182
+ );
2183
+ } catch {
2184
+ response.statusCode = 500;
2185
+ response.setHeader("content-type", "application/json; charset=utf-8");
2186
+ response.end(JSON.stringify({ code: "INSPECTOR_REPORT_FAILED" }));
2187
+ }
2188
+ };
2189
+ server.middlewares.use(endpointPath, middleware);
2190
+ return () => prioritizeMiddleware(server, middleware);
2191
+ },
2192
+ handleHotUpdate({ server }) {
2193
+ revision += 1;
2194
+ server.hot.send({ type: "custom", event: "riebeckite:inspector" });
2195
+ }
2196
+ };
2197
+ }
2198
+ function currentPageFromRequest(url) {
2199
+ const value = new URL(url ?? endpointPath, "http://localhost").searchParams.get(
2200
+ "path"
2201
+ );
2202
+ return value && value.startsWith("/") && !value.startsWith("//") ? value : "/";
2203
+ }
2204
+ function prioritizeMiddleware(server, middleware) {
2205
+ const stack = server.middlewares.stack;
2206
+ const index = stack?.findIndex(
2207
+ (layer) => layer.handle === middleware || layer.route === endpointPath
2208
+ ) ?? -1;
2209
+ if (index > 0 && stack) stack.unshift(...stack.splice(index, 1));
2210
+ }
2211
+ function isLocalRequest(host, server) {
2212
+ if (!host) return false;
2213
+ const hostname = host.replace(/:\d+$/, "").toLowerCase();
2214
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]")
2215
+ return true;
2216
+ const address = server.httpServer?.address();
2217
+ return typeof address === "object" && address?.address === hostname;
2218
+ }
2219
+ function inspectorClientModule() {
2220
+ return `
2221
+ const endpoint = ${JSON.stringify(endpointPath)};
2222
+ const panelId = "riebeckite-development-inspector";
2223
+
2224
+ export function initDevelopmentInspector() {
2225
+ let panel;
2226
+ let launcher;
2227
+ let controller;
2228
+ let generation = 0;
2229
+ let report;
2230
+ let activeTab = 0;
2231
+ const tabs = ["Overview", "Diagnostics", "Dependencies", "Plugins", "Output"];
2232
+ const refresh = async () => {
2233
+ if (!panel?.isConnected) return;
2234
+ controller?.abort();
2235
+ controller = new AbortController();
2236
+ const current = ++generation;
2237
+ try {
2238
+ const response = await fetch(endpoint + "?path=" + encodeURIComponent(location.pathname), { cache: "no-store", signal: controller.signal });
2239
+ if (!response.ok) throw new Error("Inspector report is unavailable.");
2240
+ const next = await response.json();
2241
+ if (current !== generation || !panel?.isConnected) return;
2242
+ report = next;
2243
+ render();
2244
+ } catch (error) {
2245
+ if (error.name === "AbortError" || current !== generation) return;
2246
+ renderFailure(panel.shadowRoot, error instanceof Error ? error.message : String(error));
2247
+ panel.shadowRoot.querySelector("[data-close]").addEventListener("click", close);
2248
+ }
2249
+ };
2250
+ const open = () => {
2251
+ if (!panel) {
2252
+ panel = document.createElement("div");
2253
+ panel.id = panelId;
2254
+ panel.attachShadow({ mode: "open" });
2255
+ document.body.append(panel);
2256
+ }
2257
+ refresh();
2258
+ };
2259
+ const close = () => {
2260
+ generation += 1;
2261
+ controller?.abort();
2262
+ panel?.remove();
2263
+ launcher?.focus();
2264
+ };
2265
+ launcher = document.createElement("button");
2266
+ launcher.type = "button";
2267
+ launcher.textContent = "Inspector";
2268
+ launcher.setAttribute("aria-label", "Open Riebeckite Development Inspector");
2269
+ launcher.style.cssText = "position:fixed;right:16px;bottom:16px;z-index:2147483647;border:1px solid #434343;border-radius:4px;background:#171717;color:#fff;padding:8px 12px;font:600 12px system-ui;cursor:pointer";
2270
+ launcher.addEventListener("click", open);
2271
+ document.body.append(launcher);
2272
+ window.addEventListener("keydown", (event) => {
2273
+ const editable = event.target instanceof HTMLElement && (event.target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(event.target.tagName));
2274
+ if (event.key === "Escape" && panel?.isConnected) {
2275
+ event.preventDefault();
2276
+ close();
2277
+ } else if (event.key.toLowerCase() === "r" && event.ctrlKey && event.altKey && !editable) {
2278
+ event.preventDefault();
2279
+ panel?.isConnected ? close() : open();
2280
+ }
2281
+ });
2282
+ import.meta.hot?.on("riebeckite:inspector", refresh);
2283
+
2284
+ function render() {
2285
+ 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>';
2287
+ root.querySelector("[data-close]").addEventListener("click", close);
2288
+ root.querySelectorAll("[data-tab]").forEach((button) => button.addEventListener("click", () => { activeTab = Number(button.dataset.tab); render(); }));
2289
+ root.querySelector("[role=tablist]").addEventListener("keydown", (event) => {
2290
+ if (event.key === "Home") activeTab = 0;
2291
+ else if (event.key === "End") activeTab = tabs.length - 1;
2292
+ else if (event.key === "ArrowRight" || event.key === "ArrowDown") activeTab = (activeTab + 1) % tabs.length;
2293
+ else if (event.key === "ArrowLeft" || event.key === "ArrowUp") activeTab = (activeTab + tabs.length - 1) % tabs.length;
2294
+ else return;
2295
+ event.preventDefault(); render(); root.querySelector('[data-tab="' + activeTab + '"]').focus();
2296
+ });
2297
+ }
2298
+ function panelContent() {
2299
+ 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
+ if (activeTab === 1) return diagnosticList(report.diagnostics);
2301
+ if (activeTab === 2) return unavailable("Dependencies", report.capabilities.dependencies);
2302
+ if (activeTab === 3) return '<ul>' + (report.plugins.map((plugin) => '<li>' + escapeHtml(plugin) + '</li>').join("") || "<li>No plugins configured.</li>") + '</ul>';
2303
+ return unavailable("Output", report.capabilities.output);
2304
+ }
2305
+ }
2306
+
2307
+ function diagnosticList(diagnostics) {
2308
+ return '<ul>' + (diagnostics.map((diagnostic) =>
2309
+ '<li data-severity="' + escapeHtml(diagnostic.severity) + '"><b>' + escapeHtml(diagnostic.code) + '</b> ' + escapeHtml(diagnostic.message) + location(diagnostic) + '</li>'
2310
+ ).join("") || "<li>No diagnostic findings.</li>") + '</ul>';
2311
+ }
2312
+
2313
+ function unavailable(subject, capability) {
2314
+ return '<p class="partial">' + escapeHtml(subject) + ': ' + escapeHtml(capability) + ' in the development inspector.</p>';
2315
+ }
2316
+
2317
+ function renderFailure(root, message) {
2318
+ root.innerHTML = '<style>' + styles + '</style><section role="dialog" aria-modal="false" aria-labelledby="rb-failure-title"><header><strong id="rb-failure-title">Riebeckite Inspector</strong><button type="button" data-close aria-label="Close inspector">Close</button></header><p class="failure" aria-live="polite">' + escapeHtml(message) + '</p></section>';
2319
+ }
2320
+
2321
+ function location(diagnostic) {
2322
+ const location = diagnostic.location;
2323
+ return location?.file ? ' <small>(' + escapeHtml(location.file) + (location.line ? ':' + location.line : '') + ')</small>' : '';
2324
+ }
2325
+
2326
+ function escapeHtml(value) {
2327
+ return String(value).replace(/[&<>"]/g, (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[character]);
2328
+ }
2329
+
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}}';
2331
+ `;
2332
+ }
2333
+
2024
2334
  // src/vite_runner.ts
2025
2335
  import fs7 from "node:fs/promises";
2026
2336
  import path9 from "node:path";
@@ -2081,8 +2391,21 @@ async function findWorkspaceRoot(configRoot) {
2081
2391
  async function startHonoxDevServer(options) {
2082
2392
  const root = path9.resolve(options.root);
2083
2393
  await withWorkingDirectory(root, async () => {
2084
- const server = await createServer2({ root });
2085
- await server.listen();
2394
+ const server = await createServer2({ root, server: options.server });
2395
+ const restartFiles = new Set(
2396
+ options.restartOnChange?.map((file) => path9.resolve(file))
2397
+ );
2398
+ if (restartFiles.size > 0) {
2399
+ server.watcher.add([...restartFiles]);
2400
+ server.watcher.on("change", (file) => {
2401
+ if (restartFiles.has(path9.resolve(file))) void server.restart();
2402
+ });
2403
+ }
2404
+ await server.listen(options.server?.port);
2405
+ options.onServerReady?.([
2406
+ ...server.resolvedUrls?.local ?? [],
2407
+ ...server.resolvedUrls?.network ?? []
2408
+ ]);
2086
2409
  server.printUrls();
2087
2410
  await waitForShutdown(server);
2088
2411
  });
@@ -2239,7 +2562,8 @@ function riebeckite(options = {}, onApplicationResolved) {
2239
2562
  appRoot: () => requireApplication(application).appRoot,
2240
2563
  contentRoot: () => requireApplication(application).contentRoot,
2241
2564
  exclude: () => getConfig().content.exclude ?? []
2242
- })
2565
+ }),
2566
+ riebeckiteDevelopmentInspector(() => requireApplication(application))
2243
2567
  ];
2244
2568
  }
2245
2569
  function requireApplication(application) {
package/dist/server.js CHANGED
@@ -130,7 +130,7 @@ function mountRiebeckiteEndpoints(app, options) {
130
130
  for (const endpoint of endpoints) {
131
131
  const method = endpoint.method ?? "GET";
132
132
  const handler = async (context) => {
133
- const manifest = await options.content.getManifest();
133
+ const manifest = endpoint.requiresManifest === false ? void 0 : await options.content.getManifest();
134
134
  const request = await toPluginEndpointRequest(context, method);
135
135
  const response = await endpoint.handler({
136
136
  config: options.config,
@@ -1,3 +1,3 @@
1
- import { type ResolvedRiebeckiteConfig } from "@riebeckite/core";
1
+ import type { ResolvedRiebeckiteConfig } from "@riebeckite/core";
2
2
  import type { Plugin } from "vite";
3
- export declare function riebeckiteClientModule(getConfig: () => ResolvedRiebeckiteConfig): Plugin;
3
+ export declare function riebeckiteClientModule(getConfig: () => Pick<ResolvedRiebeckiteConfig, "plugins">): Plugin;
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from "vite";
2
+ import type { ResolvedHonoxApplication } from "./vite_runner.js";
3
+ export declare function riebeckiteDevelopmentInspector(getApplication: () => ResolvedHonoxApplication): Plugin;
@@ -13,3 +13,4 @@ export declare function emptyBuildOutputDirectory(outDir: string): Promise<void>
13
13
  export declare function preserveClientBuildArtifacts(outDir: string): Promise<ClientBuildArtifacts | undefined>;
14
14
  export declare function restoreClientBuildArtifacts(outDir: string, artifacts: ClientBuildArtifacts | undefined): Promise<void>;
15
15
  export declare function discardClientBuildArtifacts(artifacts: ClientBuildArtifacts | undefined): Promise<void>;
16
+ export declare function collectBuildOutputPaths(directory: string, relativeDirectory?: string): Promise<string[]>;
@@ -1,3 +1,4 @@
1
+ import type { OutputDescriptor } from "@riebeckite/core";
1
2
  import type { toSSG } from "hono/ssg";
2
3
  export type GeneratedOutputAsset = {
3
4
  type: "asset";
@@ -44,18 +45,9 @@ export type SsgModule = {
44
45
  }>;
45
46
  };
46
47
  getOutputChangeSet(): Promise<{
47
- affected: readonly {
48
- kind: string;
49
- path: string;
50
- }[];
51
- removed: readonly {
52
- kind: string;
53
- path: string;
54
- }[];
55
- unchanged: readonly {
56
- kind: string;
57
- path: string;
58
- }[];
48
+ affected: readonly OutputDescriptor[];
49
+ removed: readonly OutputDescriptor[];
50
+ unchanged: readonly OutputDescriptor[];
59
51
  fullRegenerationRequired: boolean;
60
52
  candidateOutputCount: number;
61
53
  affectedOutputCount: number;
@@ -97,6 +89,19 @@ export type SsgOutputMetrics = {
97
89
  manifestHookCacheMiss: number;
98
90
  manifestHookDurationMs: number;
99
91
  manifestHookPlugins: Record<string, unknown>;
92
+ plannedOutputCount: number;
93
+ actualOutputCount: number;
94
+ matchedOutputCount: number;
95
+ missingInPlanCount: number;
96
+ missingInDistCount: number;
97
+ unknownOutputCount: number;
98
+ ownerConflictCount: number;
99
+ publicationViolationCount: number;
100
+ plannedGenerateOutputCount: number;
101
+ plannedReuseOutputCount: number;
102
+ plannedRemoveOutputCount: number;
103
+ plannedUnknownOutputCount: number;
104
+ outputPlanMemoryDeltaBytes: number;
100
105
  outputCacheDecision: OutputCacheDecision;
101
106
  outputCacheRejectionReason: OutputCacheRejectionReason | null;
102
107
  timingsMs: Record<string, number>;
@@ -10,7 +10,6 @@ export type PrimitiveClassProps = {
10
10
  className?: string;
11
11
  };
12
12
  export type ArticleProps = PrimitiveProps & {
13
- "data-slot"?: string;
14
13
  post?: PostContent;
15
14
  entry?: PublicContentEntry;
16
15
  };
@@ -26,7 +25,6 @@ export type ArticleHeaderProps = (PrimitiveClassProps & {
26
25
  });
27
26
  export type ArticleContentProps = PrimitiveClassProps & {
28
27
  children?: PrimitiveChildren;
29
- "data-slot"?: string;
30
28
  };
31
29
  export type ArticleMetaProps = PrimitiveProps & {
32
30
  label?: string;
@@ -15,14 +15,7 @@ import {
15
15
  import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
16
16
  import { createElement } from "hono/jsx";
17
17
  function Article(props) {
18
- const article = /* @__PURE__ */ jsx(
19
- "article",
20
- {
21
- class: joinClassNames("rb-article", props.class, props.className),
22
- "data-slot": props["data-slot"] ?? "article",
23
- children: props.children
24
- }
25
- );
18
+ const article = /* @__PURE__ */ jsx("article", { class: joinClassNames("rb-article", props.class, props.className), children: props.children });
26
19
  if (!props.post) return article;
27
20
  return /* @__PURE__ */ jsx(ArticleProvider, { entry: props.entry, post: props.post, children: article });
28
21
  }
@@ -68,8 +61,7 @@ function ArticleContent(props) {
68
61
  props.class,
69
62
  props.className
70
63
  );
71
- const dataSlot = props["data-slot"] ?? "article-body";
72
- return /* @__PURE__ */ jsx("div", { class: className, "data-slot": dataSlot, children: props.children });
64
+ return /* @__PURE__ */ jsx("div", { class: className, children: props.children });
73
65
  }
74
66
  function HtmlFragment(props) {
75
67
  return raw(props.html);
@@ -3,6 +3,13 @@ import { type RiebeckiteConfigLoaderOptions } from "./config_loader.js";
3
3
  export type HonoxApplicationOptions = {
4
4
  root: string;
5
5
  tracer?: Tracer;
6
+ server?: {
7
+ host?: string;
8
+ open?: boolean;
9
+ port?: number;
10
+ };
11
+ onServerReady?: (urls: readonly string[]) => void;
12
+ restartOnChange?: readonly string[];
6
13
  };
7
14
  export type ResolvedHonoxApplication = {
8
15
  config: ResolvedRiebeckiteConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/honox",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,13 +44,14 @@
44
44
  "hono": "^4.12.25",
45
45
  "honox": "0.1.56",
46
46
  "vite": "^8.0.9",
47
- "@riebeckite/core": "0.0.29",
48
- "@riebeckite/ui": "0.0.29",
49
- "@riebeckite/plugin-color-mode": "0.0.29"
47
+ "@riebeckite/core": "0.0.31",
48
+ "@riebeckite/diagnostics": "0.0.31",
49
+ "@riebeckite/plugin-color-mode": "0.0.31",
50
+ "@riebeckite/ui": "0.0.31"
50
51
  },
51
52
  "devDependencies": {
52
53
  "tsx": "^4.22.4",
53
- "@riebeckite/test": "0.0.29"
54
+ "@riebeckite/test": "0.0.31"
54
55
  },
55
56
  "publishConfig": {
56
57
  "access": "public"