@timber-js/app 0.2.0-alpha.23 → 0.2.0-alpha.25

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-render.d.ts","sourceRoot":"","sources":["../../src/server/ssr-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA0DvC;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE;IAAE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC7F,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAKrC;AAkHD;;;;;;;;;;;;GAYG;AACH,2CAA2C;AAC3C,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,UAAU,CAAC,CA2B5B;AAWD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,EACtC,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,GACvB,QAAQ,CASV"}
1
+ {"version":3,"file":"ssr-render.d.ts","sourceRoot":"","sources":["../../src/server/ssr-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA0EvC;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE;IAAE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC7F,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAKrC;AAkHD;;;;;;;;;;;;GAYG;AACH,2CAA2C;AAC3C,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,UAAU,CAAC,CA2B5B;AAWD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,EACtC,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,GACvB,QAAQ,CASV"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timber-js/app",
3
- "version": "0.2.0-alpha.23",
3
+ "version": "0.2.0-alpha.25",
4
4
  "description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
5
5
  "keywords": [
6
6
  "cloudflare-workers",
@@ -21,7 +21,7 @@
21
21
  */
22
22
 
23
23
  import type { ReactNode } from 'react';
24
- import { renderToReadableStream, renderToPipeableStream } from 'react-dom/server';
24
+ import { renderToReadableStream } from 'react-dom/server';
25
25
 
26
26
  import { formatSsrError } from './error-formatter.js';
27
27
 
@@ -54,9 +54,11 @@ const NOINDEX_SCRIPT =
54
54
  let _useNodeStreams = false;
55
55
  let _PassThrough: typeof import('node:stream').PassThrough | null = null;
56
56
  let _ReadableToWeb: ((readable: import('node:stream').Readable) => ReadableStream) | null = null;
57
+ let _renderToPipeableStream: typeof import('react-dom/server').renderToPipeableStream | null = null;
57
58
 
58
59
  try {
59
- // Dynamic import to avoid bundling node:stream for CF Workers builds.
60
+ // Dynamic imports to avoid bundling node:stream and the Node.js-specific
61
+ // react-dom/server entry for CF Workers builds.
60
62
  // On Node.js/Bun this resolves to native C++ streams.
61
63
  // On CF Workers this either fails or returns a JS polyfill.
62
64
  const nodeStream = await import('node:stream');
@@ -68,16 +70,30 @@ try {
68
70
  typeof process !== 'undefined' &&
69
71
  process.release?.name === 'node'
70
72
  ) {
71
- _useNodeStreams = true;
72
- _PassThrough = nodeStream.PassThrough;
73
- _ReadableToWeb = nodeStream.Readable.toWeb as (
74
- readable: import('node:stream').Readable
75
- ) => ReadableStream;
73
+ // Dynamically import renderToPipeableStream from the Node.js-specific
74
+ // entry point. The SSR bundle resolves react-dom/server to the edge/browser
75
+ // export (which lacks renderToPipeableStream), so we import the .node file
76
+ // directly. This is safe because we're inside a process.release.name === 'node'
77
+ // guard — this code only runs on real Node.js.
78
+ const reactDomServer = await import('react-dom/server.node');
79
+ if (typeof reactDomServer.renderToPipeableStream === 'function') {
80
+ _useNodeStreams = true;
81
+ _PassThrough = nodeStream.PassThrough;
82
+ _ReadableToWeb = nodeStream.Readable.toWeb as (
83
+ readable: import('node:stream').Readable
84
+ ) => ReadableStream;
85
+ _renderToPipeableStream = reactDomServer.renderToPipeableStream;
86
+ }
76
87
  }
77
- } catch {
78
- // node:stream not available — use Web Streams path
88
+ } catch (e) {
89
+ // node:stream or renderToPipeableStream not available — use Web Streams path
90
+ // eslint-disable-next-line no-console
91
+ console.log(`[timber] SSR stream detection: falling back to Web Streams (${e instanceof Error ? e.message : e})`);
79
92
  }
80
93
 
94
+ // eslint-disable-next-line no-console
95
+ console.log(`[timber] SSR render path: ${_useNodeStreams ? 'renderToPipeableStream (Node.js native)' : 'renderToReadableStream (Web Streams)'}`);
96
+
81
97
  /**
82
98
  * Render a React element tree to a ReadableStream of HTML.
83
99
  *
@@ -127,7 +143,7 @@ async function renderViaPipeableStream(
127
143
  // Suppress unhandled rejection if nobody awaits allReady
128
144
  allReady.catch(() => {});
129
145
 
130
- const { pipe, abort } = renderToPipeableStream(element, {
146
+ const { pipe, abort } = _renderToPipeableStream!(element, {
131
147
  bootstrapScriptContent: options?.bootstrapScriptContent || undefined,
132
148
 
133
149
  onShellReady() {