@nodegx/preview 0.0.0-stage → 0.2.0
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/LICENSE +674 -0
- package/README.md +161 -2
- package/bin/nodegx-deploy.js +20 -0
- package/bin/noodl-preview.js +14 -0
- package/dist/browser/noodl-graph-target.js +508 -0
- package/dist/browser/noodl-preview-in-page.js +101 -0
- package/dist/external/deploy/index.html +90 -0
- package/dist/external/deploy/index.js +23 -0
- package/dist/external/deploy/index.json +9 -0
- package/dist/external/deploy/load_terminator.js +1 -0
- package/dist/external/deploy/noodl-app.png +0 -0
- package/dist/external/deploy/noodl.deploy.js +2 -0
- package/dist/external/deploy/noodl.deploy.js.LICENSE.txt +20 -0
- package/dist/external/deploy/react-dom.production.min.js +267 -0
- package/dist/external/deploy/react.production.min.js +31 -0
- package/dist/external/deploy/react19/VERSION +2 -0
- package/dist/external/deploy/react19/react-dom.production.min.js +51 -0
- package/dist/external/deploy/react19/react.production.min.js +21 -0
- package/dist/nodegx-deploy.cjs +195103 -0
- package/dist/nodegx-deploy.inputs.json +988 -0
- package/dist/noodl-preview.cjs +194389 -0
- package/dist/noodl-preview.inputs.json +975 -0
- package/dist/package.json +6 -0
- package/package.json +41 -4
package/README.md
CHANGED
|
@@ -1,3 +1,162 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nodegx/preview — standalone live-preview harness
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Render a NodeGX (OpenNoodl) project in a browser **with no editor process**, and
|
|
4
|
+
reload it automatically when the files on disk change.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx @nodegx/preview ./my-project --open
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
That is the whole recipe: **point it at the folder your agent is editing.** An
|
|
11
|
+
MCP server, a script, or Claude writes v2 files; this watches them and the page
|
|
12
|
+
updates. It is the "see it" half of the AI-authoring loop — the editor's own
|
|
13
|
+
live preview is driven by its in-memory model over a WebSocket and cannot see
|
|
14
|
+
anything written to disk from outside.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
noodl-preview <project-dir> [options]
|
|
22
|
+
|
|
23
|
+
--port <n> Port to listen on (default 8575, 0 for any free port)
|
|
24
|
+
--host <addr> Address to bind (default 127.0.0.1)
|
|
25
|
+
--debounce <ms> Quiet period before rebuilding after a change (default 120)
|
|
26
|
+
--no-watch Render once and serve; do not watch
|
|
27
|
+
--open Open the preview in the default browser
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Accepts a **v2 project directory** (`nodegx.project.json` + `components/`) or a
|
|
31
|
+
**legacy `project.json`** (the directory or the file).
|
|
32
|
+
|
|
33
|
+
From the repo root, `npm run preview -- <dir>` builds the harness first, so it is
|
|
34
|
+
always in step with the sources. Direct invocation is
|
|
35
|
+
`node packages/noodl-preview/bin/noodl-preview.js <dir>`.
|
|
36
|
+
|
|
37
|
+
### Prerequisites
|
|
38
|
+
|
|
39
|
+
Installed from npm, the package needs nothing else. It carries the viewer runtime it renders with.
|
|
40
|
+
|
|
41
|
+
In a checkout of the NodeGX repository (`npm run preview -- ./my-project --open`), the deployed viewer runtime (`packages/noodl-editor/src/external/deploy/`) is a
|
|
42
|
+
build artifact and is not committed. If it is missing, the CLI says so and how to
|
|
43
|
+
fix it:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run build:editor:_viewer
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## What it does
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
project dir ──watch──> read ──> SUB-006 validate ──> ProjectModel ──> Exporter ──> serve ──SSE──> browser
|
|
55
|
+
│ │
|
|
56
|
+
└── errors ────────────────────────────────────────> diagnostics overlay
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- **Renders through the real deploy path.** The page it serves is the deployed
|
|
60
|
+
runtime template (`external/deploy/index.html` + `noodl.deploy.js`) calling
|
|
61
|
+
`renderDeployed`, fed by `Exporter.exportToJSON` with bundles and hashes on —
|
|
62
|
+
the same call `deployToFolder` makes. Component bundles are served from
|
|
63
|
+
`/noodl_bundles/<id>.json` exactly as a real deploy lays them out; project
|
|
64
|
+
assets are served from the project folder. Nothing about the export is
|
|
65
|
+
re-implemented here.
|
|
66
|
+
- **Validates before it renders.** Every snapshot goes through the SUB-006
|
|
67
|
+
semantic validator first. On errors the preview keeps the *last good render*
|
|
68
|
+
and puts the diagnostics on top of it, so a half-written edit reads as "the
|
|
69
|
+
edit isn't finished" instead of "the tool is broken". Warnings never block.
|
|
70
|
+
- **Reloads on change.** Chokidar watches the directory with a debounce (one
|
|
71
|
+
rebuild per burst of writes), and an injected SSE client reloads the page.
|
|
72
|
+
- **Touches nothing.** The harness only ever reads. It is safe to run against a
|
|
73
|
+
project the editor has open — it binds port 8575, clear of the editor's viewer
|
|
74
|
+
server on 8574.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Verified behaviour
|
|
79
|
+
|
|
80
|
+
Checked in headless Chrome against the `tests/fixtures/hello-world` project with
|
|
81
|
+
the Electron editor closed:
|
|
82
|
+
|
|
83
|
+
| | |
|
|
84
|
+
|---|---|
|
|
85
|
+
| Standalone render | "Hello World!" painted, console clean, no editor process |
|
|
86
|
+
| Live edit | a script rewriting `nodes.json` showed up in the browser inside 1s (rebuilds measured at 3–10 ms; the wall-clock cost is the debounce plus a page reload) |
|
|
87
|
+
| Invalid edit | a dangling connection produced the diagnostics overlay over the previous render — the broken graph never reached the runtime |
|
|
88
|
+
| Recovery | removing the bad connection cleared the overlay and re-rendered |
|
|
89
|
+
|
|
90
|
+
Also run against the real 176-component corpus project
|
|
91
|
+
(`packages/noodl-editor/tests/testfs/big-merge-test-mine`, legacy format): it
|
|
92
|
+
loads, validates (12 warnings, 0 errors) and exports in **733 ms**, and the page
|
|
93
|
+
does *not* paint — because one of the project's own bundled modules
|
|
94
|
+
(`noodl_modules/se-topp-fovea`) calls `Noodl.Collection.apply(this, arguments)`,
|
|
95
|
+
the ES5 Backbone pattern, against today's `class Collection extends Array` in
|
|
96
|
+
`noodl-runtime/src/collection.js`. That is a pre-existing module/runtime
|
|
97
|
+
incompatibility in the fixture — a real `deployToFolder` deploy of that project
|
|
98
|
+
fails identically — not a harness fault. It is recorded here because it is what
|
|
99
|
+
the harness is *for*: the whole pipeline (module injection, asset serving,
|
|
100
|
+
runtime setup) ran, and the failure surfaced where a real one would.
|
|
101
|
+
|
|
102
|
+
`npm --prefix packages/noodl-preview test` runs the same paths over HTTP against
|
|
103
|
+
the built CLI (14 specs). They drive `dist/noodl-preview.cjs` rather than the
|
|
104
|
+
TypeScript sources on purpose: the risk in this package is the *bundle* — the
|
|
105
|
+
platform binding, module stubs, and headless node-register load — and testing the
|
|
106
|
+
sources would exercise none of it.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## How it works headlessly
|
|
111
|
+
|
|
112
|
+
The interesting part is that the editor's export pipeline runs in plain Node at
|
|
113
|
+
all. `Exporter.exportToJSON` needs a `ProjectModel` and a populated
|
|
114
|
+
`NodeLibrary`, both of which normally only exist inside the running Electron app.
|
|
115
|
+
Four shims are enough (all in `build.mjs` and `src/headless.ts`):
|
|
116
|
+
|
|
117
|
+
1. `@noodl/platform` bound to `@noodl/platform-node`, imported before any editor
|
|
118
|
+
module — several read `platform.getUserDataPath()` at module scope.
|
|
119
|
+
2. `bugtracker` stubbed; at import time it hijacks `console.log` and writes to a
|
|
120
|
+
log file, which a CLI must not do.
|
|
121
|
+
3. The browser DOM globals the viewer's node modules touch at module scope
|
|
122
|
+
(shared with the node-catalog generator's `dom-shim.js`).
|
|
123
|
+
4. `NodeLibrary` fed from `NoodlRuntime.getNodeLibrary()` — the same node-library
|
|
124
|
+
JSON the editor receives over the WebSocket, produced in-process instead.
|
|
125
|
+
|
|
126
|
+
No node metadata, export logic, or runtime behaviour is duplicated.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Upgrade path: incremental hot-update
|
|
131
|
+
|
|
132
|
+
This harness does a **full page reload** on every change. That is deliberate for
|
|
133
|
+
a spike — it is a small amount of glue over engines that already exist, and it is
|
|
134
|
+
enough to demonstrate the loop.
|
|
135
|
+
|
|
136
|
+
The upgrade, when the experience proves it wants it, is to act as an `editor`
|
|
137
|
+
-role client of the existing viewer server (`packages/noodl-editor/src/main/src/
|
|
138
|
+
web-server.js`, port 8574) and emit the same `export`/`modelUpdate` messages
|
|
139
|
+
`ViewerConnection.ts` sends, computing the diff from before/after exports. That
|
|
140
|
+
buys true in-place updates at the cost of re-implementing the diff protocol —
|
|
141
|
+
worth it only once the payoff is proven. Deliberately not built here.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Layout
|
|
146
|
+
|
|
147
|
+
| File | Purpose |
|
|
148
|
+
|------|---------|
|
|
149
|
+
| `src/cli.ts` | Argument parsing and the watch → rebuild → serve loop |
|
|
150
|
+
| `src/headless.ts` | Platform binding + node-library bootstrap |
|
|
151
|
+
| `src/loader.ts` | Project dir → validated export JSON, bundles and HTML |
|
|
152
|
+
| `src/validate.ts` | The SUB-006 gate |
|
|
153
|
+
| `src/server.ts` | Static + generated routes, SSE channel |
|
|
154
|
+
| `src/client.ts` | The injected browser script and diagnostics overlay |
|
|
155
|
+
| `src/watcher.ts` | Debounced chokidar watch |
|
|
156
|
+
|
|
157
|
+
Task spec: `dev-docs/tasks/phase-13-format-ai-substrate/SUB-009-LIVE-PREVIEW-HARNESS.md`
|
|
158
|
+
|
|
159
|
+
## Licence
|
|
160
|
+
|
|
161
|
+
The preview is licensed GPL-3.0-only because it bundles code from the NodeGX editor. The source is in
|
|
162
|
+
[The-Low-Code-Foundation/NodeGX](https://github.com/The-Low-Code-Foundation/NodeGX), under `packages/noodl-preview`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* P112 OWN-016 — `nodegx deploy` from an npm install: `npx -y --package @nodegx/preview nodegx-deploy <project> <out>`.
|
|
4
|
+
*
|
|
5
|
+
* The deploy engine (`dist/nodegx-deploy.cjs`, HLS-015) already shipped in this package for `@nodegx/export`'s
|
|
6
|
+
* `nodegx deploy` to spawn, but `@nodegx/export` is not published and refuses outside a checkout by design. The
|
|
7
|
+
* engine itself was always a complete CLI: `<project-dir> <out-dir> [--base-url <url>]`, one JSON report on stdout,
|
|
8
|
+
* everything human on stderr. This gives it a name an install can run.
|
|
9
|
+
*/
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const engine = path.join(__dirname, '..', 'dist', 'nodegx-deploy.cjs');
|
|
14
|
+
if (!fs.existsSync(engine)) {
|
|
15
|
+
process.stderr.write(
|
|
16
|
+
'nodegx-deploy: dist/nodegx-deploy.cjs is missing.\n' + 'Build it first: npm --prefix packages/noodl-preview run build\n'
|
|
17
|
+
);
|
|
18
|
+
process.exit(2);
|
|
19
|
+
}
|
|
20
|
+
require(engine);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const dist = path.join(__dirname, '..', 'dist', 'noodl-preview.cjs');
|
|
6
|
+
if (!fs.existsSync(dist)) {
|
|
7
|
+
process.stderr.write(
|
|
8
|
+
'noodl-preview: dist/noodl-preview.cjs is missing.\n' +
|
|
9
|
+
'Build it first: npm --prefix packages/noodl-preview run build\n' +
|
|
10
|
+
'(or run `npm run preview -- <project-dir>` from the repo root, which builds for you)\n'
|
|
11
|
+
);
|
|
12
|
+
process.exit(2);
|
|
13
|
+
}
|
|
14
|
+
require(dist);
|