hadars 0.4.0 → 0.4.2-rc.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/dist/{chunk-TV37IMRB.js → chunk-2TMQUXFL.js} +10 -10
- package/dist/{chunk-2J2L2H3H.js → chunk-NYLXE7T7.js} +6 -6
- package/dist/{chunk-OS3V4CPN.js → chunk-OZUZS2PD.js} +4 -4
- package/dist/cli.js +467 -495
- package/dist/cloudflare.cjs +11 -11
- package/dist/cloudflare.js +3 -3
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/lambda.cjs +11 -11
- package/dist/lambda.js +7 -7
- package/dist/loader.cjs +90 -54
- package/dist/slim-react/index.cjs +13 -13
- package/dist/slim-react/index.js +2 -2
- package/dist/slim-react/jsx-runtime.cjs +2 -4
- package/dist/slim-react/jsx-runtime.js +1 -1
- package/dist/ssr-render-worker.js +174 -161
- package/dist/ssr-watch.js +40 -74
- package/package.json +8 -10
- package/cli-lib.ts +0 -676
- package/cli.ts +0 -36
- package/index.ts +0 -17
- package/src/build.ts +0 -797
- package/src/cloudflare.ts +0 -140
- package/src/index.tsx +0 -41
- package/src/lambda.ts +0 -287
- package/src/slim-react/context.ts +0 -55
- package/src/slim-react/dispatcher.ts +0 -87
- package/src/slim-react/hooks.ts +0 -137
- package/src/slim-react/index.ts +0 -232
- package/src/slim-react/jsx-runtime.ts +0 -7
- package/src/slim-react/jsx.ts +0 -53
- package/src/slim-react/render.ts +0 -1101
- package/src/slim-react/renderContext.ts +0 -294
- package/src/slim-react/types.ts +0 -33
- package/src/source/context.ts +0 -113
- package/src/source/graphiql.ts +0 -101
- package/src/source/inference.ts +0 -260
- package/src/source/runner.ts +0 -138
- package/src/source/store.ts +0 -50
- package/src/ssr-render-worker.ts +0 -116
- package/src/ssr-watch.ts +0 -62
- package/src/static.ts +0 -109
- package/src/types/global.d.ts +0 -5
- package/src/types/hadars.ts +0 -350
- package/src/utils/Head.tsx +0 -462
- package/src/utils/clientScript.tsx +0 -71
- package/src/utils/cookies.ts +0 -16
- package/src/utils/loader.ts +0 -335
- package/src/utils/proxyHandler.tsx +0 -104
- package/src/utils/request.tsx +0 -9
- package/src/utils/response.tsx +0 -141
- package/src/utils/rspack.ts +0 -467
- package/src/utils/runtime.ts +0 -19
- package/src/utils/serve.ts +0 -155
- package/src/utils/ssrHandler.ts +0 -239
- package/src/utils/staticFile.ts +0 -43
- package/src/utils/template.html +0 -11
- package/src/utils/upgradeRequest.tsx +0 -19
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
2
4
|
|
|
3
5
|
// cli.ts
|
|
4
6
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -25,7 +27,9 @@ var getCORSHeaders = (req) => {
|
|
|
25
27
|
var createProxyHandler = (options) => {
|
|
26
28
|
const { proxy, proxyCORS } = options;
|
|
27
29
|
if (!proxy) {
|
|
28
|
-
return () =>
|
|
30
|
+
return () => {
|
|
31
|
+
return;
|
|
32
|
+
};
|
|
29
33
|
}
|
|
30
34
|
if (typeof proxy === "function") {
|
|
31
35
|
return async (req) => {
|
|
@@ -47,13 +51,13 @@ var createProxyHandler = (options) => {
|
|
|
47
51
|
headers: modifiedHeaders
|
|
48
52
|
});
|
|
49
53
|
}
|
|
50
|
-
return res ||
|
|
54
|
+
return res || undefined;
|
|
51
55
|
};
|
|
52
56
|
}
|
|
53
57
|
const proxyRules = Object.entries(proxy).sort((a, b) => b[0].length - a[0].length);
|
|
54
58
|
return async (req) => {
|
|
55
|
-
for (const [
|
|
56
|
-
if (req.pathname.startsWith(
|
|
59
|
+
for (const [path, target] of proxyRules) {
|
|
60
|
+
if (req.pathname.startsWith(path)) {
|
|
57
61
|
if (req.method === "OPTIONS" && proxyCORS) {
|
|
58
62
|
return new Response(null, {
|
|
59
63
|
status: 204,
|
|
@@ -61,7 +65,7 @@ var createProxyHandler = (options) => {
|
|
|
61
65
|
});
|
|
62
66
|
}
|
|
63
67
|
const targetURL = new URL(target);
|
|
64
|
-
targetURL.pathname = targetURL.pathname.replace(/\/$/, "") + req.pathname.slice(
|
|
68
|
+
targetURL.pathname = targetURL.pathname.replace(/\/$/, "") + req.pathname.slice(path.length);
|
|
65
69
|
targetURL.search = req.search;
|
|
66
70
|
const sendHeaders = cloneHeaders(req.headers);
|
|
67
71
|
sendHeaders.set("Host", targetURL.host);
|
|
@@ -69,9 +73,8 @@ var createProxyHandler = (options) => {
|
|
|
69
73
|
const proxyReq = new Request(targetURL.toString(), {
|
|
70
74
|
method: req.method,
|
|
71
75
|
headers: sendHeaders,
|
|
72
|
-
body: hasBody ? req.body :
|
|
76
|
+
body: hasBody ? req.body : undefined,
|
|
73
77
|
redirect: "follow",
|
|
74
|
-
// Node.js (undici) requires duplex:'half' when body is a ReadableStream
|
|
75
78
|
...hasBody ? { duplex: "half" } : {}
|
|
76
79
|
});
|
|
77
80
|
const res = await fetch(proxyReq);
|
|
@@ -91,7 +94,7 @@ var createProxyHandler = (options) => {
|
|
|
91
94
|
});
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
|
-
return
|
|
97
|
+
return;
|
|
95
98
|
};
|
|
96
99
|
};
|
|
97
100
|
|
|
@@ -140,11 +143,10 @@ var upgradeHandler = (options) => {
|
|
|
140
143
|
};
|
|
141
144
|
|
|
142
145
|
// src/slim-react/types.ts
|
|
143
|
-
var SLIM_ELEMENT =
|
|
144
|
-
var REACT19_ELEMENT =
|
|
145
|
-
var FRAGMENT_TYPE =
|
|
146
|
-
var SUSPENSE_TYPE =
|
|
147
|
-
|
|
146
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
147
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
148
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
149
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
148
150
|
// src/slim-react/jsx.ts
|
|
149
151
|
function createElement(type, props, ...children) {
|
|
150
152
|
const normalizedProps = { ...props || {} };
|
|
@@ -166,7 +168,8 @@ function createElement(type, props, ...children) {
|
|
|
166
168
|
// src/slim-react/renderContext.ts
|
|
167
169
|
var MAP_KEY = "__slimReactContextMap";
|
|
168
170
|
var _g = globalThis;
|
|
169
|
-
if (!("__slimReactContextMap" in _g))
|
|
171
|
+
if (!("__slimReactContextMap" in _g))
|
|
172
|
+
_g[MAP_KEY] = null;
|
|
170
173
|
function swapContextMap(map) {
|
|
171
174
|
const prev = _g[MAP_KEY];
|
|
172
175
|
_g[MAP_KEY] = map;
|
|
@@ -184,18 +187,19 @@ function restoreUnsuspend(u) {
|
|
|
184
187
|
}
|
|
185
188
|
function getContextValue(context) {
|
|
186
189
|
const map = _g[MAP_KEY];
|
|
187
|
-
if (map && map.has(context))
|
|
190
|
+
if (map && map.has(context))
|
|
191
|
+
return map.get(context);
|
|
188
192
|
const c = context;
|
|
189
193
|
return "_defaultValue" in c ? c._defaultValue : c._currentValue;
|
|
190
194
|
}
|
|
191
195
|
function pushContextValue(context, value) {
|
|
192
196
|
let map = _g[MAP_KEY];
|
|
193
197
|
if (map === null) {
|
|
194
|
-
map =
|
|
198
|
+
map = new Map;
|
|
195
199
|
_g[MAP_KEY] = map;
|
|
196
200
|
}
|
|
197
201
|
const c = context;
|
|
198
|
-
const prev = map.has(context) ? map.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
|
|
202
|
+
const prev = map.has(context) ? map.get(context) : ("_defaultValue" in c) ? c._defaultValue : c._currentValue;
|
|
199
203
|
map.set(context, value);
|
|
200
204
|
return prev;
|
|
201
205
|
}
|
|
@@ -206,7 +210,8 @@ var GLOBAL_KEY = "__slimReactRenderState";
|
|
|
206
210
|
var EMPTY = { id: 1, overflow: "" };
|
|
207
211
|
var _stateCache = null;
|
|
208
212
|
function s() {
|
|
209
|
-
if (_stateCache !== null)
|
|
213
|
+
if (_stateCache !== null)
|
|
214
|
+
return _stateCache;
|
|
210
215
|
if (!_g[GLOBAL_KEY]) {
|
|
211
216
|
_g[GLOBAL_KEY] = { currentTreeContext: { ...EMPTY }, localIdCounter: 0, idPrefix: "" };
|
|
212
217
|
}
|
|
@@ -276,8 +281,6 @@ function snapshotContext() {
|
|
|
276
281
|
tree: { id: ctx.id, overflow: ctx.overflow },
|
|
277
282
|
localId: st.localIdCounter,
|
|
278
283
|
treeDepth: depth,
|
|
279
|
-
// Snapshot the live stack so that popTreeContext reads correct saved values
|
|
280
|
-
// even if another concurrent render's resetRenderState stomped the arrays.
|
|
281
284
|
idStack: _treeIdStack.slice(0, depth),
|
|
282
285
|
ovStack: _treeOvStack.slice(0, depth)
|
|
283
286
|
};
|
|
@@ -289,14 +292,15 @@ function restoreContext(snap) {
|
|
|
289
292
|
ctx.overflow = snap.tree.overflow;
|
|
290
293
|
st.localIdCounter = snap.localId;
|
|
291
294
|
_treeDepth = snap.treeDepth;
|
|
292
|
-
for (let i = 0;
|
|
295
|
+
for (let i = 0;i < snap.treeDepth; i++) {
|
|
293
296
|
_treeIdStack[i] = snap.idStack[i];
|
|
294
297
|
_treeOvStack[i] = snap.ovStack[i];
|
|
295
298
|
}
|
|
296
299
|
}
|
|
297
300
|
function getTreeId() {
|
|
298
301
|
const { id, overflow } = s().currentTreeContext;
|
|
299
|
-
if (id === 1)
|
|
302
|
+
if (id === 1)
|
|
303
|
+
return overflow;
|
|
300
304
|
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
301
305
|
return stripped + overflow;
|
|
302
306
|
}
|
|
@@ -305,26 +309,22 @@ function makeId() {
|
|
|
305
309
|
const treeId = getTreeId();
|
|
306
310
|
const n = st.localIdCounter++;
|
|
307
311
|
let id = "_R_" + st.idPrefix + treeId;
|
|
308
|
-
if (n > 0)
|
|
312
|
+
if (n > 0)
|
|
313
|
+
id += "H" + n.toString(32);
|
|
309
314
|
return id + "_";
|
|
310
315
|
}
|
|
311
316
|
|
|
312
317
|
// src/slim-react/hooks.ts
|
|
313
318
|
function useState(initialState) {
|
|
314
319
|
const value = typeof initialState === "function" ? initialState() : initialState;
|
|
315
|
-
return [value, () => {
|
|
316
|
-
}];
|
|
320
|
+
return [value, () => {}];
|
|
317
321
|
}
|
|
318
322
|
function useReducer(_reducer, initialState) {
|
|
319
|
-
return [initialState, () => {
|
|
320
|
-
}];
|
|
321
|
-
}
|
|
322
|
-
function useEffect(_effect, _deps) {
|
|
323
|
-
}
|
|
324
|
-
function useLayoutEffect(_effect, _deps) {
|
|
325
|
-
}
|
|
326
|
-
function useInsertionEffect(_effect, _deps) {
|
|
323
|
+
return [initialState, () => {}];
|
|
327
324
|
}
|
|
325
|
+
function useEffect(_effect, _deps) {}
|
|
326
|
+
function useLayoutEffect(_effect, _deps) {}
|
|
327
|
+
function useInsertionEffect(_effect, _deps) {}
|
|
328
328
|
function useRef(initialValue) {
|
|
329
329
|
return { current: initialValue };
|
|
330
330
|
}
|
|
@@ -334,10 +334,8 @@ function useMemo(factory, _deps) {
|
|
|
334
334
|
function useCallback(callback, _deps) {
|
|
335
335
|
return callback;
|
|
336
336
|
}
|
|
337
|
-
function useDebugValue(_value, _format) {
|
|
338
|
-
}
|
|
339
|
-
function useImperativeHandle(_ref, _createHandle, _deps) {
|
|
340
|
-
}
|
|
337
|
+
function useDebugValue(_value, _format) {}
|
|
338
|
+
function useImperativeHandle(_ref, _createHandle, _deps) {}
|
|
341
339
|
function useSyncExternalStore(_subscribe, getSnapshot, getServerSnapshot) {
|
|
342
340
|
return (getServerSnapshot || getSnapshot)();
|
|
343
341
|
}
|
|
@@ -348,23 +346,22 @@ function useDeferredValue(value) {
|
|
|
348
346
|
return value;
|
|
349
347
|
}
|
|
350
348
|
function useOptimistic(passthrough) {
|
|
351
|
-
return [passthrough, () => {
|
|
352
|
-
}];
|
|
349
|
+
return [passthrough, () => {}];
|
|
353
350
|
}
|
|
354
351
|
function useActionState(_action, initialState, _permalink) {
|
|
355
|
-
return [initialState, () => {
|
|
356
|
-
}, false];
|
|
352
|
+
return [initialState, () => {}, false];
|
|
357
353
|
}
|
|
358
354
|
function use(usable) {
|
|
359
|
-
if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
|
|
355
|
+
if (typeof usable === "object" && usable !== null && (("_currentValue" in usable) || ("_defaultValue" in usable))) {
|
|
360
356
|
return getContextValue(usable);
|
|
361
357
|
}
|
|
362
358
|
const promise = usable;
|
|
363
|
-
if (promise.status === "fulfilled")
|
|
364
|
-
|
|
359
|
+
if (promise.status === "fulfilled")
|
|
360
|
+
return promise.value;
|
|
361
|
+
if (promise.status === "rejected")
|
|
362
|
+
throw promise.reason;
|
|
365
363
|
throw promise;
|
|
366
364
|
}
|
|
367
|
-
|
|
368
365
|
// src/slim-react/dispatcher.ts
|
|
369
366
|
import * as ReactNS from "react";
|
|
370
367
|
var _reactInternalsKey = "__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
|
|
@@ -389,20 +386,20 @@ var slimDispatcher = {
|
|
|
389
386
|
useOptimistic,
|
|
390
387
|
useActionState,
|
|
391
388
|
use,
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
useCacheRefresh: () => () => {
|
|
395
|
-
},
|
|
389
|
+
useMemoCache: (size) => new Array(size).fill(undefined),
|
|
390
|
+
useCacheRefresh: () => () => {},
|
|
396
391
|
useHostTransitionStatus: () => false
|
|
397
392
|
};
|
|
398
393
|
function installDispatcher() {
|
|
399
|
-
if (!_internals)
|
|
394
|
+
if (!_internals)
|
|
395
|
+
return null;
|
|
400
396
|
const prev = _internals.H;
|
|
401
397
|
_internals.H = slimDispatcher;
|
|
402
398
|
return prev;
|
|
403
399
|
}
|
|
404
400
|
function restoreDispatcher(prev) {
|
|
405
|
-
if (_internals)
|
|
401
|
+
if (_internals)
|
|
402
|
+
_internals.H = prev;
|
|
406
403
|
}
|
|
407
404
|
|
|
408
405
|
// src/slim-react/render.ts
|
|
@@ -414,7 +411,7 @@ function restoreRenderCtx(ctx) {
|
|
|
414
411
|
restoreUnsuspend(ctx.u);
|
|
415
412
|
restoreContext(ctx.t);
|
|
416
413
|
}
|
|
417
|
-
var VOID_ELEMENTS =
|
|
414
|
+
var VOID_ELEMENTS = new Set([
|
|
418
415
|
"area",
|
|
419
416
|
"base",
|
|
420
417
|
"br",
|
|
@@ -433,16 +430,18 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
433
430
|
var HTML_ESC = { "&": "&", "<": "<", ">": ">", "'": "'" };
|
|
434
431
|
var HTML_ESC_RE = /[&<>']/;
|
|
435
432
|
function escapeHtml(str) {
|
|
436
|
-
if (!HTML_ESC_RE.test(str))
|
|
433
|
+
if (!HTML_ESC_RE.test(str))
|
|
434
|
+
return str;
|
|
437
435
|
return str.replace(/[&<>']/g, (c) => HTML_ESC[c]);
|
|
438
436
|
}
|
|
439
437
|
var ATTR_ESC = { "&": "&", '"': """, "<": "<", ">": ">" };
|
|
440
438
|
var ATTR_ESC_RE = /[&"<>]/;
|
|
441
439
|
function escapeAttr(str) {
|
|
442
|
-
if (!ATTR_ESC_RE.test(str))
|
|
440
|
+
if (!ATTR_ESC_RE.test(str))
|
|
441
|
+
return str;
|
|
443
442
|
return str.replace(/[&"<>]/g, (c) => ATTR_ESC[c]);
|
|
444
443
|
}
|
|
445
|
-
var UNITLESS_CSS =
|
|
444
|
+
var UNITLESS_CSS = new Set([
|
|
446
445
|
"animationIterationCount",
|
|
447
446
|
"aspectRatio",
|
|
448
447
|
"borderImageOutset",
|
|
@@ -488,15 +487,17 @@ var UNITLESS_CSS = /* @__PURE__ */ new Set([
|
|
|
488
487
|
"strokeOpacity",
|
|
489
488
|
"strokeWidth"
|
|
490
489
|
]);
|
|
491
|
-
var _cssKeyCache =
|
|
490
|
+
var _cssKeyCache = new Map;
|
|
492
491
|
function styleObjectToString(style) {
|
|
493
492
|
let result = "";
|
|
494
493
|
for (const key in style) {
|
|
495
494
|
const value = style[key];
|
|
496
|
-
if (value == null || typeof value === "boolean")
|
|
497
|
-
|
|
495
|
+
if (value == null || typeof value === "boolean")
|
|
496
|
+
continue;
|
|
497
|
+
if (result)
|
|
498
|
+
result += ";";
|
|
498
499
|
let cssKey = _cssKeyCache.get(key);
|
|
499
|
-
if (cssKey ===
|
|
500
|
+
if (cssKey === undefined) {
|
|
500
501
|
cssKey = key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
501
502
|
_cssKeyCache.set(key, cssKey);
|
|
502
503
|
}
|
|
@@ -509,7 +510,6 @@ function styleObjectToString(style) {
|
|
|
509
510
|
return result;
|
|
510
511
|
}
|
|
511
512
|
var SVG_ATTR_MAP = {
|
|
512
|
-
// Presentation / geometry
|
|
513
513
|
accentHeight: "accent-height",
|
|
514
514
|
alignmentBaseline: "alignment-baseline",
|
|
515
515
|
arabicForm: "arabic-form",
|
|
@@ -580,7 +580,6 @@ var SVG_ATTR_MAP = {
|
|
|
580
580
|
wordSpacing: "word-spacing",
|
|
581
581
|
writingMode: "writing-mode",
|
|
582
582
|
xHeight: "x-height",
|
|
583
|
-
// Namespace-prefixed
|
|
584
583
|
xlinkActuate: "xlink:actuate",
|
|
585
584
|
xlinkArcrole: "xlink:arcrole",
|
|
586
585
|
xlinkHref: "xlink:href",
|
|
@@ -593,7 +592,6 @@ var SVG_ATTR_MAP = {
|
|
|
593
592
|
xmlSpace: "xml:space",
|
|
594
593
|
xmlns: "xmlns",
|
|
595
594
|
xmlnsXlink: "xmlns:xlink",
|
|
596
|
-
// Filter / lighting
|
|
597
595
|
baseFrequency: "baseFrequency",
|
|
598
596
|
colorInterpolation_filters: "color-interpolation-filters",
|
|
599
597
|
diffuseConstant: "diffuseConstant",
|
|
@@ -639,9 +637,9 @@ var SVG_ATTR_MAP = {
|
|
|
639
637
|
xChannelSelector: "xChannelSelector",
|
|
640
638
|
yChannelSelector: "yChannelSelector"
|
|
641
639
|
};
|
|
642
|
-
var TEXTAREA_SKIP_PROPS =
|
|
643
|
-
var SELECT_SKIP_PROPS =
|
|
644
|
-
var INTERNAL_PROPS =
|
|
640
|
+
var TEXTAREA_SKIP_PROPS = new Set(["value", "defaultValue", "children"]);
|
|
641
|
+
var SELECT_SKIP_PROPS = new Set(["value", "defaultValue"]);
|
|
642
|
+
var INTERNAL_PROPS = new Set([
|
|
645
643
|
"children",
|
|
646
644
|
"key",
|
|
647
645
|
"ref",
|
|
@@ -651,10 +649,13 @@ var INTERNAL_PROPS = /* @__PURE__ */ new Set([
|
|
|
651
649
|
]);
|
|
652
650
|
function writeAttributes(writer, props, isSvg, skip) {
|
|
653
651
|
for (const key in props) {
|
|
654
|
-
if (skip !==
|
|
652
|
+
if (skip !== undefined && skip.has(key))
|
|
653
|
+
continue;
|
|
655
654
|
const value = props[key];
|
|
656
|
-
if (INTERNAL_PROPS.has(key))
|
|
657
|
-
|
|
655
|
+
if (INTERNAL_PROPS.has(key))
|
|
656
|
+
continue;
|
|
657
|
+
if (key.length > 2 && key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) >= 65 && key.charCodeAt(2) <= 90)
|
|
658
|
+
continue;
|
|
658
659
|
let attrName;
|
|
659
660
|
if (isSvg && key in SVG_ATTR_MAP) {
|
|
660
661
|
attrName = SVG_ATTR_MAP[key];
|
|
@@ -677,13 +678,15 @@ function writeAttributes(writer, props, isSvg, skip) {
|
|
|
677
678
|
}
|
|
678
679
|
if (key === "style" && typeof value === "object") {
|
|
679
680
|
const styleStr = styleObjectToString(value);
|
|
680
|
-
if (styleStr)
|
|
681
|
+
if (styleStr)
|
|
682
|
+
writer.write(` style="${escapeAttr(styleStr)}"`);
|
|
681
683
|
continue;
|
|
682
684
|
}
|
|
683
685
|
writer.write(` ${attrName}="${escapeAttr(typeof value === "string" ? value : String(value))}"`);
|
|
684
686
|
}
|
|
685
687
|
}
|
|
686
|
-
|
|
688
|
+
|
|
689
|
+
class BufferWriter {
|
|
687
690
|
data = "";
|
|
688
691
|
lastWasText = false;
|
|
689
692
|
write(chunk) {
|
|
@@ -694,19 +697,20 @@ var BufferWriter = class _BufferWriter {
|
|
|
694
697
|
this.data += s2;
|
|
695
698
|
this.lastWasText = true;
|
|
696
699
|
}
|
|
697
|
-
/** Flush accumulated output into a parent writer and reset. */
|
|
698
700
|
flushTo(target) {
|
|
699
|
-
if (!this.data)
|
|
700
|
-
|
|
701
|
+
if (!this.data)
|
|
702
|
+
return;
|
|
703
|
+
if (target instanceof BufferWriter) {
|
|
701
704
|
target.data += this.data;
|
|
702
705
|
} else {
|
|
703
706
|
target.write(this.data);
|
|
704
707
|
}
|
|
705
708
|
target.lastWasText = this.lastWasText;
|
|
706
709
|
}
|
|
707
|
-
}
|
|
710
|
+
}
|
|
708
711
|
function renderNode(node, writer, isSvg = false) {
|
|
709
|
-
if (node == null || typeof node === "boolean")
|
|
712
|
+
if (node == null || typeof node === "boolean")
|
|
713
|
+
return;
|
|
710
714
|
if (typeof node === "string") {
|
|
711
715
|
writer.text(escapeHtml(node));
|
|
712
716
|
return;
|
|
@@ -724,7 +728,8 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
724
728
|
}
|
|
725
729
|
if ("$$typeof" in obj) {
|
|
726
730
|
const elType = obj["$$typeof"];
|
|
727
|
-
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
731
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
732
|
+
return;
|
|
728
733
|
const element = node;
|
|
729
734
|
const { type, props } = element;
|
|
730
735
|
if (type === FRAGMENT_TYPE) {
|
|
@@ -745,19 +750,22 @@ function renderNode(node, writer, isSvg = false) {
|
|
|
745
750
|
}
|
|
746
751
|
}
|
|
747
752
|
function markSelectedOptionsMulti(children, selectedValues) {
|
|
748
|
-
if (children == null || typeof children === "boolean")
|
|
749
|
-
|
|
753
|
+
if (children == null || typeof children === "boolean")
|
|
754
|
+
return children;
|
|
755
|
+
if (typeof children === "string" || typeof children === "number")
|
|
756
|
+
return children;
|
|
750
757
|
if (Array.isArray(children)) {
|
|
751
758
|
return children.map((c) => markSelectedOptionsMulti(c, selectedValues));
|
|
752
759
|
}
|
|
753
760
|
if (typeof children === "object" && "$$typeof" in children) {
|
|
754
761
|
const elType = children["$$typeof"];
|
|
755
|
-
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
762
|
+
if (elType !== SLIM_ELEMENT && elType !== REACT19_ELEMENT)
|
|
763
|
+
return children;
|
|
756
764
|
const el = children;
|
|
757
765
|
if (el.type === "option") {
|
|
758
|
-
const optValue = el.props.value !==
|
|
766
|
+
const optValue = el.props.value !== undefined ? el.props.value : el.props.children;
|
|
759
767
|
const isSelected = selectedValues.has(String(optValue));
|
|
760
|
-
return { ...el, props: { ...el.props, selected: isSelected ||
|
|
768
|
+
return { ...el, props: { ...el.props, selected: isSelected || undefined } };
|
|
761
769
|
}
|
|
762
770
|
if (el.type === "optgroup" || el.type === FRAGMENT_TYPE) {
|
|
763
771
|
const newChildren = markSelectedOptionsMulti(el.props.children, selectedValues);
|
|
@@ -782,7 +790,7 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
782
790
|
writer.write("<select");
|
|
783
791
|
writeAttributes(writer, props, false, SELECT_SKIP_PROPS);
|
|
784
792
|
writer.write(">");
|
|
785
|
-
const selectedSet = selectedValue == null ? null : Array.isArray(selectedValue) ? new Set(selectedValue.map(String)) :
|
|
793
|
+
const selectedSet = selectedValue == null ? null : Array.isArray(selectedValue) ? new Set(selectedValue.map(String)) : new Set([String(selectedValue)]);
|
|
786
794
|
const patchedChildren = selectedSet != null ? markSelectedOptionsMulti(props.children, selectedSet) : props.children;
|
|
787
795
|
const inner2 = renderChildren(patchedChildren, writer, false);
|
|
788
796
|
if (inner2 && typeof inner2.then === "function") {
|
|
@@ -801,7 +809,7 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
801
809
|
}
|
|
802
810
|
writer.write(">");
|
|
803
811
|
const childContext = tag === "foreignObject" ? false : childSvg;
|
|
804
|
-
let inner =
|
|
812
|
+
let inner = undefined;
|
|
805
813
|
if (props.dangerouslySetInnerHTML) {
|
|
806
814
|
writer.write(props.dangerouslySetInnerHTML.__html);
|
|
807
815
|
} else {
|
|
@@ -814,37 +822,31 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
814
822
|
}
|
|
815
823
|
writer.write(`</${tag}>`);
|
|
816
824
|
}
|
|
817
|
-
var REACT_MEMO =
|
|
818
|
-
var REACT_FORWARD_REF =
|
|
819
|
-
var REACT_PROVIDER =
|
|
820
|
-
var REACT_CONTEXT =
|
|
821
|
-
var REACT_CONSUMER =
|
|
822
|
-
var REACT_LAZY =
|
|
823
|
-
var SUSPENSE_RETRY_LIMIT =
|
|
825
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
826
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
827
|
+
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
828
|
+
var REACT_CONTEXT = Symbol.for("react.context");
|
|
829
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
830
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
831
|
+
var SUSPENSE_RETRY_LIMIT = Symbol("SuspenseRetryLimit");
|
|
824
832
|
var MAX_COMPONENT_SUSPENSE_RETRIES = 25;
|
|
825
833
|
function patchPromiseStatus(p) {
|
|
826
834
|
const w = p;
|
|
827
|
-
if (w.status)
|
|
835
|
+
if (w.status)
|
|
836
|
+
return;
|
|
828
837
|
w.status = "pending";
|
|
829
|
-
w.then(
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
w.reason = r;
|
|
837
|
-
}
|
|
838
|
-
);
|
|
838
|
+
w.then((v) => {
|
|
839
|
+
w.status = "fulfilled";
|
|
840
|
+
w.value = v;
|
|
841
|
+
}, (r) => {
|
|
842
|
+
w.status = "rejected";
|
|
843
|
+
w.reason = r;
|
|
844
|
+
});
|
|
839
845
|
}
|
|
840
846
|
function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
841
847
|
const typeOf = type.$$typeof;
|
|
842
848
|
if (typeOf === REACT_MEMO) {
|
|
843
|
-
return renderNode(
|
|
844
|
-
{ $$typeof: SLIM_ELEMENT, type: type.type, props, key: null },
|
|
845
|
-
writer,
|
|
846
|
-
isSvg
|
|
847
|
-
);
|
|
849
|
+
return renderNode({ $$typeof: SLIM_ELEMENT, type: type.type, props, key: null }, writer, isSvg);
|
|
848
850
|
}
|
|
849
851
|
if (typeOf === REACT_FORWARD_REF) {
|
|
850
852
|
return renderComponent(type.render, props, writer, isSvg);
|
|
@@ -855,7 +857,8 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
855
857
|
resolved = type._init(type._payload);
|
|
856
858
|
} catch (e) {
|
|
857
859
|
if (e && typeof e.then === "function") {
|
|
858
|
-
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES)
|
|
860
|
+
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES)
|
|
861
|
+
throw SUSPENSE_RETRY_LIMIT;
|
|
859
862
|
patchPromiseStatus(e);
|
|
860
863
|
const rctx = captureRenderCtx();
|
|
861
864
|
return e.then(() => {
|
|
@@ -870,7 +873,7 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
870
873
|
}
|
|
871
874
|
if (typeOf === REACT_CONSUMER) {
|
|
872
875
|
const ctx2 = type._context;
|
|
873
|
-
const value = ctx2 ? getContextValue(ctx2) :
|
|
876
|
+
const value = ctx2 ? getContextValue(ctx2) : undefined;
|
|
874
877
|
const result2 = typeof props.children === "function" ? props.children(value) : null;
|
|
875
878
|
const savedScope2 = pushComponentScope();
|
|
876
879
|
const finish = () => popComponentScope(savedScope2);
|
|
@@ -897,17 +900,14 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
897
900
|
const r2 = renderChildren(props.children, writer, isSvg);
|
|
898
901
|
if (r2 && typeof r2.then === "function") {
|
|
899
902
|
const rctx = captureRenderCtx();
|
|
900
|
-
return r2.then(
|
|
901
|
-
()
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
(
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
throw e;
|
|
909
|
-
}
|
|
910
|
-
);
|
|
903
|
+
return r2.then(() => {
|
|
904
|
+
restoreRenderCtx(rctx);
|
|
905
|
+
finish();
|
|
906
|
+
}, (e) => {
|
|
907
|
+
restoreRenderCtx(rctx);
|
|
908
|
+
finish();
|
|
909
|
+
throw e;
|
|
910
|
+
});
|
|
911
911
|
}
|
|
912
912
|
finish();
|
|
913
913
|
return;
|
|
@@ -919,7 +919,8 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
919
919
|
const instance = new type(props);
|
|
920
920
|
if (typeof type.getDerivedStateFromProps === "function") {
|
|
921
921
|
const derived = type.getDerivedStateFromProps(props, instance.state ?? {});
|
|
922
|
-
if (derived != null)
|
|
922
|
+
if (derived != null)
|
|
923
|
+
instance.state = { ...instance.state ?? {}, ...derived };
|
|
923
924
|
}
|
|
924
925
|
result = instance.render();
|
|
925
926
|
} else {
|
|
@@ -928,9 +929,11 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
928
929
|
} catch (e) {
|
|
929
930
|
restoreDispatcher(prevDispatcher);
|
|
930
931
|
popComponentScope(savedScope);
|
|
931
|
-
if (isProvider)
|
|
932
|
+
if (isProvider)
|
|
933
|
+
popContextValue(ctx, prevCtxValue);
|
|
932
934
|
if (e && typeof e.then === "function") {
|
|
933
|
-
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES)
|
|
935
|
+
if (_suspenseRetries + 1 >= MAX_COMPONENT_SUSPENSE_RETRIES)
|
|
936
|
+
throw SUSPENSE_RETRY_LIMIT;
|
|
934
937
|
patchPromiseStatus(e);
|
|
935
938
|
const rctx = captureRenderCtx();
|
|
936
939
|
return e.then(() => {
|
|
@@ -956,61 +959,68 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
956
959
|
const r2 = renderNode(resolved, writer, isSvg);
|
|
957
960
|
if (r2 && typeof r2.then === "function") {
|
|
958
961
|
const rctx2 = captureRenderCtx();
|
|
959
|
-
return r2.then(
|
|
960
|
-
()
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
962
|
+
return r2.then(() => {
|
|
963
|
+
restoreRenderCtx(rctx2);
|
|
964
|
+
if (asyncSavedIdTree !== undefined)
|
|
965
|
+
popTreeContext(asyncSavedIdTree);
|
|
966
|
+
popComponentScope(savedScope);
|
|
967
|
+
if (isProvider)
|
|
968
|
+
popContextValue(ctx, prevCtxValue);
|
|
969
|
+
}, (e) => {
|
|
970
|
+
restoreRenderCtx(rctx2);
|
|
971
|
+
if (asyncSavedIdTree !== undefined)
|
|
972
|
+
popTreeContext(asyncSavedIdTree);
|
|
973
|
+
popComponentScope(savedScope);
|
|
974
|
+
if (isProvider)
|
|
975
|
+
popContextValue(ctx, prevCtxValue);
|
|
976
|
+
throw e;
|
|
977
|
+
});
|
|
974
978
|
}
|
|
975
|
-
if (asyncSavedIdTree !==
|
|
979
|
+
if (asyncSavedIdTree !== undefined)
|
|
980
|
+
popTreeContext(asyncSavedIdTree);
|
|
976
981
|
popComponentScope(savedScope);
|
|
977
|
-
if (isProvider)
|
|
982
|
+
if (isProvider)
|
|
983
|
+
popContextValue(ctx, prevCtxValue);
|
|
978
984
|
}, (e) => {
|
|
979
985
|
restoreRenderCtx(rctx);
|
|
980
986
|
popComponentScope(savedScope);
|
|
981
|
-
if (isProvider)
|
|
987
|
+
if (isProvider)
|
|
988
|
+
popContextValue(ctx, prevCtxValue);
|
|
982
989
|
throw e;
|
|
983
990
|
});
|
|
984
991
|
}
|
|
985
992
|
const r = renderNode(result, writer, isSvg);
|
|
986
993
|
if (r && typeof r.then === "function") {
|
|
987
994
|
const rctx = captureRenderCtx();
|
|
988
|
-
return r.then(
|
|
989
|
-
()
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
995
|
+
return r.then(() => {
|
|
996
|
+
restoreRenderCtx(rctx);
|
|
997
|
+
if (savedIdTree !== undefined)
|
|
998
|
+
popTreeContext(savedIdTree);
|
|
999
|
+
popComponentScope(savedScope);
|
|
1000
|
+
if (isProvider)
|
|
1001
|
+
popContextValue(ctx, prevCtxValue);
|
|
1002
|
+
}, (e) => {
|
|
1003
|
+
restoreRenderCtx(rctx);
|
|
1004
|
+
if (savedIdTree !== undefined)
|
|
1005
|
+
popTreeContext(savedIdTree);
|
|
1006
|
+
popComponentScope(savedScope);
|
|
1007
|
+
if (isProvider)
|
|
1008
|
+
popContextValue(ctx, prevCtxValue);
|
|
1009
|
+
throw e;
|
|
1010
|
+
});
|
|
1003
1011
|
}
|
|
1004
|
-
if (savedIdTree !==
|
|
1012
|
+
if (savedIdTree !== undefined)
|
|
1013
|
+
popTreeContext(savedIdTree);
|
|
1005
1014
|
popComponentScope(savedScope);
|
|
1006
|
-
if (isProvider)
|
|
1015
|
+
if (isProvider)
|
|
1016
|
+
popContextValue(ctx, prevCtxValue);
|
|
1007
1017
|
}
|
|
1008
1018
|
function renderChildArray(children, writer, isSvg) {
|
|
1009
1019
|
return renderChildArrayFrom(children, 0, writer, isSvg);
|
|
1010
1020
|
}
|
|
1011
1021
|
function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
1012
1022
|
const totalChildren = children.length;
|
|
1013
|
-
for (let i = startIndex;
|
|
1023
|
+
for (let i = startIndex;i < totalChildren; i++) {
|
|
1014
1024
|
const child = children[i];
|
|
1015
1025
|
if ((typeof child === "string" || typeof child === "number") && writer.lastWasText) {
|
|
1016
1026
|
writer.write("<!-- -->");
|
|
@@ -1029,7 +1039,8 @@ function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
|
1029
1039
|
}
|
|
1030
1040
|
}
|
|
1031
1041
|
function renderChildren(children, writer, isSvg = false) {
|
|
1032
|
-
if (children == null)
|
|
1042
|
+
if (children == null)
|
|
1043
|
+
return;
|
|
1033
1044
|
if (Array.isArray(children)) {
|
|
1034
1045
|
return renderChildArray(children, writer, isSvg);
|
|
1035
1046
|
}
|
|
@@ -1040,7 +1051,7 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
1040
1051
|
const snap = snapshotContext();
|
|
1041
1052
|
const savedMap = captureMap();
|
|
1042
1053
|
const savedMapClone = savedMap ? new Map(savedMap) : null;
|
|
1043
|
-
const buffer = new BufferWriter
|
|
1054
|
+
const buffer = new BufferWriter;
|
|
1044
1055
|
try {
|
|
1045
1056
|
const r = renderNode(children, buffer, isSvg);
|
|
1046
1057
|
if (r && typeof r.then === "function") {
|
|
@@ -1071,13 +1082,11 @@ async function renderSuspense(props, writer, isSvg = false) {
|
|
|
1071
1082
|
}
|
|
1072
1083
|
}
|
|
1073
1084
|
}
|
|
1074
|
-
var _streamEncoder = new TextEncoder
|
|
1085
|
+
var _streamEncoder = new TextEncoder;
|
|
1075
1086
|
var NULL_WRITER = {
|
|
1076
1087
|
lastWasText: false,
|
|
1077
|
-
write(_c) {
|
|
1078
|
-
}
|
|
1079
|
-
text(_s) {
|
|
1080
|
-
}
|
|
1088
|
+
write(_c) {},
|
|
1089
|
+
text(_s) {}
|
|
1081
1090
|
};
|
|
1082
1091
|
async function renderPreflight(element, options) {
|
|
1083
1092
|
const idPrefix = options?.identifierPrefix ?? "";
|
|
@@ -1123,7 +1132,6 @@ async function renderToString(element, options) {
|
|
|
1123
1132
|
swapContextMap(prev);
|
|
1124
1133
|
}
|
|
1125
1134
|
}
|
|
1126
|
-
|
|
1127
1135
|
// src/utils/response.tsx
|
|
1128
1136
|
var ESC = { "&": "&", "<": "<", ">": ">", '"': """ };
|
|
1129
1137
|
var escAttr = (s2) => s2.replace(/[&<>"]/g, (c) => ESC[c] ?? c);
|
|
@@ -1143,14 +1151,17 @@ function renderHeadTag(tag, id, opts, selfClose = false) {
|
|
|
1143
1151
|
let attrs = ` id="${escAttr(id)}"`;
|
|
1144
1152
|
let inner = "";
|
|
1145
1153
|
for (const [k, v] of Object.entries(opts)) {
|
|
1146
|
-
if (k === "key" || k === "children")
|
|
1154
|
+
if (k === "key" || k === "children")
|
|
1155
|
+
continue;
|
|
1147
1156
|
if (k === "dangerouslySetInnerHTML") {
|
|
1148
1157
|
inner = v.__html ?? "";
|
|
1149
1158
|
continue;
|
|
1150
1159
|
}
|
|
1151
1160
|
const attr = ATTR[k] ?? k;
|
|
1152
|
-
if (v === true)
|
|
1153
|
-
|
|
1161
|
+
if (v === true)
|
|
1162
|
+
attrs += ` ${attr}`;
|
|
1163
|
+
else if (v !== false && v != null)
|
|
1164
|
+
attrs += ` ${attr}="${escAttr(String(v))}"`;
|
|
1154
1165
|
}
|
|
1155
1166
|
return selfClose ? `<${tag}${attrs}>` : `<${tag}${attrs}>${inner}</${tag}>`;
|
|
1156
1167
|
}
|
|
@@ -1177,7 +1188,7 @@ var getReactResponse = async (req, opts) => {
|
|
|
1177
1188
|
location: req.location,
|
|
1178
1189
|
context
|
|
1179
1190
|
};
|
|
1180
|
-
const unsuspend = { cache:
|
|
1191
|
+
const unsuspend = { cache: new Map };
|
|
1181
1192
|
globalThis.__hadarsUnsuspend = unsuspend;
|
|
1182
1193
|
globalThis.__hadarsContext = context;
|
|
1183
1194
|
const element = createElement(App, props);
|
|
@@ -1226,7 +1237,7 @@ import path from "node:path";
|
|
|
1226
1237
|
import { fileURLToPath } from "node:url";
|
|
1227
1238
|
import pathMod from "node:path";
|
|
1228
1239
|
import { existsSync } from "node:fs";
|
|
1229
|
-
var
|
|
1240
|
+
var __dirname2 = process.cwd();
|
|
1230
1241
|
var packageDir = pathMod.dirname(fileURLToPath(import.meta.url));
|
|
1231
1242
|
var clientScriptPath = pathMod.resolve(packageDir, "template.html");
|
|
1232
1243
|
var loaderPath = existsSync(pathMod.resolve(packageDir, "loader.cjs")) ? pathMod.resolve(packageDir, "loader.cjs") : pathMod.resolve(packageDir, "loader.ts");
|
|
@@ -1239,13 +1250,10 @@ var getConfigBase = (mode, isServerBuild = false) => {
|
|
|
1239
1250
|
},
|
|
1240
1251
|
resolve: {
|
|
1241
1252
|
modules: [
|
|
1242
|
-
path.resolve(
|
|
1243
|
-
// 'node_modules' (relative) enables the standard upward-traversal
|
|
1244
|
-
// resolution so rspack can find transitive deps (e.g. webpack-dev-server)
|
|
1245
|
-
// that live in a parent node_modules when running from a sub-project.
|
|
1253
|
+
path.resolve(__dirname2, "node_modules"),
|
|
1246
1254
|
"node_modules"
|
|
1247
1255
|
],
|
|
1248
|
-
tsConfig: path.resolve(
|
|
1256
|
+
tsConfig: path.resolve(__dirname2, "tsconfig.json"),
|
|
1249
1257
|
extensions: [".tsx", ".ts", ".js", ".jsx"]
|
|
1250
1258
|
},
|
|
1251
1259
|
module: {
|
|
@@ -1267,8 +1275,6 @@ var getConfigBase = (mode, isServerBuild = false) => {
|
|
|
1267
1275
|
},
|
|
1268
1276
|
exclude: [loaderPath],
|
|
1269
1277
|
use: [
|
|
1270
|
-
// Transforms loadModule('./path') based on build target.
|
|
1271
|
-
// Runs before swc-loader (loaders execute right-to-left).
|
|
1272
1278
|
{
|
|
1273
1279
|
loader: loaderPath,
|
|
1274
1280
|
options: { server: isServerBuild }
|
|
@@ -1333,9 +1339,7 @@ var getConfigBase = (mode, isServerBuild = false) => {
|
|
|
1333
1339
|
var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
1334
1340
|
const { base } = opts;
|
|
1335
1341
|
const isDev = opts.mode === "development";
|
|
1336
|
-
const isServerBuild = Boolean(
|
|
1337
|
-
opts.output && typeof opts.output === "object" && (opts.output.library || String(opts.output.filename || "").includes("ssr"))
|
|
1338
|
-
);
|
|
1342
|
+
const isServerBuild = Boolean(opts.output && typeof opts.output === "object" && (opts.output.library || String(opts.output.filename || "").includes("ssr")));
|
|
1339
1343
|
const Config = getConfigBase(opts.mode, isServerBuild);
|
|
1340
1344
|
const localConfig = {
|
|
1341
1345
|
...Config,
|
|
@@ -1366,7 +1370,7 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1366
1370
|
useEntry.options.jsc.experimental.runPluginFirst = true;
|
|
1367
1371
|
const existingPlugins = Array.isArray(useEntry.options.jsc.experimental.plugins) ? useEntry.options.jsc.experimental.plugins : [];
|
|
1368
1372
|
const incomingPlugins = Array.isArray(opts.swcPlugins) ? opts.swcPlugins : [];
|
|
1369
|
-
const seen =
|
|
1373
|
+
const seen = new Set;
|
|
1370
1374
|
const merged = [];
|
|
1371
1375
|
for (const p of existingPlugins.concat(incomingPlugins)) {
|
|
1372
1376
|
const name = Array.isArray(p) && p.length > 0 ? String(p[0]) : String(p);
|
|
@@ -1400,31 +1404,24 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1400
1404
|
const slimReactIndex = pathMod.resolve(packageDir, "slim-react", "index.js");
|
|
1401
1405
|
const slimReactJsx = pathMod.resolve(packageDir, "slim-react", "jsx-runtime.js");
|
|
1402
1406
|
const resolveAliases = isServerBuild ? {
|
|
1403
|
-
// Route all React imports to slim-react for SSR.
|
|
1404
1407
|
react: slimReactIndex,
|
|
1405
1408
|
"react/jsx-runtime": slimReactJsx,
|
|
1406
1409
|
"react/jsx-dev-runtime": slimReactJsx
|
|
1407
|
-
|
|
1408
|
-
// resolved through the alias above to slim-react. If left external,
|
|
1409
|
-
// emotion loads real React from node_modules and calls
|
|
1410
|
-
// ReactSharedInternals.H.useContext which requires React's dispatcher.
|
|
1411
|
-
} : void 0;
|
|
1410
|
+
} : undefined;
|
|
1412
1411
|
const externals = isServerBuild ? [
|
|
1413
|
-
// Node.js built-ins — must not be bundled; resolved by the runtime.
|
|
1414
1412
|
"node:fs",
|
|
1415
1413
|
"node:path",
|
|
1416
1414
|
"node:os",
|
|
1417
1415
|
"node:stream",
|
|
1418
1416
|
"node:util",
|
|
1419
|
-
// @emotion/server is only used outside component rendering (CSS extraction)
|
|
1420
|
-
// and does not call React hooks, so it is safe to leave as external.
|
|
1421
1417
|
"@emotion/server"
|
|
1422
|
-
] :
|
|
1418
|
+
] : undefined;
|
|
1423
1419
|
const effectiveReactDev = isServerBuild ? false : opts.reactMode === "development" ? true : opts.reactMode === "production" ? false : isDev;
|
|
1424
|
-
if (!isServerBuild && opts.reactMode !==
|
|
1420
|
+
if (!isServerBuild && opts.reactMode !== undefined) {
|
|
1425
1421
|
const rules = localConfig.module?.rules ?? [];
|
|
1426
1422
|
for (const rule of rules) {
|
|
1427
|
-
if (!rule?.use || !Array.isArray(rule.use))
|
|
1423
|
+
if (!rule?.use || !Array.isArray(rule.use))
|
|
1424
|
+
continue;
|
|
1428
1425
|
for (const entry2 of rule.use) {
|
|
1429
1426
|
if (entry2?.loader?.includes("swc-loader")) {
|
|
1430
1427
|
entry2.options = entry2.options ?? {};
|
|
@@ -1439,7 +1436,7 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1439
1436
|
}
|
|
1440
1437
|
const extraPlugins = [];
|
|
1441
1438
|
const defineValues = { ...opts.define ?? {} };
|
|
1442
|
-
if (!isServerBuild && opts.reactMode !==
|
|
1439
|
+
if (!isServerBuild && opts.reactMode !== undefined) {
|
|
1443
1440
|
defineValues["process.env.NODE_ENV"] = JSON.stringify(opts.reactMode);
|
|
1444
1441
|
}
|
|
1445
1442
|
if (Object.keys(defineValues).length > 0) {
|
|
@@ -1451,10 +1448,7 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1451
1448
|
const resolveConfig = {
|
|
1452
1449
|
extensions: [".tsx", ".ts", ".js", ".jsx"],
|
|
1453
1450
|
alias: resolveAliases,
|
|
1454
|
-
// for server builds prefer the package "main"/"module" fields and avoid "browser" so we don't pick browser-specific entrypoints
|
|
1455
1451
|
mainFields: isServerBuild ? ["main", "module"] : ["browser", "module", "main"],
|
|
1456
|
-
// for server builds exclude the "browser" condition so packages with package.json
|
|
1457
|
-
// "exports" conditions (e.g. @emotion/*) resolve their Node/CJS entry, not the browser build
|
|
1458
1452
|
...isServerBuild ? { conditionNames: ["node", "require", "default"] } : {}
|
|
1459
1453
|
};
|
|
1460
1454
|
const optimization = !isServerBuild && !isDev ? {
|
|
@@ -1471,7 +1465,7 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1471
1465
|
}
|
|
1472
1466
|
},
|
|
1473
1467
|
...opts.optimization ?? {}
|
|
1474
|
-
} : opts.optimization ? { ...opts.optimization } :
|
|
1468
|
+
} : opts.optimization ? { ...opts.optimization } : undefined;
|
|
1475
1469
|
return {
|
|
1476
1470
|
entry,
|
|
1477
1471
|
output: {
|
|
@@ -1479,17 +1473,10 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1479
1473
|
clean: false
|
|
1480
1474
|
},
|
|
1481
1475
|
mode: opts.mode,
|
|
1482
|
-
// Persist transformed modules to disk — subsequent starts only recompile
|
|
1483
|
-
// changed files, making repeat dev starts significantly faster.
|
|
1484
1476
|
cache: true,
|
|
1485
1477
|
externals,
|
|
1486
|
-
// externalsPresets.node externalises ALL Node.js built-ins (bare names
|
|
1487
|
-
// and the node: prefix) for both static and dynamic imports. This
|
|
1488
|
-
// complements the explicit `externals` array: the preset handles the
|
|
1489
|
-
// node: URI scheme that rspack cannot resolve as a file, while the
|
|
1490
|
-
// array keeps '@emotion/server' as an explicit external.
|
|
1491
1478
|
...isServerBuild ? { externalsPresets: { node: true } } : {},
|
|
1492
|
-
...optimization !==
|
|
1479
|
+
...optimization !== undefined ? { optimization } : {},
|
|
1493
1480
|
plugins: [
|
|
1494
1481
|
!isServerBuild && new rspack.HtmlRspackPlugin({
|
|
1495
1482
|
publicPath: base || "/",
|
|
@@ -1505,10 +1492,7 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1505
1492
|
const asset = compilation.assets["out.html"];
|
|
1506
1493
|
if (asset) {
|
|
1507
1494
|
const html = asset.source();
|
|
1508
|
-
const updated = html.replace(
|
|
1509
|
-
/(<script\b[^>]*\btype="module"[^>]*)(>)/g,
|
|
1510
|
-
(match, before, end) => before.includes("async") ? match : `${before} async${end}`
|
|
1511
|
-
);
|
|
1495
|
+
const updated = html.replace(/(<script\b[^>]*\btype="module"[^>]*)(>)/g, (match, before, end) => before.includes("async") ? match : `${before} async${end}`);
|
|
1512
1496
|
compilation.assets["out.html"] = {
|
|
1513
1497
|
source: () => updated,
|
|
1514
1498
|
size: () => Buffer.byteLength(updated)
|
|
@@ -1518,28 +1502,20 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1518
1502
|
});
|
|
1519
1503
|
}
|
|
1520
1504
|
},
|
|
1521
|
-
isDev && !isServerBuild && new ReactRefreshPlugin
|
|
1522
|
-
includeHotPlugin && isDev && !isServerBuild && new rspack.HotModuleReplacementPlugin
|
|
1505
|
+
isDev && !isServerBuild && new ReactRefreshPlugin,
|
|
1506
|
+
includeHotPlugin && isDev && !isServerBuild && new rspack.HotModuleReplacementPlugin,
|
|
1523
1507
|
...extraPlugins,
|
|
1524
1508
|
...opts.plugins ?? []
|
|
1525
1509
|
],
|
|
1526
1510
|
...localConfig,
|
|
1527
|
-
// Merge base resolve (modules, tsConfig, extensions) with per-build resolve
|
|
1528
|
-
// (alias, mainFields). The spread order matters: resolveConfig wins for keys
|
|
1529
|
-
// it defines, localConfig.resolve wins for keys it defines exclusively.
|
|
1530
1511
|
resolve: {
|
|
1531
1512
|
...localConfig.resolve,
|
|
1532
1513
|
...resolveConfig
|
|
1533
1514
|
},
|
|
1534
|
-
// HMR is not implemented for module chunk format, so disable outputModule
|
|
1535
|
-
// for client builds. SSR builds still need it for dynamic import() of exports.
|
|
1536
1515
|
experiments: {
|
|
1537
1516
|
...localConfig.experiments || {},
|
|
1538
1517
|
outputModule: isServerBuild
|
|
1539
1518
|
},
|
|
1540
|
-
// Prevent rspack from watching its own build output — without this the
|
|
1541
|
-
// SSR watcher writing .hadars/index.ssr.js triggers the client compiler
|
|
1542
|
-
// and vice versa, causing an infinite rebuild loop.
|
|
1543
1519
|
watchOptions: {
|
|
1544
1520
|
ignored: ["**/node_modules/**", "**/.hadars/**", "/tmp/**"]
|
|
1545
1521
|
}
|
|
@@ -1551,7 +1527,7 @@ var createClientCompiler = (entry, opts) => {
|
|
|
1551
1527
|
var compileEntry = async (entry, opts) => {
|
|
1552
1528
|
const compiler = rspack(buildCompilerConfig(entry, opts, true));
|
|
1553
1529
|
if (opts.watch) {
|
|
1554
|
-
await new Promise((
|
|
1530
|
+
await new Promise((resolve, reject) => {
|
|
1555
1531
|
let first = true;
|
|
1556
1532
|
compiler.watch({ ignored: ["**/node_modules/**", "**/.hadars/**", "/tmp/**"] }, (err, stats) => {
|
|
1557
1533
|
if (err) {
|
|
@@ -1566,7 +1542,7 @@ var compileEntry = async (entry, opts) => {
|
|
|
1566
1542
|
console.log(stats?.toString({ colors: true }));
|
|
1567
1543
|
if (first) {
|
|
1568
1544
|
first = false;
|
|
1569
|
-
|
|
1545
|
+
resolve(stats);
|
|
1570
1546
|
} else {
|
|
1571
1547
|
try {
|
|
1572
1548
|
opts.onChange && opts.onChange(stats);
|
|
@@ -1578,7 +1554,7 @@ var compileEntry = async (entry, opts) => {
|
|
|
1578
1554
|
});
|
|
1579
1555
|
return;
|
|
1580
1556
|
}
|
|
1581
|
-
await new Promise((
|
|
1557
|
+
await new Promise((resolve, reject) => {
|
|
1582
1558
|
compiler.run((err, stats) => {
|
|
1583
1559
|
if (err) {
|
|
1584
1560
|
reject(err);
|
|
@@ -1588,7 +1564,7 @@ var compileEntry = async (entry, opts) => {
|
|
|
1588
1564
|
colors: true,
|
|
1589
1565
|
preset: "minimal"
|
|
1590
1566
|
}));
|
|
1591
|
-
|
|
1567
|
+
resolve(stats);
|
|
1592
1568
|
});
|
|
1593
1569
|
});
|
|
1594
1570
|
};
|
|
@@ -1600,13 +1576,11 @@ var isNode = !isBun && !isDeno;
|
|
|
1600
1576
|
|
|
1601
1577
|
// src/utils/serve.ts
|
|
1602
1578
|
function nodeReadableToWebStream(readable) {
|
|
1603
|
-
const enc = new TextEncoder
|
|
1579
|
+
const enc = new TextEncoder;
|
|
1604
1580
|
return new ReadableStream({
|
|
1605
1581
|
start(controller) {
|
|
1606
1582
|
readable.on("data", (chunk) => {
|
|
1607
|
-
controller.enqueue(
|
|
1608
|
-
typeof chunk === "string" ? enc.encode(chunk) : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)
|
|
1609
|
-
);
|
|
1583
|
+
controller.enqueue(typeof chunk === "string" ? enc.encode(chunk) : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
1610
1584
|
});
|
|
1611
1585
|
readable.on("end", () => controller.close());
|
|
1612
1586
|
readable.on("error", (err) => controller.error(err));
|
|
@@ -1636,7 +1610,7 @@ async function serve(port, fetchHandler, websocket) {
|
|
|
1636
1610
|
websocket,
|
|
1637
1611
|
async fetch(req, server2) {
|
|
1638
1612
|
const ctx = { upgrade: (r) => server2.upgrade(r) };
|
|
1639
|
-
return await fetchHandler(req, ctx) ??
|
|
1613
|
+
return await fetchHandler(req, ctx) ?? undefined;
|
|
1640
1614
|
}
|
|
1641
1615
|
});
|
|
1642
1616
|
return;
|
|
@@ -1660,7 +1634,7 @@ async function serve(port, fetchHandler, websocket) {
|
|
|
1660
1634
|
chunks.push(chunk);
|
|
1661
1635
|
}
|
|
1662
1636
|
}
|
|
1663
|
-
const body = chunks.length > 0 ? Buffer.concat(chunks) :
|
|
1637
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;
|
|
1664
1638
|
const url = `http://localhost:${port}${nodeReq.url ?? "/"}`;
|
|
1665
1639
|
const reqInit = {
|
|
1666
1640
|
method: nodeReq.method ?? "GET",
|
|
@@ -1682,21 +1656,21 @@ async function serve(port, fetchHandler, websocket) {
|
|
|
1682
1656
|
const reader = response.body.getReader();
|
|
1683
1657
|
while (true) {
|
|
1684
1658
|
const { done, value } = await reader.read();
|
|
1685
|
-
if (done)
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
);
|
|
1659
|
+
if (done)
|
|
1660
|
+
break;
|
|
1661
|
+
await new Promise((resolve, reject) => nodeRes.write(value, (err) => err ? reject(err) : resolve()));
|
|
1689
1662
|
}
|
|
1690
1663
|
}
|
|
1691
1664
|
} catch (err) {
|
|
1692
1665
|
console.error("[hadars] request error", err);
|
|
1693
|
-
if (!nodeRes.headersSent)
|
|
1666
|
+
if (!nodeRes.headersSent)
|
|
1667
|
+
nodeRes.writeHead(500);
|
|
1694
1668
|
} finally {
|
|
1695
1669
|
nodeRes.end();
|
|
1696
1670
|
}
|
|
1697
1671
|
});
|
|
1698
|
-
await new Promise((
|
|
1699
|
-
server.listen(port, () =>
|
|
1672
|
+
await new Promise((resolve, reject) => {
|
|
1673
|
+
server.listen(port, () => resolve());
|
|
1700
1674
|
server.once("error", reject);
|
|
1701
1675
|
});
|
|
1702
1676
|
}
|
|
@@ -1752,7 +1726,7 @@ import cluster from "node:cluster";
|
|
|
1752
1726
|
// src/utils/ssrHandler.ts
|
|
1753
1727
|
var HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
1754
1728
|
var BODY_MARKER = '<meta name="HADARS_BODY">';
|
|
1755
|
-
var encoder = new TextEncoder
|
|
1729
|
+
var encoder = new TextEncoder;
|
|
1756
1730
|
function buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml) {
|
|
1757
1731
|
const headHtml = buildHeadHtml(head);
|
|
1758
1732
|
const precontentResult = getPrecontentHtml(headHtml);
|
|
@@ -1765,9 +1739,7 @@ function buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml)
|
|
|
1765
1739
|
controller.enqueue(encoder.encode(`<div id="app">${bodyHtml}</div>`));
|
|
1766
1740
|
const { clientProps } = await finalize();
|
|
1767
1741
|
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
1768
|
-
controller.enqueue(encoder.encode(
|
|
1769
|
-
`<script id="hadars" type="application/json">${scriptContent}</script>` + postContent
|
|
1770
|
-
));
|
|
1742
|
+
controller.enqueue(encoder.encode(`<script id="hadars" type="application/json">${scriptContent}</script>` + postContent));
|
|
1771
1743
|
controller.close();
|
|
1772
1744
|
} catch (err) {
|
|
1773
1745
|
controller.error(err);
|
|
@@ -1810,7 +1782,8 @@ async function transformStream(data, stream) {
|
|
|
1810
1782
|
const reader = stream.readable.getReader();
|
|
1811
1783
|
while (true) {
|
|
1812
1784
|
const { done, value } = await reader.read();
|
|
1813
|
-
if (done)
|
|
1785
|
+
if (done)
|
|
1786
|
+
break;
|
|
1814
1787
|
chunks.push(value);
|
|
1815
1788
|
}
|
|
1816
1789
|
const total = chunks.reduce((n, c) => n + c.length, 0);
|
|
@@ -1856,8 +1829,8 @@ async function serveFromEntry(entry, req) {
|
|
|
1856
1829
|
return new Response(plain.buffer, { status: entry.status, headers });
|
|
1857
1830
|
}
|
|
1858
1831
|
function createRenderCache(opts, handler) {
|
|
1859
|
-
const store =
|
|
1860
|
-
const inFlight =
|
|
1832
|
+
const store = new Map;
|
|
1833
|
+
const inFlight = new Map;
|
|
1861
1834
|
return async (req, ctx) => {
|
|
1862
1835
|
const hadarsReq = parseRequest(req);
|
|
1863
1836
|
const cacheOpts = await opts(hadarsReq);
|
|
@@ -1866,7 +1839,8 @@ function createRenderCache(opts, handler) {
|
|
|
1866
1839
|
const entry = store.get(key);
|
|
1867
1840
|
if (entry) {
|
|
1868
1841
|
const expired = entry.expiresAt != null && Date.now() >= entry.expiresAt;
|
|
1869
|
-
if (!expired)
|
|
1842
|
+
if (!expired)
|
|
1843
|
+
return serveFromEntry(entry, req);
|
|
1870
1844
|
store.delete(key);
|
|
1871
1845
|
}
|
|
1872
1846
|
let flight = inFlight.get(key);
|
|
@@ -1883,7 +1857,8 @@ function createRenderCache(opts, handler) {
|
|
|
1883
1857
|
inFlight.set(key, flight);
|
|
1884
1858
|
}
|
|
1885
1859
|
const newEntry = await flight;
|
|
1886
|
-
if (newEntry)
|
|
1860
|
+
if (newEntry)
|
|
1861
|
+
return serveFromEntry(newEntry, req);
|
|
1887
1862
|
}
|
|
1888
1863
|
return handler(req, ctx);
|
|
1889
1864
|
};
|
|
@@ -1891,20 +1866,24 @@ function createRenderCache(opts, handler) {
|
|
|
1891
1866
|
|
|
1892
1867
|
// src/source/runner.ts
|
|
1893
1868
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
1894
|
-
import { createRequire } from "node:module";
|
|
1869
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
1895
1870
|
|
|
1896
1871
|
// src/source/store.ts
|
|
1897
|
-
|
|
1898
|
-
byId =
|
|
1899
|
-
byType =
|
|
1872
|
+
class NodeStore {
|
|
1873
|
+
byId = new Map;
|
|
1874
|
+
byType = new Map;
|
|
1900
1875
|
createNode(node) {
|
|
1901
|
-
if (!node.id)
|
|
1902
|
-
|
|
1876
|
+
if (!node.id)
|
|
1877
|
+
throw new Error("[hadars] createNode: node.id must be a non-empty string");
|
|
1878
|
+
if (!node.internal?.type)
|
|
1879
|
+
throw new Error("[hadars] createNode: node.internal.type must be a non-empty string");
|
|
1903
1880
|
this.byId.set(node.id, node);
|
|
1904
1881
|
const list = this.byType.get(node.internal.type) ?? [];
|
|
1905
1882
|
const idx = list.findIndex((n) => n.id === node.id);
|
|
1906
|
-
if (idx >= 0)
|
|
1907
|
-
|
|
1883
|
+
if (idx >= 0)
|
|
1884
|
+
list[idx] = node;
|
|
1885
|
+
else
|
|
1886
|
+
list.push(node);
|
|
1908
1887
|
this.byType.set(node.internal.type, list);
|
|
1909
1888
|
}
|
|
1910
1889
|
getNode(id) {
|
|
@@ -1919,13 +1898,13 @@ var NodeStore = class {
|
|
|
1919
1898
|
getTypes() {
|
|
1920
1899
|
return Array.from(this.byType.keys());
|
|
1921
1900
|
}
|
|
1922
|
-
}
|
|
1901
|
+
}
|
|
1923
1902
|
|
|
1924
1903
|
// src/source/context.ts
|
|
1925
1904
|
import { createHash } from "node:crypto";
|
|
1926
1905
|
import { EventEmitter } from "node:events";
|
|
1927
|
-
function makeGatsbyContext(store, pluginName, pluginOptions = {}, emitter = new EventEmitter
|
|
1928
|
-
const cacheMap =
|
|
1906
|
+
function makeGatsbyContext(store, pluginName, pluginOptions = {}, emitter = new EventEmitter) {
|
|
1907
|
+
const cacheMap = new Map;
|
|
1929
1908
|
const cache = {
|
|
1930
1909
|
get: (key) => Promise.resolve(cacheMap.get(key)),
|
|
1931
1910
|
set: (key, value) => {
|
|
@@ -1942,29 +1921,29 @@ function makeGatsbyContext(store, pluginName, pluginOptions = {}, emitter = new
|
|
|
1942
1921
|
process.exit(1);
|
|
1943
1922
|
},
|
|
1944
1923
|
verbose: (msg) => {
|
|
1945
|
-
if (process.env.HADARS_VERBOSE)
|
|
1924
|
+
if (process.env.HADARS_VERBOSE)
|
|
1925
|
+
console.log(`[${pluginName}] ${msg}`);
|
|
1946
1926
|
},
|
|
1947
1927
|
activityTimer: (name) => ({
|
|
1948
1928
|
start: () => {
|
|
1949
|
-
if (process.env.HADARS_VERBOSE)
|
|
1929
|
+
if (process.env.HADARS_VERBOSE)
|
|
1930
|
+
console.log(`[${pluginName}] ▶ ${name}`);
|
|
1950
1931
|
},
|
|
1951
1932
|
end: () => {
|
|
1952
|
-
if (process.env.HADARS_VERBOSE)
|
|
1933
|
+
if (process.env.HADARS_VERBOSE)
|
|
1934
|
+
console.log(`[${pluginName}] ■ ${name}`);
|
|
1953
1935
|
}
|
|
1954
1936
|
}),
|
|
1955
|
-
|
|
1956
|
-
setErrorMap: () => {
|
|
1957
|
-
},
|
|
1937
|
+
setErrorMap: () => {},
|
|
1958
1938
|
log: (msg) => console.log(`[${pluginName}] ${msg}`),
|
|
1959
|
-
success: (msg) => console.log(`[${pluginName}]
|
|
1939
|
+
success: (msg) => console.log(`[${pluginName}] ✓ ${msg}`)
|
|
1960
1940
|
};
|
|
1961
1941
|
const actions = {
|
|
1962
1942
|
createNode: (node) => store.createNode(node),
|
|
1963
1943
|
deleteNode: ({ id }) => {
|
|
1964
|
-
console.warn(`[${pluginName}] deleteNode("${id}") called but is not supported by hadars
|
|
1944
|
+
console.warn(`[${pluginName}] deleteNode("${id}") called but is not supported by hadars — node will remain in the store.`);
|
|
1965
1945
|
},
|
|
1966
|
-
touchNode: () => {
|
|
1967
|
-
}
|
|
1946
|
+
touchNode: () => {}
|
|
1968
1947
|
};
|
|
1969
1948
|
return {
|
|
1970
1949
|
actions,
|
|
@@ -1978,11 +1957,9 @@ function makeGatsbyContext(store, pluginName, pluginOptions = {}, emitter = new
|
|
|
1978
1957
|
getNodesByType: (t) => store.getNodesByType(t),
|
|
1979
1958
|
cache,
|
|
1980
1959
|
reporter,
|
|
1981
|
-
// Stubs for rarely-used Gatsby internals that plugins may destructure
|
|
1982
1960
|
store: {},
|
|
1983
1961
|
emitter,
|
|
1984
|
-
tracing: { startSpan: () => ({ finish: () => {
|
|
1985
|
-
} }) },
|
|
1962
|
+
tracing: { startSpan: () => ({ finish: () => {} }) },
|
|
1986
1963
|
schema: {},
|
|
1987
1964
|
parentSpan: null
|
|
1988
1965
|
};
|
|
@@ -1991,14 +1968,14 @@ function makeGatsbyContext(store, pluginName, pluginOptions = {}, emitter = new
|
|
|
1991
1968
|
// src/source/runner.ts
|
|
1992
1969
|
var SETTLE_IDLE_MS = 300;
|
|
1993
1970
|
var SETTLE_TIMEOUT_MS = 1e4;
|
|
1994
|
-
var SOURCE_NODES_TIMEOUT_MS =
|
|
1971
|
+
var SOURCE_NODES_TIMEOUT_MS = 30000;
|
|
1995
1972
|
function waitForSettle(getLastNodeTime) {
|
|
1996
|
-
return new Promise((
|
|
1973
|
+
return new Promise((resolve) => {
|
|
1997
1974
|
const deadline = Date.now() + SETTLE_TIMEOUT_MS;
|
|
1998
1975
|
const check = () => {
|
|
1999
1976
|
const idle = Date.now() - getLastNodeTime();
|
|
2000
1977
|
if (idle >= SETTLE_IDLE_MS || Date.now() >= deadline) {
|
|
2001
|
-
|
|
1978
|
+
resolve();
|
|
2002
1979
|
} else {
|
|
2003
1980
|
const t2 = setTimeout(check, 50);
|
|
2004
1981
|
t2.unref?.();
|
|
@@ -2009,35 +1986,35 @@ function waitForSettle(getLastNodeTime) {
|
|
|
2009
1986
|
});
|
|
2010
1987
|
}
|
|
2011
1988
|
function withTimeout(promise, ms, label) {
|
|
2012
|
-
return new Promise((
|
|
1989
|
+
return new Promise((resolve, reject) => {
|
|
2013
1990
|
const t = setTimeout(() => reject(new Error(`[hadars] "${label}" timed out after ${ms}ms`)), ms);
|
|
2014
1991
|
t.unref?.();
|
|
2015
|
-
promise.then(
|
|
1992
|
+
promise.then(resolve, reject).finally(() => clearTimeout(t));
|
|
2016
1993
|
});
|
|
2017
1994
|
}
|
|
2018
1995
|
async function runSources(sources) {
|
|
2019
|
-
const store = new NodeStore
|
|
1996
|
+
const store = new NodeStore;
|
|
2020
1997
|
for (const entry of sources) {
|
|
2021
|
-
const { resolve
|
|
1998
|
+
const { resolve, options = {} } = entry;
|
|
2022
1999
|
let mod;
|
|
2023
|
-
if (typeof
|
|
2024
|
-
const projectRequire =
|
|
2000
|
+
if (typeof resolve === "string") {
|
|
2001
|
+
const projectRequire = createRequire2(process.cwd() + "/package.json");
|
|
2025
2002
|
let pkgPath;
|
|
2026
2003
|
try {
|
|
2027
|
-
pkgPath = projectRequire.resolve(`${
|
|
2004
|
+
pkgPath = projectRequire.resolve(`${resolve}/gatsby-node`);
|
|
2028
2005
|
} catch {
|
|
2029
|
-
pkgPath = projectRequire.resolve(
|
|
2006
|
+
pkgPath = projectRequire.resolve(resolve);
|
|
2030
2007
|
}
|
|
2031
2008
|
mod = await import(pkgPath);
|
|
2032
2009
|
} else {
|
|
2033
|
-
mod =
|
|
2010
|
+
mod = resolve;
|
|
2034
2011
|
}
|
|
2035
2012
|
if (typeof mod.sourceNodes !== "function") {
|
|
2036
|
-
const name = typeof
|
|
2037
|
-
console.warn(`[hadars] source plugin ${name} does not export sourceNodes
|
|
2013
|
+
const name = typeof resolve === "string" ? resolve : "(module)";
|
|
2014
|
+
console.warn(`[hadars] source plugin ${name} does not export sourceNodes — skipping`);
|
|
2038
2015
|
continue;
|
|
2039
2016
|
}
|
|
2040
|
-
const pluginName = typeof
|
|
2017
|
+
const pluginName = typeof resolve === "string" ? resolve : "hadars-source";
|
|
2041
2018
|
let lastNodeTime = Date.now();
|
|
2042
2019
|
const trackingStore = new Proxy(store, {
|
|
2043
2020
|
get(target, prop) {
|
|
@@ -2050,19 +2027,13 @@ async function runSources(sources) {
|
|
|
2050
2027
|
return target[prop];
|
|
2051
2028
|
}
|
|
2052
2029
|
});
|
|
2053
|
-
const emitter = new EventEmitter2
|
|
2030
|
+
const emitter = new EventEmitter2;
|
|
2054
2031
|
const ctx = makeGatsbyContext(trackingStore, pluginName, options, emitter);
|
|
2055
2032
|
try {
|
|
2056
|
-
await withTimeout(
|
|
2057
|
-
Promise.resolve(mod.sourceNodes(ctx, options)),
|
|
2058
|
-
SOURCE_NODES_TIMEOUT_MS,
|
|
2059
|
-
`${pluginName} sourceNodes`
|
|
2060
|
-
);
|
|
2033
|
+
await withTimeout(Promise.resolve(mod.sourceNodes(ctx, options)), SOURCE_NODES_TIMEOUT_MS, `${pluginName} sourceNodes`);
|
|
2061
2034
|
} catch (err) {
|
|
2062
2035
|
const cause = err instanceof Error ? err : new Error(String(err));
|
|
2063
|
-
const wrapped = new Error(
|
|
2064
|
-
`[hadars] source plugin "${pluginName}" threw during sourceNodes: ${cause.message}`
|
|
2065
|
-
);
|
|
2036
|
+
const wrapped = new Error(`[hadars] source plugin "${pluginName}" threw during sourceNodes: ${cause.message}`);
|
|
2066
2037
|
wrapped.cause = cause;
|
|
2067
2038
|
throw wrapped;
|
|
2068
2039
|
}
|
|
@@ -2075,12 +2046,14 @@ async function runSources(sources) {
|
|
|
2075
2046
|
|
|
2076
2047
|
// src/source/inference.ts
|
|
2077
2048
|
function inferScalar(value) {
|
|
2078
|
-
if (typeof value === "boolean")
|
|
2079
|
-
|
|
2049
|
+
if (typeof value === "boolean")
|
|
2050
|
+
return "Boolean";
|
|
2051
|
+
if (typeof value === "number")
|
|
2052
|
+
return Number.isInteger(value) ? "Int" : "Float";
|
|
2080
2053
|
return "String";
|
|
2081
2054
|
}
|
|
2082
2055
|
function inferFieldShape(value, seenTypes) {
|
|
2083
|
-
if (value === null || value ===
|
|
2056
|
+
if (value === null || value === undefined) {
|
|
2084
2057
|
return { type: "String", nullable: true };
|
|
2085
2058
|
}
|
|
2086
2059
|
if (Array.isArray(value)) {
|
|
@@ -2092,16 +2065,18 @@ function inferFieldShape(value, seenTypes) {
|
|
|
2092
2065
|
}
|
|
2093
2066
|
return { type: inferScalar(value), nullable: true };
|
|
2094
2067
|
}
|
|
2095
|
-
var INTERNAL_FIELDS =
|
|
2068
|
+
var INTERNAL_FIELDS = new Set(["id", "internal", "__typename", "parent", "children"]);
|
|
2096
2069
|
var isReservedFieldName = (name) => name.startsWith("__");
|
|
2097
|
-
var FILTERABLE_SCALARS =
|
|
2070
|
+
var FILTERABLE_SCALARS = new Set(["String", "Int", "Float", "Boolean", "ID"]);
|
|
2098
2071
|
function buildTypeFields(nodes) {
|
|
2099
|
-
const fieldMap =
|
|
2072
|
+
const fieldMap = new Map;
|
|
2100
2073
|
for (const node of nodes) {
|
|
2101
2074
|
for (const [key, val] of Object.entries(node)) {
|
|
2102
|
-
if (INTERNAL_FIELDS.has(key) || isReservedFieldName(key))
|
|
2103
|
-
|
|
2104
|
-
|
|
2075
|
+
if (INTERNAL_FIELDS.has(key) || isReservedFieldName(key))
|
|
2076
|
+
continue;
|
|
2077
|
+
if (fieldMap.has(key))
|
|
2078
|
+
continue;
|
|
2079
|
+
const { type } = inferFieldShape(val, new Set);
|
|
2105
2080
|
fieldMap.set(key, {
|
|
2106
2081
|
name: key,
|
|
2107
2082
|
type,
|
|
@@ -2117,7 +2092,8 @@ function buildTypeSDL(typeName, fields) {
|
|
|
2117
2092
|
...fields.map((f) => ` ${f.name}: ${f.type}`)
|
|
2118
2093
|
];
|
|
2119
2094
|
return `type ${typeName} {
|
|
2120
|
-
${lines.join(
|
|
2095
|
+
${lines.join(`
|
|
2096
|
+
`)}
|
|
2121
2097
|
}`;
|
|
2122
2098
|
}
|
|
2123
2099
|
function queryNames(typeName) {
|
|
@@ -2134,8 +2110,8 @@ function buildSingleArgs(fields) {
|
|
|
2134
2110
|
async function loadAndBuildSchema(store) {
|
|
2135
2111
|
let gql;
|
|
2136
2112
|
try {
|
|
2137
|
-
const { createRequire:
|
|
2138
|
-
const projectRequire =
|
|
2113
|
+
const { createRequire: createRequire3 } = await import("node:module");
|
|
2114
|
+
const projectRequire = createRequire3(process.cwd() + "/package.json");
|
|
2139
2115
|
const graphqlPath = projectRequire.resolve("graphql");
|
|
2140
2116
|
gql = await import(graphqlPath);
|
|
2141
2117
|
} catch {
|
|
@@ -2147,29 +2123,29 @@ async function loadAndBuildSchema(store) {
|
|
|
2147
2123
|
const rawSdl2 = "type Query { _empty: String }";
|
|
2148
2124
|
return { schema: buildSchema(rawSdl2), sdl: rawSdl2, gql };
|
|
2149
2125
|
}
|
|
2150
|
-
const typeFields = new Map(
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
);
|
|
2156
|
-
const typeSDLs = types.map(
|
|
2157
|
-
(typeName) => buildTypeSDL(typeName, typeFields.get(typeName))
|
|
2158
|
-
);
|
|
2126
|
+
const typeFields = new Map(types.map((typeName) => {
|
|
2127
|
+
const nodes = store.getNodesByType(typeName);
|
|
2128
|
+
return [typeName, buildTypeFields(nodes)];
|
|
2129
|
+
}));
|
|
2130
|
+
const typeSDLs = types.map((typeName) => buildTypeSDL(typeName, typeFields.get(typeName)));
|
|
2159
2131
|
const queryFields = types.map((typeName) => {
|
|
2160
2132
|
const { single, all } = queryNames(typeName);
|
|
2161
2133
|
const args = buildSingleArgs(typeFields.get(typeName));
|
|
2162
2134
|
return [
|
|
2163
2135
|
` ${single}(${args}): ${typeName}`,
|
|
2164
2136
|
` ${all}: [${typeName}!]!`
|
|
2165
|
-
].join(
|
|
2137
|
+
].join(`
|
|
2138
|
+
`);
|
|
2166
2139
|
});
|
|
2167
2140
|
const rawSdl = [
|
|
2168
2141
|
...typeSDLs,
|
|
2169
2142
|
`type Query {
|
|
2170
|
-
${queryFields.join(
|
|
2143
|
+
${queryFields.join(`
|
|
2144
|
+
`)}
|
|
2171
2145
|
}`
|
|
2172
|
-
].join(
|
|
2146
|
+
].join(`
|
|
2147
|
+
|
|
2148
|
+
`);
|
|
2173
2149
|
let schema;
|
|
2174
2150
|
try {
|
|
2175
2151
|
schema = buildSchema(rawSdl);
|
|
@@ -2183,7 +2159,8 @@ function toQueryString(query, print) {
|
|
|
2183
2159
|
}
|
|
2184
2160
|
async function buildSchemaExecutor(store) {
|
|
2185
2161
|
const built = await loadAndBuildSchema(store);
|
|
2186
|
-
if (!built)
|
|
2162
|
+
if (!built)
|
|
2163
|
+
return null;
|
|
2187
2164
|
const { schema, gql } = built;
|
|
2188
2165
|
const { graphql, print } = gql;
|
|
2189
2166
|
const types = store.getTypes();
|
|
@@ -2196,9 +2173,7 @@ async function buildSchemaExecutor(store) {
|
|
|
2196
2173
|
rootValue[all] = () => store.getNodesByType(typeName);
|
|
2197
2174
|
rootValue[single] = (args) => {
|
|
2198
2175
|
const nodes = store.getNodesByType(typeName);
|
|
2199
|
-
return nodes.find(
|
|
2200
|
-
(node) => Object.entries(args).every(([k, v]) => v === void 0 || node[k] === v)
|
|
2201
|
-
) ?? null;
|
|
2176
|
+
return nodes.find((node) => Object.entries(args).every(([k, v]) => v === undefined || node[k] === v)) ?? null;
|
|
2202
2177
|
};
|
|
2203
2178
|
}
|
|
2204
2179
|
return (query, variables) => graphql({ schema, rootValue, source: toQueryString(query, print), variableValues: variables });
|
|
@@ -2210,8 +2185,8 @@ async function buildSchemaSDL(store) {
|
|
|
2210
2185
|
async function introspectExecutorSDL(executor) {
|
|
2211
2186
|
let gql;
|
|
2212
2187
|
try {
|
|
2213
|
-
const { createRequire:
|
|
2214
|
-
const projectRequire =
|
|
2188
|
+
const { createRequire: createRequire3 } = await import("node:module");
|
|
2189
|
+
const projectRequire = createRequire3(process.cwd() + "/package.json");
|
|
2215
2190
|
const graphqlPath = projectRequire.resolve("graphql");
|
|
2216
2191
|
gql = await import(graphqlPath);
|
|
2217
2192
|
} catch {
|
|
@@ -2235,7 +2210,7 @@ var GRAPHIQL_HTML = `<!doctype html>
|
|
|
2235
2210
|
<head>
|
|
2236
2211
|
<meta charset="utf-8">
|
|
2237
2212
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
2238
|
-
<title>GraphiQL
|
|
2213
|
+
<title>GraphiQL — hadars</title>
|
|
2239
2214
|
<style>
|
|
2240
2215
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2241
2216
|
body { height: 100vh; overflow: hidden; }
|
|
@@ -2264,9 +2239,10 @@ function createGraphiqlHandler(executor) {
|
|
|
2264
2239
|
try {
|
|
2265
2240
|
url = new URL(req.url);
|
|
2266
2241
|
} catch {
|
|
2267
|
-
return
|
|
2242
|
+
return;
|
|
2268
2243
|
}
|
|
2269
|
-
if (url.pathname !== GRAPHQL_PATH)
|
|
2244
|
+
if (url.pathname !== GRAPHQL_PATH)
|
|
2245
|
+
return;
|
|
2270
2246
|
if (req.method === "GET") {
|
|
2271
2247
|
return new Response(GRAPHIQL_HTML, {
|
|
2272
2248
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
@@ -2283,7 +2259,7 @@ function createGraphiqlHandler(executor) {
|
|
|
2283
2259
|
});
|
|
2284
2260
|
}
|
|
2285
2261
|
if (typeof body.query !== "string" || !body.query.trim()) {
|
|
2286
|
-
return new Response(JSON.stringify({ errors: [{ message: 'Missing or invalid "query" field
|
|
2262
|
+
return new Response(JSON.stringify({ errors: [{ message: 'Missing or invalid "query" field — must be a non-empty string' }] }), {
|
|
2287
2263
|
status: 400,
|
|
2288
2264
|
headers: { "Content-Type": "application/json" }
|
|
2289
2265
|
});
|
|
@@ -2313,23 +2289,22 @@ async function processHtmlTemplate(templatePath) {
|
|
|
2313
2289
|
while ((m = styleRegex.exec(html)) !== null) {
|
|
2314
2290
|
matches.push({ full: m[0], attrs: m[1] ?? "", css: m[2] ?? "" });
|
|
2315
2291
|
}
|
|
2316
|
-
if (matches.length === 0)
|
|
2292
|
+
if (matches.length === 0)
|
|
2293
|
+
return templatePath;
|
|
2317
2294
|
await ensureHadarsTmpDir();
|
|
2318
2295
|
const sourceHash = crypto.createHash("md5").update(html).digest("hex").slice(0, 8);
|
|
2319
2296
|
const cachedPath = pathMod2.join(HADARS_TMP_DIR, `template-${sourceHash}.html`);
|
|
2320
2297
|
try {
|
|
2321
2298
|
await fs.access(cachedPath);
|
|
2322
2299
|
return cachedPath;
|
|
2323
|
-
} catch {
|
|
2324
|
-
}
|
|
2300
|
+
} catch {}
|
|
2325
2301
|
const { default: postcss } = await import("postcss");
|
|
2326
2302
|
let plugins = [];
|
|
2327
2303
|
try {
|
|
2328
|
-
const { default:
|
|
2329
|
-
const config = await
|
|
2304
|
+
const { default: loadConfig } = await import("postcss-load-config");
|
|
2305
|
+
const config = await loadConfig({}, process.cwd());
|
|
2330
2306
|
plugins = config.plugins ?? [];
|
|
2331
|
-
} catch {
|
|
2332
|
-
}
|
|
2307
|
+
} catch {}
|
|
2333
2308
|
let processedHtml = html;
|
|
2334
2309
|
for (const { full, attrs, css } of matches) {
|
|
2335
2310
|
try {
|
|
@@ -2342,12 +2317,11 @@ async function processHtmlTemplate(templatePath) {
|
|
|
2342
2317
|
await fs.writeFile(cachedPath, processedHtml);
|
|
2343
2318
|
return cachedPath;
|
|
2344
2319
|
}
|
|
2345
|
-
|
|
2320
|
+
|
|
2321
|
+
class RenderWorkerPool {
|
|
2346
2322
|
workers = [];
|
|
2347
|
-
pending =
|
|
2348
|
-
|
|
2349
|
-
// them when that worker crashes.
|
|
2350
|
-
workerPending = /* @__PURE__ */ new Map();
|
|
2323
|
+
pending = new Map;
|
|
2324
|
+
workerPending = new Map;
|
|
2351
2325
|
nextId = 0;
|
|
2352
2326
|
rrIndex = 0;
|
|
2353
2327
|
_Worker = null;
|
|
@@ -2361,23 +2335,28 @@ var RenderWorkerPool = class {
|
|
|
2361
2335
|
this._ssrBundlePath = ssrBundlePath;
|
|
2362
2336
|
import("node:worker_threads").then(({ Worker }) => {
|
|
2363
2337
|
this._Worker = Worker;
|
|
2364
|
-
for (let i = 0;
|
|
2338
|
+
for (let i = 0;i < size; i++)
|
|
2339
|
+
this._spawnWorker();
|
|
2365
2340
|
}).catch((err) => {
|
|
2366
2341
|
console.error("[hadars] Failed to initialise render worker pool:", err);
|
|
2367
2342
|
});
|
|
2368
2343
|
}
|
|
2369
2344
|
_spawnWorker() {
|
|
2370
|
-
if (!this._Worker)
|
|
2345
|
+
if (!this._Worker)
|
|
2346
|
+
return;
|
|
2371
2347
|
const w = new this._Worker(this._workerPath, { workerData: { ssrBundlePath: this._ssrBundlePath } });
|
|
2372
|
-
this.workerPending.set(w,
|
|
2348
|
+
this.workerPending.set(w, new Set);
|
|
2373
2349
|
w.on("message", (msg) => {
|
|
2374
2350
|
const { id, html, headHtml, status, error } = msg;
|
|
2375
2351
|
const p = this.pending.get(id);
|
|
2376
|
-
if (!p)
|
|
2352
|
+
if (!p)
|
|
2353
|
+
return;
|
|
2377
2354
|
this.pending.delete(id);
|
|
2378
2355
|
this.workerPending.get(w)?.delete(id);
|
|
2379
|
-
if (error)
|
|
2380
|
-
|
|
2356
|
+
if (error)
|
|
2357
|
+
p.reject(new Error(error));
|
|
2358
|
+
else
|
|
2359
|
+
p.resolve({ html, headHtml, status });
|
|
2381
2360
|
});
|
|
2382
2361
|
w.on("error", (err) => {
|
|
2383
2362
|
console.error("[hadars] Render worker error:", err);
|
|
@@ -2393,7 +2372,8 @@ var RenderWorkerPool = class {
|
|
|
2393
2372
|
}
|
|
2394
2373
|
_handleWorkerDeath(w, err) {
|
|
2395
2374
|
const idx = this.workers.indexOf(w);
|
|
2396
|
-
if (idx !== -1)
|
|
2375
|
+
if (idx !== -1)
|
|
2376
|
+
this.workers.splice(idx, 1);
|
|
2397
2377
|
const ids = this.workerPending.get(w);
|
|
2398
2378
|
if (ids) {
|
|
2399
2379
|
for (const id of ids) {
|
|
@@ -2409,21 +2389,21 @@ var RenderWorkerPool = class {
|
|
|
2409
2389
|
this._spawnWorker();
|
|
2410
2390
|
}
|
|
2411
2391
|
nextWorker() {
|
|
2412
|
-
if (this.workers.length === 0)
|
|
2392
|
+
if (this.workers.length === 0)
|
|
2393
|
+
return;
|
|
2413
2394
|
const w = this.workers[this.rrIndex % this.workers.length];
|
|
2414
2395
|
this.rrIndex++;
|
|
2415
2396
|
return w;
|
|
2416
2397
|
}
|
|
2417
|
-
/** Run the full SSR lifecycle in a worker thread. Returns html, headHtml, status. */
|
|
2418
2398
|
renderFull(req) {
|
|
2419
|
-
return new Promise((
|
|
2399
|
+
return new Promise((resolve, reject) => {
|
|
2420
2400
|
const w = this.nextWorker();
|
|
2421
2401
|
if (!w) {
|
|
2422
2402
|
reject(new Error("[hadars] No render workers available"));
|
|
2423
2403
|
return;
|
|
2424
2404
|
}
|
|
2425
2405
|
const id = this.nextId++;
|
|
2426
|
-
this.pending.set(id, { kind: "renderFull", resolve
|
|
2406
|
+
this.pending.set(id, { kind: "renderFull", resolve, reject });
|
|
2427
2407
|
this.workerPending.get(w)?.add(id);
|
|
2428
2408
|
try {
|
|
2429
2409
|
w.postMessage({ id, type: "renderFull", streaming: false, request: req });
|
|
@@ -2437,10 +2417,15 @@ var RenderWorkerPool = class {
|
|
|
2437
2417
|
async terminate() {
|
|
2438
2418
|
await Promise.all(this.workers.map((w) => w.terminate()));
|
|
2439
2419
|
}
|
|
2440
|
-
}
|
|
2420
|
+
}
|
|
2441
2421
|
async function serializeRequest(req) {
|
|
2442
2422
|
const isGetOrHead = ["GET", "HEAD"].includes(req.method ?? "GET");
|
|
2443
|
-
|
|
2423
|
+
let body = null;
|
|
2424
|
+
if (!isGetOrHead) {
|
|
2425
|
+
try {
|
|
2426
|
+
body = new Uint8Array(await req.arrayBuffer());
|
|
2427
|
+
} catch {}
|
|
2428
|
+
}
|
|
2444
2429
|
const headers = {};
|
|
2445
2430
|
req.headers.forEach((v, k) => {
|
|
2446
2431
|
headers[k] = v;
|
|
@@ -2457,7 +2442,7 @@ async function serializeRequest(req) {
|
|
|
2457
2442
|
};
|
|
2458
2443
|
}
|
|
2459
2444
|
var SSR_FILENAME = "index.ssr.js";
|
|
2460
|
-
var
|
|
2445
|
+
var __dirname3 = process.cwd();
|
|
2461
2446
|
var getSuffix = (mode) => mode === "development" ? `?v=${Date.now()}` : "";
|
|
2462
2447
|
var HadarsFolder = "./.hadars";
|
|
2463
2448
|
var StaticPath = `${HadarsFolder}/static`;
|
|
@@ -2484,18 +2469,18 @@ var resolveWorkerCmd = (packageDir2) => {
|
|
|
2484
2469
|
const allArgs = [...process.execArgv, process.argv[1] ?? ""];
|
|
2485
2470
|
const hasTsx = allArgs.some((a) => a.includes("tsx"));
|
|
2486
2471
|
const hasTsNode = allArgs.some((a) => a.includes("ts-node"));
|
|
2487
|
-
if (hasTsx)
|
|
2488
|
-
|
|
2472
|
+
if (hasTsx)
|
|
2473
|
+
return ["tsx", tsPath];
|
|
2474
|
+
if (hasTsNode)
|
|
2475
|
+
return ["ts-node", tsPath];
|
|
2489
2476
|
}
|
|
2490
2477
|
if (existsSync2(jsPath)) {
|
|
2491
2478
|
return ["node", jsPath];
|
|
2492
2479
|
}
|
|
2493
|
-
throw new Error(
|
|
2494
|
-
`[hadars] SSR worker not found. Expected:
|
|
2480
|
+
throw new Error(`[hadars] SSR worker not found. Expected:
|
|
2495
2481
|
${jsPath}
|
|
2496
2482
|
Run "npm run build:cli" to compile it, or launch hadars via a TypeScript runner:
|
|
2497
|
-
npx tsx cli.ts dev`
|
|
2498
|
-
);
|
|
2483
|
+
npx tsx cli.ts dev`);
|
|
2499
2484
|
};
|
|
2500
2485
|
var dev = async (options) => {
|
|
2501
2486
|
await fs.rm(HadarsFolder, { recursive: true, force: true });
|
|
@@ -2508,7 +2493,7 @@ var dev = async (options) => {
|
|
|
2508
2493
|
let handleGraphiql = null;
|
|
2509
2494
|
let devStaticCtx;
|
|
2510
2495
|
if (options.sources && options.sources.length > 0) {
|
|
2511
|
-
console.log(`[hadars] Running ${options.sources.length} source plugin(s)
|
|
2496
|
+
console.log(`[hadars] Running ${options.sources.length} source plugin(s)…`);
|
|
2512
2497
|
try {
|
|
2513
2498
|
const store = await runSources(options.sources);
|
|
2514
2499
|
const executor = await buildSchemaExecutor(store);
|
|
@@ -2517,13 +2502,13 @@ var dev = async (options) => {
|
|
|
2517
2502
|
handleGraphiql = createGraphiqlHandler(executor);
|
|
2518
2503
|
console.log(`[hadars] GraphiQL available at http://localhost:${port}${GRAPHQL_PATH}`);
|
|
2519
2504
|
} else {
|
|
2520
|
-
console.warn("[hadars] `graphql` package not found
|
|
2505
|
+
console.warn("[hadars] `graphql` package not found — GraphiQL disabled. Run: npm install graphql");
|
|
2521
2506
|
}
|
|
2522
2507
|
} catch (err) {
|
|
2523
2508
|
console.error("[hadars] Source plugin error:", err);
|
|
2524
2509
|
}
|
|
2525
2510
|
}
|
|
2526
|
-
const entry = pathMod2.resolve(
|
|
2511
|
+
const entry = pathMod2.resolve(__dirname3, options.entry);
|
|
2527
2512
|
const hmrPort = options.hmrPort ?? port + 1;
|
|
2528
2513
|
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
2529
2514
|
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.tsx");
|
|
@@ -2538,12 +2523,12 @@ var dev = async (options) => {
|
|
|
2538
2523
|
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
2539
2524
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
2540
2525
|
let ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
2541
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(
|
|
2526
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname3, options.htmlTemplate)) : undefined;
|
|
2542
2527
|
const clientCompiler = createClientCompiler(tmpFilePath, {
|
|
2543
2528
|
target: "web",
|
|
2544
2529
|
output: {
|
|
2545
2530
|
filename: "index.js",
|
|
2546
|
-
path: pathMod2.resolve(
|
|
2531
|
+
path: pathMod2.resolve(__dirname3, StaticPath)
|
|
2547
2532
|
},
|
|
2548
2533
|
base: baseURL,
|
|
2549
2534
|
mode: "development",
|
|
@@ -2570,12 +2555,12 @@ var dev = async (options) => {
|
|
|
2570
2555
|
}, clientCompiler);
|
|
2571
2556
|
console.log(`Starting HMR dev server on port ${hmrPort}`);
|
|
2572
2557
|
let clientResolved = false;
|
|
2573
|
-
const clientBuildDone = new Promise((
|
|
2558
|
+
const clientBuildDone = new Promise((resolve, reject) => {
|
|
2574
2559
|
clientCompiler.hooks.done.tap("initial-build", (stats) => {
|
|
2575
2560
|
if (!clientResolved) {
|
|
2576
2561
|
clientResolved = true;
|
|
2577
2562
|
console.log(stats.toString({ colors: true }));
|
|
2578
|
-
|
|
2563
|
+
resolve();
|
|
2579
2564
|
}
|
|
2580
2565
|
});
|
|
2581
2566
|
devServer.start().catch(reject);
|
|
@@ -2595,9 +2580,9 @@ var dev = async (options) => {
|
|
|
2595
2580
|
child.stdin?.end();
|
|
2596
2581
|
const cleanupChild = () => {
|
|
2597
2582
|
try {
|
|
2598
|
-
if (!child.killed)
|
|
2599
|
-
|
|
2600
|
-
}
|
|
2583
|
+
if (!child.killed)
|
|
2584
|
+
child.kill();
|
|
2585
|
+
} catch {}
|
|
2601
2586
|
};
|
|
2602
2587
|
process.once("exit", cleanupChild);
|
|
2603
2588
|
process.once("SIGINT", () => {
|
|
@@ -2612,7 +2597,7 @@ var dev = async (options) => {
|
|
|
2612
2597
|
const stderrWebStream = nodeReadableToWebStream(child.stderr);
|
|
2613
2598
|
const marker = "ssr-watch: initial-build-complete";
|
|
2614
2599
|
const rebuildMarker = "ssr-watch: SSR rebuilt";
|
|
2615
|
-
const decoder = new TextDecoder
|
|
2600
|
+
const decoder = new TextDecoder;
|
|
2616
2601
|
let stdoutReader = null;
|
|
2617
2602
|
const ssrBuildDone = (async () => {
|
|
2618
2603
|
let gotMarker = false;
|
|
@@ -2620,7 +2605,7 @@ var dev = async (options) => {
|
|
|
2620
2605
|
stdoutReader = stdoutWebStream.getReader();
|
|
2621
2606
|
let buf = "";
|
|
2622
2607
|
const start = Date.now();
|
|
2623
|
-
const timeoutMs =
|
|
2608
|
+
const timeoutMs = 20000;
|
|
2624
2609
|
while (Date.now() - start < timeoutMs) {
|
|
2625
2610
|
const { done, value } = await stdoutReader.read();
|
|
2626
2611
|
if (done) {
|
|
@@ -2631,8 +2616,7 @@ var dev = async (options) => {
|
|
|
2631
2616
|
buf += chunk;
|
|
2632
2617
|
try {
|
|
2633
2618
|
process.stdout.write(chunk);
|
|
2634
|
-
} catch (e) {
|
|
2635
|
-
}
|
|
2619
|
+
} catch (e) {}
|
|
2636
2620
|
if (buf.includes(marker)) {
|
|
2637
2621
|
gotMarker = true;
|
|
2638
2622
|
break;
|
|
@@ -2654,19 +2638,18 @@ var dev = async (options) => {
|
|
|
2654
2638
|
try {
|
|
2655
2639
|
while (true) {
|
|
2656
2640
|
const { done, value } = await reader.read();
|
|
2657
|
-
if (done)
|
|
2641
|
+
if (done)
|
|
2642
|
+
break;
|
|
2658
2643
|
const chunk = decoder.decode(value, { stream: true });
|
|
2659
2644
|
try {
|
|
2660
2645
|
process.stdout.write(chunk);
|
|
2661
|
-
} catch (e) {
|
|
2662
|
-
}
|
|
2646
|
+
} catch (e) {}
|
|
2663
2647
|
if (chunk.includes(rebuildMarker)) {
|
|
2664
2648
|
ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
2665
2649
|
console.log("[hadars] SSR bundle updated, build id:", ssrBuildId);
|
|
2666
2650
|
}
|
|
2667
2651
|
}
|
|
2668
|
-
} catch (e) {
|
|
2669
|
-
}
|
|
2652
|
+
} catch (e) {}
|
|
2670
2653
|
})();
|
|
2671
2654
|
}
|
|
2672
2655
|
});
|
|
@@ -2675,40 +2658,43 @@ var dev = async (options) => {
|
|
|
2675
2658
|
const r = stderrWebStream.getReader();
|
|
2676
2659
|
while (true) {
|
|
2677
2660
|
const { done, value } = await r.read();
|
|
2678
|
-
if (done)
|
|
2661
|
+
if (done)
|
|
2662
|
+
break;
|
|
2679
2663
|
try {
|
|
2680
2664
|
process.stderr.write(decoder.decode(value));
|
|
2681
|
-
} catch (e) {
|
|
2682
|
-
}
|
|
2665
|
+
} catch (e) {}
|
|
2683
2666
|
}
|
|
2684
|
-
} catch (e) {
|
|
2685
|
-
}
|
|
2667
|
+
} catch (e) {}
|
|
2686
2668
|
})();
|
|
2687
|
-
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
2688
|
-
readyPromise.then(() => fs.readFile(pathMod2.join(__dirname2, StaticPath, "out.html"), "utf-8"))
|
|
2689
|
-
);
|
|
2669
|
+
const getPrecontentHtml = makePrecontentHtmlGetter(readyPromise.then(() => fs.readFile(pathMod2.join(__dirname3, StaticPath, "out.html"), "utf-8")));
|
|
2690
2670
|
await serve(port, async (req, ctx) => {
|
|
2691
2671
|
await readyPromise;
|
|
2692
2672
|
const request = parseRequest(req);
|
|
2693
2673
|
if (handler) {
|
|
2694
2674
|
const res = await handler(request);
|
|
2695
|
-
if (res)
|
|
2675
|
+
if (res)
|
|
2676
|
+
return res;
|
|
2696
2677
|
}
|
|
2697
|
-
if (handleWS && handleWS(request, ctx))
|
|
2678
|
+
if (handleWS && handleWS(request, ctx))
|
|
2679
|
+
return;
|
|
2698
2680
|
if (handleGraphiql) {
|
|
2699
2681
|
const graphiqlRes = await handleGraphiql(req);
|
|
2700
|
-
if (graphiqlRes)
|
|
2682
|
+
if (graphiqlRes)
|
|
2683
|
+
return graphiqlRes;
|
|
2701
2684
|
}
|
|
2702
2685
|
const proxied = await handleProxy(request);
|
|
2703
|
-
if (proxied)
|
|
2686
|
+
if (proxied)
|
|
2687
|
+
return proxied;
|
|
2704
2688
|
const url = new URL(request.url);
|
|
2705
2689
|
const path2 = url.pathname;
|
|
2706
|
-
const staticRes = await tryServeFile(pathMod2.join(
|
|
2707
|
-
if (staticRes)
|
|
2690
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, path2));
|
|
2691
|
+
if (staticRes)
|
|
2692
|
+
return staticRes;
|
|
2708
2693
|
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
2709
2694
|
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
2710
|
-
if (projectRes)
|
|
2711
|
-
|
|
2695
|
+
if (projectRes)
|
|
2696
|
+
return projectRes;
|
|
2697
|
+
const ssrComponentPath = pathMod2.join(__dirname3, HadarsFolder, SSR_FILENAME);
|
|
2712
2698
|
const importPath = pathToFileURL(ssrComponentPath).href + `?t=${ssrBuildId}`;
|
|
2713
2699
|
try {
|
|
2714
2700
|
const {
|
|
@@ -2737,8 +2723,7 @@ var dev = async (options) => {
|
|
|
2737
2723
|
return buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml);
|
|
2738
2724
|
} catch (err) {
|
|
2739
2725
|
console.error("[hadars] SSR render error:", err);
|
|
2740
|
-
options.onError?.(err, request)?.catch?.(() => {
|
|
2741
|
-
});
|
|
2726
|
+
options.onError?.(err, request)?.catch?.(() => {});
|
|
2742
2727
|
const msg = (err?.stack ?? err?.message ?? String(err)).replace(/</g, "<");
|
|
2743
2728
|
return new Response(`<!doctype html><pre style="white-space:pre-wrap">${msg}</pre>`, {
|
|
2744
2729
|
status: 500,
|
|
@@ -2749,7 +2734,7 @@ var dev = async (options) => {
|
|
|
2749
2734
|
};
|
|
2750
2735
|
var build = async (options) => {
|
|
2751
2736
|
validateOptions(options);
|
|
2752
|
-
const entry = pathMod2.resolve(
|
|
2737
|
+
const entry = pathMod2.resolve(__dirname3, options.entry);
|
|
2753
2738
|
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
2754
2739
|
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.js");
|
|
2755
2740
|
let clientScript = "";
|
|
@@ -2762,15 +2747,14 @@ var build = async (options) => {
|
|
|
2762
2747
|
await ensureHadarsTmpDir();
|
|
2763
2748
|
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
2764
2749
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
2765
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(
|
|
2750
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname3, options.htmlTemplate)) : undefined;
|
|
2766
2751
|
console.log("Building client and server bundles in parallel...");
|
|
2767
2752
|
await Promise.all([
|
|
2768
2753
|
compileEntry(tmpFilePath, {
|
|
2769
2754
|
target: "web",
|
|
2770
2755
|
output: {
|
|
2771
|
-
// Content hash: filename is stable when code is unchanged → better browser/CDN cache.
|
|
2772
2756
|
filename: "index.[contenthash:8].js",
|
|
2773
|
-
path: pathMod2.resolve(
|
|
2757
|
+
path: pathMod2.resolve(__dirname3, StaticPath)
|
|
2774
2758
|
},
|
|
2775
2759
|
base: options.baseURL,
|
|
2776
2760
|
mode: "production",
|
|
@@ -2783,11 +2767,11 @@ var build = async (options) => {
|
|
|
2783
2767
|
reactMode: options.reactMode,
|
|
2784
2768
|
htmlTemplate: resolvedHtmlTemplate
|
|
2785
2769
|
}),
|
|
2786
|
-
compileEntry(pathMod2.resolve(
|
|
2770
|
+
compileEntry(pathMod2.resolve(__dirname3, options.entry), {
|
|
2787
2771
|
output: {
|
|
2788
2772
|
iife: false,
|
|
2789
2773
|
filename: SSR_FILENAME,
|
|
2790
|
-
path: pathMod2.resolve(
|
|
2774
|
+
path: pathMod2.resolve(__dirname3, HadarsFolder),
|
|
2791
2775
|
publicPath: "",
|
|
2792
2776
|
library: { type: "module" }
|
|
2793
2777
|
},
|
|
@@ -2809,15 +2793,14 @@ var run = async (options) => {
|
|
|
2809
2793
|
let { port = 9090, workers = 1 } = options;
|
|
2810
2794
|
if (isNode && workers > 1 && cluster.isPrimary) {
|
|
2811
2795
|
console.log(`[hadars] Starting ${workers} worker processes on port ${port}`);
|
|
2812
|
-
for (let i = 0;
|
|
2796
|
+
for (let i = 0;i < workers; i++) {
|
|
2813
2797
|
cluster.fork();
|
|
2814
2798
|
}
|
|
2815
2799
|
cluster.on("exit", (worker, code, signal) => {
|
|
2816
2800
|
console.warn(`[hadars] Worker ${worker.process.pid} exited (${signal ?? code}), restarting...`);
|
|
2817
2801
|
cluster.fork();
|
|
2818
2802
|
});
|
|
2819
|
-
await new Promise(() => {
|
|
2820
|
-
});
|
|
2803
|
+
await new Promise(() => {});
|
|
2821
2804
|
return;
|
|
2822
2805
|
}
|
|
2823
2806
|
const handleProxy = createProxyHandler(options);
|
|
@@ -2830,39 +2813,39 @@ var run = async (options) => {
|
|
|
2830
2813
|
const workerJs = pathMod2.resolve(packageDir2, "ssr-render-worker.js");
|
|
2831
2814
|
const workerTs = pathMod2.resolve(packageDir2, "ssr-render-worker.ts");
|
|
2832
2815
|
const workerFile = existsSync2(workerJs) ? workerJs : workerTs;
|
|
2833
|
-
const ssrBundlePath = pathMod2.resolve(
|
|
2816
|
+
const ssrBundlePath = pathMod2.resolve(__dirname3, HadarsFolder, SSR_FILENAME);
|
|
2834
2817
|
renderPool = new RenderWorkerPool(workerFile, workers, ssrBundlePath);
|
|
2835
2818
|
console.log(`[hadars] SSR render pool: ${workers} worker threads`);
|
|
2836
2819
|
}
|
|
2837
|
-
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
2838
|
-
|
|
2839
|
-
);
|
|
2840
|
-
const componentPath = pathToFileURL(
|
|
2841
|
-
pathMod2.resolve(__dirname2, HadarsFolder, SSR_FILENAME)
|
|
2842
|
-
).href;
|
|
2820
|
+
const getPrecontentHtml = makePrecontentHtmlGetter(fs.readFile(pathMod2.join(__dirname3, StaticPath, "out.html"), "utf-8"));
|
|
2821
|
+
const componentPath = pathToFileURL(pathMod2.resolve(__dirname3, HadarsFolder, SSR_FILENAME)).href;
|
|
2843
2822
|
const ssrModulePromise = import(componentPath);
|
|
2844
2823
|
const runHandler = async (req, ctx) => {
|
|
2845
2824
|
const request = parseRequest(req);
|
|
2846
2825
|
if (handler) {
|
|
2847
2826
|
const res = await handler(request);
|
|
2848
|
-
if (res)
|
|
2827
|
+
if (res)
|
|
2828
|
+
return res;
|
|
2849
2829
|
}
|
|
2850
|
-
if (handleWS && handleWS(request, ctx))
|
|
2830
|
+
if (handleWS && handleWS(request, ctx))
|
|
2831
|
+
return;
|
|
2851
2832
|
const proxied = await handleProxy(request);
|
|
2852
|
-
if (proxied)
|
|
2833
|
+
if (proxied)
|
|
2834
|
+
return proxied;
|
|
2853
2835
|
const url = new URL(request.url);
|
|
2854
2836
|
const path2 = url.pathname;
|
|
2855
|
-
const staticRes = await tryServeFile(pathMod2.join(
|
|
2856
|
-
if (staticRes)
|
|
2837
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, path2));
|
|
2838
|
+
if (staticRes)
|
|
2839
|
+
return staticRes;
|
|
2857
2840
|
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
2858
2841
|
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
2859
|
-
if (projectRes)
|
|
2842
|
+
if (projectRes)
|
|
2843
|
+
return projectRes;
|
|
2860
2844
|
const routeClean = path2.replace(/(^\/|\/$)/g, "");
|
|
2861
2845
|
if (routeClean) {
|
|
2862
|
-
const routeRes = await tryServeFile(
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
if (routeRes) return routeRes;
|
|
2846
|
+
const routeRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, routeClean, "index.html"));
|
|
2847
|
+
if (routeRes)
|
|
2848
|
+
return routeRes;
|
|
2866
2849
|
}
|
|
2867
2850
|
try {
|
|
2868
2851
|
const {
|
|
@@ -2898,16 +2881,11 @@ var run = async (options) => {
|
|
|
2898
2881
|
return buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml);
|
|
2899
2882
|
} catch (err) {
|
|
2900
2883
|
console.error("[hadars] SSR render error:", err);
|
|
2901
|
-
options.onError?.(err, request)?.catch?.(() => {
|
|
2902
|
-
});
|
|
2884
|
+
options.onError?.(err, request)?.catch?.(() => {});
|
|
2903
2885
|
return new Response("Internal Server Error", { status: 500 });
|
|
2904
2886
|
}
|
|
2905
2887
|
};
|
|
2906
|
-
await serve(
|
|
2907
|
-
port,
|
|
2908
|
-
options.cache ? createRenderCache(options.cache, runHandler) : runHandler,
|
|
2909
|
-
options.websocket
|
|
2910
|
-
);
|
|
2888
|
+
await serve(port, options.cache ? createRenderCache(options.cache, runHandler) : runHandler, options.websocket);
|
|
2911
2889
|
};
|
|
2912
2890
|
|
|
2913
2891
|
// src/static.ts
|
|
@@ -2916,9 +2894,7 @@ import { join, basename } from "node:path";
|
|
|
2916
2894
|
async function renderStaticSite(opts) {
|
|
2917
2895
|
const { ssrModule, htmlSource, staticSrc, paths, outputDir } = opts;
|
|
2918
2896
|
const staticCtx = {
|
|
2919
|
-
graphql: opts.graphql ?? (() => Promise.reject(
|
|
2920
|
-
new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")
|
|
2921
|
-
))
|
|
2897
|
+
graphql: opts.graphql ?? (() => Promise.reject(new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")))
|
|
2922
2898
|
};
|
|
2923
2899
|
const getPrecontentHtml = makePrecontentHtmlGetter(Promise.resolve(htmlSource));
|
|
2924
2900
|
await mkdir(outputDir, { recursive: true });
|
|
@@ -2946,11 +2922,7 @@ async function renderStaticSite(opts) {
|
|
|
2946
2922
|
await mkdir(pageDir, { recursive: true });
|
|
2947
2923
|
await writeFile(join(pageDir, "index.html"), html, "utf-8");
|
|
2948
2924
|
const serverData = staticClientProps.__serverData ?? {};
|
|
2949
|
-
await writeFile(
|
|
2950
|
-
join(pageDir, "index.json"),
|
|
2951
|
-
JSON.stringify({ serverData }),
|
|
2952
|
-
"utf-8"
|
|
2953
|
-
);
|
|
2925
|
+
await writeFile(join(pageDir, "index.json"), JSON.stringify({ serverData }), "utf-8");
|
|
2954
2926
|
rendered.push(urlPath);
|
|
2955
2927
|
} catch (err) {
|
|
2956
2928
|
errors.push({
|
|
@@ -2973,7 +2945,8 @@ var SUPPORTED = ["hadars.config.js", "hadars.config.mjs", "hadars.config.cjs", "
|
|
|
2973
2945
|
function findConfig(cwd) {
|
|
2974
2946
|
for (const name of SUPPORTED) {
|
|
2975
2947
|
const p = resolve(cwd, name);
|
|
2976
|
-
if (existsSync3(p))
|
|
2948
|
+
if (existsSync3(p))
|
|
2949
|
+
return p;
|
|
2977
2950
|
}
|
|
2978
2951
|
return null;
|
|
2979
2952
|
}
|
|
@@ -3009,38 +2982,38 @@ async function exportSchema(config, outputFile) {
|
|
|
3009
2982
|
console.log(`Schema inferred for types: ${store.getTypes().join(", ") || "(none)"}`);
|
|
3010
2983
|
sdl = await buildSchemaSDL(store);
|
|
3011
2984
|
if (!sdl) {
|
|
3012
|
-
console.error(
|
|
3013
|
-
|
|
3014
|
-
|
|
2985
|
+
console.error(`Error: \`graphql\` package not found.
|
|
2986
|
+
Source plugins require graphql-js to be installed:
|
|
2987
|
+
|
|
2988
|
+
npm install graphql
|
|
2989
|
+
`);
|
|
3015
2990
|
process.exit(1);
|
|
3016
2991
|
}
|
|
3017
2992
|
} else if (config.graphql) {
|
|
3018
2993
|
console.log("Introspecting custom GraphQL executor...");
|
|
3019
2994
|
sdl = await introspectExecutorSDL(config.graphql);
|
|
3020
2995
|
if (!sdl) {
|
|
3021
|
-
console.error(
|
|
3022
|
-
|
|
3023
|
-
|
|
2996
|
+
console.error(`Error: \`graphql\` package not found.
|
|
2997
|
+
Schema export requires graphql-js to be installed:
|
|
2998
|
+
|
|
2999
|
+
npm install graphql
|
|
3000
|
+
`);
|
|
3024
3001
|
process.exit(1);
|
|
3025
3002
|
}
|
|
3026
3003
|
} else {
|
|
3027
|
-
console.error(
|
|
3028
|
-
"Error: no GraphQL source configured.\nAdd `sources` or a `graphql` executor to your hadars.config.ts first.\n"
|
|
3029
|
-
);
|
|
3004
|
+
console.error("Error: no GraphQL source configured.\nAdd `sources` or a `graphql` executor to your hadars.config.ts first.\n");
|
|
3030
3005
|
process.exit(1);
|
|
3031
3006
|
}
|
|
3032
3007
|
await writeFile2(outputFile, sdl, "utf-8");
|
|
3033
3008
|
console.log(`Schema written to ${outputFile}`);
|
|
3034
3009
|
console.log(`
|
|
3035
|
-
Next steps
|
|
3010
|
+
Next steps — generate TypeScript types with graphql-codegen:`);
|
|
3036
3011
|
console.log(` npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations`);
|
|
3037
3012
|
console.log(` npx graphql-codegen --schema ${outputFile} --documents "src/**/*.tsx" --out src/gql/`);
|
|
3038
3013
|
}
|
|
3039
3014
|
async function exportStatic(config, outputDir, cwd) {
|
|
3040
3015
|
if (!config.paths) {
|
|
3041
|
-
console.error(
|
|
3042
|
-
"Error: `paths` is not defined in your hadars config.\nAdd a `paths` function that returns the list of URLs to pre-render:\n\n paths: () => ['/', '/about', '/contact']\n"
|
|
3043
|
-
);
|
|
3016
|
+
console.error("Error: `paths` is not defined in your hadars config.\nAdd a `paths` function that returns the list of URLs to pre-render:\n\n paths: () => ['/', '/about', '/contact']\n");
|
|
3044
3017
|
process.exit(1);
|
|
3045
3018
|
}
|
|
3046
3019
|
console.log("Building hadars project...");
|
|
@@ -3066,9 +3039,11 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3066
3039
|
if (!graphql) {
|
|
3067
3040
|
const inferred = await buildSchemaExecutor(store);
|
|
3068
3041
|
if (!inferred) {
|
|
3069
|
-
console.error(
|
|
3070
|
-
|
|
3071
|
-
|
|
3042
|
+
console.error(`Error: \`graphql\` package not found.
|
|
3043
|
+
Source plugins require graphql-js to be installed:
|
|
3044
|
+
|
|
3045
|
+
npm install graphql
|
|
3046
|
+
`);
|
|
3072
3047
|
process.exit(1);
|
|
3073
3048
|
}
|
|
3074
3049
|
graphql = inferred;
|
|
@@ -3076,9 +3051,7 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3076
3051
|
}
|
|
3077
3052
|
}
|
|
3078
3053
|
const staticCtx = {
|
|
3079
|
-
graphql: graphql ?? (() => Promise.reject(
|
|
3080
|
-
new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")
|
|
3081
|
-
))
|
|
3054
|
+
graphql: graphql ?? (() => Promise.reject(new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")))
|
|
3082
3055
|
};
|
|
3083
3056
|
const paths = await config.paths(staticCtx);
|
|
3084
3057
|
console.log(`Pre-rendering ${paths.length} page(s)...`);
|
|
@@ -3090,11 +3063,14 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3090
3063
|
outputDir: outDir,
|
|
3091
3064
|
graphql
|
|
3092
3065
|
});
|
|
3093
|
-
for (const p of rendered)
|
|
3094
|
-
|
|
3066
|
+
for (const p of rendered)
|
|
3067
|
+
console.log(` [200] ${p}`);
|
|
3068
|
+
for (const { path: path2, error } of errors)
|
|
3069
|
+
console.error(` [ERR] ${path2}: ${error.message}`);
|
|
3095
3070
|
console.log(`
|
|
3096
3071
|
Exported to ${outputDir}/`);
|
|
3097
|
-
if (errors.length > 0)
|
|
3072
|
+
if (errors.length > 0)
|
|
3073
|
+
console.log(` ${errors.length} page(s) failed`);
|
|
3098
3074
|
console.log(`
|
|
3099
3075
|
Serve locally:`);
|
|
3100
3076
|
console.log(` npx serve ${outputDir}`);
|
|
@@ -3120,27 +3096,24 @@ async function bundleCloudflare(config, configPath, outputFile, cwd) {
|
|
|
3120
3096
|
`import { createCloudflareHandler } from ${JSON.stringify(cloudflareModule)};`,
|
|
3121
3097
|
`import config from ${JSON.stringify(configPath)};`,
|
|
3122
3098
|
`export default createCloudflareHandler(config as any, { ssrModule: ssrModule as any, outHtml });`
|
|
3123
|
-
].join(
|
|
3099
|
+
].join(`
|
|
3100
|
+
`) + `
|
|
3101
|
+
`;
|
|
3124
3102
|
await writeFile2(shimPath, shim, "utf-8");
|
|
3125
3103
|
try {
|
|
3126
3104
|
const { build: esbuild } = await import("esbuild");
|
|
3127
|
-
console.log(`Bundling Cloudflare Worker
|
|
3105
|
+
console.log(`Bundling Cloudflare Worker → ${outputFile}`);
|
|
3128
3106
|
await esbuild({
|
|
3129
3107
|
entryPoints: [shimPath],
|
|
3130
3108
|
bundle: true,
|
|
3131
|
-
// 'browser' avoids Node.js built-in shims; CF Workers uses Web APIs.
|
|
3132
|
-
// If you use node:* APIs in your app code, add nodejs_compat to wrangler.toml.
|
|
3133
3109
|
platform: "browser",
|
|
3134
3110
|
format: "esm",
|
|
3135
3111
|
target: ["es2022"],
|
|
3136
3112
|
outfile: outputFile,
|
|
3137
3113
|
sourcemap: false,
|
|
3138
3114
|
loader: { ".html": "text", ".tsx": "tsx", ".ts": "ts" },
|
|
3139
|
-
// @rspack/* is build-time only — never imported at Worker runtime.
|
|
3140
3115
|
external: ["@rspack/*"],
|
|
3141
|
-
|
|
3142
|
-
// esbuild's attempt to polyfill node:crypto.
|
|
3143
|
-
define: { "global": "globalThis" }
|
|
3116
|
+
define: { global: "globalThis" }
|
|
3144
3117
|
});
|
|
3145
3118
|
console.log(`Cloudflare Worker bundle written to ${outputFile}`);
|
|
3146
3119
|
console.log(`
|
|
@@ -3156,8 +3129,7 @@ Deploy instructions:`);
|
|
|
3156
3129
|
console.log(` and all other requests to the Worker.`);
|
|
3157
3130
|
console.log(` 4. Deploy: wrangler deploy`);
|
|
3158
3131
|
} finally {
|
|
3159
|
-
await unlink(shimPath).catch(() => {
|
|
3160
|
-
});
|
|
3132
|
+
await unlink(shimPath).catch(() => {});
|
|
3161
3133
|
}
|
|
3162
3134
|
}
|
|
3163
3135
|
async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
@@ -3181,11 +3153,13 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
3181
3153
|
`import { createLambdaHandler } from ${JSON.stringify(lambdaModule)};`,
|
|
3182
3154
|
`import config from ${JSON.stringify(configPath)};`,
|
|
3183
3155
|
`export const handler = createLambdaHandler(config as any, { ssrModule: ssrModule as any, outHtml });`
|
|
3184
|
-
].join(
|
|
3156
|
+
].join(`
|
|
3157
|
+
`) + `
|
|
3158
|
+
`;
|
|
3185
3159
|
await writeFile2(shimPath, shim, "utf-8");
|
|
3186
3160
|
try {
|
|
3187
3161
|
const { build: esbuild } = await import("esbuild");
|
|
3188
|
-
console.log(`Bundling Lambda handler
|
|
3162
|
+
console.log(`Bundling Lambda handler → ${outputFile}`);
|
|
3189
3163
|
await esbuild({
|
|
3190
3164
|
entryPoints: [shimPath],
|
|
3191
3165
|
bundle: true,
|
|
@@ -3195,10 +3169,6 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
3195
3169
|
outfile: outputFile,
|
|
3196
3170
|
sourcemap: false,
|
|
3197
3171
|
loader: { ".html": "text", ".tsx": "tsx", ".ts": "ts" },
|
|
3198
|
-
// @rspack/* contains native binaries and is build-time only —
|
|
3199
|
-
// it is never imported at Lambda runtime, so mark it external.
|
|
3200
|
-
// Everything else (React, hadars runtime, etc.) is bundled in to
|
|
3201
|
-
// produce a truly self-contained single-file deployment.
|
|
3202
3172
|
external: ["@rspack/*"]
|
|
3203
3173
|
});
|
|
3204
3174
|
console.log(`Lambda bundle written to ${outputFile}`);
|
|
@@ -3209,10 +3179,9 @@ Deploy instructions:`);
|
|
|
3209
3179
|
console.log(` 2. Upload lambda-deploy/ as your Lambda function code`);
|
|
3210
3180
|
console.log(` 3. Set handler to: lambda.handler (runtime: Node.js 20.x)`);
|
|
3211
3181
|
console.log(` 4. Upload .hadars/static/ assets to S3 and serve via CloudFront`);
|
|
3212
|
-
console.log(` (the Lambda handler does not serve static JS/CSS
|
|
3182
|
+
console.log(` (the Lambda handler does not serve static JS/CSS — route those to S3)`);
|
|
3213
3183
|
} finally {
|
|
3214
|
-
await unlink(shimPath).catch(() => {
|
|
3215
|
-
});
|
|
3184
|
+
await unlink(shimPath).catch(() => {});
|
|
3216
3185
|
}
|
|
3217
3186
|
}
|
|
3218
3187
|
var TEMPLATES = {
|
|
@@ -3227,11 +3196,12 @@ var TEMPLATES = {
|
|
|
3227
3196
|
start: "hadars run"
|
|
3228
3197
|
},
|
|
3229
3198
|
dependencies: {
|
|
3230
|
-
|
|
3199
|
+
hadars: "latest",
|
|
3231
3200
|
react: "^19.0.0",
|
|
3232
3201
|
"react-dom": "^19.0.0"
|
|
3233
3202
|
}
|
|
3234
|
-
}, null, 2) +
|
|
3203
|
+
}, null, 2) + `
|
|
3204
|
+
`,
|
|
3235
3205
|
"hadars.config.ts": () => `import type { HadarsOptions } from 'hadars';
|
|
3236
3206
|
|
|
3237
3207
|
const config: HadarsOptions = {
|
|
@@ -3255,7 +3225,8 @@ export default config;
|
|
|
3255
3225
|
strict: true,
|
|
3256
3226
|
skipLibCheck: true
|
|
3257
3227
|
}
|
|
3258
|
-
}, null, 2) +
|
|
3228
|
+
}, null, 2) + `
|
|
3229
|
+
`,
|
|
3259
3230
|
".gitignore": () => `node_modules/
|
|
3260
3231
|
.hadars/
|
|
3261
3232
|
dist/
|
|
@@ -3400,29 +3371,29 @@ const App: HadarsApp<{}> = () => {
|
|
|
3400
3371
|
</p>
|
|
3401
3372
|
<div className="hero-actions">
|
|
3402
3373
|
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>
|
|
3403
|
-
Try the counter
|
|
3374
|
+
Try the counter ↓
|
|
3404
3375
|
</button>
|
|
3405
3376
|
</div>
|
|
3406
3377
|
</section>
|
|
3407
3378
|
|
|
3408
3379
|
<div className="features">
|
|
3409
3380
|
<div className="card">
|
|
3410
|
-
<div className="card-icon"
|
|
3381
|
+
<div className="card-icon">⚡</div>
|
|
3411
3382
|
<h3>Server-side rendering</h3>
|
|
3412
|
-
<p>Pages render on the server and hydrate on the client
|
|
3383
|
+
<p>Pages render on the server and hydrate on the client — great for SEO and first paint.</p>
|
|
3413
3384
|
</div>
|
|
3414
3385
|
<div className="card">
|
|
3415
|
-
<div className="card-icon">\
|
|
3386
|
+
<div className="card-icon">\uD83D\uDD25</div>
|
|
3416
3387
|
<h3>Hot module reload</h3>
|
|
3417
3388
|
<p>Changes in <code>src/App.tsx</code> reflect instantly in the browser during development.</p>
|
|
3418
3389
|
</div>
|
|
3419
3390
|
<div className="card">
|
|
3420
|
-
<div className="card-icon">\
|
|
3391
|
+
<div className="card-icon">\uD83D\uDCE6</div>
|
|
3421
3392
|
<h3>Zero config</h3>
|
|
3422
3393
|
<p>One config file. Export a React component, run <code>hadars dev</code>, done.</p>
|
|
3423
3394
|
</div>
|
|
3424
3395
|
<div className="card">
|
|
3425
|
-
<div className="card-icon">\
|
|
3396
|
+
<div className="card-icon">\uD83D\uDDC4️</div>
|
|
3426
3397
|
<h3>Server data hooks</h3>
|
|
3427
3398
|
<p>Use <code>useServerData</code> to fetch data on the server without extra round-trips.</p>
|
|
3428
3399
|
</div>
|
|
@@ -3433,7 +3404,7 @@ const App: HadarsApp<{}> = () => {
|
|
|
3433
3404
|
<h2>Client interactivity works</h2>
|
|
3434
3405
|
<div className="counter">{count}</div>
|
|
3435
3406
|
<div className="demo-actions">
|
|
3436
|
-
<button className="btn btn-ghost" onClick={() => setCount(c => c - 1)}
|
|
3407
|
+
<button className="btn btn-ghost" onClick={() => setCount(c => c - 1)}>− dec</button>
|
|
3437
3408
|
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>+ inc</button>
|
|
3438
3409
|
</div>
|
|
3439
3410
|
</div>
|
|
@@ -3553,12 +3524,13 @@ if (typeof globalThis.Bun === "undefined" && typeof globalThis.Deno === "undefin
|
|
|
3553
3524
|
const fwd = (sig) => () => {
|
|
3554
3525
|
try {
|
|
3555
3526
|
child.kill(sig);
|
|
3556
|
-
} catch {
|
|
3557
|
-
}
|
|
3527
|
+
} catch {}
|
|
3558
3528
|
};
|
|
3559
|
-
for (const sig of sigs)
|
|
3529
|
+
for (const sig of sigs)
|
|
3530
|
+
process.on(sig, fwd(sig));
|
|
3560
3531
|
child.on("error", (err) => {
|
|
3561
|
-
for (const sig of sigs)
|
|
3532
|
+
for (const sig of sigs)
|
|
3533
|
+
process.removeAllListeners(sig);
|
|
3562
3534
|
if (err.code !== "ENOENT") {
|
|
3563
3535
|
console.error(err);
|
|
3564
3536
|
process.exit(1);
|