hadars 0.4.1 → 0.4.2
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 +462 -496
- 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 -805
- 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,15 +2417,14 @@ 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;
|
|
2444
2424
|
if (!isGetOrHead) {
|
|
2445
2425
|
try {
|
|
2446
2426
|
body = new Uint8Array(await req.arrayBuffer());
|
|
2447
|
-
} catch {
|
|
2448
|
-
}
|
|
2427
|
+
} catch {}
|
|
2449
2428
|
}
|
|
2450
2429
|
const headers = {};
|
|
2451
2430
|
req.headers.forEach((v, k) => {
|
|
@@ -2463,7 +2442,7 @@ async function serializeRequest(req) {
|
|
|
2463
2442
|
};
|
|
2464
2443
|
}
|
|
2465
2444
|
var SSR_FILENAME = "index.ssr.js";
|
|
2466
|
-
var
|
|
2445
|
+
var __dirname3 = process.cwd();
|
|
2467
2446
|
var getSuffix = (mode) => mode === "development" ? `?v=${Date.now()}` : "";
|
|
2468
2447
|
var HadarsFolder = "./.hadars";
|
|
2469
2448
|
var StaticPath = `${HadarsFolder}/static`;
|
|
@@ -2490,18 +2469,18 @@ var resolveWorkerCmd = (packageDir2) => {
|
|
|
2490
2469
|
const allArgs = [...process.execArgv, process.argv[1] ?? ""];
|
|
2491
2470
|
const hasTsx = allArgs.some((a) => a.includes("tsx"));
|
|
2492
2471
|
const hasTsNode = allArgs.some((a) => a.includes("ts-node"));
|
|
2493
|
-
if (hasTsx)
|
|
2494
|
-
|
|
2472
|
+
if (hasTsx)
|
|
2473
|
+
return ["tsx", tsPath];
|
|
2474
|
+
if (hasTsNode)
|
|
2475
|
+
return ["ts-node", tsPath];
|
|
2495
2476
|
}
|
|
2496
2477
|
if (existsSync2(jsPath)) {
|
|
2497
2478
|
return ["node", jsPath];
|
|
2498
2479
|
}
|
|
2499
|
-
throw new Error(
|
|
2500
|
-
`[hadars] SSR worker not found. Expected:
|
|
2480
|
+
throw new Error(`[hadars] SSR worker not found. Expected:
|
|
2501
2481
|
${jsPath}
|
|
2502
2482
|
Run "npm run build:cli" to compile it, or launch hadars via a TypeScript runner:
|
|
2503
|
-
npx tsx cli.ts dev`
|
|
2504
|
-
);
|
|
2483
|
+
npx tsx cli.ts dev`);
|
|
2505
2484
|
};
|
|
2506
2485
|
var dev = async (options) => {
|
|
2507
2486
|
await fs.rm(HadarsFolder, { recursive: true, force: true });
|
|
@@ -2514,7 +2493,7 @@ var dev = async (options) => {
|
|
|
2514
2493
|
let handleGraphiql = null;
|
|
2515
2494
|
let devStaticCtx;
|
|
2516
2495
|
if (options.sources && options.sources.length > 0) {
|
|
2517
|
-
console.log(`[hadars] Running ${options.sources.length} source plugin(s)
|
|
2496
|
+
console.log(`[hadars] Running ${options.sources.length} source plugin(s)…`);
|
|
2518
2497
|
try {
|
|
2519
2498
|
const store = await runSources(options.sources);
|
|
2520
2499
|
const executor = await buildSchemaExecutor(store);
|
|
@@ -2523,13 +2502,13 @@ var dev = async (options) => {
|
|
|
2523
2502
|
handleGraphiql = createGraphiqlHandler(executor);
|
|
2524
2503
|
console.log(`[hadars] GraphiQL available at http://localhost:${port}${GRAPHQL_PATH}`);
|
|
2525
2504
|
} else {
|
|
2526
|
-
console.warn("[hadars] `graphql` package not found
|
|
2505
|
+
console.warn("[hadars] `graphql` package not found — GraphiQL disabled. Run: npm install graphql");
|
|
2527
2506
|
}
|
|
2528
2507
|
} catch (err) {
|
|
2529
2508
|
console.error("[hadars] Source plugin error:", err);
|
|
2530
2509
|
}
|
|
2531
2510
|
}
|
|
2532
|
-
const entry = pathMod2.resolve(
|
|
2511
|
+
const entry = pathMod2.resolve(__dirname3, options.entry);
|
|
2533
2512
|
const hmrPort = options.hmrPort ?? port + 1;
|
|
2534
2513
|
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
2535
2514
|
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.tsx");
|
|
@@ -2544,12 +2523,12 @@ var dev = async (options) => {
|
|
|
2544
2523
|
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
2545
2524
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
2546
2525
|
let ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
2547
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(
|
|
2526
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname3, options.htmlTemplate)) : undefined;
|
|
2548
2527
|
const clientCompiler = createClientCompiler(tmpFilePath, {
|
|
2549
2528
|
target: "web",
|
|
2550
2529
|
output: {
|
|
2551
2530
|
filename: "index.js",
|
|
2552
|
-
path: pathMod2.resolve(
|
|
2531
|
+
path: pathMod2.resolve(__dirname3, StaticPath)
|
|
2553
2532
|
},
|
|
2554
2533
|
base: baseURL,
|
|
2555
2534
|
mode: "development",
|
|
@@ -2576,12 +2555,12 @@ var dev = async (options) => {
|
|
|
2576
2555
|
}, clientCompiler);
|
|
2577
2556
|
console.log(`Starting HMR dev server on port ${hmrPort}`);
|
|
2578
2557
|
let clientResolved = false;
|
|
2579
|
-
const clientBuildDone = new Promise((
|
|
2558
|
+
const clientBuildDone = new Promise((resolve, reject) => {
|
|
2580
2559
|
clientCompiler.hooks.done.tap("initial-build", (stats) => {
|
|
2581
2560
|
if (!clientResolved) {
|
|
2582
2561
|
clientResolved = true;
|
|
2583
2562
|
console.log(stats.toString({ colors: true }));
|
|
2584
|
-
|
|
2563
|
+
resolve();
|
|
2585
2564
|
}
|
|
2586
2565
|
});
|
|
2587
2566
|
devServer.start().catch(reject);
|
|
@@ -2601,9 +2580,9 @@ var dev = async (options) => {
|
|
|
2601
2580
|
child.stdin?.end();
|
|
2602
2581
|
const cleanupChild = () => {
|
|
2603
2582
|
try {
|
|
2604
|
-
if (!child.killed)
|
|
2605
|
-
|
|
2606
|
-
}
|
|
2583
|
+
if (!child.killed)
|
|
2584
|
+
child.kill();
|
|
2585
|
+
} catch {}
|
|
2607
2586
|
};
|
|
2608
2587
|
process.once("exit", cleanupChild);
|
|
2609
2588
|
process.once("SIGINT", () => {
|
|
@@ -2618,7 +2597,7 @@ var dev = async (options) => {
|
|
|
2618
2597
|
const stderrWebStream = nodeReadableToWebStream(child.stderr);
|
|
2619
2598
|
const marker = "ssr-watch: initial-build-complete";
|
|
2620
2599
|
const rebuildMarker = "ssr-watch: SSR rebuilt";
|
|
2621
|
-
const decoder = new TextDecoder
|
|
2600
|
+
const decoder = new TextDecoder;
|
|
2622
2601
|
let stdoutReader = null;
|
|
2623
2602
|
const ssrBuildDone = (async () => {
|
|
2624
2603
|
let gotMarker = false;
|
|
@@ -2626,7 +2605,7 @@ var dev = async (options) => {
|
|
|
2626
2605
|
stdoutReader = stdoutWebStream.getReader();
|
|
2627
2606
|
let buf = "";
|
|
2628
2607
|
const start = Date.now();
|
|
2629
|
-
const timeoutMs =
|
|
2608
|
+
const timeoutMs = 20000;
|
|
2630
2609
|
while (Date.now() - start < timeoutMs) {
|
|
2631
2610
|
const { done, value } = await stdoutReader.read();
|
|
2632
2611
|
if (done) {
|
|
@@ -2637,8 +2616,7 @@ var dev = async (options) => {
|
|
|
2637
2616
|
buf += chunk;
|
|
2638
2617
|
try {
|
|
2639
2618
|
process.stdout.write(chunk);
|
|
2640
|
-
} catch (e) {
|
|
2641
|
-
}
|
|
2619
|
+
} catch (e) {}
|
|
2642
2620
|
if (buf.includes(marker)) {
|
|
2643
2621
|
gotMarker = true;
|
|
2644
2622
|
break;
|
|
@@ -2660,19 +2638,18 @@ var dev = async (options) => {
|
|
|
2660
2638
|
try {
|
|
2661
2639
|
while (true) {
|
|
2662
2640
|
const { done, value } = await reader.read();
|
|
2663
|
-
if (done)
|
|
2641
|
+
if (done)
|
|
2642
|
+
break;
|
|
2664
2643
|
const chunk = decoder.decode(value, { stream: true });
|
|
2665
2644
|
try {
|
|
2666
2645
|
process.stdout.write(chunk);
|
|
2667
|
-
} catch (e) {
|
|
2668
|
-
}
|
|
2646
|
+
} catch (e) {}
|
|
2669
2647
|
if (chunk.includes(rebuildMarker)) {
|
|
2670
2648
|
ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
2671
2649
|
console.log("[hadars] SSR bundle updated, build id:", ssrBuildId);
|
|
2672
2650
|
}
|
|
2673
2651
|
}
|
|
2674
|
-
} catch (e) {
|
|
2675
|
-
}
|
|
2652
|
+
} catch (e) {}
|
|
2676
2653
|
})();
|
|
2677
2654
|
}
|
|
2678
2655
|
});
|
|
@@ -2681,40 +2658,43 @@ var dev = async (options) => {
|
|
|
2681
2658
|
const r = stderrWebStream.getReader();
|
|
2682
2659
|
while (true) {
|
|
2683
2660
|
const { done, value } = await r.read();
|
|
2684
|
-
if (done)
|
|
2661
|
+
if (done)
|
|
2662
|
+
break;
|
|
2685
2663
|
try {
|
|
2686
2664
|
process.stderr.write(decoder.decode(value));
|
|
2687
|
-
} catch (e) {
|
|
2688
|
-
}
|
|
2665
|
+
} catch (e) {}
|
|
2689
2666
|
}
|
|
2690
|
-
} catch (e) {
|
|
2691
|
-
}
|
|
2667
|
+
} catch (e) {}
|
|
2692
2668
|
})();
|
|
2693
|
-
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
2694
|
-
readyPromise.then(() => fs.readFile(pathMod2.join(__dirname2, StaticPath, "out.html"), "utf-8"))
|
|
2695
|
-
);
|
|
2669
|
+
const getPrecontentHtml = makePrecontentHtmlGetter(readyPromise.then(() => fs.readFile(pathMod2.join(__dirname3, StaticPath, "out.html"), "utf-8")));
|
|
2696
2670
|
await serve(port, async (req, ctx) => {
|
|
2697
2671
|
await readyPromise;
|
|
2698
2672
|
const request = parseRequest(req);
|
|
2699
2673
|
if (handler) {
|
|
2700
2674
|
const res = await handler(request);
|
|
2701
|
-
if (res)
|
|
2675
|
+
if (res)
|
|
2676
|
+
return res;
|
|
2702
2677
|
}
|
|
2703
|
-
if (handleWS && handleWS(request, ctx))
|
|
2678
|
+
if (handleWS && handleWS(request, ctx))
|
|
2679
|
+
return;
|
|
2704
2680
|
if (handleGraphiql) {
|
|
2705
2681
|
const graphiqlRes = await handleGraphiql(req);
|
|
2706
|
-
if (graphiqlRes)
|
|
2682
|
+
if (graphiqlRes)
|
|
2683
|
+
return graphiqlRes;
|
|
2707
2684
|
}
|
|
2708
2685
|
const proxied = await handleProxy(request);
|
|
2709
|
-
if (proxied)
|
|
2686
|
+
if (proxied)
|
|
2687
|
+
return proxied;
|
|
2710
2688
|
const url = new URL(request.url);
|
|
2711
2689
|
const path2 = url.pathname;
|
|
2712
|
-
const staticRes = await tryServeFile(pathMod2.join(
|
|
2713
|
-
if (staticRes)
|
|
2690
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, path2));
|
|
2691
|
+
if (staticRes)
|
|
2692
|
+
return staticRes;
|
|
2714
2693
|
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
2715
2694
|
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
2716
|
-
if (projectRes)
|
|
2717
|
-
|
|
2695
|
+
if (projectRes)
|
|
2696
|
+
return projectRes;
|
|
2697
|
+
const ssrComponentPath = pathMod2.join(__dirname3, HadarsFolder, SSR_FILENAME);
|
|
2718
2698
|
const importPath = pathToFileURL(ssrComponentPath).href + `?t=${ssrBuildId}`;
|
|
2719
2699
|
try {
|
|
2720
2700
|
const {
|
|
@@ -2743,8 +2723,7 @@ var dev = async (options) => {
|
|
|
2743
2723
|
return buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml);
|
|
2744
2724
|
} catch (err) {
|
|
2745
2725
|
console.error("[hadars] SSR render error:", err);
|
|
2746
|
-
options.onError?.(err, request)?.catch?.(() => {
|
|
2747
|
-
});
|
|
2726
|
+
options.onError?.(err, request)?.catch?.(() => {});
|
|
2748
2727
|
const msg = (err?.stack ?? err?.message ?? String(err)).replace(/</g, "<");
|
|
2749
2728
|
return new Response(`<!doctype html><pre style="white-space:pre-wrap">${msg}</pre>`, {
|
|
2750
2729
|
status: 500,
|
|
@@ -2755,7 +2734,7 @@ var dev = async (options) => {
|
|
|
2755
2734
|
};
|
|
2756
2735
|
var build = async (options) => {
|
|
2757
2736
|
validateOptions(options);
|
|
2758
|
-
const entry = pathMod2.resolve(
|
|
2737
|
+
const entry = pathMod2.resolve(__dirname3, options.entry);
|
|
2759
2738
|
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
2760
2739
|
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.js");
|
|
2761
2740
|
let clientScript = "";
|
|
@@ -2768,15 +2747,14 @@ var build = async (options) => {
|
|
|
2768
2747
|
await ensureHadarsTmpDir();
|
|
2769
2748
|
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
2770
2749
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
2771
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(
|
|
2750
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname3, options.htmlTemplate)) : undefined;
|
|
2772
2751
|
console.log("Building client and server bundles in parallel...");
|
|
2773
2752
|
await Promise.all([
|
|
2774
2753
|
compileEntry(tmpFilePath, {
|
|
2775
2754
|
target: "web",
|
|
2776
2755
|
output: {
|
|
2777
|
-
// Content hash: filename is stable when code is unchanged → better browser/CDN cache.
|
|
2778
2756
|
filename: "index.[contenthash:8].js",
|
|
2779
|
-
path: pathMod2.resolve(
|
|
2757
|
+
path: pathMod2.resolve(__dirname3, StaticPath)
|
|
2780
2758
|
},
|
|
2781
2759
|
base: options.baseURL,
|
|
2782
2760
|
mode: "production",
|
|
@@ -2789,11 +2767,11 @@ var build = async (options) => {
|
|
|
2789
2767
|
reactMode: options.reactMode,
|
|
2790
2768
|
htmlTemplate: resolvedHtmlTemplate
|
|
2791
2769
|
}),
|
|
2792
|
-
compileEntry(pathMod2.resolve(
|
|
2770
|
+
compileEntry(pathMod2.resolve(__dirname3, options.entry), {
|
|
2793
2771
|
output: {
|
|
2794
2772
|
iife: false,
|
|
2795
2773
|
filename: SSR_FILENAME,
|
|
2796
|
-
path: pathMod2.resolve(
|
|
2774
|
+
path: pathMod2.resolve(__dirname3, HadarsFolder),
|
|
2797
2775
|
publicPath: "",
|
|
2798
2776
|
library: { type: "module" }
|
|
2799
2777
|
},
|
|
@@ -2815,15 +2793,14 @@ var run = async (options) => {
|
|
|
2815
2793
|
let { port = 9090, workers = 1 } = options;
|
|
2816
2794
|
if (isNode && workers > 1 && cluster.isPrimary) {
|
|
2817
2795
|
console.log(`[hadars] Starting ${workers} worker processes on port ${port}`);
|
|
2818
|
-
for (let i = 0;
|
|
2796
|
+
for (let i = 0;i < workers; i++) {
|
|
2819
2797
|
cluster.fork();
|
|
2820
2798
|
}
|
|
2821
2799
|
cluster.on("exit", (worker, code, signal) => {
|
|
2822
2800
|
console.warn(`[hadars] Worker ${worker.process.pid} exited (${signal ?? code}), restarting...`);
|
|
2823
2801
|
cluster.fork();
|
|
2824
2802
|
});
|
|
2825
|
-
await new Promise(() => {
|
|
2826
|
-
});
|
|
2803
|
+
await new Promise(() => {});
|
|
2827
2804
|
return;
|
|
2828
2805
|
}
|
|
2829
2806
|
const handleProxy = createProxyHandler(options);
|
|
@@ -2836,39 +2813,39 @@ var run = async (options) => {
|
|
|
2836
2813
|
const workerJs = pathMod2.resolve(packageDir2, "ssr-render-worker.js");
|
|
2837
2814
|
const workerTs = pathMod2.resolve(packageDir2, "ssr-render-worker.ts");
|
|
2838
2815
|
const workerFile = existsSync2(workerJs) ? workerJs : workerTs;
|
|
2839
|
-
const ssrBundlePath = pathMod2.resolve(
|
|
2816
|
+
const ssrBundlePath = pathMod2.resolve(__dirname3, HadarsFolder, SSR_FILENAME);
|
|
2840
2817
|
renderPool = new RenderWorkerPool(workerFile, workers, ssrBundlePath);
|
|
2841
2818
|
console.log(`[hadars] SSR render pool: ${workers} worker threads`);
|
|
2842
2819
|
}
|
|
2843
|
-
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
2844
|
-
|
|
2845
|
-
);
|
|
2846
|
-
const componentPath = pathToFileURL(
|
|
2847
|
-
pathMod2.resolve(__dirname2, HadarsFolder, SSR_FILENAME)
|
|
2848
|
-
).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;
|
|
2849
2822
|
const ssrModulePromise = import(componentPath);
|
|
2850
2823
|
const runHandler = async (req, ctx) => {
|
|
2851
2824
|
const request = parseRequest(req);
|
|
2852
2825
|
if (handler) {
|
|
2853
2826
|
const res = await handler(request);
|
|
2854
|
-
if (res)
|
|
2827
|
+
if (res)
|
|
2828
|
+
return res;
|
|
2855
2829
|
}
|
|
2856
|
-
if (handleWS && handleWS(request, ctx))
|
|
2830
|
+
if (handleWS && handleWS(request, ctx))
|
|
2831
|
+
return;
|
|
2857
2832
|
const proxied = await handleProxy(request);
|
|
2858
|
-
if (proxied)
|
|
2833
|
+
if (proxied)
|
|
2834
|
+
return proxied;
|
|
2859
2835
|
const url = new URL(request.url);
|
|
2860
2836
|
const path2 = url.pathname;
|
|
2861
|
-
const staticRes = await tryServeFile(pathMod2.join(
|
|
2862
|
-
if (staticRes)
|
|
2837
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, path2));
|
|
2838
|
+
if (staticRes)
|
|
2839
|
+
return staticRes;
|
|
2863
2840
|
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
2864
2841
|
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
2865
|
-
if (projectRes)
|
|
2842
|
+
if (projectRes)
|
|
2843
|
+
return projectRes;
|
|
2866
2844
|
const routeClean = path2.replace(/(^\/|\/$)/g, "");
|
|
2867
2845
|
if (routeClean) {
|
|
2868
|
-
const routeRes = await tryServeFile(
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
if (routeRes) return routeRes;
|
|
2846
|
+
const routeRes = await tryServeFile(pathMod2.join(__dirname3, StaticPath, routeClean, "index.html"));
|
|
2847
|
+
if (routeRes)
|
|
2848
|
+
return routeRes;
|
|
2872
2849
|
}
|
|
2873
2850
|
try {
|
|
2874
2851
|
const {
|
|
@@ -2904,16 +2881,11 @@ var run = async (options) => {
|
|
|
2904
2881
|
return buildSsrResponse(head, status, getAppBody, finalize, getPrecontentHtml);
|
|
2905
2882
|
} catch (err) {
|
|
2906
2883
|
console.error("[hadars] SSR render error:", err);
|
|
2907
|
-
options.onError?.(err, request)?.catch?.(() => {
|
|
2908
|
-
});
|
|
2884
|
+
options.onError?.(err, request)?.catch?.(() => {});
|
|
2909
2885
|
return new Response("Internal Server Error", { status: 500 });
|
|
2910
2886
|
}
|
|
2911
2887
|
};
|
|
2912
|
-
await serve(
|
|
2913
|
-
port,
|
|
2914
|
-
options.cache ? createRenderCache(options.cache, runHandler) : runHandler,
|
|
2915
|
-
options.websocket
|
|
2916
|
-
);
|
|
2888
|
+
await serve(port, options.cache ? createRenderCache(options.cache, runHandler) : runHandler, options.websocket);
|
|
2917
2889
|
};
|
|
2918
2890
|
|
|
2919
2891
|
// src/static.ts
|
|
@@ -2922,9 +2894,7 @@ import { join, basename } from "node:path";
|
|
|
2922
2894
|
async function renderStaticSite(opts) {
|
|
2923
2895
|
const { ssrModule, htmlSource, staticSrc, paths, outputDir } = opts;
|
|
2924
2896
|
const staticCtx = {
|
|
2925
|
-
graphql: opts.graphql ?? (() => Promise.reject(
|
|
2926
|
-
new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")
|
|
2927
|
-
))
|
|
2897
|
+
graphql: opts.graphql ?? (() => Promise.reject(new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")))
|
|
2928
2898
|
};
|
|
2929
2899
|
const getPrecontentHtml = makePrecontentHtmlGetter(Promise.resolve(htmlSource));
|
|
2930
2900
|
await mkdir(outputDir, { recursive: true });
|
|
@@ -2952,11 +2922,7 @@ async function renderStaticSite(opts) {
|
|
|
2952
2922
|
await mkdir(pageDir, { recursive: true });
|
|
2953
2923
|
await writeFile(join(pageDir, "index.html"), html, "utf-8");
|
|
2954
2924
|
const serverData = staticClientProps.__serverData ?? {};
|
|
2955
|
-
await writeFile(
|
|
2956
|
-
join(pageDir, "index.json"),
|
|
2957
|
-
JSON.stringify({ serverData }),
|
|
2958
|
-
"utf-8"
|
|
2959
|
-
);
|
|
2925
|
+
await writeFile(join(pageDir, "index.json"), JSON.stringify({ serverData }), "utf-8");
|
|
2960
2926
|
rendered.push(urlPath);
|
|
2961
2927
|
} catch (err) {
|
|
2962
2928
|
errors.push({
|
|
@@ -2979,7 +2945,8 @@ var SUPPORTED = ["hadars.config.js", "hadars.config.mjs", "hadars.config.cjs", "
|
|
|
2979
2945
|
function findConfig(cwd) {
|
|
2980
2946
|
for (const name of SUPPORTED) {
|
|
2981
2947
|
const p = resolve(cwd, name);
|
|
2982
|
-
if (existsSync3(p))
|
|
2948
|
+
if (existsSync3(p))
|
|
2949
|
+
return p;
|
|
2983
2950
|
}
|
|
2984
2951
|
return null;
|
|
2985
2952
|
}
|
|
@@ -3015,38 +2982,38 @@ async function exportSchema(config, outputFile) {
|
|
|
3015
2982
|
console.log(`Schema inferred for types: ${store.getTypes().join(", ") || "(none)"}`);
|
|
3016
2983
|
sdl = await buildSchemaSDL(store);
|
|
3017
2984
|
if (!sdl) {
|
|
3018
|
-
console.error(
|
|
3019
|
-
|
|
3020
|
-
|
|
2985
|
+
console.error(`Error: \`graphql\` package not found.
|
|
2986
|
+
Source plugins require graphql-js to be installed:
|
|
2987
|
+
|
|
2988
|
+
npm install graphql
|
|
2989
|
+
`);
|
|
3021
2990
|
process.exit(1);
|
|
3022
2991
|
}
|
|
3023
2992
|
} else if (config.graphql) {
|
|
3024
2993
|
console.log("Introspecting custom GraphQL executor...");
|
|
3025
2994
|
sdl = await introspectExecutorSDL(config.graphql);
|
|
3026
2995
|
if (!sdl) {
|
|
3027
|
-
console.error(
|
|
3028
|
-
|
|
3029
|
-
|
|
2996
|
+
console.error(`Error: \`graphql\` package not found.
|
|
2997
|
+
Schema export requires graphql-js to be installed:
|
|
2998
|
+
|
|
2999
|
+
npm install graphql
|
|
3000
|
+
`);
|
|
3030
3001
|
process.exit(1);
|
|
3031
3002
|
}
|
|
3032
3003
|
} else {
|
|
3033
|
-
console.error(
|
|
3034
|
-
"Error: no GraphQL source configured.\nAdd `sources` or a `graphql` executor to your hadars.config.ts first.\n"
|
|
3035
|
-
);
|
|
3004
|
+
console.error("Error: no GraphQL source configured.\nAdd `sources` or a `graphql` executor to your hadars.config.ts first.\n");
|
|
3036
3005
|
process.exit(1);
|
|
3037
3006
|
}
|
|
3038
3007
|
await writeFile2(outputFile, sdl, "utf-8");
|
|
3039
3008
|
console.log(`Schema written to ${outputFile}`);
|
|
3040
3009
|
console.log(`
|
|
3041
|
-
Next steps
|
|
3010
|
+
Next steps — generate TypeScript types with graphql-codegen:`);
|
|
3042
3011
|
console.log(` npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations`);
|
|
3043
3012
|
console.log(` npx graphql-codegen --schema ${outputFile} --documents "src/**/*.tsx" --out src/gql/`);
|
|
3044
3013
|
}
|
|
3045
3014
|
async function exportStatic(config, outputDir, cwd) {
|
|
3046
3015
|
if (!config.paths) {
|
|
3047
|
-
console.error(
|
|
3048
|
-
"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"
|
|
3049
|
-
);
|
|
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");
|
|
3050
3017
|
process.exit(1);
|
|
3051
3018
|
}
|
|
3052
3019
|
console.log("Building hadars project...");
|
|
@@ -3072,9 +3039,11 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3072
3039
|
if (!graphql) {
|
|
3073
3040
|
const inferred = await buildSchemaExecutor(store);
|
|
3074
3041
|
if (!inferred) {
|
|
3075
|
-
console.error(
|
|
3076
|
-
|
|
3077
|
-
|
|
3042
|
+
console.error(`Error: \`graphql\` package not found.
|
|
3043
|
+
Source plugins require graphql-js to be installed:
|
|
3044
|
+
|
|
3045
|
+
npm install graphql
|
|
3046
|
+
`);
|
|
3078
3047
|
process.exit(1);
|
|
3079
3048
|
}
|
|
3080
3049
|
graphql = inferred;
|
|
@@ -3082,9 +3051,7 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3082
3051
|
}
|
|
3083
3052
|
}
|
|
3084
3053
|
const staticCtx = {
|
|
3085
|
-
graphql: graphql ?? (() => Promise.reject(
|
|
3086
|
-
new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")
|
|
3087
|
-
))
|
|
3054
|
+
graphql: graphql ?? (() => Promise.reject(new Error("[hadars] No graphql executor configured. Add a `graphql` function to your hadars.config.")))
|
|
3088
3055
|
};
|
|
3089
3056
|
const paths = await config.paths(staticCtx);
|
|
3090
3057
|
console.log(`Pre-rendering ${paths.length} page(s)...`);
|
|
@@ -3096,11 +3063,14 @@ async function exportStatic(config, outputDir, cwd) {
|
|
|
3096
3063
|
outputDir: outDir,
|
|
3097
3064
|
graphql
|
|
3098
3065
|
});
|
|
3099
|
-
for (const p of rendered)
|
|
3100
|
-
|
|
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}`);
|
|
3101
3070
|
console.log(`
|
|
3102
3071
|
Exported to ${outputDir}/`);
|
|
3103
|
-
if (errors.length > 0)
|
|
3072
|
+
if (errors.length > 0)
|
|
3073
|
+
console.log(` ${errors.length} page(s) failed`);
|
|
3104
3074
|
console.log(`
|
|
3105
3075
|
Serve locally:`);
|
|
3106
3076
|
console.log(` npx serve ${outputDir}`);
|
|
@@ -3126,27 +3096,24 @@ async function bundleCloudflare(config, configPath, outputFile, cwd) {
|
|
|
3126
3096
|
`import { createCloudflareHandler } from ${JSON.stringify(cloudflareModule)};`,
|
|
3127
3097
|
`import config from ${JSON.stringify(configPath)};`,
|
|
3128
3098
|
`export default createCloudflareHandler(config as any, { ssrModule: ssrModule as any, outHtml });`
|
|
3129
|
-
].join(
|
|
3099
|
+
].join(`
|
|
3100
|
+
`) + `
|
|
3101
|
+
`;
|
|
3130
3102
|
await writeFile2(shimPath, shim, "utf-8");
|
|
3131
3103
|
try {
|
|
3132
3104
|
const { build: esbuild } = await import("esbuild");
|
|
3133
|
-
console.log(`Bundling Cloudflare Worker
|
|
3105
|
+
console.log(`Bundling Cloudflare Worker → ${outputFile}`);
|
|
3134
3106
|
await esbuild({
|
|
3135
3107
|
entryPoints: [shimPath],
|
|
3136
3108
|
bundle: true,
|
|
3137
|
-
// 'browser' avoids Node.js built-in shims; CF Workers uses Web APIs.
|
|
3138
|
-
// If you use node:* APIs in your app code, add nodejs_compat to wrangler.toml.
|
|
3139
3109
|
platform: "browser",
|
|
3140
3110
|
format: "esm",
|
|
3141
3111
|
target: ["es2022"],
|
|
3142
3112
|
outfile: outputFile,
|
|
3143
3113
|
sourcemap: false,
|
|
3144
3114
|
loader: { ".html": "text", ".tsx": "tsx", ".ts": "ts" },
|
|
3145
|
-
// @rspack/* is build-time only — never imported at Worker runtime.
|
|
3146
3115
|
external: ["@rspack/*"],
|
|
3147
|
-
|
|
3148
|
-
// esbuild's attempt to polyfill node:crypto.
|
|
3149
|
-
define: { "global": "globalThis" }
|
|
3116
|
+
define: { global: "globalThis" }
|
|
3150
3117
|
});
|
|
3151
3118
|
console.log(`Cloudflare Worker bundle written to ${outputFile}`);
|
|
3152
3119
|
console.log(`
|
|
@@ -3162,8 +3129,7 @@ Deploy instructions:`);
|
|
|
3162
3129
|
console.log(` and all other requests to the Worker.`);
|
|
3163
3130
|
console.log(` 4. Deploy: wrangler deploy`);
|
|
3164
3131
|
} finally {
|
|
3165
|
-
await unlink(shimPath).catch(() => {
|
|
3166
|
-
});
|
|
3132
|
+
await unlink(shimPath).catch(() => {});
|
|
3167
3133
|
}
|
|
3168
3134
|
}
|
|
3169
3135
|
async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
@@ -3187,11 +3153,13 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
3187
3153
|
`import { createLambdaHandler } from ${JSON.stringify(lambdaModule)};`,
|
|
3188
3154
|
`import config from ${JSON.stringify(configPath)};`,
|
|
3189
3155
|
`export const handler = createLambdaHandler(config as any, { ssrModule: ssrModule as any, outHtml });`
|
|
3190
|
-
].join(
|
|
3156
|
+
].join(`
|
|
3157
|
+
`) + `
|
|
3158
|
+
`;
|
|
3191
3159
|
await writeFile2(shimPath, shim, "utf-8");
|
|
3192
3160
|
try {
|
|
3193
3161
|
const { build: esbuild } = await import("esbuild");
|
|
3194
|
-
console.log(`Bundling Lambda handler
|
|
3162
|
+
console.log(`Bundling Lambda handler → ${outputFile}`);
|
|
3195
3163
|
await esbuild({
|
|
3196
3164
|
entryPoints: [shimPath],
|
|
3197
3165
|
bundle: true,
|
|
@@ -3201,10 +3169,6 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
3201
3169
|
outfile: outputFile,
|
|
3202
3170
|
sourcemap: false,
|
|
3203
3171
|
loader: { ".html": "text", ".tsx": "tsx", ".ts": "ts" },
|
|
3204
|
-
// @rspack/* contains native binaries and is build-time only —
|
|
3205
|
-
// it is never imported at Lambda runtime, so mark it external.
|
|
3206
|
-
// Everything else (React, hadars runtime, etc.) is bundled in to
|
|
3207
|
-
// produce a truly self-contained single-file deployment.
|
|
3208
3172
|
external: ["@rspack/*"]
|
|
3209
3173
|
});
|
|
3210
3174
|
console.log(`Lambda bundle written to ${outputFile}`);
|
|
@@ -3215,10 +3179,9 @@ Deploy instructions:`);
|
|
|
3215
3179
|
console.log(` 2. Upload lambda-deploy/ as your Lambda function code`);
|
|
3216
3180
|
console.log(` 3. Set handler to: lambda.handler (runtime: Node.js 20.x)`);
|
|
3217
3181
|
console.log(` 4. Upload .hadars/static/ assets to S3 and serve via CloudFront`);
|
|
3218
|
-
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)`);
|
|
3219
3183
|
} finally {
|
|
3220
|
-
await unlink(shimPath).catch(() => {
|
|
3221
|
-
});
|
|
3184
|
+
await unlink(shimPath).catch(() => {});
|
|
3222
3185
|
}
|
|
3223
3186
|
}
|
|
3224
3187
|
var TEMPLATES = {
|
|
@@ -3233,11 +3196,12 @@ var TEMPLATES = {
|
|
|
3233
3196
|
start: "hadars run"
|
|
3234
3197
|
},
|
|
3235
3198
|
dependencies: {
|
|
3236
|
-
|
|
3199
|
+
hadars: "latest",
|
|
3237
3200
|
react: "^19.0.0",
|
|
3238
3201
|
"react-dom": "^19.0.0"
|
|
3239
3202
|
}
|
|
3240
|
-
}, null, 2) +
|
|
3203
|
+
}, null, 2) + `
|
|
3204
|
+
`,
|
|
3241
3205
|
"hadars.config.ts": () => `import type { HadarsOptions } from 'hadars';
|
|
3242
3206
|
|
|
3243
3207
|
const config: HadarsOptions = {
|
|
@@ -3261,7 +3225,8 @@ export default config;
|
|
|
3261
3225
|
strict: true,
|
|
3262
3226
|
skipLibCheck: true
|
|
3263
3227
|
}
|
|
3264
|
-
}, null, 2) +
|
|
3228
|
+
}, null, 2) + `
|
|
3229
|
+
`,
|
|
3265
3230
|
".gitignore": () => `node_modules/
|
|
3266
3231
|
.hadars/
|
|
3267
3232
|
dist/
|
|
@@ -3406,29 +3371,29 @@ const App: HadarsApp<{}> = () => {
|
|
|
3406
3371
|
</p>
|
|
3407
3372
|
<div className="hero-actions">
|
|
3408
3373
|
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>
|
|
3409
|
-
Try the counter
|
|
3374
|
+
Try the counter ↓
|
|
3410
3375
|
</button>
|
|
3411
3376
|
</div>
|
|
3412
3377
|
</section>
|
|
3413
3378
|
|
|
3414
3379
|
<div className="features">
|
|
3415
3380
|
<div className="card">
|
|
3416
|
-
<div className="card-icon"
|
|
3381
|
+
<div className="card-icon">⚡</div>
|
|
3417
3382
|
<h3>Server-side rendering</h3>
|
|
3418
|
-
<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>
|
|
3419
3384
|
</div>
|
|
3420
3385
|
<div className="card">
|
|
3421
|
-
<div className="card-icon">\
|
|
3386
|
+
<div className="card-icon">\uD83D\uDD25</div>
|
|
3422
3387
|
<h3>Hot module reload</h3>
|
|
3423
3388
|
<p>Changes in <code>src/App.tsx</code> reflect instantly in the browser during development.</p>
|
|
3424
3389
|
</div>
|
|
3425
3390
|
<div className="card">
|
|
3426
|
-
<div className="card-icon">\
|
|
3391
|
+
<div className="card-icon">\uD83D\uDCE6</div>
|
|
3427
3392
|
<h3>Zero config</h3>
|
|
3428
3393
|
<p>One config file. Export a React component, run <code>hadars dev</code>, done.</p>
|
|
3429
3394
|
</div>
|
|
3430
3395
|
<div className="card">
|
|
3431
|
-
<div className="card-icon">\
|
|
3396
|
+
<div className="card-icon">\uD83D\uDDC4️</div>
|
|
3432
3397
|
<h3>Server data hooks</h3>
|
|
3433
3398
|
<p>Use <code>useServerData</code> to fetch data on the server without extra round-trips.</p>
|
|
3434
3399
|
</div>
|
|
@@ -3439,7 +3404,7 @@ const App: HadarsApp<{}> = () => {
|
|
|
3439
3404
|
<h2>Client interactivity works</h2>
|
|
3440
3405
|
<div className="counter">{count}</div>
|
|
3441
3406
|
<div className="demo-actions">
|
|
3442
|
-
<button className="btn btn-ghost" onClick={() => setCount(c => c - 1)}
|
|
3407
|
+
<button className="btn btn-ghost" onClick={() => setCount(c => c - 1)}>− dec</button>
|
|
3443
3408
|
<button className="btn btn-primary" onClick={() => setCount(c => c + 1)}>+ inc</button>
|
|
3444
3409
|
</div>
|
|
3445
3410
|
</div>
|
|
@@ -3559,12 +3524,13 @@ if (typeof globalThis.Bun === "undefined" && typeof globalThis.Deno === "undefin
|
|
|
3559
3524
|
const fwd = (sig) => () => {
|
|
3560
3525
|
try {
|
|
3561
3526
|
child.kill(sig);
|
|
3562
|
-
} catch {
|
|
3563
|
-
}
|
|
3527
|
+
} catch {}
|
|
3564
3528
|
};
|
|
3565
|
-
for (const sig of sigs)
|
|
3529
|
+
for (const sig of sigs)
|
|
3530
|
+
process.on(sig, fwd(sig));
|
|
3566
3531
|
child.on("error", (err) => {
|
|
3567
|
-
for (const sig of sigs)
|
|
3532
|
+
for (const sig of sigs)
|
|
3533
|
+
process.removeAllListeners(sig);
|
|
3568
3534
|
if (err.code !== "ENOENT") {
|
|
3569
3535
|
console.error(err);
|
|
3570
3536
|
process.exit(1);
|