@riebeckite/honox 0.0.28 → 0.0.30

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(
@@ -2081,8 +2185,21 @@ async function findWorkspaceRoot(configRoot) {
2081
2185
  async function startHonoxDevServer(options) {
2082
2186
  const root = path9.resolve(options.root);
2083
2187
  await withWorkingDirectory(root, async () => {
2084
- const server = await createServer2({ root });
2085
- await server.listen();
2188
+ const server = await createServer2({ root, server: options.server });
2189
+ const restartFiles = new Set(
2190
+ options.restartOnChange?.map((file) => path9.resolve(file))
2191
+ );
2192
+ if (restartFiles.size > 0) {
2193
+ server.watcher.add([...restartFiles]);
2194
+ server.watcher.on("change", (file) => {
2195
+ if (restartFiles.has(path9.resolve(file))) void server.restart();
2196
+ });
2197
+ }
2198
+ await server.listen(options.server?.port);
2199
+ options.onServerReady?.([
2200
+ ...server.resolvedUrls?.local ?? [],
2201
+ ...server.resolvedUrls?.network ?? []
2202
+ ]);
2086
2203
  server.printUrls();
2087
2204
  await waitForShutdown(server);
2088
2205
  });
@@ -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>;
@@ -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.28",
3
+ "version": "0.0.30",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,13 +44,13 @@
44
44
  "hono": "^4.12.25",
45
45
  "honox": "0.1.56",
46
46
  "vite": "^8.0.9",
47
- "@riebeckite/core": "0.0.28",
48
- "@riebeckite/ui": "0.0.28",
49
- "@riebeckite/plugin-color-mode": "0.0.28"
47
+ "@riebeckite/core": "0.0.30",
48
+ "@riebeckite/ui": "0.0.30",
49
+ "@riebeckite/plugin-color-mode": "0.0.30"
50
50
  },
51
51
  "devDependencies": {
52
52
  "tsx": "^4.22.4",
53
- "@riebeckite/test": "0.0.28"
53
+ "@riebeckite/test": "0.0.30"
54
54
  },
55
55
  "publishConfig": {
56
56
  "access": "public"