hadars 0.4.2 → 0.4.3-rc.1
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-FZOSW2PU.js} +80 -18
- package/dist/{chunk-NYLXE7T7.js → chunk-W5ZSLBP3.js} +1 -1
- package/dist/cli.js +332 -226
- package/dist/cloudflare.cjs +85 -34
- package/dist/cloudflare.js +3 -2
- package/dist/index.js +2 -0
- package/dist/lambda.cjs +85 -34
- package/dist/lambda.js +3 -2
- package/dist/slim-react/index.cjs +105 -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 +88 -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,22 @@ 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
|
+
var _k19 = "__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
|
|
279
|
+
var _k18 = "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED";
|
|
280
|
+
function _detect() {
|
|
281
|
+
if (_detected) return;
|
|
282
|
+
_detected = true;
|
|
283
|
+
const r19 = ReactNS[_k19];
|
|
284
|
+
if (r19) {
|
|
285
|
+
_r19 = r19;
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const raw = ReactNS[_k18];
|
|
289
|
+
if (raw?.ReactCurrentDispatcher) _r18 = raw;
|
|
290
|
+
}
|
|
248
291
|
var slimDispatcher = {
|
|
249
292
|
useId: makeId,
|
|
250
293
|
readContext: (ctx) => getContextValue(ctx),
|
|
@@ -272,13 +315,23 @@ var slimDispatcher = {
|
|
|
272
315
|
useHostTransitionStatus: () => false
|
|
273
316
|
};
|
|
274
317
|
function installDispatcher() {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
318
|
+
_detect();
|
|
319
|
+
if (_r19) {
|
|
320
|
+
const prev = _r19.H;
|
|
321
|
+
_r19.H = slimDispatcher;
|
|
322
|
+
return prev;
|
|
323
|
+
}
|
|
324
|
+
if (_r18) {
|
|
325
|
+
const prev = _r18.ReactCurrentDispatcher.current;
|
|
326
|
+
_r18.ReactCurrentDispatcher.current = slimDispatcher;
|
|
327
|
+
return prev;
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
279
330
|
}
|
|
280
331
|
function restoreDispatcher(prev) {
|
|
281
|
-
|
|
332
|
+
_detect();
|
|
333
|
+
if (_r19) _r19.H = prev;
|
|
334
|
+
else if (_r18) _r18.ReactCurrentDispatcher.current = prev;
|
|
282
335
|
}
|
|
283
336
|
|
|
284
337
|
// src/slim-react/render.ts
|
|
@@ -535,7 +588,7 @@ function writeAttributes(writer, props, isSvg, skip) {
|
|
|
535
588
|
if (isSvg && key in SVG_ATTR_MAP) {
|
|
536
589
|
attrName = SVG_ATTR_MAP[key];
|
|
537
590
|
} else {
|
|
538
|
-
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key;
|
|
591
|
+
attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key === "defaultValue" ? "value" : key === "defaultChecked" ? "checked" : key === "contentEditable" && REACT_MAJOR < 19 ? "contenteditable" : key;
|
|
539
592
|
}
|
|
540
593
|
if (value === false || value == null) {
|
|
541
594
|
if (value === false && (attrName.charCodeAt(0) === 97 && attrName.startsWith("aria-") || attrName.charCodeAt(0) === 100 && attrName.startsWith("data-"))) {
|
|
@@ -744,7 +797,8 @@ function renderComponent(type, props, writer, isSvg, _suspenseRetries = 0) {
|
|
|
744
797
|
const LazyComp = resolved?.default ?? resolved;
|
|
745
798
|
return renderComponent(LazyComp, props, writer, isSvg);
|
|
746
799
|
}
|
|
747
|
-
|
|
800
|
+
const isConsumer = typeOf === REACT_CONSUMER || typeOf === REACT_CONTEXT && "_context" in type && !("value" in props);
|
|
801
|
+
if (isConsumer) {
|
|
748
802
|
const ctx2 = type._context;
|
|
749
803
|
const value = ctx2 ? getContextValue(ctx2) : void 0;
|
|
750
804
|
const result2 = typeof props.children === "function" ? props.children(value) : null;
|
|
@@ -1130,7 +1184,12 @@ var Component = class {
|
|
|
1130
1184
|
};
|
|
1131
1185
|
var PureComponent = class extends Component {
|
|
1132
1186
|
};
|
|
1133
|
-
var version =
|
|
1187
|
+
var version = REACT_VERSION;
|
|
1188
|
+
var __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
|
|
1189
|
+
ReactCurrentDispatcher: { current: null },
|
|
1190
|
+
ReactCurrentBatchConfig: { transition: null },
|
|
1191
|
+
ReactCurrentOwner: { current: null }
|
|
1192
|
+
};
|
|
1134
1193
|
var React = {
|
|
1135
1194
|
// Hooks
|
|
1136
1195
|
useState,
|
|
@@ -1174,7 +1233,9 @@ var React = {
|
|
|
1174
1233
|
renderToReadableStream: renderToStream,
|
|
1175
1234
|
renderPreflight,
|
|
1176
1235
|
// Version
|
|
1177
|
-
version
|
|
1236
|
+
version,
|
|
1237
|
+
// React 18 internals
|
|
1238
|
+
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
1178
1239
|
};
|
|
1179
1240
|
var slim_react_default = React;
|
|
1180
1241
|
|
|
@@ -1213,5 +1274,6 @@ export {
|
|
|
1213
1274
|
Component,
|
|
1214
1275
|
PureComponent,
|
|
1215
1276
|
version,
|
|
1277
|
+
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
|
|
1216
1278
|
slim_react_default
|
|
1217
1279
|
};
|