hadars 0.1.28 → 0.1.30
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/dist/cli.js +162 -37
- package/dist/index.cjs +1 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -4
- package/dist/slim-react/index.cjs +87 -10
- package/dist/slim-react/index.d.ts +11 -3
- package/dist/slim-react/index.js +77 -10
- package/dist/ssr-render-worker.js +152 -23
- package/dist/utils/Head.tsx +6 -8
- package/package.json +5 -3
- package/src/build.ts +13 -8
- package/src/slim-react/dispatcher.ts +84 -0
- package/src/slim-react/index.ts +1 -1
- package/src/slim-react/render.ts +52 -8
- package/src/slim-react/renderContext.ts +14 -8
- package/src/ssr-render-worker.ts +11 -16
- package/src/utils/Head.tsx +6 -8
- package/src/utils/response.tsx +8 -23
package/dist/cli.js
CHANGED
|
@@ -141,7 +141,6 @@ var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
|
141
141
|
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
142
142
|
|
|
143
143
|
// src/slim-react/jsx.ts
|
|
144
|
-
var Fragment = FRAGMENT_TYPE;
|
|
145
144
|
function createElement(type, props, ...children) {
|
|
146
145
|
const normalizedProps = { ...props || {} };
|
|
147
146
|
if (children.length === 1) {
|
|
@@ -198,10 +197,11 @@ function s() {
|
|
|
198
197
|
}
|
|
199
198
|
return g[GLOBAL_KEY];
|
|
200
199
|
}
|
|
201
|
-
function resetRenderState() {
|
|
200
|
+
function resetRenderState(idPrefix = "") {
|
|
202
201
|
const st = s();
|
|
203
202
|
st.currentTreeContext = { ...EMPTY };
|
|
204
203
|
st.localIdCounter = 0;
|
|
204
|
+
st.idPrefix = idPrefix;
|
|
205
205
|
}
|
|
206
206
|
function pushTreeContext(totalChildren, index) {
|
|
207
207
|
const st = s();
|
|
@@ -242,6 +242,9 @@ function pushComponentScope() {
|
|
|
242
242
|
function popComponentScope(saved) {
|
|
243
243
|
s().localIdCounter = saved;
|
|
244
244
|
}
|
|
245
|
+
function componentCalledUseId() {
|
|
246
|
+
return s().localIdCounter > 0;
|
|
247
|
+
}
|
|
245
248
|
function snapshotContext() {
|
|
246
249
|
const st = s();
|
|
247
250
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -251,6 +254,121 @@ function restoreContext(snap) {
|
|
|
251
254
|
st.currentTreeContext = { ...snap.tree };
|
|
252
255
|
st.localIdCounter = snap.localId;
|
|
253
256
|
}
|
|
257
|
+
function getTreeId() {
|
|
258
|
+
const { id, overflow } = s().currentTreeContext;
|
|
259
|
+
if (id === 1)
|
|
260
|
+
return overflow;
|
|
261
|
+
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
262
|
+
return stripped + overflow;
|
|
263
|
+
}
|
|
264
|
+
function makeId() {
|
|
265
|
+
const st = s();
|
|
266
|
+
const treeId = getTreeId();
|
|
267
|
+
const n = st.localIdCounter++;
|
|
268
|
+
let id = "_R_" + st.idPrefix + treeId;
|
|
269
|
+
if (n > 0)
|
|
270
|
+
id += "H" + n.toString(32);
|
|
271
|
+
return id + "_";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/slim-react/hooks.ts
|
|
275
|
+
function useState(initialState) {
|
|
276
|
+
const value = typeof initialState === "function" ? initialState() : initialState;
|
|
277
|
+
return [value, () => {
|
|
278
|
+
}];
|
|
279
|
+
}
|
|
280
|
+
function useReducer(_reducer, initialState) {
|
|
281
|
+
return [initialState, () => {
|
|
282
|
+
}];
|
|
283
|
+
}
|
|
284
|
+
function useEffect(_effect, _deps) {
|
|
285
|
+
}
|
|
286
|
+
function useLayoutEffect(_effect, _deps) {
|
|
287
|
+
}
|
|
288
|
+
function useInsertionEffect(_effect, _deps) {
|
|
289
|
+
}
|
|
290
|
+
function useRef(initialValue) {
|
|
291
|
+
return { current: initialValue };
|
|
292
|
+
}
|
|
293
|
+
function useMemo(factory, _deps) {
|
|
294
|
+
return factory();
|
|
295
|
+
}
|
|
296
|
+
function useCallback(callback, _deps) {
|
|
297
|
+
return callback;
|
|
298
|
+
}
|
|
299
|
+
function useDebugValue(_value, _format) {
|
|
300
|
+
}
|
|
301
|
+
function useImperativeHandle(_ref, _createHandle, _deps) {
|
|
302
|
+
}
|
|
303
|
+
function useSyncExternalStore(_subscribe, getSnapshot, getServerSnapshot) {
|
|
304
|
+
return (getServerSnapshot || getSnapshot)();
|
|
305
|
+
}
|
|
306
|
+
function useTransition() {
|
|
307
|
+
return [false, (cb) => cb()];
|
|
308
|
+
}
|
|
309
|
+
function useDeferredValue(value) {
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
function useOptimistic(passthrough) {
|
|
313
|
+
return [passthrough, () => {
|
|
314
|
+
}];
|
|
315
|
+
}
|
|
316
|
+
function useActionState(_action, initialState, _permalink) {
|
|
317
|
+
return [initialState, () => {
|
|
318
|
+
}, false];
|
|
319
|
+
}
|
|
320
|
+
function use(usable) {
|
|
321
|
+
if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
|
|
322
|
+
return getContextValue(usable);
|
|
323
|
+
}
|
|
324
|
+
const promise = usable;
|
|
325
|
+
if (promise.status === "fulfilled")
|
|
326
|
+
return promise.value;
|
|
327
|
+
if (promise.status === "rejected")
|
|
328
|
+
throw promise.reason;
|
|
329
|
+
throw promise;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/slim-react/dispatcher.ts
|
|
333
|
+
import * as ReactNS from "react";
|
|
334
|
+
var _internals = ReactNS.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
335
|
+
var slimDispatcher = {
|
|
336
|
+
useId: makeId,
|
|
337
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
338
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
339
|
+
useState,
|
|
340
|
+
useReducer,
|
|
341
|
+
useEffect,
|
|
342
|
+
useLayoutEffect,
|
|
343
|
+
useInsertionEffect,
|
|
344
|
+
useRef,
|
|
345
|
+
useMemo,
|
|
346
|
+
useCallback,
|
|
347
|
+
useDebugValue,
|
|
348
|
+
useImperativeHandle,
|
|
349
|
+
useSyncExternalStore,
|
|
350
|
+
useTransition,
|
|
351
|
+
useDeferredValue,
|
|
352
|
+
useOptimistic,
|
|
353
|
+
useActionState,
|
|
354
|
+
use,
|
|
355
|
+
// React internals that compiled output may call
|
|
356
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
357
|
+
useCacheRefresh: () => () => {
|
|
358
|
+
},
|
|
359
|
+
useHostTransitionStatus: () => false
|
|
360
|
+
};
|
|
361
|
+
function installDispatcher() {
|
|
362
|
+
if (!_internals)
|
|
363
|
+
return null;
|
|
364
|
+
const prev = _internals.H;
|
|
365
|
+
_internals.H = slimDispatcher;
|
|
366
|
+
return prev;
|
|
367
|
+
}
|
|
368
|
+
function restoreDispatcher(prev) {
|
|
369
|
+
if (_internals)
|
|
370
|
+
_internals.H = prev;
|
|
371
|
+
}
|
|
254
372
|
|
|
255
373
|
// src/slim-react/render.ts
|
|
256
374
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
@@ -655,6 +773,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
655
773
|
return;
|
|
656
774
|
}
|
|
657
775
|
let result;
|
|
776
|
+
const prevDispatcher = installDispatcher();
|
|
658
777
|
try {
|
|
659
778
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
660
779
|
const instance = new type(props);
|
|
@@ -668,12 +787,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
668
787
|
result = type(props);
|
|
669
788
|
}
|
|
670
789
|
} catch (e) {
|
|
790
|
+
restoreDispatcher(prevDispatcher);
|
|
671
791
|
popComponentScope(savedScope);
|
|
672
792
|
if (isProvider)
|
|
673
793
|
popContextValue(ctx, prevCtxValue);
|
|
674
794
|
throw e;
|
|
675
795
|
}
|
|
796
|
+
restoreDispatcher(prevDispatcher);
|
|
797
|
+
let savedIdTree;
|
|
798
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
799
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
800
|
+
}
|
|
676
801
|
const finish = () => {
|
|
802
|
+
if (savedIdTree !== void 0)
|
|
803
|
+
popTreeContext(savedIdTree);
|
|
677
804
|
popComponentScope(savedScope);
|
|
678
805
|
if (isProvider)
|
|
679
806
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -682,22 +809,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
682
809
|
const m = captureMap();
|
|
683
810
|
return result.then((resolved) => {
|
|
684
811
|
swapContextMap(m);
|
|
812
|
+
let asyncSavedIdTree;
|
|
813
|
+
if (componentCalledUseId()) {
|
|
814
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
815
|
+
}
|
|
816
|
+
const asyncFinish = () => {
|
|
817
|
+
if (asyncSavedIdTree !== void 0)
|
|
818
|
+
popTreeContext(asyncSavedIdTree);
|
|
819
|
+
popComponentScope(savedScope);
|
|
820
|
+
if (isProvider)
|
|
821
|
+
popContextValue(ctx, prevCtxValue);
|
|
822
|
+
};
|
|
685
823
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
686
824
|
if (r2 && typeof r2.then === "function") {
|
|
687
825
|
const m2 = captureMap();
|
|
688
826
|
return r2.then(
|
|
689
827
|
() => {
|
|
690
828
|
swapContextMap(m2);
|
|
691
|
-
|
|
829
|
+
asyncFinish();
|
|
692
830
|
},
|
|
693
831
|
(e) => {
|
|
694
832
|
swapContextMap(m2);
|
|
695
|
-
|
|
833
|
+
asyncFinish();
|
|
696
834
|
throw e;
|
|
697
835
|
}
|
|
698
836
|
);
|
|
699
837
|
}
|
|
700
|
-
|
|
838
|
+
asyncFinish();
|
|
701
839
|
}, (e) => {
|
|
702
840
|
swapContextMap(m);
|
|
703
841
|
finish();
|
|
@@ -777,8 +915,8 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
777
915
|
const snap = snapshotContext();
|
|
778
916
|
while (attempts < MAX_SUSPENSE_RETRIES) {
|
|
779
917
|
restoreContext(snap);
|
|
918
|
+
let buffer = new BufferWriter();
|
|
780
919
|
try {
|
|
781
|
-
const buffer = new BufferWriter();
|
|
782
920
|
const r = renderNode(children, buffer, isSvg);
|
|
783
921
|
if (r && typeof r.then === "function") {
|
|
784
922
|
const m = captureMap();
|
|
@@ -812,12 +950,13 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
812
950
|
}
|
|
813
951
|
writer.write("<!--/$-->");
|
|
814
952
|
}
|
|
815
|
-
async function renderToString(element) {
|
|
953
|
+
async function renderToString(element, options) {
|
|
954
|
+
const idPrefix = options?.identifierPrefix ?? "";
|
|
816
955
|
const contextMap = /* @__PURE__ */ new Map();
|
|
817
956
|
const prev = swapContextMap(contextMap);
|
|
818
957
|
try {
|
|
819
958
|
for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
|
|
820
|
-
resetRenderState();
|
|
959
|
+
resetRenderState(idPrefix);
|
|
821
960
|
swapContextMap(contextMap);
|
|
822
961
|
const chunks = [];
|
|
823
962
|
const writer = {
|
|
@@ -934,31 +1073,14 @@ var getReactResponse = async (req, opts) => {
|
|
|
934
1073
|
location: req.location,
|
|
935
1074
|
...Object.keys(serverData).length > 0 ? { __serverData: serverData } : {}
|
|
936
1075
|
};
|
|
937
|
-
const
|
|
938
|
-
Fragment,
|
|
939
|
-
null,
|
|
940
|
-
createElement(
|
|
941
|
-
"div",
|
|
942
|
-
{ id: "app" },
|
|
943
|
-
createElement(App, { ...props, location: req.location, context })
|
|
944
|
-
),
|
|
945
|
-
createElement("script", {
|
|
946
|
-
id: "hadars",
|
|
947
|
-
type: "application/json",
|
|
948
|
-
dangerouslySetInnerHTML: {
|
|
949
|
-
__html: JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c")
|
|
950
|
-
}
|
|
951
|
-
})
|
|
952
|
-
);
|
|
1076
|
+
const appProps = { ...props, location: req.location, context };
|
|
953
1077
|
return {
|
|
954
|
-
|
|
1078
|
+
App,
|
|
1079
|
+
appProps,
|
|
1080
|
+
clientProps,
|
|
955
1081
|
unsuspend,
|
|
956
1082
|
status: context.head.status,
|
|
957
|
-
headHtml: getHeadHtml(context.head)
|
|
958
|
-
renderPayload: {
|
|
959
|
-
appProps: { ...props, location: req.location, context },
|
|
960
|
-
clientProps
|
|
961
|
-
}
|
|
1083
|
+
headHtml: getHeadHtml(context.head)
|
|
962
1084
|
};
|
|
963
1085
|
};
|
|
964
1086
|
|
|
@@ -1692,7 +1814,7 @@ var RenderWorkerPool = class {
|
|
|
1692
1814
|
await Promise.all(this.workers.map((w) => w.terminate()));
|
|
1693
1815
|
}
|
|
1694
1816
|
};
|
|
1695
|
-
async function buildSsrResponse(
|
|
1817
|
+
async function buildSsrResponse(App, appProps, clientProps, headHtml, status, getPrecontentHtml, unsuspendForRender) {
|
|
1696
1818
|
const responseStream = new ReadableStream({
|
|
1697
1819
|
async start(controller) {
|
|
1698
1820
|
const [precontentHtml, postContent] = await getPrecontentHtml(headHtml);
|
|
@@ -1700,12 +1822,15 @@ async function buildSsrResponse(ReactPage, headHtml, status, getPrecontentHtml,
|
|
|
1700
1822
|
let bodyHtml;
|
|
1701
1823
|
try {
|
|
1702
1824
|
globalThis.__hadarsUnsuspend = unsuspendForRender;
|
|
1703
|
-
bodyHtml = await renderToString(
|
|
1825
|
+
bodyHtml = await renderToString(createElement(App, appProps));
|
|
1704
1826
|
} finally {
|
|
1705
1827
|
globalThis.__hadarsUnsuspend = null;
|
|
1706
1828
|
}
|
|
1707
1829
|
bodyHtml = processSegmentCache(bodyHtml);
|
|
1708
|
-
|
|
1830
|
+
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
1831
|
+
controller.enqueue(encoder.encode(
|
|
1832
|
+
`<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` + postContent
|
|
1833
|
+
));
|
|
1709
1834
|
controller.close();
|
|
1710
1835
|
}
|
|
1711
1836
|
});
|
|
@@ -2075,7 +2200,7 @@ var dev = async (options) => {
|
|
|
2075
2200
|
getAfterRenderProps,
|
|
2076
2201
|
getFinalProps
|
|
2077
2202
|
} = await import(importPath);
|
|
2078
|
-
const {
|
|
2203
|
+
const { App, appProps, clientProps, unsuspend, status, headHtml } = await getReactResponse(request, {
|
|
2079
2204
|
document: {
|
|
2080
2205
|
body: Component,
|
|
2081
2206
|
lang: "en",
|
|
@@ -2084,7 +2209,7 @@ var dev = async (options) => {
|
|
|
2084
2209
|
getFinalProps
|
|
2085
2210
|
}
|
|
2086
2211
|
});
|
|
2087
|
-
return buildSsrResponse(
|
|
2212
|
+
return buildSsrResponse(App, appProps, clientProps, headHtml, status, getPrecontentHtml, unsuspend);
|
|
2088
2213
|
} catch (err) {
|
|
2089
2214
|
console.error("[hadars] SSR render error:", err);
|
|
2090
2215
|
const msg = (err?.stack ?? err?.message ?? String(err)).replace(/</g, "<");
|
|
@@ -2229,7 +2354,7 @@ var run = async (options) => {
|
|
|
2229
2354
|
status: wStatus
|
|
2230
2355
|
});
|
|
2231
2356
|
}
|
|
2232
|
-
const {
|
|
2357
|
+
const { App, appProps, clientProps, unsuspend, status, headHtml } = await getReactResponse(request, {
|
|
2233
2358
|
document: {
|
|
2234
2359
|
body: Component,
|
|
2235
2360
|
lang: "en",
|
|
@@ -2238,7 +2363,7 @@ var run = async (options) => {
|
|
|
2238
2363
|
getFinalProps
|
|
2239
2364
|
}
|
|
2240
2365
|
});
|
|
2241
|
-
return buildSsrResponse(
|
|
2366
|
+
return buildSsrResponse(App, appProps, clientProps, headHtml, status, getPrecontentHtml, unsuspend);
|
|
2242
2367
|
} catch (err) {
|
|
2243
2368
|
console.error("[hadars] SSR render error:", err);
|
|
2244
2369
|
return new Response("Internal Server Error", { status: 500 });
|
package/dist/index.cjs
CHANGED
|
@@ -183,10 +183,7 @@ function initServerDataCache(data) {
|
|
|
183
183
|
function useServerData(key, fn) {
|
|
184
184
|
const cacheKey = Array.isArray(key) ? JSON.stringify(key) : key;
|
|
185
185
|
if (typeof window !== "undefined") {
|
|
186
|
-
|
|
187
|
-
return clientServerDataCache.get(cacheKey);
|
|
188
|
-
}
|
|
189
|
-
return fn();
|
|
186
|
+
return clientServerDataCache.get(cacheKey);
|
|
190
187
|
}
|
|
191
188
|
const unsuspend = globalThis.__hadarsUnsuspend;
|
|
192
189
|
if (!unsuspend)
|
package/dist/index.d.ts
CHANGED
|
@@ -205,6 +205,9 @@ declare function initServerDataCache(data: Record<string, unknown>): void;
|
|
|
205
205
|
* awaited, the cache entry is then cleared so that the next render re-calls
|
|
206
206
|
* `fn()` — at that point the Suspense hook returns synchronously.
|
|
207
207
|
*
|
|
208
|
+
* `fn` is **server-only**: it is never called in the browser. The resolved value
|
|
209
|
+
* is serialised into `__serverData` and returned from cache during hydration.
|
|
210
|
+
*
|
|
208
211
|
* @example
|
|
209
212
|
* const user = useServerData('current_user', () => db.getUser(id));
|
|
210
213
|
* const post = useServerData(['post', postId], () => db.getPost(postId));
|
package/dist/index.js
CHANGED
|
@@ -140,10 +140,7 @@ function initServerDataCache(data) {
|
|
|
140
140
|
function useServerData(key, fn) {
|
|
141
141
|
const cacheKey = Array.isArray(key) ? JSON.stringify(key) : key;
|
|
142
142
|
if (typeof window !== "undefined") {
|
|
143
|
-
|
|
144
|
-
return clientServerDataCache.get(cacheKey);
|
|
145
|
-
}
|
|
146
|
-
return fn();
|
|
143
|
+
return clientServerDataCache.get(cacheKey);
|
|
147
144
|
}
|
|
148
145
|
const unsuspend = globalThis.__hadarsUnsuspend;
|
|
149
146
|
if (!unsuspend)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/slim-react/index.ts
|
|
@@ -138,10 +148,11 @@ function s() {
|
|
|
138
148
|
}
|
|
139
149
|
return g[GLOBAL_KEY];
|
|
140
150
|
}
|
|
141
|
-
function resetRenderState() {
|
|
151
|
+
function resetRenderState(idPrefix = "") {
|
|
142
152
|
const st = s();
|
|
143
153
|
st.currentTreeContext = { ...EMPTY };
|
|
144
154
|
st.localIdCounter = 0;
|
|
155
|
+
st.idPrefix = idPrefix;
|
|
145
156
|
}
|
|
146
157
|
function pushTreeContext(totalChildren, index) {
|
|
147
158
|
const st = s();
|
|
@@ -182,6 +193,9 @@ function pushComponentScope() {
|
|
|
182
193
|
function popComponentScope(saved) {
|
|
183
194
|
s().localIdCounter = saved;
|
|
184
195
|
}
|
|
196
|
+
function componentCalledUseId() {
|
|
197
|
+
return s().localIdCounter > 0;
|
|
198
|
+
}
|
|
185
199
|
function snapshotContext() {
|
|
186
200
|
const st = s();
|
|
187
201
|
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
@@ -202,7 +216,7 @@ function makeId() {
|
|
|
202
216
|
const st = s();
|
|
203
217
|
const treeId = getTreeId();
|
|
204
218
|
const n = st.localIdCounter++;
|
|
205
|
-
let id = "
|
|
219
|
+
let id = "_R_" + st.idPrefix + treeId;
|
|
206
220
|
if (n > 0)
|
|
207
221
|
id += "H" + n.toString(32);
|
|
208
222
|
return id + "_";
|
|
@@ -298,6 +312,47 @@ function createContext(defaultValue) {
|
|
|
298
312
|
return context;
|
|
299
313
|
}
|
|
300
314
|
|
|
315
|
+
// src/slim-react/dispatcher.ts
|
|
316
|
+
var ReactNS = __toESM(require("react"), 1);
|
|
317
|
+
var _internals = ReactNS.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
318
|
+
var slimDispatcher = {
|
|
319
|
+
useId: makeId,
|
|
320
|
+
readContext: (ctx) => getContextValue(ctx),
|
|
321
|
+
useContext: (ctx) => getContextValue(ctx),
|
|
322
|
+
useState,
|
|
323
|
+
useReducer,
|
|
324
|
+
useEffect,
|
|
325
|
+
useLayoutEffect,
|
|
326
|
+
useInsertionEffect,
|
|
327
|
+
useRef,
|
|
328
|
+
useMemo,
|
|
329
|
+
useCallback,
|
|
330
|
+
useDebugValue,
|
|
331
|
+
useImperativeHandle,
|
|
332
|
+
useSyncExternalStore,
|
|
333
|
+
useTransition,
|
|
334
|
+
useDeferredValue,
|
|
335
|
+
useOptimistic,
|
|
336
|
+
useActionState,
|
|
337
|
+
use,
|
|
338
|
+
// React internals that compiled output may call
|
|
339
|
+
useMemoCache: (size) => new Array(size).fill(void 0),
|
|
340
|
+
useCacheRefresh: () => () => {
|
|
341
|
+
},
|
|
342
|
+
useHostTransitionStatus: () => false
|
|
343
|
+
};
|
|
344
|
+
function installDispatcher() {
|
|
345
|
+
if (!_internals)
|
|
346
|
+
return null;
|
|
347
|
+
const prev = _internals.H;
|
|
348
|
+
_internals.H = slimDispatcher;
|
|
349
|
+
return prev;
|
|
350
|
+
}
|
|
351
|
+
function restoreDispatcher(prev) {
|
|
352
|
+
if (_internals)
|
|
353
|
+
_internals.H = prev;
|
|
354
|
+
}
|
|
355
|
+
|
|
301
356
|
// src/slim-react/render.ts
|
|
302
357
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
303
358
|
"area",
|
|
@@ -701,6 +756,7 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
701
756
|
return;
|
|
702
757
|
}
|
|
703
758
|
let result;
|
|
759
|
+
const prevDispatcher = installDispatcher();
|
|
704
760
|
try {
|
|
705
761
|
if (type.prototype && typeof type.prototype.render === "function") {
|
|
706
762
|
const instance = new type(props);
|
|
@@ -714,12 +770,20 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
714
770
|
result = type(props);
|
|
715
771
|
}
|
|
716
772
|
} catch (e) {
|
|
773
|
+
restoreDispatcher(prevDispatcher);
|
|
717
774
|
popComponentScope(savedScope);
|
|
718
775
|
if (isProvider)
|
|
719
776
|
popContextValue(ctx, prevCtxValue);
|
|
720
777
|
throw e;
|
|
721
778
|
}
|
|
779
|
+
restoreDispatcher(prevDispatcher);
|
|
780
|
+
let savedIdTree;
|
|
781
|
+
if (!(result instanceof Promise) && componentCalledUseId()) {
|
|
782
|
+
savedIdTree = pushTreeContext(1, 0);
|
|
783
|
+
}
|
|
722
784
|
const finish = () => {
|
|
785
|
+
if (savedIdTree !== void 0)
|
|
786
|
+
popTreeContext(savedIdTree);
|
|
723
787
|
popComponentScope(savedScope);
|
|
724
788
|
if (isProvider)
|
|
725
789
|
popContextValue(ctx, prevCtxValue);
|
|
@@ -728,22 +792,33 @@ function renderComponent(type, props, writer, isSvg) {
|
|
|
728
792
|
const m = captureMap();
|
|
729
793
|
return result.then((resolved) => {
|
|
730
794
|
swapContextMap(m);
|
|
795
|
+
let asyncSavedIdTree;
|
|
796
|
+
if (componentCalledUseId()) {
|
|
797
|
+
asyncSavedIdTree = pushTreeContext(1, 0);
|
|
798
|
+
}
|
|
799
|
+
const asyncFinish = () => {
|
|
800
|
+
if (asyncSavedIdTree !== void 0)
|
|
801
|
+
popTreeContext(asyncSavedIdTree);
|
|
802
|
+
popComponentScope(savedScope);
|
|
803
|
+
if (isProvider)
|
|
804
|
+
popContextValue(ctx, prevCtxValue);
|
|
805
|
+
};
|
|
731
806
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
732
807
|
if (r2 && typeof r2.then === "function") {
|
|
733
808
|
const m2 = captureMap();
|
|
734
809
|
return r2.then(
|
|
735
810
|
() => {
|
|
736
811
|
swapContextMap(m2);
|
|
737
|
-
|
|
812
|
+
asyncFinish();
|
|
738
813
|
},
|
|
739
814
|
(e) => {
|
|
740
815
|
swapContextMap(m2);
|
|
741
|
-
|
|
816
|
+
asyncFinish();
|
|
742
817
|
throw e;
|
|
743
818
|
}
|
|
744
819
|
);
|
|
745
820
|
}
|
|
746
|
-
|
|
821
|
+
asyncFinish();
|
|
747
822
|
}, (e) => {
|
|
748
823
|
swapContextMap(m);
|
|
749
824
|
finish();
|
|
@@ -823,8 +898,8 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
823
898
|
const snap = snapshotContext();
|
|
824
899
|
while (attempts < MAX_SUSPENSE_RETRIES) {
|
|
825
900
|
restoreContext(snap);
|
|
901
|
+
let buffer = new BufferWriter();
|
|
826
902
|
try {
|
|
827
|
-
const buffer = new BufferWriter();
|
|
828
903
|
const r = renderNode(children, buffer, isSvg);
|
|
829
904
|
if (r && typeof r.then === "function") {
|
|
830
905
|
const m = captureMap();
|
|
@@ -858,12 +933,13 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
858
933
|
}
|
|
859
934
|
writer.write("<!--/$-->");
|
|
860
935
|
}
|
|
861
|
-
function renderToStream(element) {
|
|
936
|
+
function renderToStream(element, options) {
|
|
862
937
|
const encoder = new TextEncoder();
|
|
938
|
+
const idPrefix = options?.identifierPrefix ?? "";
|
|
863
939
|
const contextMap = /* @__PURE__ */ new Map();
|
|
864
940
|
return new ReadableStream({
|
|
865
941
|
async start(controller) {
|
|
866
|
-
resetRenderState();
|
|
942
|
+
resetRenderState(idPrefix);
|
|
867
943
|
const prev = swapContextMap(contextMap);
|
|
868
944
|
const writer = {
|
|
869
945
|
lastWasText: false,
|
|
@@ -892,12 +968,13 @@ function renderToStream(element) {
|
|
|
892
968
|
}
|
|
893
969
|
});
|
|
894
970
|
}
|
|
895
|
-
async function renderToString(element) {
|
|
971
|
+
async function renderToString(element, options) {
|
|
972
|
+
const idPrefix = options?.identifierPrefix ?? "";
|
|
896
973
|
const contextMap = /* @__PURE__ */ new Map();
|
|
897
974
|
const prev = swapContextMap(contextMap);
|
|
898
975
|
try {
|
|
899
976
|
for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
|
|
900
|
-
resetRenderState();
|
|
977
|
+
resetRenderState(idPrefix);
|
|
901
978
|
swapContextMap(contextMap);
|
|
902
979
|
const chunks = [];
|
|
903
980
|
const writer = {
|
|
@@ -80,19 +80,27 @@ declare function createContext<T>(defaultValue: T): Context<T>;
|
|
|
80
80
|
* until the async data is ready, then continues – exactly as requested.
|
|
81
81
|
*/
|
|
82
82
|
|
|
83
|
+
interface RenderOptions {
|
|
84
|
+
/**
|
|
85
|
+
* Must match the `identifierPrefix` option passed to `hydrateRoot` on the
|
|
86
|
+
* client so that `useId()` generates identical IDs on server and client.
|
|
87
|
+
* Defaults to `""` (React's default).
|
|
88
|
+
*/
|
|
89
|
+
identifierPrefix?: string;
|
|
90
|
+
}
|
|
83
91
|
/**
|
|
84
92
|
* Render a component tree to a `ReadableStream<Uint8Array>`.
|
|
85
93
|
*
|
|
86
94
|
* The stream pauses at `<Suspense>` boundaries until the suspended
|
|
87
95
|
* promise resolves, then continues writing HTML.
|
|
88
96
|
*/
|
|
89
|
-
declare function renderToStream(element: SlimNode): ReadableStream<Uint8Array>;
|
|
97
|
+
declare function renderToStream(element: SlimNode, options?: RenderOptions): ReadableStream<Uint8Array>;
|
|
90
98
|
/**
|
|
91
99
|
* Convenience: render to a complete HTML string.
|
|
92
100
|
* Retries the full tree when a component throws a Promise (Suspense protocol),
|
|
93
101
|
* so useServerData and similar hooks work without requiring explicit <Suspense>.
|
|
94
102
|
*/
|
|
95
|
-
declare function renderToString(element: SlimNode): Promise<string>;
|
|
103
|
+
declare function renderToString(element: SlimNode, options?: RenderOptions): Promise<string>;
|
|
96
104
|
|
|
97
105
|
/**
|
|
98
106
|
* slim-react – a lightweight, SSR-only React-compatible runtime.
|
|
@@ -179,4 +187,4 @@ declare const React: {
|
|
|
179
187
|
version: string;
|
|
180
188
|
};
|
|
181
189
|
|
|
182
|
-
export { Children, Component, Context, PureComponent, SlimElement, SlimNode, Suspense, cloneElement, createContext, createElement, React as default, forwardRef, isValidElement, lazy, memo, renderToStream as renderToReadableStream, renderToStream, renderToString, startTransition, use, useActionState, useCallback, useContext, useDebugValue, useDeferredValue, useEffect, useFormStatus, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition, version };
|
|
190
|
+
export { Children, Component, Context, PureComponent, RenderOptions, SlimElement, SlimNode, Suspense, cloneElement, createContext, createElement, React as default, forwardRef, isValidElement, lazy, memo, renderToStream as renderToReadableStream, renderToStream, renderToString, startTransition, use, useActionState, useCallback, useContext, useDebugValue, useDeferredValue, useEffect, useFormStatus, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition, version };
|