@vertz/ui-server 0.2.31 → 0.2.33
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/README.md +54 -50
- package/dist/bun-dev-server.d.ts +14 -1
- package/dist/bun-dev-server.js +56 -4
- package/dist/index.d.ts +301 -233
- package/dist/index.js +81 -151
- package/dist/node-handler.d.ts +76 -23
- package/dist/node-handler.js +2 -2
- package/dist/shared/{chunk-wb5fv233.js → chunk-2kx402c1.js} +62 -8
- package/dist/shared/{chunk-34fexgex.js → chunk-hx7drzm3.js} +599 -409
- package/dist/shared/{chunk-es0406qq.js → chunk-xdb8qn68.js} +17 -5
- package/dist/ssr/index.d.ts +119 -57
- package/dist/ssr/index.js +5 -4
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -85,14 +85,14 @@ const html = await renderToHTML(App, {
|
|
|
85
85
|
|
|
86
86
|
**Options:**
|
|
87
87
|
|
|
88
|
-
| Option
|
|
89
|
-
|
|
90
|
-
| `app`
|
|
91
|
-
| `url`
|
|
92
|
-
| `theme`
|
|
93
|
-
| `styles`
|
|
94
|
-
| `head`
|
|
95
|
-
| `container` | `string`
|
|
88
|
+
| Option | Type | Description |
|
|
89
|
+
| ----------- | ------------- | ----------------------------------------- |
|
|
90
|
+
| `app` | `() => VNode` | App component function |
|
|
91
|
+
| `url` | `string` | Request URL for SSR routing |
|
|
92
|
+
| `theme` | `Theme` | Theme definition for CSS vars |
|
|
93
|
+
| `styles` | `string[]` | Global CSS strings to inject |
|
|
94
|
+
| `head` | `object` | Head config: `title`, `meta[]`, `links[]` |
|
|
95
|
+
| `container` | `string` | Container selector (default `'#app'`) |
|
|
96
96
|
|
|
97
97
|
### `renderPage(vnode, options?)`
|
|
98
98
|
|
|
@@ -113,18 +113,18 @@ return renderPage(<App />, {
|
|
|
113
113
|
|
|
114
114
|
**Options:**
|
|
115
115
|
|
|
116
|
-
| Option
|
|
117
|
-
|
|
118
|
-
| `status`
|
|
119
|
-
| `title`
|
|
120
|
-
| `description` | `string`
|
|
121
|
-
| `lang`
|
|
122
|
-
| `favicon`
|
|
123
|
-
| `og`
|
|
124
|
-
| `twitter`
|
|
125
|
-
| `scripts`
|
|
126
|
-
| `styles`
|
|
127
|
-
| `head`
|
|
116
|
+
| Option | Type | Description |
|
|
117
|
+
| ------------- | ---------- | ---------------------------------------------------------- |
|
|
118
|
+
| `status` | `number` | HTTP status code (default `200`) |
|
|
119
|
+
| `title` | `string` | Page title |
|
|
120
|
+
| `description` | `string` | Meta description |
|
|
121
|
+
| `lang` | `string` | HTML lang attribute (default `'en'`) |
|
|
122
|
+
| `favicon` | `string` | Favicon URL |
|
|
123
|
+
| `og` | `object` | Open Graph: `title`, `description`, `image`, `url`, `type` |
|
|
124
|
+
| `twitter` | `object` | Twitter card: `card`, `site` |
|
|
125
|
+
| `scripts` | `string[]` | Script URLs for end of body |
|
|
126
|
+
| `styles` | `string[]` | Stylesheet URLs for head |
|
|
127
|
+
| `head` | `string` | Raw HTML escape hatch for head |
|
|
128
128
|
|
|
129
129
|
### `renderToStream(tree, options?)`
|
|
130
130
|
|
|
@@ -148,6 +148,7 @@ return new Response(stream, {
|
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
**Options:**
|
|
151
|
+
|
|
151
152
|
- `nonce?: string` — CSP nonce for inline scripts
|
|
152
153
|
|
|
153
154
|
### `serializeToHtml(node)`
|
|
@@ -203,11 +204,11 @@ removeDomShim();
|
|
|
203
204
|
|
|
204
205
|
**Note:** `renderToHTML` handles DOM shim setup and teardown automatically. You only need these when using lower-level rendering APIs.
|
|
205
206
|
|
|
206
|
-
| Export
|
|
207
|
-
|
|
207
|
+
| Export | Description |
|
|
208
|
+
| ------------------ | -------------------------------------------- |
|
|
208
209
|
| `installDomShim()` | Install the minimal DOM shim on `globalThis` |
|
|
209
|
-
| `removeDomShim()`
|
|
210
|
-
| `toVNode(element)` | Convert an SSR element to a VNode
|
|
210
|
+
| `removeDomShim()` | Remove the DOM shim from `globalThis` |
|
|
211
|
+
| `toVNode(element)` | Convert an SSR element to a VNode |
|
|
211
212
|
|
|
212
213
|
---
|
|
213
214
|
|
|
@@ -228,6 +229,7 @@ const headHtml = renderHeadToHtml(headCollector.getEntries());
|
|
|
228
229
|
```
|
|
229
230
|
|
|
230
231
|
**`HeadCollector` methods:**
|
|
232
|
+
|
|
231
233
|
- `addTitle(text)` — Add a `<title>` tag
|
|
232
234
|
- `addMeta(attrs)` — Add a `<meta>` tag
|
|
233
235
|
- `addLink(attrs)` — Add a `<link>` tag
|
|
@@ -266,7 +268,9 @@ const hydratedNode = wrapWithHydrationMarkers(counterNode, {
|
|
|
266
268
|
<div data-v-id="Counter" data-v-key="counter-0">
|
|
267
269
|
<span>Count: 0</span>
|
|
268
270
|
<button>+</button>
|
|
269
|
-
<script type="application/json">
|
|
271
|
+
<script type="application/json">
|
|
272
|
+
{ "initial": 0 }
|
|
273
|
+
</script>
|
|
270
274
|
</div>
|
|
271
275
|
```
|
|
272
276
|
|
|
@@ -363,24 +367,24 @@ await server.listen();
|
|
|
363
367
|
|
|
364
368
|
**Options:**
|
|
365
369
|
|
|
366
|
-
| Option
|
|
367
|
-
|
|
368
|
-
| `entry`
|
|
369
|
-
| `port`
|
|
370
|
-
| `host`
|
|
371
|
-
| `viteConfig`
|
|
372
|
-
| `middleware`
|
|
373
|
-
| `skipModuleInvalidation` | `boolean`
|
|
374
|
-
| `logRequests`
|
|
370
|
+
| Option | Type | Default | Description |
|
|
371
|
+
| ------------------------ | -------------- | ----------- | ----------------------------------------- |
|
|
372
|
+
| `entry` | `string` | (required) | Path to the SSR entry module |
|
|
373
|
+
| `port` | `number` | `5173` | Port to listen on |
|
|
374
|
+
| `host` | `string` | `'0.0.0.0'` | Host to bind to |
|
|
375
|
+
| `viteConfig` | `InlineConfig` | `{}` | Custom Vite configuration |
|
|
376
|
+
| `middleware` | `function` | — | Custom middleware before SSR handler |
|
|
377
|
+
| `skipModuleInvalidation` | `boolean` | `false` | Skip invalidating modules on each request |
|
|
378
|
+
| `logRequests` | `boolean` | `true` | Log requests to console |
|
|
375
379
|
|
|
376
380
|
**`DevServer` interface:**
|
|
377
381
|
|
|
378
|
-
| Property/Method | Description
|
|
379
|
-
|
|
380
|
-
| `listen()`
|
|
381
|
-
| `close()`
|
|
382
|
-
| `vite`
|
|
383
|
-
| `httpServer`
|
|
382
|
+
| Property/Method | Description |
|
|
383
|
+
| --------------- | ------------------------------ |
|
|
384
|
+
| `listen()` | Start the server |
|
|
385
|
+
| `close()` | Stop the server |
|
|
386
|
+
| `vite` | The underlying `ViteDevServer` |
|
|
387
|
+
| `httpServer` | The underlying `http.Server` |
|
|
384
388
|
|
|
385
389
|
The entry module should export a `renderToString(url: string)` function that returns HTML.
|
|
386
390
|
|
|
@@ -390,11 +394,11 @@ The entry module should export a `renderToString(url: string)` function that ret
|
|
|
390
394
|
|
|
391
395
|
The `@vertz/ui-server/jsx-runtime` subpath provides a server-side JSX factory that produces VNode trees compatible with `renderToStream`. During SSR, Vite's `ssrLoadModule` swaps this in automatically.
|
|
392
396
|
|
|
393
|
-
| Export
|
|
394
|
-
|
|
395
|
-
| `jsx`
|
|
396
|
-
| `jsxs`
|
|
397
|
-
| `Fragment` | Fragment component
|
|
397
|
+
| Export | Description |
|
|
398
|
+
| ---------- | ------------------------------------- |
|
|
399
|
+
| `jsx` | JSX factory for single-child elements |
|
|
400
|
+
| `jsxs` | JSX factory for multi-child elements |
|
|
401
|
+
| `Fragment` | Fragment component |
|
|
398
402
|
|
|
399
403
|
---
|
|
400
404
|
|
|
@@ -430,11 +434,11 @@ import type {
|
|
|
430
434
|
|
|
431
435
|
## Utilities
|
|
432
436
|
|
|
433
|
-
| Export
|
|
434
|
-
|
|
435
|
-
| `streamToString(stream)`
|
|
436
|
-
| `collectStreamChunks(stream)` | Collect stream chunks as a `string[]`
|
|
437
|
-
| `encodeChunk(html)`
|
|
437
|
+
| Export | Description |
|
|
438
|
+
| ----------------------------- | -------------------------------------------------- |
|
|
439
|
+
| `streamToString(stream)` | Convert a `ReadableStream<Uint8Array>` to a string |
|
|
440
|
+
| `collectStreamChunks(stream)` | Collect stream chunks as a `string[]` |
|
|
441
|
+
| `encodeChunk(html)` | Encode a string to a `Uint8Array` chunk |
|
|
438
442
|
|
|
439
443
|
---
|
|
440
444
|
|
package/dist/bun-dev-server.d.ts
CHANGED
|
@@ -133,6 +133,19 @@ declare function isStaleGraphError(message: string): boolean;
|
|
|
133
133
|
* addEventListener("DOMContentLoaded",function(event){location.reload()})
|
|
134
134
|
*/
|
|
135
135
|
declare function isReloadStub(text: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Determine whether the dev server should check for a stale dev bundler
|
|
138
|
+
* (and potentially restart) after a file change.
|
|
139
|
+
*
|
|
140
|
+
* When the bundle hash changed, the dev bundler processed the update
|
|
141
|
+
* successfully — HMR will deliver it. Checking for a reload stub would
|
|
142
|
+
* race with Bun's internal update and produce false positives.
|
|
143
|
+
*
|
|
144
|
+
* When the hash did NOT change, the dev bundler may be stuck (e.g. new
|
|
145
|
+
* file imported for the first time). The stale check is needed to detect
|
|
146
|
+
* this and auto-restart.
|
|
147
|
+
*/
|
|
148
|
+
declare function shouldCheckStaleBundler(hashChanged: boolean): boolean;
|
|
136
149
|
/** A resolved stack frame for terminal logging. */
|
|
137
150
|
interface TerminalStackFrame {
|
|
138
151
|
functionName: string | null;
|
|
@@ -244,4 +257,4 @@ declare function clearSSRRequireCache(): number;
|
|
|
244
257
|
* SSR is always on. HMR always works. No mode toggle needed.
|
|
245
258
|
*/
|
|
246
259
|
declare function createBunDevServer(options: BunDevServerOptions): BunDevServer;
|
|
247
|
-
export { parseHMRAssets, isStaleGraphError, isReloadStub, generateSSRPageHtml, formatTerminalRuntimeError, detectFaviconTag, createRuntimeErrorDeduplicator, createFetchInterceptor, createBunDevServer, clearSSRRequireCache, buildScriptTag, SSRPageHtmlOptions, HMRAssets, FetchInterceptorOptions, ErrorDetail, ErrorCategory, BunDevServerOptions, BunDevServer };
|
|
260
|
+
export { shouldCheckStaleBundler, parseHMRAssets, isStaleGraphError, isReloadStub, generateSSRPageHtml, formatTerminalRuntimeError, detectFaviconTag, createRuntimeErrorDeduplicator, createFetchInterceptor, createBunDevServer, clearSSRRequireCache, buildScriptTag, SSRPageHtmlOptions, HMRAssets, FetchInterceptorOptions, ErrorDetail, ErrorCategory, BunDevServerOptions, BunDevServer };
|
package/dist/bun-dev-server.js
CHANGED
|
@@ -2556,6 +2556,9 @@ function isStaleGraphError(message) {
|
|
|
2556
2556
|
function isReloadStub(text) {
|
|
2557
2557
|
return text.trimStart().startsWith("try{location.reload()}");
|
|
2558
2558
|
}
|
|
2559
|
+
function shouldCheckStaleBundler(hashChanged) {
|
|
2560
|
+
return !hashChanged;
|
|
2561
|
+
}
|
|
2559
2562
|
var MAX_TERMINAL_STACK_FRAMES = 5;
|
|
2560
2563
|
function formatTerminalRuntimeError(errors, parsedStack) {
|
|
2561
2564
|
const primary = errors[0];
|
|
@@ -2883,6 +2886,7 @@ var BUILD_ERROR_LOADER = [
|
|
|
2883
2886
|
"fetch(src).then(function(r){return r.text()}).then(function(t){",
|
|
2884
2887
|
"if(t.trimStart().startsWith('try{location.reload()}')){",
|
|
2885
2888
|
"fetch('/__vertz_build_check').then(function(r){return r.json()}).then(function(j){",
|
|
2889
|
+
`if(j.restarting){showOverlay('Restarting dev server','<p style="margin:0;color:#666;font-size:12px">Stale module graph detected. Restarting...</p>');sessionStorage.removeItem('__vertz_stub_retry');return}`,
|
|
2886
2890
|
"if(j.errors&&j.errors.length>0){showOverlay('Build failed',formatErrors(j.errors),j)}",
|
|
2887
2891
|
"else{var V2=window.__vertz_overlay;",
|
|
2888
2892
|
"if(V2&&V2._autoRestart&&V2._canAutoRestart&&V2._canAutoRestart()){",
|
|
@@ -3045,6 +3049,7 @@ function createBunDevServer(options) {
|
|
|
3045
3049
|
pendingRuntimeError = null;
|
|
3046
3050
|
}
|
|
3047
3051
|
clearGraceUntil = Date.now() + 5000;
|
|
3052
|
+
autoRestartTimestamps.length = 0;
|
|
3048
3053
|
const msg = JSON.stringify({ type: "clear" });
|
|
3049
3054
|
for (const ws of wsClients) {
|
|
3050
3055
|
ws.sendText(msg);
|
|
@@ -3061,6 +3066,7 @@ function createBunDevServer(options) {
|
|
|
3061
3066
|
pendingRuntimeError = null;
|
|
3062
3067
|
}
|
|
3063
3068
|
clearGraceUntil = 0;
|
|
3069
|
+
autoRestartTimestamps.length = 0;
|
|
3064
3070
|
const msg = JSON.stringify({ type: "clear" });
|
|
3065
3071
|
for (const ws of wsClients) {
|
|
3066
3072
|
ws.sendText(msg);
|
|
@@ -3488,6 +3494,20 @@ if (import.meta.hot) import.meta.hot.accept();
|
|
|
3488
3494
|
if (lastBuildError) {
|
|
3489
3495
|
return Response.json({ errors: [{ message: lastBuildError }] });
|
|
3490
3496
|
}
|
|
3497
|
+
if (bundledScriptUrl && !isRestarting && canAutoRestart()) {
|
|
3498
|
+
try {
|
|
3499
|
+
const bundleRes = await fetch(`http://${host}:${server?.port}${bundledScriptUrl}`);
|
|
3500
|
+
const bundleText = await bundleRes.text();
|
|
3501
|
+
if (isReloadStub(bundleText)) {
|
|
3502
|
+
autoRestartTimestamps.push(Date.now());
|
|
3503
|
+
if (logRequests) {
|
|
3504
|
+
console.log("[Server] Build check: dev bundler stale \u2014 restarting");
|
|
3505
|
+
}
|
|
3506
|
+
devServer.restart();
|
|
3507
|
+
return Response.json({ errors: [], restarting: true });
|
|
3508
|
+
}
|
|
3509
|
+
} catch {}
|
|
3510
|
+
}
|
|
3491
3511
|
return Response.json({ errors: [] });
|
|
3492
3512
|
} catch (e) {
|
|
3493
3513
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -3852,6 +3872,27 @@ data: {}
|
|
|
3852
3872
|
console.warn("[Server] Could not discover HMR bundled URL:", e);
|
|
3853
3873
|
}
|
|
3854
3874
|
}
|
|
3875
|
+
async function checkAndRestartIfBundlerStale() {
|
|
3876
|
+
if (!bundledScriptUrl || !server || isRestarting)
|
|
3877
|
+
return false;
|
|
3878
|
+
try {
|
|
3879
|
+
const bundleRes = await fetch(`http://${host}:${server.port}${bundledScriptUrl}`);
|
|
3880
|
+
const bundleText = await bundleRes.text();
|
|
3881
|
+
if (isReloadStub(bundleText)) {
|
|
3882
|
+
if (canAutoRestart()) {
|
|
3883
|
+
autoRestartTimestamps.push(Date.now());
|
|
3884
|
+
if (logRequests) {
|
|
3885
|
+
console.log("[Server] Dev bundler still serving reload stub after SSR recovery \u2014 restarting");
|
|
3886
|
+
}
|
|
3887
|
+
devServer.restart();
|
|
3888
|
+
return true;
|
|
3889
|
+
} else if (logRequests) {
|
|
3890
|
+
console.log("[Server] Dev bundler stale but auto-restart cap reached");
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
} catch {}
|
|
3894
|
+
return false;
|
|
3895
|
+
}
|
|
3855
3896
|
stopped = false;
|
|
3856
3897
|
if (existsSync2(srcDir)) {
|
|
3857
3898
|
srcWatcherRef = watch2(srcDir, { recursive: true }, (_event, filename) => {
|
|
@@ -3875,6 +3916,7 @@ data: {}
|
|
|
3875
3916
|
await discoverHMRAssets();
|
|
3876
3917
|
if (stopped)
|
|
3877
3918
|
return;
|
|
3919
|
+
let hashChanged = false;
|
|
3878
3920
|
try {
|
|
3879
3921
|
const clientRelative = rawClientSrc.replace(/^\//, "");
|
|
3880
3922
|
const result = await Bun.build({
|
|
@@ -3906,10 +3948,12 @@ data: {}
|
|
|
3906
3948
|
if (stopped)
|
|
3907
3949
|
return;
|
|
3908
3950
|
await discoverHMRAssets();
|
|
3909
|
-
if (bundledScriptUrl !== prevUrl)
|
|
3951
|
+
if (bundledScriptUrl !== prevUrl) {
|
|
3952
|
+
hashChanged = true;
|
|
3910
3953
|
break;
|
|
3954
|
+
}
|
|
3911
3955
|
}
|
|
3912
|
-
if (bundledScriptUrl && server && !isRestarting) {
|
|
3956
|
+
if (!hashChanged && bundledScriptUrl && server && !isRestarting) {
|
|
3913
3957
|
try {
|
|
3914
3958
|
const bundleRes = await fetch(`http://${host}:${server.port}${bundledScriptUrl}`);
|
|
3915
3959
|
const bundleText = await bundleRes.text();
|
|
@@ -3927,7 +3971,6 @@ data: {}
|
|
|
3927
3971
|
}
|
|
3928
3972
|
} catch {}
|
|
3929
3973
|
}
|
|
3930
|
-
clearErrorForFileChange();
|
|
3931
3974
|
}
|
|
3932
3975
|
} catch {}
|
|
3933
3976
|
if (stopped)
|
|
@@ -3977,8 +4020,10 @@ data: {}
|
|
|
3977
4020
|
return;
|
|
3978
4021
|
}
|
|
3979
4022
|
if (logRequests) {
|
|
3980
|
-
console.log("[Server] SSR in fallback mode \u2014
|
|
4023
|
+
console.log("[Server] SSR in fallback mode \u2014 restarting dev server");
|
|
3981
4024
|
}
|
|
4025
|
+
devServer.restart();
|
|
4026
|
+
return;
|
|
3982
4027
|
}
|
|
3983
4028
|
const cacheCleared = clearSSRRequireCache();
|
|
3984
4029
|
logger.log("watcher", "cache-cleared", { entries: cacheCleared });
|
|
@@ -4002,6 +4047,9 @@ data: {}
|
|
|
4002
4047
|
if (logRequests) {
|
|
4003
4048
|
console.log("[Server] SSR module refreshed");
|
|
4004
4049
|
}
|
|
4050
|
+
if (!hashChanged && await checkAndRestartIfBundlerStale())
|
|
4051
|
+
return;
|
|
4052
|
+
clearErrorForFileChange();
|
|
4005
4053
|
} catch {
|
|
4006
4054
|
logger.log("watcher", "ssr-reload", { status: "retry" });
|
|
4007
4055
|
if (stopped)
|
|
@@ -4028,6 +4076,9 @@ data: {}
|
|
|
4028
4076
|
if (logRequests) {
|
|
4029
4077
|
console.log("[Server] SSR module refreshed (retry)");
|
|
4030
4078
|
}
|
|
4079
|
+
if (!hashChanged && await checkAndRestartIfBundlerStale())
|
|
4080
|
+
return;
|
|
4081
|
+
clearErrorForFileChange();
|
|
4031
4082
|
} catch (e2) {
|
|
4032
4083
|
console.error("[Server] Failed to refresh SSR module:", e2);
|
|
4033
4084
|
const errMsg = e2 instanceof Error ? e2.message : String(e2);
|
|
@@ -4138,6 +4189,7 @@ data: {}
|
|
|
4138
4189
|
return devServer;
|
|
4139
4190
|
}
|
|
4140
4191
|
export {
|
|
4192
|
+
shouldCheckStaleBundler,
|
|
4141
4193
|
parseHMRAssets,
|
|
4142
4194
|
isStaleGraphError,
|
|
4143
4195
|
isReloadStub,
|