Skip to content

Commit 189b200

Browse files
committed
docs(guide): align data-inspector tutorial with the app/ + src/node/ + playgrounds/ layout
1 parent a31b5ff commit 189b200

1 file changed

Lines changed: 24 additions & 23 deletions

File tree

‎docs/content/1.guide/1.tutorial-server-data-inspector.md‎

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ You'll need [Node 24+](https://nodejs.org/) and a terminal. Every code block is
1313

1414
A devframe is two halves talking over a typed connection: the **node side** exposes functions, and the **browser side** calls them and renders the results. Devframe is everything in between: the wire, the UI hosting, auth, builds, and a CLI.
1515

16+
The two halves live in their own folders: the node side under `src/node/`, the web app under `app/`. A `playgrounds/` folder holds hosts that boot the built tool. We'll fill these in as we go.
17+
1618
## Step 1: Define the tool
1719

1820
Everything starts with `defineDevframe`: your tool's name, plus a `setup` where you register what it can do. Create the project and the definition:
@@ -23,7 +25,7 @@ npm init -y && npm pkg set type=module
2325
npm install devframe && npm install -D typescript
2426
```
2527

26-
```ts [src/data-inspector.ts]
28+
```ts [src/node/data-inspector.ts]
2729
import { defineDevframe } from 'devframe'
2830

2931
// Some example server-side data, whatever you want to peek at while your
@@ -95,7 +97,7 @@ npm install react react-dom @devframes/vite
9597
npm install -D vite @vitejs/plugin-react @types/react @types/react-dom
9698
```
9799

98-
```html [client/index.html]
100+
```html [app/index.html]
99101
<!doctype html>
100102
<html>
101103
<head>
@@ -109,14 +111,14 @@ npm install -D vite @vitejs/plugin-react @types/react @types/react-dom
109111
</html>
110112
```
111113

112-
```tsx [client/main.tsx]
114+
```tsx [app/main.tsx]
113115
import { createRoot } from 'react-dom/client'
114116
import { App } from './App'
115117

116118
createRoot(document.getElementById('app')!).render(<App />)
117119
```
118120

119-
```tsx [client/App.tsx]
121+
```tsx [app/App.tsx]
120122
import type { DevframeRpcClient } from 'devframe/client'
121123
import { connectDevframe } from 'devframe/client'
122124
import { useEffect, useState } from 'react'
@@ -173,14 +175,13 @@ export function App() {
173175

174176
To try what we've built, let Vite serve the UI and hand RPC traffic to devframe:
175177

176-
```ts [vite.client.config.ts]
178+
```ts [app/vite.config.ts]
177179
import { devframeViteBridge } from '@devframes/vite/single'
178180
import react from '@vitejs/plugin-react'
179181
import { defineConfig } from 'vite'
180-
import dataInspectorFrame from './src/data-inspector.ts'
182+
import dataInspectorFrame from '../src/node/data-inspector.ts'
181183

182184
export default defineConfig({
183-
root: 'client',
184185
base: './', // relative asset URLs, so the built UI works under any mount path
185186
build: { outDir: '../dist/client', emptyOutDir: true },
186187
plugins: [
@@ -193,27 +194,27 @@ export default defineConfig({
193194
```
194195

195196
```sh
196-
npx vite --config vite.client.config.ts
197+
npx vite --config app/vite.config.ts
197198
```
198199

199200
Open the printed URL. The three keys and their types show up, and typing `config.port` or `users.0.name` and hitting **Query** prints the value. Button → `call` → your `handler` → back to the page: that's the whole devframe working.
200201

201202
> [!WARNING]
202203
> `auth: false` trusts anything that can reach the port. It's off here to keep the tutorial simple; turn it on for anything you publish or expose beyond localhost. See [Security](/guide/security).
203204
204-
From here on we reuse this same `src/data-inspector.ts` and `client/` unchanged; all that changes is where they run.
205+
From here on we reuse this same `src/node/data-inspector.ts` and `app/` unchanged; all that changes is where they run.
205206

206207
## Step 4: Dock it in a hub
207208

208209
A [hub](/guide/hub) puts many devframes behind one interface, each a **dock entry** you switch between, the tool's own UI in an iframe. Since our SPA uses a bare `connectDevframe()`, it already works anywhere; the hub just needs the built UI, so point the definition at it:
209210

210-
```ts [src/data-inspector.ts]
211+
```ts [src/node/data-inspector.ts]
211212
import { fileURLToPath } from 'node:url'
212213
// …
213214
const dataInspectorFrame = defineDevframe({
214215
id: 'data-inspector',
215216
/** … */
216-
clientAssets: fileURLToPath(new URL('../dist/client', import.meta.url)),
217+
clientAssets: fileURLToPath(new URL('../../dist/client', import.meta.url)),
217218
setup(ctx) { /* unchanged */ },
218219
})
219220
```
@@ -222,14 +223,14 @@ Build the UI and stand up a one-devframe hub:
222223

223224
```sh
224225
npm install @devframes/hub @devframes/hub-ui
225-
npx vite build --config vite.client.config.ts
226+
npx vite build --config app/vite.config.ts
226227
```
227228

228-
```ts [vite.hub.config.ts]
229+
```ts [playgrounds/hub.config.ts]
229230
import { createUi } from '@devframes/hub-ui'
230231
import { viteDevframeHub } from '@devframes/vite/hub'
231232
import { defineConfig } from 'vite'
232-
import dataInspectorFrame from './src/data-inspector.ts'
233+
import dataInspectorFrame from '../src/node/data-inspector.ts'
233234

234235
export default defineConfig({
235236
plugins: [
@@ -242,7 +243,7 @@ export default defineConfig({
242243
```
243244

244245
```sh
245-
npx vite --config vite.hub.config.ts
246+
npx vite --config playgrounds/hub.config.ts
246247
```
247248

248249
Your inspector now sits in the hub's dock rail as a dock entry. Add more to `devframes: [...]` (your own or the [built-in devframes](/add-ons)) and each gets its own. (The hub prints a code to authorize on first connect.)
@@ -265,14 +266,14 @@ ctx.rpc.register({
265266

266267
```js [scripts/build.mjs]
267268
import { createBuild } from 'devframe/adapters/build'
268-
import dataInspectorFrame from '../src/data-inspector.ts'
269+
import dataInspectorFrame from '../src/node/data-inspector.ts'
269270

270271
await createBuild(dataInspectorFrame, { outDir: 'dist-static' })
271272
```
272273

273274
```sh
274-
npx vite build # refresh dist/client
275-
node scripts/build.mjs # → dist-static/
275+
npx vite build --config app/vite.config.ts # refresh dist/client
276+
node scripts/build.mjs # → dist-static/
276277
```
277278

278279
Serve `dist-static/` anywhere and the meta list renders from the baked snapshot, no Node in sight. `query` takes an argument, so it still needs the live node side (next), or you can bake specific inputs ([Client Assets](/guide/client-assets)).
@@ -281,16 +282,16 @@ Serve `dist-static/` anywhere and the meta list renders from the baked snapshot,
281282

282283
The definition never depended on Vite. `createDevServer` runs the tool on its own, serving the UI from `clientAssets` and answering RPC live:
283284

284-
```js [scripts/serve.mjs]
285+
```js [playgrounds/serve.mjs]
285286
import { createDevServer } from 'devframe/adapters/dev'
286-
import dataInspectorFrame from '../src/data-inspector.ts'
287+
import dataInspectorFrame from '../src/node/data-inspector.ts'
287288

288289
await createDevServer(dataInspectorFrame, { openBrowser: true })
289290
```
290291

291292
```sh
292-
npx vite build
293-
node scripts/serve.mjs
293+
npx vite build --config app/vite.config.ts
294+
node playgrounds/serve.mjs
294295
```
295296

296297
Same UI, same live calls, no bundler in the loop: this is what you'd drop into your own Node program.
@@ -302,7 +303,7 @@ Finally, wrap that dev server in a CLI. `devframe/adapters/cac` turns a devframe
302303
```js [bin.mjs]
303304
#!/usr/bin/env node
304305
import { createCac } from 'devframe/adapters/cac'
305-
import dataInspectorFrame from './src/data-inspector.ts'
306+
import dataInspectorFrame from './src/node/data-inspector.ts'
306307

307308
createCac(dataInspectorFrame).parse()
308309
```

0 commit comments

Comments
 (0)