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 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,22 @@ 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
+ 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
- if (!_internals) return null;
276
- const prev = _internals.H;
277
- _internals.H = slimDispatcher;
278
- return prev;
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
- if (_internals) _internals.H = prev;
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
- if (typeOf === REACT_CONSUMER) {
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 = "19.1.1";
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
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  renderPreflight,
3
3
  renderToString
4
- } from "./chunk-2TMQUXFL.js";
4
+ } from "./chunk-FZOSW2PU.js";
5
5
  import {
6
6
  createElement
7
7
  } from "./chunk-OZUZS2PD.js";