also looking at this
feat(cli): --headless, and make DevTools reachable at all
#61
9 files
+340
-6
| @@ -10,6 +10,7 @@ The Craft JavaScript Bridge provides a seamless interface for your web applicati | ||
| 10 | 10 | - [Application Menu (macOS)](#application-menu-macos) |
| 11 | 11 | - [Global Shortcuts (macOS)](#global-shortcuts-macos) |
| 12 | 12 | - [Settings and Preferences (macOS)](#settings-and-preferences-macos) |
| 13 | - [Headless mode](#headless-mode) | |
| 13 | 14 | - [Window API](#window-api) |
| 14 | 15 | - [App API](#app-api) |
| 15 | 16 | - [TypeScript Support](#typescript-support) |
| @@ -464,6 +465,61 @@ const { domain, readCommand } = await craft.prefs.info() | ||
| 464 | 465 | craft namespaces its keys, so `clear()` and `keys()` cannot disturb the window |
| 465 | 466 | positions and inspector state AppKit and WebKit keep in the same domain. |
| 466 | 467 | |
| 468 | ## Headless mode | |
| 469 | ||
| 470 | `craft --headless` builds the window and never puts it on screen. The page | |
| 471 | loads, JavaScript runs, and the webview stays capturable — a snapshot taken | |
| 472 | after script has mutated the DOM reflects the mutation. | |
| 473 | ||
| 474 | ```bash | |
| 475 | craft http://localhost:3000 --headless --timing | |
| 476 | ``` | |
| 477 | ||
| 478 | Also `headless: true` in `craft.json`, and `window.headless` on `AppConfig`. | |
| 479 | ||
| 480 | The motivating case is measurement: a perf loop that launches craft repeatedly | |
| 481 | no longer flashes a window at the operator each time, which is worth doing on | |
| 482 | its own terms. | |
| 483 | ||
| 484 | ### What it cannot do | |
| 485 | ||
| 486 | **It does not animate.** An unshown window does not drive the compositor, so | |
| 487 | `requestAnimationFrame` stops after the first frame and page timers fall to | |
| 488 | roughly 1Hz. That means, silently: | |
| 489 | ||
| 490 | - CSS and JavaScript animations stay on frame one | |
| 491 | - canvas and WebGL render loops never advance | |
| 492 | - charting libraries that redraw on rAF show their initial state | |
| 493 | - "wait until the spinner stops" — implemented with `setInterval` — crawls | |
| 494 | ||
| 495 | Drive the page with explicit calls, and take readiness from load completion | |
| 496 | rather than from a polling loop inside the page. No invisible window | |
| 497 | configuration avoids this: what drives the compositor is the window being | |
| 498 | *unoccluded*, which needs activation, which means stealing focus and showing a | |
| 499 | Dock icon — a worse trade for the operator this mode exists to help. | |
| 500 | ||
| 501 | `--headless` and `--menubar-only` are contradictory (a menubar app has no | |
| 502 | window to hide) and passing both is an error rather than a silent no-op. | |
| 503 | ||
| 504 | ### Inspecting a running window | |
| 505 | ||
| 506 | `craft --dev-tools` enables the Web Inspector and makes the webview appear in | |
| 507 | Safari's **Develop** menu. | |
| 508 | ||
| 509 | This flag is new because there was previously no way to turn DevTools *on*: | |
| 510 | the setting defaulted to off and the only flag, `--no-devtools`, set it off | |
| 511 | again. And even when it was enabled through `craft.json`, the inspector did not | |
| 512 | work on macOS 13.3 or later, which introduced `isInspectable` defaulting to | |
| 513 | `NO` — craft set only the older `developerExtrasEnabled`, which stopped being | |
| 514 | sufficient. | |
| 515 | ||
| 516 | It is a **debugging affordance, not automation**. It opens no port and prints | |
| 517 | no endpoint, because there is nothing to print: WebKit on macOS has no | |
| 518 | socket-based inspector server — an inspectable `WKWebView` holds no internet | |
| 519 | sockets at all — and `safaridriver` refuses to attach to anything that is not | |
| 520 | Safari. Driving a craft page from another process needs a control channel craft | |
| 521 | owns, which does not exist yet. | |
| 522 | ||
| 467 | 523 | ## Window API |
| 468 | 524 | |
| 469 | 525 | Control the application window from JavaScript. |
| @@ -697,6 +753,7 @@ async function onComplete() { | ||
| 697 | 753 | | Tray Menu | �� | �� | �� | |
| 698 | 754 | | Window Control | ✅ | ✅ | ✅ | |
| 699 | 755 | | Hide Dock Icon | ✅ | ➖ | ➖ | |
| 756 | | Headless | ✅ | �� | �� | | |
| 700 | 757 | | Global Shortcuts | ✅ | �� | �� | |
| 701 | 758 | | Settings… item | ✅ | �� | �� | |
| 702 | 759 | | Preferences | ✅ | �� | �� | |