hadars 0.4.2 → 0.4.3-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -14
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-2TMQUXFL.js → chunk-BNBZ3XYX.js} +78 -18
- package/dist/{chunk-NYLXE7T7.js → chunk-YCCTGINV.js} +1 -1
- package/dist/cli.js +330 -226
- package/dist/cloudflare.cjs +83 -34
- package/dist/cloudflare.js +3 -2
- package/dist/index.js +2 -0
- package/dist/lambda.cjs +83 -34
- package/dist/lambda.js +3 -2
- package/dist/slim-react/index.cjs +103 -45
- package/dist/slim-react/index.d.cts +24 -2
- package/dist/slim-react/index.d.ts +24 -2
- package/dist/slim-react/index.js +4 -1
- package/dist/slim-react/jsx-runtime.js +1 -0
- package/dist/ssr-render-worker.js +86 -37
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -21,30 +21,30 @@ Bring your own router (or none), keep your components as plain React, and get SS
|
|
|
21
21
|
## Benchmarks
|
|
22
22
|
|
|
23
23
|
<!-- BENCHMARK_START -->
|
|
24
|
-
> Last run: 2026-04-
|
|
25
|
-
> hadars is **9.
|
|
24
|
+
> Last run: 2026-04-17 · 120s · 100 connections · Bun runtime
|
|
25
|
+
> hadars is **9.5x faster** in requests/sec
|
|
26
26
|
|
|
27
27
|
**Throughput** (autocannon, 120s)
|
|
28
28
|
|
|
29
29
|
| Metric | hadars | Next.js |
|
|
30
30
|
|---|---:|---:|
|
|
31
|
-
| Requests/sec | **
|
|
32
|
-
| Latency median | **
|
|
33
|
-
| Latency p99 | **
|
|
34
|
-
| Throughput | **
|
|
35
|
-
| Peak RSS |
|
|
36
|
-
| Avg RSS |
|
|
37
|
-
| Build time |
|
|
31
|
+
| Requests/sec | **218** | 23 |
|
|
32
|
+
| Latency median | **446 ms** | 2421 ms |
|
|
33
|
+
| Latency p99 | **838 ms** | 3244 ms |
|
|
34
|
+
| Throughput | **62.07** MB/s | 12.6 MB/s |
|
|
35
|
+
| Peak RSS | 1032.7 MB | **514.0 MB** |
|
|
36
|
+
| Avg RSS | 842.2 MB | **462.8 MB** |
|
|
37
|
+
| Build time | 1.1 s | 5.3 s |
|
|
38
38
|
|
|
39
39
|
**Page load** (Playwright · Chromium headless · median)
|
|
40
40
|
|
|
41
41
|
| Metric | hadars | Next.js |
|
|
42
42
|
|---|---:|---:|
|
|
43
|
-
| TTFB | **
|
|
44
|
-
| FCP | **
|
|
45
|
-
| DOMContentLoaded | **
|
|
46
|
-
| Load | **
|
|
47
|
-
| Peak RSS |
|
|
43
|
+
| TTFB | **15 ms** | 33 ms |
|
|
44
|
+
| FCP | **76 ms** | 112 ms |
|
|
45
|
+
| DOMContentLoaded | **31 ms** | 101 ms |
|
|
46
|
+
| Load | **96 ms** | 139 ms |
|
|
47
|
+
| Peak RSS | 508.0 MB | **299.5 MB** |
|
|
48
48
|
<!-- BENCHMARK_END -->
|
|
49
49
|
|
|
50
50
|
## Quick start
|
|
@@ -240,6 +240,45 @@ const config: HadarsOptions = {
|
|
|
240
240
|
export default config;
|
|
241
241
|
```
|
|
242
242
|
|
|
243
|
+
### swcPlugins example
|
|
244
|
+
|
|
245
|
+
SWC plugins let you apply compiler transforms (Relay, emotion, styled-components, etc.) to every file in both the client and SSR bundles.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import type { HadarsOptions } from 'hadars';
|
|
249
|
+
|
|
250
|
+
const config: HadarsOptions = {
|
|
251
|
+
entry: 'src/App.tsx',
|
|
252
|
+
swcPlugins: [
|
|
253
|
+
['@swc/plugin-relay', { rootDir: process.cwd(), artifactDirectory: 'src/__generated__' }],
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export default config;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Plugin version compatibility** — SWC plugins are compiled against a specific version of `swc_core` and will silently fail or crash if the version doesn't match rspack's internal SWC. For `@rspack/core@1.6.8` the compatible plugins are:
|
|
261
|
+
|
|
262
|
+
| Plugin | Version |
|
|
263
|
+
|---|---|
|
|
264
|
+
| `@swc/plugin-relay` | `10.0.0` |
|
|
265
|
+
| `@swc/plugin-emotion` | `12.0.0` |
|
|
266
|
+
| `@swc/plugin-styled-components` | `10.0.0` |
|
|
267
|
+
| `@swc/plugin-styled-jsx` | `11.0.0` |
|
|
268
|
+
| `@swc/plugin-jest` | `10.0.0` |
|
|
269
|
+
| `@swc/plugin-formatjs` | `7.0.0` |
|
|
270
|
+
| `@swc/plugin-transform-imports` | `10.0.0` |
|
|
271
|
+
| `@swc/plugin-loadable-components` | `9.0.0` |
|
|
272
|
+
| `@swc/plugin-prefresh` | `10.0.0` |
|
|
273
|
+
| `swc-plugin-css-modules` | `6.0.0` |
|
|
274
|
+
| `swc-plugin-pre-paths` | `6.0.0` |
|
|
275
|
+
| `swc-plugin-transform-remove-imports` | `7.0.0` |
|
|
276
|
+
| `@lingui/swc-plugin` | `5.9.0` |
|
|
277
|
+
|
|
278
|
+
Install the exact version listed — do **not** use `latest` or a semver range. The full compatibility matrix for other rspack versions is at [plugins.swc.rs](https://plugins.swc.rs).
|
|
279
|
+
|
|
280
|
+
> The `@swc/core` package in hadars's `optionalDependencies` is used only by the hadars loader for its own AST transforms. It is a separate concern from the SWC version bundled inside rspack that runs your plugins.
|
|
281
|
+
|
|
243
282
|
### Error monitoring example
|
|
244
283
|
|
|
245
284
|
```ts
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
__require
|
|
10
|
+
};
|
|
@@ -6,8 +6,12 @@ import {
|
|
|
6
6
|
SUSPENSE_TYPE,
|
|
7
7
|
createElement
|
|
8
8
|
} from "./chunk-OZUZS2PD.js";
|
|
9
|
+
import {
|
|
10
|
+
__require
|
|
11
|
+
} from "./chunk-3RG5ZIWI.js";
|
|
9
12
|
|
|
10
13
|
// src/slim-react/renderContext.ts
|
|
14
|
+
import { createRequire as _nodeCreateRequire } from "module";
|
|
11
15
|
var MAP_KEY = "__slimReactContextMap";
|
|
12
16
|
var _g = globalThis;
|
|
13
17
|
if (!("__slimReactContextMap" in _g)) _g[MAP_KEY] = null;
|
|
@@ -29,8 +33,7 @@ function restoreUnsuspend(u) {
|
|
|
29
33
|
function getContextValue(context) {
|
|
30
34
|
const map = _g[MAP_KEY];
|
|
31
35
|
if (map && map.has(context)) return map.get(context);
|
|
32
|
-
|
|
33
|
-
return "_defaultValue" in c ? c._defaultValue : c._currentValue;
|
|
36
|
+
return context._currentValue;
|
|
34
37
|
}
|
|
35
38
|
function pushContextValue(context, value) {
|
|
36
39
|
let map = _g[MAP_KEY];
|
|
@@ -38,8 +41,7 @@ function pushContextValue(context, value) {
|
|
|
38
41
|
map = /* @__PURE__ */ new Map();
|
|
39
42
|
_g[MAP_KEY] = map;
|
|
40
43
|
}
|
|
41
|
-
const
|
|
42
|
-
const prev = map.has(context) ? map.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
|
|
44
|
+
const prev = map.has(context) ? map.get(context) : context._currentValue;
|
|
43
45
|
map.set(context, value);
|
|
44
46
|
return prev;
|
|
45
47
|
}
|
|
@@ -144,13 +146,40 @@ function getTreeId() {
|
|
|
144
146
|
const stripped = (id & ~(1 << 31 - Math.clz32(id))).toString(32);
|
|
145
147
|
return stripped + overflow;
|
|
146
148
|
}
|
|
149
|
+
var _detectReact = () => {
|
|
150
|
+
if (typeof __HADARS_REACT_MAJOR__ !== "undefined") {
|
|
151
|
+
const major = parseInt(String(__HADARS_REACT_MAJOR__), 10);
|
|
152
|
+
return {
|
|
153
|
+
major,
|
|
154
|
+
// Exact patch version is unknown from the define alone; use a
|
|
155
|
+
// representative fallback. Most libraries only check the major.
|
|
156
|
+
version: major < 19 ? "18.3.1" : "19.1.1"
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const parse = (ver) => ({ major: parseInt(ver.split(".")[0], 10), version: ver });
|
|
160
|
+
try {
|
|
161
|
+
return parse(__require("react").version);
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const req = _nodeCreateRequire(process.cwd() + "/__hadars__.js");
|
|
166
|
+
return parse(req("react").version);
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
return { major: 19, version: "19.1.1" };
|
|
170
|
+
};
|
|
171
|
+
var _react = _detectReact();
|
|
172
|
+
var REACT_MAJOR = _react.major;
|
|
173
|
+
var REACT_VERSION = _react.version;
|
|
147
174
|
function makeId() {
|
|
148
175
|
const st = s();
|
|
149
176
|
const treeId = getTreeId();
|
|
150
177
|
const n = st.localIdCounter++;
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
|
|
178
|
+
const suffix = n > 0 ? "H" + n.toString(32) : "";
|
|
179
|
+
if (REACT_MAJOR < 19) {
|
|
180
|
+
return ":" + st.idPrefix + "R" + treeId + suffix + ":";
|
|
181
|
+
}
|
|
182
|
+
return "_R_" + st.idPrefix + treeId + suffix + "_";
|
|
154
183
|
}
|
|
155
184
|
|
|
156
185
|
// src/slim-react/hooks.ts
|
|
@@ -243,8 +272,20 @@ function createContext(defaultValue) {
|
|
|
243
272
|
|
|
244
273
|
// src/slim-react/dispatcher.ts
|
|
245
274
|
import * as ReactNS from "react";
|
|
246
|
-
var
|
|
247
|
-
var
|
|
275
|
+
var _r19;
|
|
276
|
+
var _r18;
|
|
277
|
+
var _detected = false;
|
|
278
|
+
function _detect() {
|
|
279
|
+
if (_detected) return;
|
|
280
|
+
_detected = true;
|
|
281
|
+
const r19 = ReactNS["__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE"];
|
|
282
|
+
if (r19) {
|
|
283
|
+
_r19 = r19;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const raw = ReactNS["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"];
|
|
287
|
+
if (raw?.ReactCurrentDispatcher) _r18 = raw;
|
|
288
|
+
}
|
|
248
289
|
var slimDispatcher = {
|
|
249
290
|
useId: makeId,
|
|
250
291
|
readContext: (ctx) => getContextValue(ctx),
|
|
@@ -272,13 +313,23 @@ var slimDispatcher = {
|
|
|
272
313
|
useHostTransitionStatus: () => false
|
|
273
314
|
};
|
|
274
315
|
function installDispatcher() {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
316
|
+
_detect();
|
|
317
|
+
if (_r19) {
|
|
318
|
+
const prev = _r19.H;
|
|
319
|
+
_r19.H = slimDispatcher;
|
|
320
|
+
return prev;
|
|
321
|
+
}
|
|
322
|
+
if (_r18) {
|
|
323
|
+
const prev = _r18.ReactCurrentDispatcher.current;
|
|
324
|
+
_r18.ReactCurrentDispatcher.current = slimDispatcher;
|
|
325
|
+
return prev;
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
279
328
|
}
|
|
280
329
|
function restoreDispatcher(prev) {
|
|
281
|
-
|
|
330
|
+
_detect();
|
|
331
|
+
if (_r19) _r19.H = prev;
|
|
332
|
+
else if (_r18) _r18.ReactCurrentDispatcher.current = prev;
|
|
282
333
|
}
|
|
283
334
|
|
|
284
335
|
// src/slim-react/render.ts
|
|
@@ -535,7 +586,7 @@ function writeAttributes(writer, props, isSvg, skip) {
|
|
|
535
586
|
if (isSvg && key in SVG_ATTR_MAP) {
|
|
536
587
|
attrName = SVG_ATTR_MAP[key];
|
|
537
588
|
} else {
|
|
538
|
-
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key;
|
|
589
|
+
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key === "contentEditable" && REACT_MAJOR < 19 ? "contenteditable" : key;
|
|
539
590
|
}
|
|
540
591
|
if (value === false || value == null) {
|
|
541
592
|
if (value === false && (attrName.charCodeAt(0) === 97 && attrName.startsWith("aria-") || attrName.charCodeAt(0) === 100 && attrName.startsWith("data-"))) {
|
|
@@ -744,7 +795,8 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
744
795
|
const LazyComp = resolved?.default ?? resolved;
|
|
745
796
|
return renderComponent(LazyComp, props, writer, isSvg);
|
|
746
797
|
}
|
|
747
|
-
|
|
798
|
+
const isConsumer = typeOf === REACT_CONSUMER || typeOf === REACT_CONTEXT && "_context" in type && !("value" in props);
|
|
799
|
+
if (isConsumer) {
|
|
748
800
|
const ctx2 = type._context;
|
|
749
801
|
const value = ctx2 ? getContextValue(ctx2) : void 0;
|
|
750
802
|
const result2 = typeof props.children === "function" ? props.children(value) : null;
|
|
@@ -1130,7 +1182,12 @@ var Component = class {
|
|
|
1130
1182
|
};
|
|
1131
1183
|
var PureComponent = class extends Component {
|
|
1132
1184
|
};
|
|
1133
|
-
var version =
|
|
1185
|
+
var version = REACT_VERSION;
|
|
1186
|
+
var __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED2 = {
|
|
1187
|
+
ReactCurrentDispatcher: { current: null },
|
|
1188
|
+
ReactCurrentBatchConfig: { transition: null },
|
|
1189
|
+
ReactCurrentOwner: { current: null }
|
|
1190
|
+
};
|
|
1134
1191
|
var React = {
|
|
1135
1192
|
// Hooks
|
|
1136
1193
|
useState,
|
|
@@ -1174,7 +1231,9 @@ var React = {
|
|
|
1174
1231
|
renderToReadableStream: renderToStream,
|
|
1175
1232
|
renderPreflight,
|
|
1176
1233
|
// Version
|
|
1177
|
-
version
|
|
1234
|
+
version,
|
|
1235
|
+
// React 18 internals
|
|
1236
|
+
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED2
|
|
1178
1237
|
};
|
|
1179
1238
|
var slim_react_default = React;
|
|
1180
1239
|
|
|
@@ -1213,5 +1272,6 @@ export {
|
|
|
1213
1272
|
Component,
|
|
1214
1273
|
PureComponent,
|
|
1215
1274
|
version,
|
|
1275
|
+
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED2 as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
|
|
1216
1276
|
slim_react_default
|
|
1217
1277
|
};
|