You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6013aa3
Browse filesBrowse the repository at this point in the historyBrowse files
feat(hub-ui-onboard): add a tiny stand-in that installs the hub UI on demand
A host can now make DevTools an opt-in install without losing discovery.
`@devframes/hub-ui-onboard` ships one ~20 kB browser file served at the
hub base, offers Install / Disable, runs the project's package manager
with the configured packages, and hands the base to the real hub in the
same process when the host returns a handler from `onInstalled`.
It depends on neither `devframe` nor `@devframes/hub`; node-side errors
use the new `DF90xx` range through `nostics` directly.
Copy file name to clipboardExpand all lines: .agents/03-stack-and-commands.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,7 +43,7 @@ The `pnpm test` script intentionally runs `build` first so `tsnapi` snapshots co
43
43
44
44
## Generated artifacts under `src/`
45
45
46
-
Ahead-of-time build artifacts that live under `src/` - the shadow-root stylesheets in `packages/hub-ui/src/client/.generated/`and `packages/json-render-ui/src/.generated/` - are **generated, not committed** (`.generated` is gitignored). Each owning package builds its own with `pnpm run build:css`; three things guarantee the file is on disk before anything imports it: the root `postinstall` runs `turbo run build:css`, the Turbo `typecheck` task depends on both`build:css`tasks, and each package's `build` script chains `build:css` first. A new generated-under-`src` artifact MUST follow the same shape - its own build script, declared `outputs` in `turbo.json`, and a `typecheck` dependency - and MUST NOT be checked in: a minified single-line blob conflicts on every concurrent edit.
46
+
Ahead-of-time build artifacts that live under `src/` - the shadow-root stylesheets in `packages/hub-ui/src/client/.generated/`, `packages/hub-ui-onboard/src/client/.generated/`and `packages/json-render-ui/src/.generated/` - are **generated, not committed** (`.generated` is gitignored). Each owning package builds its own with `pnpm run build:css`; three things guarantee the file is on disk before anything imports it: the root `postinstall` runs `turbo run build:css`, the Turbo `typecheck` task depends on every`build:css`task, and each package's `build` script chains `build:css` first. A new generated-under-`src` artifact MUST follow the same shape - its own build script, declared `outputs` in `turbo.json`, and a `typecheck` dependency - and MUST NOT be checked in: a minified single-line blob conflicts on every concurrent edit.
Copy file name to clipboardExpand all lines: .agents/06-design-system.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,9 +12,9 @@ Each consumer's `uno.config.ts` composes the same stack: `presetAnthonyDesign({
12
12
13
13
## Wind4 by default, Wind3 for shadow roots
14
14
15
-
Ordinary surfaces (plugins served in iframes, examples in the page) use `presetWind4()`. A surface whose stylesheet is injected into a **shadow root** (`@devframes/hub-ui`'s dock custom element, `@devframes/json-render-ui`'s renderer module) MUST build on **`presetWind3()`** instead - via `createDesignConfig({ base: presetWind3() })`, or `presetWind3()` directly. Wind4 keeps `@antfu/design`'s theme in a document `:root {}` block and registers its `--un-*` custom properties with `@property { inherits: false }`, neither of which reaches a shadow tree - its `color-mix(var(--colors-*))` semantic utilities (`bg-base`, `color-base`, …) resolve to nothing inside a shadow root. Wind3 bakes the same shortcuts to concrete `rgb()` + `.dark` variants, self-contained in the shadow tree.
15
+
Ordinary surfaces (plugins served in iframes, examples in the page) use `presetWind4()`. A surface whose stylesheet is injected into a **shadow root** (`@devframes/hub-ui`'s dock custom element, `@devframes/json-render-ui`'s renderer module, `@devframes/hub-ui-onboard`'s floating button) MUST build on **`presetWind3()`** instead - via `createDesignConfig({ base: presetWind3() })`, or `presetWind3()` directly. Wind4 keeps `@antfu/design`'s theme in a document `:root {}` block and registers its `--un-*` custom properties with `@property { inherits: false }`, neither of which reaches a shadow tree - its `color-mix(var(--colors-*))` semantic utilities (`bg-base`, `color-base`, …) resolve to nothing inside a shadow root. Wind3 bakes the same shortcuts to concrete `rgb()` + `.dark` variants, self-contained in the shadow tree.
16
16
17
-
Two shadow-root gotchas the ahead-of-time CSS builder MUST compensate for (both handled in the shared `design/build-shadow-css.ts` pipeline, consumed by `packages/{hub-ui,json-render-ui}/scripts/build-css.ts`; the Vite `unocss/vite` path for standalone SPAs and Storybook is not affected):
17
+
Two shadow-root gotchas the ahead-of-time CSS builder MUST compensate for (both handled in the shared `design/build-shadow-css.ts` pipeline, consumed by `packages/{hub-ui,hub-ui-onboard,json-render-ui}/scripts/build-css.ts`; a surface that renders none of `@antfu/design`'s Vue components passes `scanDesignComponents: false` to keep its stylesheet small; the Vite `unocss/vite` path for standalone SPAs and Storybook is not affected):
18
18
19
19
-**Plain-vs-variant shortcut drop.** When a semantic shortcut also appears **variant-prefixed** in the scanned sources (e.g. `@antfu/design`'s Tabs emits `data-[state=active]:bg-base`), a single-pass `generate(tokens)` drops the *plain*`.bg-base` / `.color-base` rule - so emit the surface tokens (`design/uno.config.ts`'s exported `shadowSurfaceSafelist`) in a **dedicated `generate()` pass** and append them.
20
20
-**`--un-*` collision with a Wind4 host.**`@property` registrations are document-global, so a host page built on Wind4 registers `--un-bg-opacity` / `--un-border-opacity` / `--un-text-opacity` as `@property { syntax: '<percentage>' }` for the whole document, including our shadow tree - which invalidates the *unitless* values Wind3 writes (`--un-border-opacity: 0.13`) and collapses the dependent `rgb(… / var(--un-*))` color (a visibly wrong border/background). Rename every `--un-` in the shadow stylesheet to a private prefix with `design/uno.config.ts`'s exported `namespaceShadowCssVars()` so it's immune to whatever the host registered.
Copy file name to clipboardExpand all lines: .agents/08-diagnostics.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
All node-side warnings and errors use structured diagnostics via [`nostics`](https://www.npmjs.com/package/nostics). Node-side code MUST NOT use raw `console.warn`, `console.error`, or `throw new Error` with ad-hoc messages - always define a coded diagnostic. Browser-only code is out of scope and keeps using `console.*` / `throw`.
4
4
5
-
Import `defineDiagnostics` (and `Diagnostic` for `instanceof` checks) from `devframe/utils/nostics`, never from `nostics` directly - it pre-wires devframe's ANSI console reporter, so a plugin's `diagnostics.ts` never builds its own reporter (`colors`, `ansiFormatter`) or depends on `nostics` itself.
5
+
Import `defineDiagnostics` (and `Diagnostic` for `instanceof` checks) from `devframe/utils/nostics`, never from `nostics` directly - it pre-wires devframe's ANSI console reporter, so a plugin's `diagnostics.ts` never builds its own reporter (`colors`, `ansiFormatter`) or depends on `nostics` itself. One exception: `@devframes/hub-ui-onboard` MUST stay free of `devframe` (a host ships it while devframe is not installed), so it imports `defineDiagnostics` and `createConsoleReporter` from `nostics` directly.
6
6
7
7
## Code ranges
8
8
@@ -16,6 +16,7 @@ Prefix: **`DF`**. Codes are sequential 4-digit numbers (e.g. `DF0033`) - check t
16
16
-`DF83xx` - messages
17
17
-`DF84xx` - commands
18
18
-`DF85xx` - built-in RPC commands
19
+
-`DF90xx` - `@devframes/hub-ui-onboard` (install, state file, hand-off)
Copy file name to clipboardExpand all lines: docs/content/1.guide/18.hub-initiate.md
+24Lines changed: 24 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,6 +63,30 @@ interface DevframeHubUi {
63
63
64
64
To add a language, add its tag and native name to `packages/hub-ui/src/locales.ts`, translate a copy of `packages/hub-ui/src/client/i18n/locales/en.json` under that tag, and register the file in the `messages` map in `packages/hub-ui/src/client/i18n/index.ts`. The i18n test fails on a missing key or a changed `{slot}`.
65
65
66
+
## Onboarding without the hub installed
67
+
68
+
`@devframes/hub-ui-onboard` is for a host that wants DevTools to be an opt-in install. It depends on neither `devframe` nor `@devframes/hub` and ships one 20 kB browser file. `createOnboarding()` returns a handler that serves a floating button at `<base>embedded.js`, the same URL the hub uses, plus three routes under `<base>__onboard/`: `GET status`, `POST install` and `POST disable`.
// Resolve from the project root; under pnpm the new packages are only reachable from there.
78
+
const hub =awaitstartHub()
79
+
returnhub.handler// every later request at <base> goes here, no restart
80
+
},
81
+
})
82
+
83
+
server.middlewares.use(onboarding.nodeMiddleware)
84
+
if (!onboarding.disabled)
85
+
injectScript(onboarding.scriptSrc)
86
+
```
87
+
88
+
Install runs the project's package manager (detected from the lockfile) with the configured `packages` only; the request body controls nothing, and a cross-origin `POST` is refused. The button polls `status` once a second and, when `onInstalled` returned a handler, loads the real `embedded.js` and removes itself. Without a handler it asks the user to restart. Disable writes `<stateDir>/hub-ui-onboard.json` (default `node_modules/.devframe`); the host reads `onboarding.disabled` on the next start and injects nothing. Mount the onboarding only when the user did not set the host's own devtools option, so an explicit `devtools: true` or `false` in the host configuration always wins. [`examples/hub-onboard-vite`](https://github.com/devframes/devframe/tree/main/examples/hub-onboard-vite) shows the whole flow on Vite.
89
+
66
90
## Renderer modules
67
91
68
92
A dock type's renderer (e.g. [JSON-Render](/guide/json-render)) composes via `initHub({ renderers })`. Each registration `{ type, file, importName? }` (`file` = a prebuilt ES module exporting a `DockRenderer`) is served at `<base>__renderers/<type>.mjs` and published into the `devframe:dock-renderers` manifest; client runtimes import it lazily on first mount:
Pass at least one package spec, for example `packages: ['@nuxt/devtools']`.
25
+
26
+
## Source
27
+
28
+
-[`packages/hub-ui-onboard/src/index.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/index.ts): `createOnboarding` throws this before it reads any other option.
description: 'The package manager exited with a non-zero code.'
4
+
---
5
+
6
+
## Message
7
+
8
+
> `{command}` exited with code `{exitCode}`.
9
+
10
+
## Cause
11
+
12
+
The Install button ran the project's package manager (`npm`, `pnpm`, `yarn`, `bun` or `deno`, detected from the lockfile) and it failed. The last lines of its error output follow the message. Common reasons: no network, a package name that does not exist, or a package manager that is not on `PATH`.
13
+
14
+
## Fix
15
+
16
+
Run the command shown in the panel in a terminal to see the full output. Fix the cause, then click Retry. The panel keeps the error until the next attempt.
17
+
18
+
## Source
19
+
20
+
-[`packages/hub-ui-onboard/src/install.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/install.ts): `runInstall` throws this when the process exits with a non-zero code. The status route reports it as `{ state: 'error', error: { code, message } }`.
description: 'The install finished, but a package is not in the project node_modules.'
4
+
---
5
+
6
+
## Message
7
+
8
+
> The install finished, but "`{name}`" is not in `{cwd}`/node_modules.
9
+
10
+
## Cause
11
+
12
+
The package manager exited with code 0, but `<cwd>/node_modules/<name>` does not exist. This happens when `cwd` points at a directory other than the one the package manager installed into, for example the workspace root instead of the package that runs the dev server.
13
+
14
+
## Fix
15
+
16
+
Set `cwd` to the project that receives the dependency. In a workspace, that is the package whose dev server mounts the onboarding handler.
17
+
18
+
## Source
19
+
20
+
-[`packages/hub-ui-onboard/src/install.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/install.ts): `runInstall` checks each named package after the command succeeds. Path, URL and alias specs are not checked, because their installed name is not in the spec.
description: '`onInstalled` threw after the packages were installed.'
4
+
---
5
+
6
+
## Message
7
+
8
+
> `onInstalled` threw after the packages were installed.
9
+
10
+
## Cause
11
+
12
+
The packages are installed. The host's `onInstalled` callback, which usually imports the new packages and starts the hub, threw. The original error is attached as `cause`.
13
+
14
+
## Fix
15
+
16
+
Read the `cause`. A frequent one is a module that cannot be resolved: resolve the new packages from the project root (`createRequire(join(cwd, 'package.json'))`), not from the config file, because under pnpm they are only reachable from there. A restart of the dev server also loads the installed packages.
17
+
18
+
## Source
19
+
20
+
-[`packages/hub-ui-onboard/src/index.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/index.ts): `install()` reports this and sets `state: 'error'` when `onInstalled` rejects.
0 commit comments