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 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-02 · 120s · 100 connections · Bun runtime
25
- > hadars is **9.3x faster** in requests/sec
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 | **158** | 17 |
32
- | Latency median | **634 ms** | 2754 ms |
33
- | Latency p99 | **1031 ms** | 4140 ms |
34
- | Throughput | **44.97** MB/s | 9.67 MB/s |
35
- | Peak RSS | 1001.1 MB | **477.2 MB** |
36
- | Avg RSS | 778.8 MB | **426.8 MB** |
37
- | Build time | 0.6 s | 6.0 s |
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 | **17 ms** | 45 ms |
44
- | FCP | **92 ms** | 140 ms |
45
- | DOMContentLoaded | **37 ms** | 127 ms |
46
- | Load | **118 ms** | 172 ms |
47
- | Peak RSS | 479.5 MB | **295.5 MB** |
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
- const c = context;
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 c = context;
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
- let id = "_R_" + st.idPrefix + treeId;
152
- if (n > 0) id += "H" + n.toString(32);
153
- return id + "_";
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 _reactInternalsKey = "__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
247
- var _internals = ReactNS[_reactInternalsKey];
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
- if (!_internals) return null;
276
- const prev = _internals.H;
277
- _internals.H = slimDispatcher;
278
- return prev;
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
- if (_internals) _internals.H = prev;
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
- if (typeOf === REACT_CONSUMER) {
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 = "19.1.1";
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
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  renderPreflight,
3
3
  renderToString
4
- } from "./chunk-2TMQUXFL.js";
4
+ } from "./chunk-BNBZ3XYX.js";
5
5
  import {
6
6
  createElement
7
7
  } from "./chunk-OZUZS2PD.js";