hadars 0.1.17 → 0.1.18
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-TGSIYGY2.js +40 -0
- package/dist/cli.js +656 -143
- package/dist/index.cjs +61 -6
- package/dist/index.d.ts +40 -1
- package/dist/index.js +58 -6
- package/dist/jsx-runtime-97ca74a5.d.ts +18 -0
- package/dist/slim-react/index.cjs +874 -0
- package/dist/slim-react/index.d.ts +180 -0
- package/dist/slim-react/index.js +784 -0
- package/dist/slim-react/jsx-runtime.cjs +51 -0
- package/dist/slim-react/jsx-runtime.d.ts +1 -0
- package/dist/slim-react/jsx-runtime.js +10 -0
- package/dist/ssr-render-worker.js +619 -108
- package/dist/ssr-watch.js +34 -13
- package/dist/utils/Head.tsx +3 -6
- package/index.ts +1 -1
- package/package.json +2 -2
- package/src/build.ts +6 -23
- package/src/components/CacheSegment.tsx +67 -0
- package/src/index.tsx +2 -0
- package/src/slim-react/context.ts +52 -0
- package/src/slim-react/hooks.ts +137 -0
- package/src/slim-react/index.ts +225 -0
- package/src/slim-react/jsx-runtime.ts +7 -0
- package/src/slim-react/jsx.ts +53 -0
- package/src/slim-react/render.ts +686 -0
- package/src/slim-react/renderContext.ts +105 -0
- package/src/slim-react/types.ts +27 -0
- package/src/ssr-render-worker.ts +83 -118
- package/src/utils/Head.tsx +3 -6
- package/src/utils/response.tsx +42 -105
- package/src/utils/rspack.ts +42 -15
- package/src/utils/segmentCache.ts +87 -0
package/dist/cli.js
CHANGED
|
@@ -134,24 +134,509 @@ var upgradeHandler = (options) => {
|
|
|
134
134
|
return null;
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
// src/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
137
|
+
// src/slim-react/types.ts
|
|
138
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
139
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
140
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
141
|
+
|
|
142
|
+
// src/slim-react/jsx.ts
|
|
143
|
+
var Fragment = FRAGMENT_TYPE;
|
|
144
|
+
function createElement(type, props, ...children) {
|
|
145
|
+
const normalizedProps = { ...props || {} };
|
|
146
|
+
if (children.length === 1) {
|
|
147
|
+
normalizedProps.children = children[0];
|
|
148
|
+
} else if (children.length > 1) {
|
|
149
|
+
normalizedProps.children = children;
|
|
150
|
+
}
|
|
151
|
+
const key = normalizedProps.key ?? null;
|
|
152
|
+
delete normalizedProps.key;
|
|
153
|
+
return {
|
|
154
|
+
$$typeof: SLIM_ELEMENT,
|
|
155
|
+
type,
|
|
156
|
+
props: normalizedProps,
|
|
157
|
+
key
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/slim-react/renderContext.ts
|
|
162
|
+
var GLOBAL_KEY = "__slimReactRenderState";
|
|
163
|
+
var EMPTY = { id: 0, overflow: "", bits: 0 };
|
|
164
|
+
function s() {
|
|
165
|
+
const g = globalThis;
|
|
166
|
+
if (!g[GLOBAL_KEY]) {
|
|
167
|
+
g[GLOBAL_KEY] = { currentTreeContext: { ...EMPTY }, localIdCounter: 0, idPrefix: "" };
|
|
168
|
+
}
|
|
169
|
+
return g[GLOBAL_KEY];
|
|
170
|
+
}
|
|
171
|
+
function resetRenderState() {
|
|
172
|
+
const st = s();
|
|
173
|
+
st.currentTreeContext = { ...EMPTY };
|
|
174
|
+
st.localIdCounter = 0;
|
|
175
|
+
}
|
|
176
|
+
function pushTreeContext(totalChildren, index) {
|
|
177
|
+
const st = s();
|
|
178
|
+
const saved = { ...st.currentTreeContext };
|
|
179
|
+
const pendingBits = 32 - Math.clz32(totalChildren);
|
|
180
|
+
const slot = index + 1;
|
|
181
|
+
const totalBits = st.currentTreeContext.bits + pendingBits;
|
|
182
|
+
if (totalBits <= 30) {
|
|
183
|
+
st.currentTreeContext = {
|
|
184
|
+
id: st.currentTreeContext.id << pendingBits | slot,
|
|
185
|
+
overflow: st.currentTreeContext.overflow,
|
|
186
|
+
bits: totalBits
|
|
187
|
+
};
|
|
188
|
+
} else {
|
|
189
|
+
let newOverflow = st.currentTreeContext.overflow;
|
|
190
|
+
if (st.currentTreeContext.bits > 0)
|
|
191
|
+
newOverflow += st.currentTreeContext.id.toString(32);
|
|
192
|
+
st.currentTreeContext = { id: 1 << pendingBits | slot, overflow: newOverflow, bits: pendingBits };
|
|
193
|
+
}
|
|
194
|
+
return saved;
|
|
195
|
+
}
|
|
196
|
+
function popTreeContext(saved) {
|
|
197
|
+
s().currentTreeContext = saved;
|
|
198
|
+
}
|
|
199
|
+
function pushComponentScope() {
|
|
200
|
+
const st = s();
|
|
201
|
+
const saved = st.localIdCounter;
|
|
202
|
+
st.localIdCounter = 0;
|
|
203
|
+
return saved;
|
|
204
|
+
}
|
|
205
|
+
function popComponentScope(saved) {
|
|
206
|
+
s().localIdCounter = saved;
|
|
207
|
+
}
|
|
208
|
+
function snapshotContext() {
|
|
209
|
+
const st = s();
|
|
210
|
+
return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
|
|
211
|
+
}
|
|
212
|
+
function restoreContext(snap) {
|
|
213
|
+
const st = s();
|
|
214
|
+
st.currentTreeContext = { ...snap.tree };
|
|
215
|
+
st.localIdCounter = snap.localId;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/slim-react/render.ts
|
|
219
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
220
|
+
"area",
|
|
221
|
+
"base",
|
|
222
|
+
"br",
|
|
223
|
+
"col",
|
|
224
|
+
"embed",
|
|
225
|
+
"hr",
|
|
226
|
+
"img",
|
|
227
|
+
"input",
|
|
228
|
+
"link",
|
|
229
|
+
"meta",
|
|
230
|
+
"param",
|
|
231
|
+
"source",
|
|
232
|
+
"track",
|
|
233
|
+
"wbr"
|
|
234
|
+
]);
|
|
235
|
+
function escapeHtml(str) {
|
|
236
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
237
|
+
}
|
|
238
|
+
function escapeAttr(str) {
|
|
239
|
+
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
240
|
+
}
|
|
241
|
+
function styleObjectToString(style) {
|
|
242
|
+
return Object.entries(style).map(([key, value]) => {
|
|
243
|
+
const cssKey = key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
244
|
+
return `${cssKey}:${value}`;
|
|
245
|
+
}).join(";");
|
|
246
|
+
}
|
|
247
|
+
var SVG_ATTR_MAP = {
|
|
248
|
+
// Presentation / geometry
|
|
249
|
+
accentHeight: "accent-height",
|
|
250
|
+
alignmentBaseline: "alignment-baseline",
|
|
251
|
+
arabicForm: "arabic-form",
|
|
252
|
+
baselineShift: "baseline-shift",
|
|
253
|
+
capHeight: "cap-height",
|
|
254
|
+
clipPath: "clip-path",
|
|
255
|
+
clipRule: "clip-rule",
|
|
256
|
+
colorInterpolation: "color-interpolation",
|
|
257
|
+
colorInterpolationFilters: "color-interpolation-filters",
|
|
258
|
+
colorProfile: "color-profile",
|
|
259
|
+
dominantBaseline: "dominant-baseline",
|
|
260
|
+
enableBackground: "enable-background",
|
|
261
|
+
fillOpacity: "fill-opacity",
|
|
262
|
+
fillRule: "fill-rule",
|
|
263
|
+
floodColor: "flood-color",
|
|
264
|
+
floodOpacity: "flood-opacity",
|
|
265
|
+
fontFamily: "font-family",
|
|
266
|
+
fontSize: "font-size",
|
|
267
|
+
fontSizeAdjust: "font-size-adjust",
|
|
268
|
+
fontStretch: "font-stretch",
|
|
269
|
+
fontStyle: "font-style",
|
|
270
|
+
fontVariant: "font-variant",
|
|
271
|
+
fontWeight: "font-weight",
|
|
272
|
+
glyphName: "glyph-name",
|
|
273
|
+
glyphOrientationHorizontal: "glyph-orientation-horizontal",
|
|
274
|
+
glyphOrientationVertical: "glyph-orientation-vertical",
|
|
275
|
+
horizAdvX: "horiz-adv-x",
|
|
276
|
+
horizOriginX: "horiz-origin-x",
|
|
277
|
+
imageRendering: "image-rendering",
|
|
278
|
+
letterSpacing: "letter-spacing",
|
|
279
|
+
lightingColor: "lighting-color",
|
|
280
|
+
markerEnd: "marker-end",
|
|
281
|
+
markerMid: "marker-mid",
|
|
282
|
+
markerStart: "marker-start",
|
|
283
|
+
overlinePosition: "overline-position",
|
|
284
|
+
overlineThickness: "overline-thickness",
|
|
285
|
+
paintOrder: "paint-order",
|
|
286
|
+
panose1: "panose-1",
|
|
287
|
+
pointerEvents: "pointer-events",
|
|
288
|
+
renderingIntent: "rendering-intent",
|
|
289
|
+
shapeRendering: "shape-rendering",
|
|
290
|
+
stopColor: "stop-color",
|
|
291
|
+
stopOpacity: "stop-opacity",
|
|
292
|
+
strikethroughPosition: "strikethrough-position",
|
|
293
|
+
strikethroughThickness: "strikethrough-thickness",
|
|
294
|
+
strokeDasharray: "stroke-dasharray",
|
|
295
|
+
strokeDashoffset: "stroke-dashoffset",
|
|
296
|
+
strokeLinecap: "stroke-linecap",
|
|
297
|
+
strokeLinejoin: "stroke-linejoin",
|
|
298
|
+
strokeMiterlimit: "stroke-miterlimit",
|
|
299
|
+
strokeOpacity: "stroke-opacity",
|
|
300
|
+
strokeWidth: "stroke-width",
|
|
301
|
+
textAnchor: "text-anchor",
|
|
302
|
+
textDecoration: "text-decoration",
|
|
303
|
+
textRendering: "text-rendering",
|
|
304
|
+
underlinePosition: "underline-position",
|
|
305
|
+
underlineThickness: "underline-thickness",
|
|
306
|
+
unicodeBidi: "unicode-bidi",
|
|
307
|
+
unicodeRange: "unicode-range",
|
|
308
|
+
unitsPerEm: "units-per-em",
|
|
309
|
+
vAlphabetic: "v-alphabetic",
|
|
310
|
+
vHanging: "v-hanging",
|
|
311
|
+
vIdeographic: "v-ideographic",
|
|
312
|
+
vMathematical: "v-mathematical",
|
|
313
|
+
vertAdvY: "vert-adv-y",
|
|
314
|
+
vertOriginX: "vert-origin-x",
|
|
315
|
+
vertOriginY: "vert-origin-y",
|
|
316
|
+
wordSpacing: "word-spacing",
|
|
317
|
+
writingMode: "writing-mode",
|
|
318
|
+
xHeight: "x-height",
|
|
319
|
+
// Namespace-prefixed
|
|
320
|
+
xlinkActuate: "xlink:actuate",
|
|
321
|
+
xlinkArcrole: "xlink:arcrole",
|
|
322
|
+
xlinkHref: "xlink:href",
|
|
323
|
+
xlinkRole: "xlink:role",
|
|
324
|
+
xlinkShow: "xlink:show",
|
|
325
|
+
xlinkTitle: "xlink:title",
|
|
326
|
+
xlinkType: "xlink:type",
|
|
327
|
+
xmlBase: "xml:base",
|
|
328
|
+
xmlLang: "xml:lang",
|
|
329
|
+
xmlSpace: "xml:space",
|
|
330
|
+
xmlns: "xmlns",
|
|
331
|
+
xmlnsXlink: "xmlns:xlink",
|
|
332
|
+
// Filter / lighting
|
|
333
|
+
baseFrequency: "baseFrequency",
|
|
334
|
+
colorInterpolation_filters: "color-interpolation-filters",
|
|
335
|
+
diffuseConstant: "diffuseConstant",
|
|
336
|
+
edgeMode: "edgeMode",
|
|
337
|
+
filterUnits: "filterUnits",
|
|
338
|
+
gradientTransform: "gradientTransform",
|
|
339
|
+
gradientUnits: "gradientUnits",
|
|
340
|
+
kernelMatrix: "kernelMatrix",
|
|
341
|
+
kernelUnitLength: "kernelUnitLength",
|
|
342
|
+
lengthAdjust: "lengthAdjust",
|
|
343
|
+
limitingConeAngle: "limitingConeAngle",
|
|
344
|
+
markerHeight: "markerHeight",
|
|
345
|
+
markerWidth: "markerWidth",
|
|
346
|
+
maskContentUnits: "maskContentUnits",
|
|
347
|
+
maskUnits: "maskUnits",
|
|
348
|
+
numOctaves: "numOctaves",
|
|
349
|
+
pathLength: "pathLength",
|
|
350
|
+
patternContentUnits: "patternContentUnits",
|
|
351
|
+
patternTransform: "patternTransform",
|
|
352
|
+
patternUnits: "patternUnits",
|
|
353
|
+
pointsAtX: "pointsAtX",
|
|
354
|
+
pointsAtY: "pointsAtY",
|
|
355
|
+
pointsAtZ: "pointsAtZ",
|
|
356
|
+
preserveAspectRatio: "preserveAspectRatio",
|
|
357
|
+
primitiveUnits: "primitiveUnits",
|
|
358
|
+
refX: "refX",
|
|
359
|
+
refY: "refY",
|
|
360
|
+
repeatCount: "repeatCount",
|
|
361
|
+
repeatDur: "repeatDur",
|
|
362
|
+
specularConstant: "specularConstant",
|
|
363
|
+
specularExponent: "specularExponent",
|
|
364
|
+
spreadMethod: "spreadMethod",
|
|
365
|
+
startOffset: "startOffset",
|
|
366
|
+
stdDeviation: "stdDeviation",
|
|
367
|
+
stitchTiles: "stitchTiles",
|
|
368
|
+
surfaceScale: "surfaceScale",
|
|
369
|
+
systemLanguage: "systemLanguage",
|
|
370
|
+
tableValues: "tableValues",
|
|
371
|
+
targetX: "targetX",
|
|
372
|
+
targetY: "targetY",
|
|
373
|
+
textLength: "textLength",
|
|
374
|
+
viewBox: "viewBox",
|
|
375
|
+
xChannelSelector: "xChannelSelector",
|
|
376
|
+
yChannelSelector: "yChannelSelector"
|
|
377
|
+
};
|
|
378
|
+
function renderAttributes(props, isSvg) {
|
|
379
|
+
let attrs = "";
|
|
380
|
+
for (const [key, value] of Object.entries(props)) {
|
|
381
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML")
|
|
382
|
+
continue;
|
|
383
|
+
if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
|
|
384
|
+
continue;
|
|
385
|
+
let attrName;
|
|
386
|
+
if (isSvg && key in SVG_ATTR_MAP) {
|
|
387
|
+
attrName = SVG_ATTR_MAP[key];
|
|
388
|
+
} else {
|
|
389
|
+
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key;
|
|
390
|
+
}
|
|
391
|
+
if (value === false || value == null)
|
|
392
|
+
continue;
|
|
393
|
+
if (value === true) {
|
|
394
|
+
attrs += ` ${attrName}`;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (key === "style" && typeof value === "object") {
|
|
398
|
+
attrs += ` style="${escapeAttr(styleObjectToString(value))}"`;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
attrs += ` ${attrName}="${escapeAttr(String(value))}"`;
|
|
402
|
+
}
|
|
403
|
+
return attrs;
|
|
404
|
+
}
|
|
405
|
+
var BufferWriter = class {
|
|
406
|
+
chunks = [];
|
|
407
|
+
write(chunk) {
|
|
408
|
+
this.chunks.push(chunk);
|
|
409
|
+
}
|
|
410
|
+
flush(target) {
|
|
411
|
+
for (const c of this.chunks)
|
|
412
|
+
target.write(c);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
function renderNode(node, writer, isSvg = false) {
|
|
416
|
+
if (node == null || typeof node === "boolean")
|
|
417
|
+
return;
|
|
418
|
+
if (typeof node === "string") {
|
|
419
|
+
writer.write(escapeHtml(node));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (typeof node === "number") {
|
|
423
|
+
writer.write(String(node));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (Array.isArray(node)) {
|
|
427
|
+
return renderChildArray(node, writer, isSvg);
|
|
428
|
+
}
|
|
429
|
+
if (typeof node === "object" && node !== null && Symbol.iterator in node && !("$$typeof" in node)) {
|
|
430
|
+
return renderChildArray(
|
|
431
|
+
Array.from(node),
|
|
432
|
+
writer,
|
|
433
|
+
isSvg
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
if (typeof node === "object" && node !== null && "$$typeof" in node && node.$$typeof === SLIM_ELEMENT) {
|
|
437
|
+
const element = node;
|
|
438
|
+
const { type, props } = element;
|
|
439
|
+
if (type === FRAGMENT_TYPE) {
|
|
440
|
+
return renderChildren(props.children, writer, isSvg);
|
|
441
|
+
}
|
|
442
|
+
if (type === SUSPENSE_TYPE) {
|
|
443
|
+
return renderSuspense(props, writer, isSvg);
|
|
444
|
+
}
|
|
445
|
+
if (typeof type === "function") {
|
|
446
|
+
return renderComponent(type, props, writer, isSvg);
|
|
447
|
+
}
|
|
448
|
+
if (typeof type === "string") {
|
|
449
|
+
return renderHostElement(type, props, writer, isSvg);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function renderHostElement(tag, props, writer, isSvg) {
|
|
454
|
+
const enteringSvg = tag === "svg";
|
|
455
|
+
const childSvg = isSvg || enteringSvg;
|
|
456
|
+
const effectiveProps = enteringSvg && !props.xmlns ? { xmlns: "http://www.w3.org/2000/svg", ...props } : props;
|
|
457
|
+
writer.write(`<${tag}${renderAttributes(effectiveProps, childSvg)}>`);
|
|
458
|
+
const childContext = tag === "foreignObject" ? false : childSvg;
|
|
459
|
+
let inner = void 0;
|
|
460
|
+
if (props.dangerouslySetInnerHTML) {
|
|
461
|
+
writer.write(props.dangerouslySetInnerHTML.__html);
|
|
462
|
+
} else {
|
|
463
|
+
inner = renderChildren(props.children, writer, childContext);
|
|
464
|
+
}
|
|
465
|
+
if (inner && typeof inner.then === "function") {
|
|
466
|
+
return inner.then(() => {
|
|
467
|
+
if (!VOID_ELEMENTS.has(tag))
|
|
468
|
+
writer.write(`</${tag}>`);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
if (!VOID_ELEMENTS.has(tag))
|
|
472
|
+
writer.write(`</${tag}>`);
|
|
473
|
+
}
|
|
474
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
475
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
476
|
+
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
477
|
+
var REACT_CONTEXT = Symbol.for("react.context");
|
|
478
|
+
function renderComponent(type, props, writer, isSvg) {
|
|
479
|
+
const typeOf = type?.$$typeof;
|
|
480
|
+
if (typeOf === REACT_MEMO) {
|
|
481
|
+
return renderNode(
|
|
482
|
+
{ $$typeof: SLIM_ELEMENT, type: type.type, props, key: null },
|
|
483
|
+
writer,
|
|
484
|
+
isSvg
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
if (typeOf === REACT_FORWARD_REF) {
|
|
488
|
+
return renderComponent(type.render, props, writer, isSvg);
|
|
489
|
+
}
|
|
490
|
+
const isProvider = "_context" in type || typeOf === REACT_PROVIDER || typeOf === REACT_CONTEXT && "value" in props;
|
|
491
|
+
let prevCtxValue;
|
|
492
|
+
let ctx;
|
|
493
|
+
if (isProvider) {
|
|
494
|
+
ctx = type._context ?? type;
|
|
495
|
+
prevCtxValue = ctx._currentValue;
|
|
496
|
+
ctx._currentValue = props.value;
|
|
497
|
+
}
|
|
498
|
+
const savedScope = pushComponentScope();
|
|
499
|
+
let result;
|
|
500
|
+
try {
|
|
501
|
+
if (type.prototype && typeof type.prototype.render === "function") {
|
|
502
|
+
const instance = new type(props);
|
|
503
|
+
result = instance.render();
|
|
504
|
+
} else {
|
|
505
|
+
result = type(props);
|
|
506
|
+
}
|
|
507
|
+
} catch (e) {
|
|
508
|
+
popComponentScope(savedScope);
|
|
509
|
+
if (isProvider)
|
|
510
|
+
ctx._currentValue = prevCtxValue;
|
|
511
|
+
throw e;
|
|
512
|
+
}
|
|
513
|
+
const finish = () => {
|
|
514
|
+
popComponentScope(savedScope);
|
|
515
|
+
if (isProvider)
|
|
516
|
+
ctx._currentValue = prevCtxValue;
|
|
517
|
+
};
|
|
518
|
+
if (result instanceof Promise) {
|
|
519
|
+
return result.then((resolved) => {
|
|
520
|
+
const r2 = renderNode(resolved, writer, isSvg);
|
|
521
|
+
if (r2 && typeof r2.then === "function") {
|
|
522
|
+
return r2.then(finish);
|
|
523
|
+
}
|
|
524
|
+
finish();
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
const r = renderNode(result, writer, isSvg);
|
|
528
|
+
if (r && typeof r.then === "function") {
|
|
529
|
+
return r.then(finish);
|
|
530
|
+
}
|
|
531
|
+
finish();
|
|
532
|
+
}
|
|
533
|
+
function isTextLike(node) {
|
|
534
|
+
return typeof node === "string" || typeof node === "number";
|
|
151
535
|
}
|
|
536
|
+
function renderChildArray(children, writer, isSvg) {
|
|
537
|
+
const totalChildren = children.length;
|
|
538
|
+
for (let i = 0; i < totalChildren; i++) {
|
|
539
|
+
if (i > 0 && isTextLike(children[i]) && isTextLike(children[i - 1])) {
|
|
540
|
+
writer.write("<!-- -->");
|
|
541
|
+
}
|
|
542
|
+
const savedTree = pushTreeContext(totalChildren, i);
|
|
543
|
+
const r = renderNode(children[i], writer, isSvg);
|
|
544
|
+
if (r && typeof r.then === "function") {
|
|
545
|
+
return r.then(() => {
|
|
546
|
+
popTreeContext(savedTree);
|
|
547
|
+
return renderChildArrayFrom(children, i + 1, writer, isSvg);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
popTreeContext(savedTree);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function renderChildArrayFrom(children, startIndex, writer, isSvg) {
|
|
554
|
+
const totalChildren = children.length;
|
|
555
|
+
for (let i = startIndex; i < totalChildren; i++) {
|
|
556
|
+
if (i > 0 && isTextLike(children[i]) && isTextLike(children[i - 1])) {
|
|
557
|
+
writer.write("<!-- -->");
|
|
558
|
+
}
|
|
559
|
+
const savedTree = pushTreeContext(totalChildren, i);
|
|
560
|
+
const r = renderNode(children[i], writer, isSvg);
|
|
561
|
+
if (r && typeof r.then === "function") {
|
|
562
|
+
return r.then(() => {
|
|
563
|
+
popTreeContext(savedTree);
|
|
564
|
+
return renderChildArrayFrom(children, i + 1, writer, isSvg);
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
popTreeContext(savedTree);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function renderChildren(children, writer, isSvg = false) {
|
|
571
|
+
if (children == null)
|
|
572
|
+
return;
|
|
573
|
+
if (Array.isArray(children)) {
|
|
574
|
+
return renderChildArray(children, writer, isSvg);
|
|
575
|
+
}
|
|
576
|
+
return renderNode(children, writer, isSvg);
|
|
577
|
+
}
|
|
578
|
+
var MAX_SUSPENSE_RETRIES = 25;
|
|
579
|
+
async function renderSuspense(props, writer, isSvg = false) {
|
|
580
|
+
const { children, fallback } = props;
|
|
581
|
+
let attempts = 0;
|
|
582
|
+
const snap = snapshotContext();
|
|
583
|
+
while (attempts < MAX_SUSPENSE_RETRIES) {
|
|
584
|
+
restoreContext(snap);
|
|
585
|
+
try {
|
|
586
|
+
const buffer = new BufferWriter();
|
|
587
|
+
const r = renderNode(children, buffer, isSvg);
|
|
588
|
+
if (r && typeof r.then === "function") {
|
|
589
|
+
await r;
|
|
590
|
+
}
|
|
591
|
+
writer.write("<!--$-->");
|
|
592
|
+
buffer.flush(writer);
|
|
593
|
+
writer.write("<!--/$-->");
|
|
594
|
+
return;
|
|
595
|
+
} catch (error) {
|
|
596
|
+
if (error && typeof error.then === "function") {
|
|
597
|
+
await error;
|
|
598
|
+
attempts++;
|
|
599
|
+
} else {
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
restoreContext(snap);
|
|
605
|
+
writer.write("<!--$?-->");
|
|
606
|
+
if (fallback) {
|
|
607
|
+
const r = renderNode(fallback, writer, isSvg);
|
|
608
|
+
if (r && typeof r.then === "function")
|
|
609
|
+
await r;
|
|
610
|
+
}
|
|
611
|
+
writer.write("<!--/$-->");
|
|
612
|
+
}
|
|
613
|
+
async function renderToString(element) {
|
|
614
|
+
for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
|
|
615
|
+
resetRenderState();
|
|
616
|
+
const chunks = [];
|
|
617
|
+
const writer = { write(c) {
|
|
618
|
+
chunks.push(c);
|
|
619
|
+
} };
|
|
620
|
+
try {
|
|
621
|
+
const r = renderNode(element, writer);
|
|
622
|
+
if (r && typeof r.then === "function")
|
|
623
|
+
await r;
|
|
624
|
+
return chunks.join("");
|
|
625
|
+
} catch (error) {
|
|
626
|
+
if (error && typeof error.then === "function") {
|
|
627
|
+
await error;
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
throw new Error("[slim-react] renderToString exceeded maximum retries");
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/utils/response.tsx
|
|
152
637
|
var ESC = { "&": "&", "<": "<", ">": ">", '"': """ };
|
|
153
|
-
var escAttr = (
|
|
154
|
-
var escText = (
|
|
638
|
+
var escAttr = (s2) => s2.replace(/[&<>"]/g, (c) => ESC[c] ?? c);
|
|
639
|
+
var escText = (s2) => s2.replace(/[&<>]/g, (c) => ESC[c] ?? c);
|
|
155
640
|
var ATTR = {
|
|
156
641
|
className: "class",
|
|
157
642
|
htmlFor: "for",
|
|
@@ -195,77 +680,57 @@ var getHeadHtml = (seoData) => {
|
|
|
195
680
|
var getReactResponse = async (req, opts) => {
|
|
196
681
|
const App = opts.document.body;
|
|
197
682
|
const { getInitProps, getAfterRenderProps, getFinalProps } = opts.document;
|
|
198
|
-
const renderToStaticMarkup = await getStaticMarkupRenderer();
|
|
199
|
-
const unsuspend = {
|
|
200
|
-
cache: /* @__PURE__ */ new Map(),
|
|
201
|
-
hasPending: false
|
|
202
|
-
};
|
|
203
|
-
const processUnsuspend = async () => {
|
|
204
|
-
const pending = [...unsuspend.cache.values()].filter((e) => e.status === "pending").map((e) => e.promise);
|
|
205
|
-
await Promise.all(pending);
|
|
206
|
-
};
|
|
207
683
|
const context = {
|
|
208
|
-
head: {
|
|
209
|
-
title: "Hadars App",
|
|
210
|
-
meta: {},
|
|
211
|
-
link: {},
|
|
212
|
-
style: {},
|
|
213
|
-
script: {},
|
|
214
|
-
status: 200
|
|
215
|
-
},
|
|
216
|
-
_unsuspend: unsuspend
|
|
684
|
+
head: { title: "Hadars App", meta: {}, link: {}, style: {}, script: {}, status: 200 }
|
|
217
685
|
};
|
|
218
686
|
let props = {
|
|
219
687
|
...getInitProps ? await getInitProps(req) : {},
|
|
220
688
|
location: req.location,
|
|
221
689
|
context
|
|
222
690
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
if (unsuspend.hasPending)
|
|
234
|
-
await processUnsuspend();
|
|
235
|
-
} while (unsuspend.hasPending && ++iters < 25);
|
|
236
|
-
if (unsuspend.hasPending) {
|
|
237
|
-
console.warn("[hadars] SSR render loop hit the 25-iteration cap \u2014 some useServerData values may not be resolved. Check for data dependencies that are never fulfilled.");
|
|
238
|
-
}
|
|
239
|
-
if (getAfterRenderProps) {
|
|
240
|
-
props = await getAfterRenderProps(props, html);
|
|
241
|
-
try {
|
|
242
|
-
globalThis.__hadarsUnsuspend = unsuspend;
|
|
243
|
-
renderToStaticMarkup(/* @__PURE__ */ jsx(App, { ...{ ...props, location: req.location, context } }));
|
|
244
|
-
} finally {
|
|
245
|
-
globalThis.__hadarsUnsuspend = null;
|
|
691
|
+
const unsuspend = { cache: /* @__PURE__ */ new Map() };
|
|
692
|
+
globalThis.__hadarsUnsuspend = unsuspend;
|
|
693
|
+
try {
|
|
694
|
+
let html = await renderToString(createElement(App, props));
|
|
695
|
+
if (getAfterRenderProps) {
|
|
696
|
+
props = await getAfterRenderProps(props, html);
|
|
697
|
+
await renderToString(
|
|
698
|
+
createElement(App, { ...props, location: req.location, context })
|
|
699
|
+
);
|
|
246
700
|
}
|
|
701
|
+
} finally {
|
|
702
|
+
globalThis.__hadarsUnsuspend = null;
|
|
247
703
|
}
|
|
704
|
+
const { context: _, ...restProps } = getFinalProps ? await getFinalProps(props) : props;
|
|
248
705
|
const serverData = {};
|
|
249
|
-
for (const [
|
|
250
|
-
if (
|
|
251
|
-
serverData[
|
|
706
|
+
for (const [key, entry] of unsuspend.cache) {
|
|
707
|
+
if (entry.status === "fulfilled")
|
|
708
|
+
serverData[key] = entry.value;
|
|
252
709
|
}
|
|
253
|
-
const { context: _, ...restProps } = getFinalProps ? await getFinalProps(props) : props;
|
|
254
710
|
const clientProps = {
|
|
255
711
|
...restProps,
|
|
256
712
|
location: req.location,
|
|
257
713
|
...Object.keys(serverData).length > 0 ? { __serverData: serverData } : {}
|
|
258
714
|
};
|
|
259
|
-
const ReactPage =
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
715
|
+
const ReactPage = createElement(
|
|
716
|
+
Fragment,
|
|
717
|
+
null,
|
|
718
|
+
createElement(
|
|
719
|
+
"div",
|
|
720
|
+
{ id: "app" },
|
|
721
|
+
createElement(App, { ...props, location: req.location, context })
|
|
722
|
+
),
|
|
723
|
+
createElement("script", {
|
|
724
|
+
id: "hadars",
|
|
725
|
+
type: "application/json",
|
|
726
|
+
dangerouslySetInnerHTML: {
|
|
727
|
+
__html: JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c")
|
|
728
|
+
}
|
|
729
|
+
})
|
|
730
|
+
);
|
|
267
731
|
return {
|
|
268
732
|
ReactPage,
|
|
733
|
+
unsuspend,
|
|
269
734
|
status: context.head.status,
|
|
270
735
|
headHtml: getHeadHtml(context.head),
|
|
271
736
|
renderPayload: {
|
|
@@ -280,12 +745,12 @@ import rspack from "@rspack/core";
|
|
|
280
745
|
import ReactRefreshPlugin from "@rspack/plugin-react-refresh";
|
|
281
746
|
import path from "node:path";
|
|
282
747
|
import { fileURLToPath } from "node:url";
|
|
283
|
-
import
|
|
748
|
+
import pathMod from "node:path";
|
|
284
749
|
import { existsSync } from "node:fs";
|
|
285
750
|
var __dirname = process.cwd();
|
|
286
|
-
var packageDir =
|
|
287
|
-
var clientScriptPath =
|
|
288
|
-
var loaderPath = existsSync(
|
|
751
|
+
var packageDir = pathMod.dirname(fileURLToPath(import.meta.url));
|
|
752
|
+
var clientScriptPath = pathMod.resolve(packageDir, "template.html");
|
|
753
|
+
var loaderPath = existsSync(pathMod.resolve(packageDir, "loader.cjs")) ? pathMod.resolve(packageDir, "loader.cjs") : pathMod.resolve(packageDir, "loader.ts");
|
|
289
754
|
var getConfigBase = (mode) => {
|
|
290
755
|
const isDev = mode === "development";
|
|
291
756
|
return {
|
|
@@ -445,25 +910,21 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
445
910
|
const isServerBuild = Boolean(
|
|
446
911
|
opts.output && typeof opts.output === "object" && (opts.output.library || String(opts.output.filename || "").includes("ssr"))
|
|
447
912
|
);
|
|
913
|
+
const slimReactIndex = pathMod.resolve(packageDir, "slim-react", "index.js");
|
|
914
|
+
const slimReactJsx = pathMod.resolve(packageDir, "slim-react", "jsx-runtime.js");
|
|
448
915
|
const resolveAliases = isServerBuild ? {
|
|
449
|
-
//
|
|
450
|
-
react:
|
|
451
|
-
"react-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
"react/jsx-dev-runtime": path.resolve(process.cwd(), "node_modules", "react", "jsx-dev-runtime.js"),
|
|
455
|
-
// ensure emotion packages resolve to the project's node_modules so we don't pick up a browser-specific entry
|
|
916
|
+
// Route all React imports to slim-react for SSR.
|
|
917
|
+
react: slimReactIndex,
|
|
918
|
+
"react/jsx-runtime": slimReactJsx,
|
|
919
|
+
"react/jsx-dev-runtime": slimReactJsx,
|
|
920
|
+
// Keep emotion on the project's node_modules (server-safe entry).
|
|
456
921
|
"@emotion/react": path.resolve(process.cwd(), "node_modules", "@emotion", "react"),
|
|
457
922
|
"@emotion/server": path.resolve(process.cwd(), "node_modules", "@emotion", "server"),
|
|
458
923
|
"@emotion/cache": path.resolve(process.cwd(), "node_modules", "@emotion", "cache"),
|
|
459
924
|
"@emotion/styled": path.resolve(process.cwd(), "node_modules", "@emotion", "styled")
|
|
460
925
|
} : void 0;
|
|
461
926
|
const externals = isServerBuild ? [
|
|
462
|
-
|
|
463
|
-
"react-dom",
|
|
464
|
-
// keep common aliases external as well
|
|
465
|
-
"react/jsx-runtime",
|
|
466
|
-
"react/jsx-dev-runtime",
|
|
927
|
+
// react / react-dom are replaced by slim-react via alias above — not external.
|
|
467
928
|
// emotion should be external on server builds to avoid client/browser code
|
|
468
929
|
"@emotion/react",
|
|
469
930
|
"@emotion/server",
|
|
@@ -515,11 +976,36 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
515
976
|
plugins: [
|
|
516
977
|
new rspack.HtmlRspackPlugin({
|
|
517
978
|
publicPath: base || "/",
|
|
518
|
-
template: opts.htmlTemplate ?
|
|
979
|
+
template: opts.htmlTemplate ? pathMod.resolve(process.cwd(), opts.htmlTemplate) : clientScriptPath,
|
|
519
980
|
scriptLoading: "module",
|
|
520
981
|
filename: "out.html",
|
|
521
|
-
inject: "
|
|
982
|
+
inject: "head",
|
|
983
|
+
minify: opts.mode === "production"
|
|
522
984
|
}),
|
|
985
|
+
// Add `async` to the emitted module script so DOMContentLoaded fires
|
|
986
|
+
// as soon as HTML is parsed — without waiting for the bundle to execute.
|
|
987
|
+
// `<script type="module" async>` is valid: it downloads in parallel and
|
|
988
|
+
// executes without blocking DOMContentLoaded, while retaining module
|
|
989
|
+
// semantics (strict mode, ES imports, etc.).
|
|
990
|
+
{
|
|
991
|
+
apply(compiler) {
|
|
992
|
+
compiler.hooks.emit.tapAsync("HadarsAsyncModuleScript", (compilation, cb) => {
|
|
993
|
+
const asset = compilation.assets["out.html"];
|
|
994
|
+
if (asset) {
|
|
995
|
+
const html = asset.source();
|
|
996
|
+
const updated = html.replace(
|
|
997
|
+
/(<script\b[^>]*\btype="module"[^>]*)(>)/g,
|
|
998
|
+
(match, before, end) => before.includes("async") ? match : `${before} async${end}`
|
|
999
|
+
);
|
|
1000
|
+
compilation.assets["out.html"] = {
|
|
1001
|
+
source: () => updated,
|
|
1002
|
+
size: () => Buffer.byteLength(updated)
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
cb();
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
523
1009
|
isDev && new ReactRefreshPlugin(),
|
|
524
1010
|
includeHotPlugin && isDev && new rspack.HotModuleReplacementPlugin(),
|
|
525
1011
|
...extraPlugins
|
|
@@ -777,15 +1263,55 @@ async function tryServeFile(filePath) {
|
|
|
777
1263
|
|
|
778
1264
|
// src/build.ts
|
|
779
1265
|
import { RspackDevServer } from "@rspack/dev-server";
|
|
780
|
-
import
|
|
781
|
-
import { fileURLToPath as fileURLToPath2, pathToFileURL
|
|
782
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
1266
|
+
import pathMod2 from "node:path";
|
|
1267
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
783
1268
|
import crypto from "node:crypto";
|
|
784
1269
|
import fs from "node:fs/promises";
|
|
785
1270
|
import { existsSync as existsSync2 } from "node:fs";
|
|
786
1271
|
import os from "node:os";
|
|
787
1272
|
import { spawn } from "node:child_process";
|
|
788
1273
|
import cluster from "node:cluster";
|
|
1274
|
+
|
|
1275
|
+
// src/utils/segmentCache.ts
|
|
1276
|
+
function getStore() {
|
|
1277
|
+
const g = globalThis;
|
|
1278
|
+
if (!g.__hadarsSegmentStore) {
|
|
1279
|
+
g.__hadarsSegmentStore = /* @__PURE__ */ new Map();
|
|
1280
|
+
}
|
|
1281
|
+
return g.__hadarsSegmentStore;
|
|
1282
|
+
}
|
|
1283
|
+
function setSegment(key, html, ttl) {
|
|
1284
|
+
getStore().set(key, {
|
|
1285
|
+
html,
|
|
1286
|
+
expiresAt: ttl != null ? Date.now() + ttl : null
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
function processSegmentCache(html) {
|
|
1290
|
+
let prev;
|
|
1291
|
+
do {
|
|
1292
|
+
prev = html;
|
|
1293
|
+
html = html.replace(
|
|
1294
|
+
/<hadars-c([^>]*)>([\s\S]*?)<\/hadars-c>/g,
|
|
1295
|
+
(match, attrs, content) => {
|
|
1296
|
+
const cacheM = /data-cache="([^"]+)"/.exec(attrs);
|
|
1297
|
+
const keyM = /data-key="([^"]+)"/.exec(attrs);
|
|
1298
|
+
const ttlM = /data-ttl="(\d+)"/.exec(attrs);
|
|
1299
|
+
if (!cacheM || !keyM)
|
|
1300
|
+
return match;
|
|
1301
|
+
if (cacheM[1] === "miss") {
|
|
1302
|
+
setSegment(keyM[1], content, ttlM ? Number(ttlM[1]) : void 0);
|
|
1303
|
+
return content;
|
|
1304
|
+
}
|
|
1305
|
+
if (cacheM[1] === "hit")
|
|
1306
|
+
return content;
|
|
1307
|
+
return match;
|
|
1308
|
+
}
|
|
1309
|
+
);
|
|
1310
|
+
} while (html !== prev);
|
|
1311
|
+
return html;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// src/build.ts
|
|
789
1315
|
var encoder = new TextEncoder();
|
|
790
1316
|
async function processHtmlTemplate(templatePath) {
|
|
791
1317
|
const html = await fs.readFile(templatePath, "utf-8");
|
|
@@ -799,7 +1325,7 @@ async function processHtmlTemplate(templatePath) {
|
|
|
799
1325
|
return templatePath;
|
|
800
1326
|
await ensureHadarsTmpDir();
|
|
801
1327
|
const sourceHash = crypto.createHash("md5").update(html).digest("hex").slice(0, 8);
|
|
802
|
-
const cachedPath =
|
|
1328
|
+
const cachedPath = pathMod2.join(HADARS_TMP_DIR, `template-${sourceHash}.html`);
|
|
803
1329
|
try {
|
|
804
1330
|
await fs.access(cachedPath);
|
|
805
1331
|
return cachedPath;
|
|
@@ -827,16 +1353,6 @@ async function processHtmlTemplate(templatePath) {
|
|
|
827
1353
|
}
|
|
828
1354
|
var HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
829
1355
|
var BODY_MARKER = '<meta name="HADARS_BODY">';
|
|
830
|
-
var _renderToString = null;
|
|
831
|
-
async function getRenderToString() {
|
|
832
|
-
if (!_renderToString) {
|
|
833
|
-
const req = createRequire2(pathMod3.resolve(process.cwd(), "__hadars_fake__.js"));
|
|
834
|
-
const resolved = req.resolve("react-dom/server");
|
|
835
|
-
const mod = await import(pathToFileURL2(resolved).href);
|
|
836
|
-
_renderToString = mod.renderToString;
|
|
837
|
-
}
|
|
838
|
-
return _renderToString;
|
|
839
|
-
}
|
|
840
1356
|
var RenderWorkerPool = class {
|
|
841
1357
|
workers = [];
|
|
842
1358
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -941,19 +1457,18 @@ var RenderWorkerPool = class {
|
|
|
941
1457
|
}
|
|
942
1458
|
};
|
|
943
1459
|
async function buildSsrResponse(ReactPage, headHtml, status, getPrecontentHtml, unsuspendForRender) {
|
|
944
|
-
const renderToString = await getRenderToString();
|
|
945
1460
|
const responseStream = new ReadableStream({
|
|
946
1461
|
async start(controller) {
|
|
947
1462
|
const [precontentHtml, postContent] = await getPrecontentHtml(headHtml);
|
|
948
1463
|
controller.enqueue(encoder.encode(precontentHtml));
|
|
949
|
-
await Promise.resolve();
|
|
950
1464
|
let bodyHtml;
|
|
951
1465
|
try {
|
|
952
1466
|
globalThis.__hadarsUnsuspend = unsuspendForRender;
|
|
953
|
-
bodyHtml = renderToString(ReactPage);
|
|
1467
|
+
bodyHtml = await renderToString(ReactPage);
|
|
954
1468
|
} finally {
|
|
955
1469
|
globalThis.__hadarsUnsuspend = null;
|
|
956
1470
|
}
|
|
1471
|
+
bodyHtml = processSegmentCache(bodyHtml);
|
|
957
1472
|
controller.enqueue(encoder.encode(bodyHtml + postContent));
|
|
958
1473
|
controller.close();
|
|
959
1474
|
}
|
|
@@ -1082,7 +1597,7 @@ var __dirname2 = process.cwd();
|
|
|
1082
1597
|
var getSuffix = (mode) => mode === "development" ? `?v=${Date.now()}` : "";
|
|
1083
1598
|
var HadarsFolder = "./.hadars";
|
|
1084
1599
|
var StaticPath = `${HadarsFolder}/static`;
|
|
1085
|
-
var HADARS_TMP_DIR =
|
|
1600
|
+
var HADARS_TMP_DIR = pathMod2.join(os.tmpdir(), "hadars");
|
|
1086
1601
|
var ensureHadarsTmpDir = () => fs.mkdir(HADARS_TMP_DIR, { recursive: true });
|
|
1087
1602
|
var validateOptions = (options) => {
|
|
1088
1603
|
if (!options.entry) {
|
|
@@ -1093,8 +1608,8 @@ var validateOptions = (options) => {
|
|
|
1093
1608
|
}
|
|
1094
1609
|
};
|
|
1095
1610
|
var resolveWorkerCmd = (packageDir2) => {
|
|
1096
|
-
const tsPath =
|
|
1097
|
-
const jsPath =
|
|
1611
|
+
const tsPath = pathMod2.resolve(packageDir2, "ssr-watch.ts");
|
|
1612
|
+
const jsPath = pathMod2.resolve(packageDir2, "ssr-watch.js");
|
|
1098
1613
|
if (isBun && existsSync2(tsPath)) {
|
|
1099
1614
|
return ["bun", tsPath];
|
|
1100
1615
|
}
|
|
@@ -1128,10 +1643,10 @@ var dev = async (options) => {
|
|
|
1128
1643
|
const handleProxy = createProxyHandler(options);
|
|
1129
1644
|
const handleWS = upgradeHandler(options);
|
|
1130
1645
|
const handler = options.fetch;
|
|
1131
|
-
const entry =
|
|
1646
|
+
const entry = pathMod2.resolve(__dirname2, options.entry);
|
|
1132
1647
|
const hmrPort = options.hmrPort ?? port + 1;
|
|
1133
|
-
const packageDir2 =
|
|
1134
|
-
const clientScriptPath2 =
|
|
1648
|
+
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
1649
|
+
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.tsx");
|
|
1135
1650
|
let clientScript = "";
|
|
1136
1651
|
try {
|
|
1137
1652
|
clientScript = (await fs.readFile(clientScriptPath2, "utf-8")).replace("$_MOD_PATH$", entry + getSuffix(options.mode));
|
|
@@ -1140,15 +1655,15 @@ var dev = async (options) => {
|
|
|
1140
1655
|
throw err;
|
|
1141
1656
|
}
|
|
1142
1657
|
await ensureHadarsTmpDir();
|
|
1143
|
-
const tmpFilePath =
|
|
1658
|
+
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
1144
1659
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
1145
1660
|
let ssrBuildId = crypto.randomBytes(4).toString("hex");
|
|
1146
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(
|
|
1661
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname2, options.htmlTemplate)) : void 0;
|
|
1147
1662
|
const clientCompiler = createClientCompiler(tmpFilePath, {
|
|
1148
1663
|
target: "web",
|
|
1149
1664
|
output: {
|
|
1150
1665
|
filename: "index.js",
|
|
1151
|
-
path:
|
|
1666
|
+
path: pathMod2.resolve(__dirname2, StaticPath)
|
|
1152
1667
|
},
|
|
1153
1668
|
base: baseURL,
|
|
1154
1669
|
mode: "development",
|
|
@@ -1288,7 +1803,7 @@ var dev = async (options) => {
|
|
|
1288
1803
|
}
|
|
1289
1804
|
})();
|
|
1290
1805
|
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
1291
|
-
readyPromise.then(() => fs.readFile(
|
|
1806
|
+
readyPromise.then(() => fs.readFile(pathMod2.join(__dirname2, StaticPath, "out.html"), "utf-8"))
|
|
1292
1807
|
);
|
|
1293
1808
|
await serve(port, async (req, ctx) => {
|
|
1294
1809
|
await readyPromise;
|
|
@@ -1305,15 +1820,15 @@ var dev = async (options) => {
|
|
|
1305
1820
|
return proxied;
|
|
1306
1821
|
const url = new URL(request.url);
|
|
1307
1822
|
const path2 = url.pathname;
|
|
1308
|
-
const staticRes = await tryServeFile(
|
|
1823
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname2, StaticPath, path2));
|
|
1309
1824
|
if (staticRes)
|
|
1310
1825
|
return staticRes;
|
|
1311
|
-
const projectStaticPath =
|
|
1312
|
-
const projectRes = await tryServeFile(
|
|
1826
|
+
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
1827
|
+
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
1313
1828
|
if (projectRes)
|
|
1314
1829
|
return projectRes;
|
|
1315
|
-
const ssrComponentPath =
|
|
1316
|
-
const importPath =
|
|
1830
|
+
const ssrComponentPath = pathMod2.join(__dirname2, HadarsFolder, SSR_FILENAME);
|
|
1831
|
+
const importPath = pathToFileURL(ssrComponentPath).href + `?t=${ssrBuildId}`;
|
|
1317
1832
|
try {
|
|
1318
1833
|
const {
|
|
1319
1834
|
default: Component,
|
|
@@ -1321,7 +1836,7 @@ var dev = async (options) => {
|
|
|
1321
1836
|
getAfterRenderProps,
|
|
1322
1837
|
getFinalProps
|
|
1323
1838
|
} = await import(importPath);
|
|
1324
|
-
const { ReactPage, status, headHtml
|
|
1839
|
+
const { ReactPage, unsuspend, status, headHtml } = await getReactResponse(request, {
|
|
1325
1840
|
document: {
|
|
1326
1841
|
body: Component,
|
|
1327
1842
|
lang: "en",
|
|
@@ -1330,7 +1845,6 @@ var dev = async (options) => {
|
|
|
1330
1845
|
getFinalProps
|
|
1331
1846
|
}
|
|
1332
1847
|
});
|
|
1333
|
-
const unsuspend = renderPayload.appProps.context?._unsuspend ?? null;
|
|
1334
1848
|
return buildSsrResponse(ReactPage, headHtml, status, getPrecontentHtml, unsuspend);
|
|
1335
1849
|
} catch (err) {
|
|
1336
1850
|
console.error("[hadars] SSR render error:", err);
|
|
@@ -1344,20 +1858,20 @@ var dev = async (options) => {
|
|
|
1344
1858
|
};
|
|
1345
1859
|
var build = async (options) => {
|
|
1346
1860
|
validateOptions(options);
|
|
1347
|
-
const entry =
|
|
1348
|
-
const packageDir2 =
|
|
1349
|
-
const clientScriptPath2 =
|
|
1861
|
+
const entry = pathMod2.resolve(__dirname2, options.entry);
|
|
1862
|
+
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
1863
|
+
const clientScriptPath2 = pathMod2.resolve(packageDir2, "utils", "clientScript.js");
|
|
1350
1864
|
let clientScript = "";
|
|
1351
1865
|
try {
|
|
1352
1866
|
clientScript = (await fs.readFile(clientScriptPath2, "utf-8")).replace("$_MOD_PATH$", entry + getSuffix(options.mode));
|
|
1353
1867
|
} catch (err) {
|
|
1354
|
-
const srcClientPath =
|
|
1868
|
+
const srcClientPath = pathMod2.resolve(packageDir2, "utils", "clientScript.tsx");
|
|
1355
1869
|
clientScript = (await fs.readFile(srcClientPath, "utf-8")).replace("$_MOD_PATH$", entry + `?v=${Date.now()}`);
|
|
1356
1870
|
}
|
|
1357
1871
|
await ensureHadarsTmpDir();
|
|
1358
|
-
const tmpFilePath =
|
|
1872
|
+
const tmpFilePath = pathMod2.join(HADARS_TMP_DIR, `client-${Date.now()}.tsx`);
|
|
1359
1873
|
await fs.writeFile(tmpFilePath, clientScript);
|
|
1360
|
-
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(
|
|
1874
|
+
const resolvedHtmlTemplate = options.htmlTemplate ? await processHtmlTemplate(pathMod2.resolve(__dirname2, options.htmlTemplate)) : void 0;
|
|
1361
1875
|
console.log("Building client and server bundles in parallel...");
|
|
1362
1876
|
await Promise.all([
|
|
1363
1877
|
compileEntry(tmpFilePath, {
|
|
@@ -1365,7 +1879,7 @@ var build = async (options) => {
|
|
|
1365
1879
|
output: {
|
|
1366
1880
|
// Content hash: filename is stable when code is unchanged → better browser/CDN cache.
|
|
1367
1881
|
filename: "index.[contenthash:8].js",
|
|
1368
|
-
path:
|
|
1882
|
+
path: pathMod2.resolve(__dirname2, StaticPath)
|
|
1369
1883
|
},
|
|
1370
1884
|
base: options.baseURL,
|
|
1371
1885
|
mode: "production",
|
|
@@ -1374,11 +1888,11 @@ var build = async (options) => {
|
|
|
1374
1888
|
optimization: options.optimization,
|
|
1375
1889
|
htmlTemplate: resolvedHtmlTemplate
|
|
1376
1890
|
}),
|
|
1377
|
-
compileEntry(
|
|
1891
|
+
compileEntry(pathMod2.resolve(__dirname2, options.entry), {
|
|
1378
1892
|
output: {
|
|
1379
1893
|
iife: false,
|
|
1380
1894
|
filename: SSR_FILENAME,
|
|
1381
|
-
path:
|
|
1895
|
+
path: pathMod2.resolve(__dirname2, HadarsFolder),
|
|
1382
1896
|
publicPath: "",
|
|
1383
1897
|
library: { type: "module" }
|
|
1384
1898
|
},
|
|
@@ -1414,16 +1928,16 @@ var run = async (options) => {
|
|
|
1414
1928
|
console.log(`Starting Hadars (run) on port ${port}`);
|
|
1415
1929
|
let renderPool;
|
|
1416
1930
|
if (!isNode && workers > 1) {
|
|
1417
|
-
const packageDir2 =
|
|
1418
|
-
const workerJs =
|
|
1419
|
-
const workerTs =
|
|
1931
|
+
const packageDir2 = pathMod2.dirname(fileURLToPath2(import.meta.url));
|
|
1932
|
+
const workerJs = pathMod2.resolve(packageDir2, "ssr-render-worker.js");
|
|
1933
|
+
const workerTs = pathMod2.resolve(packageDir2, "ssr-render-worker.ts");
|
|
1420
1934
|
const workerFile = existsSync2(workerJs) ? workerJs : workerTs;
|
|
1421
|
-
const ssrBundlePath =
|
|
1935
|
+
const ssrBundlePath = pathMod2.resolve(__dirname2, HadarsFolder, SSR_FILENAME);
|
|
1422
1936
|
renderPool = new RenderWorkerPool(workerFile, workers, ssrBundlePath);
|
|
1423
1937
|
console.log(`[hadars] SSR render pool: ${workers} worker threads`);
|
|
1424
1938
|
}
|
|
1425
1939
|
const getPrecontentHtml = makePrecontentHtmlGetter(
|
|
1426
|
-
fs.readFile(
|
|
1940
|
+
fs.readFile(pathMod2.join(__dirname2, StaticPath, "out.html"), "utf-8")
|
|
1427
1941
|
);
|
|
1428
1942
|
const runHandler = async (req, ctx) => {
|
|
1429
1943
|
const request = parseRequest(req);
|
|
@@ -1439,23 +1953,23 @@ var run = async (options) => {
|
|
|
1439
1953
|
return proxied;
|
|
1440
1954
|
const url = new URL(request.url);
|
|
1441
1955
|
const path2 = url.pathname;
|
|
1442
|
-
const staticRes = await tryServeFile(
|
|
1956
|
+
const staticRes = await tryServeFile(pathMod2.join(__dirname2, StaticPath, path2));
|
|
1443
1957
|
if (staticRes)
|
|
1444
1958
|
return staticRes;
|
|
1445
|
-
const projectStaticPath =
|
|
1446
|
-
const projectRes = await tryServeFile(
|
|
1959
|
+
const projectStaticPath = pathMod2.resolve(process.cwd(), "static");
|
|
1960
|
+
const projectRes = await tryServeFile(pathMod2.join(projectStaticPath, path2));
|
|
1447
1961
|
if (projectRes)
|
|
1448
1962
|
return projectRes;
|
|
1449
1963
|
const routeClean = path2.replace(/(^\/|\/$)/g, "");
|
|
1450
1964
|
if (routeClean) {
|
|
1451
1965
|
const routeRes = await tryServeFile(
|
|
1452
|
-
|
|
1966
|
+
pathMod2.join(__dirname2, StaticPath, routeClean, "index.html")
|
|
1453
1967
|
);
|
|
1454
1968
|
if (routeRes)
|
|
1455
1969
|
return routeRes;
|
|
1456
1970
|
}
|
|
1457
|
-
const componentPath =
|
|
1458
|
-
|
|
1971
|
+
const componentPath = pathToFileURL(
|
|
1972
|
+
pathMod2.resolve(__dirname2, HadarsFolder, SSR_FILENAME)
|
|
1459
1973
|
).href;
|
|
1460
1974
|
try {
|
|
1461
1975
|
const {
|
|
@@ -1473,7 +1987,7 @@ var run = async (options) => {
|
|
|
1473
1987
|
status: wStatus
|
|
1474
1988
|
});
|
|
1475
1989
|
}
|
|
1476
|
-
const { ReactPage, status, headHtml
|
|
1990
|
+
const { ReactPage, unsuspend, status, headHtml } = await getReactResponse(request, {
|
|
1477
1991
|
document: {
|
|
1478
1992
|
body: Component,
|
|
1479
1993
|
lang: "en",
|
|
@@ -1482,7 +1996,6 @@ var run = async (options) => {
|
|
|
1482
1996
|
getFinalProps
|
|
1483
1997
|
}
|
|
1484
1998
|
});
|
|
1485
|
-
const unsuspend = renderPayload.appProps.context?._unsuspend ?? null;
|
|
1486
1999
|
return buildSsrResponse(ReactPage, headHtml, status, getPrecontentHtml, unsuspend);
|
|
1487
2000
|
} catch (err) {
|
|
1488
2001
|
console.error("[hadars] SSR render error:", err);
|