why-hydration 0.1.5 → 0.2.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/CHANGELOG.md +50 -0
- package/README.md +85 -29
- package/dist/{chunk-AS5DZZHI.js → chunk-3OAI2ZHY.js} +253 -81
- package/dist/chunk-3OAI2ZHY.js.map +1 -0
- package/dist/{chunk-AT6A77X3.cjs → chunk-KX6G7I4Y.cjs} +261 -80
- package/dist/chunk-KX6G7I4Y.cjs.map +1 -0
- package/dist/chunk-MK3TYHKM.js +966 -0
- package/dist/chunk-MK3TYHKM.js.map +1 -0
- package/dist/chunk-R7IWOK5M.cjs +989 -0
- package/dist/chunk-R7IWOK5M.cjs.map +1 -0
- package/dist/index.cjs +25 -17
- package/dist/index.d.cts +28 -4
- package/dist/index.d.ts +28 -4
- package/dist/index.js +1 -1
- package/dist/next/index.cjs +4 -4
- package/dist/next/index.d.cts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +2 -2
- package/dist/react.cjs +4 -4
- package/dist/react.d.cts +23 -3
- package/dist/react.d.ts +23 -3
- package/dist/react.js +2 -2
- package/dist/{types-6wTih14e.d.cts → types-C14vcpBO.d.cts} +9 -0
- package/dist/{types-6wTih14e.d.ts → types-C14vcpBO.d.ts} +9 -0
- package/package.json +1 -1
- package/dist/chunk-3I6F4K4L.js +0 -642
- package/dist/chunk-3I6F4K4L.js.map +0 -1
- package/dist/chunk-AS5DZZHI.js.map +0 -1
- package/dist/chunk-AT6A77X3.cjs.map +0 -1
- package/dist/chunk-OFVFNPE6.cjs +0 -665
- package/dist/chunk-OFVFNPE6.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- The overlay now speaks Arabic, and renders right-to-left data correctly in any language.
|
|
8
|
+
|
|
9
|
+
**Arabic overlay**
|
|
10
|
+
|
|
11
|
+
- On a page whose `<html lang>` is Arabic, the whole panel is in Arabic and
|
|
12
|
+
laid out right-to-left — title, buttons, category names, explanations, fixes,
|
|
13
|
+
and the scroll hint, with correct Arabic plurals. Every other page, including
|
|
14
|
+
right-to-left pages in languages the overlay does not translate, gets the
|
|
15
|
+
English panel as before.
|
|
16
|
+
- New `overlay={{ locale: 'auto' | 'en' | 'ar' }}` option. `'auto'` is the
|
|
17
|
+
default and follows `<html lang>`.
|
|
18
|
+
- The console output and the `explanation`/`suggestion` strings in `onReport`
|
|
19
|
+
stay English and are byte-identical to 0.1.5. Every built-in cause now also
|
|
20
|
+
carries `messageId` and `params`, which is how the overlay finds the
|
|
21
|
+
translation.
|
|
22
|
+
|
|
23
|
+
**Right-to-left rendering fixes**
|
|
24
|
+
|
|
25
|
+
- Arabic values no longer have their sentence punctuation moved to the wrong
|
|
26
|
+
end. Each value cell takes its direction from its own content, in either
|
|
27
|
+
panel language.
|
|
28
|
+
- Arabic values are drawn in a proportional face instead of a monospace
|
|
29
|
+
fallback, which rendered them with their letters disconnected.
|
|
30
|
+
- Selectors, component names, file paths and attribute names are isolated
|
|
31
|
+
left-to-right, and quoted values inside explanations are isolated one by one,
|
|
32
|
+
so brackets cannot mirror and tokens cannot swap places.
|
|
33
|
+
- The panel declares its own `lang`. Previously an English panel on an Arabic
|
|
34
|
+
page inherited `lang="ar"`, so screen readers voiced it with an Arabic voice.
|
|
35
|
+
|
|
36
|
+
**Other fixes**
|
|
37
|
+
|
|
38
|
+
- Invisible bidi marks (LRM, RLM, isolates…) are drawn as labelled badges in
|
|
39
|
+
the value cells, so the bidi-mark case no longer shows two identical-looking
|
|
40
|
+
values. Value cells also preserve whitespace, so whitespace-only mismatches
|
|
41
|
+
are visible.
|
|
42
|
+
- Component attribution from a React component stack no longer names a DOM tag
|
|
43
|
+
such as `<p>`; it names the nearest component you wrote.
|
|
44
|
+
- React's bare "hydration failed" message no longer adds an empty card next to
|
|
45
|
+
a real mismatch. When it is the only signal it is still reported, with text
|
|
46
|
+
that says React did not name the node, instead of "inspect the values above".
|
|
47
|
+
- React 19 hydration errors no longer produce junk reports. React 19 prints a
|
|
48
|
+
bulleted list of possible causes above its diff tree, and each bullet was
|
|
49
|
+
read as a removed ("server") diff line — five bogus "Unknown" reports per
|
|
50
|
+
mismatch, with the real client value paired against the first bullet. Only
|
|
51
|
+
the tree after React's hydration-mismatch link is read as a diff now.
|
|
52
|
+
|
|
3
53
|
## 0.1.5
|
|
4
54
|
|
|
5
55
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -60,9 +60,10 @@ together.
|
|
|
60
60
|
incidental page noise.
|
|
61
61
|
- 🌐 **Arabic-first locale detection** — digit-script mismatches (٠١٢ vs 012)
|
|
62
62
|
are a first-class cause, not an afterthought.
|
|
63
|
-
- 🔤 **
|
|
64
|
-
|
|
65
|
-
English.
|
|
63
|
+
- 🔤 **Speaks Arabic, right-to-left** — on an Arabic page (`<html lang="ar">`)
|
|
64
|
+
the overlay is in Arabic and laid out right-to-left; everywhere else it is in
|
|
65
|
+
English. Page data renders in its own direction in both, and invisible bidi
|
|
66
|
+
marks are shown instead of hidden.
|
|
66
67
|
- 🫧 **Zero production cost** — every code path is gated behind
|
|
67
68
|
`process.env.NODE_ENV`, and CI fails the build if the production bundle for
|
|
68
69
|
any entry point isn't tree-shaken to a no-op.
|
|
@@ -339,6 +340,7 @@ A page with no mismatches renders **nothing** — no overlay, no console output.
|
|
|
339
340
|
| **✕** on the hint bar | Closes just the "scroll to see all" hint; the panel stays. |
|
|
340
341
|
| `overlay={false}` | Never mounts it at all — `onReport` and the console output still work. |
|
|
341
342
|
| `overlay={{ position }}` | `bottom-right` (default), `bottom-left`, `top-right`, `top-left`. |
|
|
343
|
+
| `overlay={{ locale }}` | `'auto'` (default) follows `<html lang>`; `'en'` or `'ar'` pins the language. See [RTL and Arabic support](#rtl-and-arabic-support). |
|
|
342
344
|
|
|
343
345
|
The overlay is a *view* over the collected reports, not the collector itself:
|
|
344
346
|
dismissing it does not stop detection, and `onReport` keeps firing. If a
|
|
@@ -373,19 +375,47 @@ both how the overlay renders and what the engine can actually detect.
|
|
|
373
375
|
|
|
374
376
|
### The overlay
|
|
375
377
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
378
|
+
**The overlay speaks the page's language.** On a page whose `<html lang>` is
|
|
379
|
+
Arabic (`ar`, `ar-SA`, `ar-EG`, …) the whole panel is in Arabic and laid out
|
|
380
|
+
right-to-left: title, buttons, category names, the explanation, the fix, and
|
|
381
|
+
the scroll hint, with correct Arabic plurals. Every other page gets the English
|
|
382
|
+
panel — including right-to-left pages in languages the overlay does not
|
|
383
|
+
translate, such as Hebrew or Persian, where it stays left-to-right rather than
|
|
384
|
+
mirroring English text. Pin it either way with `overlay={{ locale: 'en' }}` or
|
|
385
|
+
`overlay={{ locale: 'ar' }}`.
|
|
386
|
+
|
|
387
|
+
What stays English: the console output, and `cause.explanation` /
|
|
388
|
+
`cause.suggestion` in the report `onReport` receives. Those are what people log,
|
|
389
|
+
grep and paste into issues, so they do not change with the page. Each report
|
|
390
|
+
also carries `cause.messageId` and `cause.params`, which is how the overlay
|
|
391
|
+
finds the translation — and how your own tooling can, too. The "Learn more"
|
|
392
|
+
links point at this README, which is in English, and say so.
|
|
393
|
+
|
|
394
|
+
**Page data renders in its own direction, in either panel.** A mismatched value
|
|
395
|
+
can be in any script, so each value cell takes its direction from its own first
|
|
396
|
+
strong character. `السعر: ١٬٤٠٠ د.ك.` reads right-to-left with its full stop at
|
|
397
|
+
the end even inside the English panel, and `Price: 1,400 KWD.` reads
|
|
398
|
+
left-to-right inside the Arabic one. Selectors, component names, file paths and
|
|
399
|
+
attribute names are code, so they are always isolated left-to-right — otherwise
|
|
400
|
+
a right-to-left line would mirror their brackets and reorder their segments.
|
|
401
|
+
Class tokens and other values quoted inside a sentence are isolated one by one,
|
|
402
|
+
so two Arabic tokens cannot swap places. Arabic is drawn in a proportional face
|
|
403
|
+
(a monospace fallback renders it with its letters disconnected), and Arabic
|
|
404
|
+
labels are never letter-spaced or uppercased, which breaks their joining.
|
|
405
|
+
|
|
406
|
+
**What differs is what you see.** Value cells preserve whitespace, so a
|
|
407
|
+
whitespace-only mismatch no longer looks like two identical strings. Invisible
|
|
408
|
+
characters that change layout — `LRM`, `RLM`, `ALM`, the bidi embeddings and
|
|
409
|
+
isolates, zero-width space, BOM — are drawn as small labelled badges rather than
|
|
410
|
+
applied, so the [bidi-mark case](#cause-locale-format) shows a visible
|
|
411
|
+
difference instead of two cells that look the same.
|
|
412
|
+
|
|
413
|
+
**It is isolated from the page.** The panel lives in a Shadow DOM, and its
|
|
414
|
+
direction is set inside it, so nothing in the host page's CSS can flip it — the
|
|
415
|
+
`all` shorthand deliberately excludes `direction` (per spec), so
|
|
416
|
+
`:host { all: initial }` alone would not be enough. The panel also declares its
|
|
417
|
+
own `lang`, so a screen reader voices it in its own language: before this, an
|
|
418
|
+
English panel on an Arabic page was read aloud with an Arabic voice.
|
|
389
419
|
|
|
390
420
|
### Detection
|
|
391
421
|
|
|
@@ -490,6 +520,7 @@ effect setup → cleanup → setup.
|
|
|
490
520
|
```ts
|
|
491
521
|
interface OverlayOptions {
|
|
492
522
|
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'; // default 'bottom-right'
|
|
523
|
+
locale?: 'auto' | 'en' | 'ar'; // default 'auto' — follows <html lang>
|
|
493
524
|
}
|
|
494
525
|
```
|
|
495
526
|
|
|
@@ -538,9 +569,11 @@ interface HydrationReport {
|
|
|
538
569
|
cause: {
|
|
539
570
|
category: HydrationCauseCategory; // one of the categories below, or "unknown"
|
|
540
571
|
confidence: number; // 0–1
|
|
541
|
-
explanation: string;
|
|
542
|
-
suggestion: string;
|
|
572
|
+
explanation: string; // always English
|
|
573
|
+
suggestion: string; // always English
|
|
543
574
|
docsUrl?: string;
|
|
575
|
+
messageId?: string; // which message produced the text, e.g. "attribute-mismatch.class"
|
|
576
|
+
params?: Record<string, string | string[]>; // the values in it, e.g. { added: ['wide'], removed: [] }
|
|
544
577
|
};
|
|
545
578
|
raw?: { reactMessage?: string }; // the original React console message, if any
|
|
546
579
|
}
|
|
@@ -701,6 +734,13 @@ drive the visual change with a CSS media query instead of a JS class toggle.
|
|
|
701
734
|
A mismatch was detected but didn't match any of the rules above. The report
|
|
702
735
|
still shows the exact server vs. client values and node path so you can
|
|
703
736
|
diagnose it directly.
|
|
737
|
+
|
|
738
|
+
React also logs a bare "hydration failed" message that names no node at all.
|
|
739
|
+
When the DOM diff or another React message has already located the mismatch,
|
|
740
|
+
that message adds nothing and is not shown. When it is the *only* signal —
|
|
741
|
+
typically because the snapshot script is missing — it is reported once, with an
|
|
742
|
+
explanation that says React did not name the node and a fix that points at the
|
|
743
|
+
snapshot script, rather than asking you to inspect values that do not exist.
|
|
704
744
|
**Fix:** compare the two values — the cause is usually one of the categories
|
|
705
745
|
above. If you find a reliable signal for it, add a custom rule via the
|
|
706
746
|
`classify` option (see [Contributing](#contributing)).
|
|
@@ -729,9 +769,12 @@ above. If you find a reliable signal for it, add a custom rule via the
|
|
|
729
769
|
budget (`npm run size`) against a real production bundle built with webpack
|
|
730
770
|
and terser — the same toolchain Next.js and CRA use for production — and
|
|
731
771
|
fails the build if the tree-shaken output for any entry point isn't reduced
|
|
732
|
-
to a near-empty stub.
|
|
733
|
-
|
|
734
|
-
|
|
772
|
+
to a near-empty stub. The budgets sit just above today's output, so even a
|
|
773
|
+
small leak fails CI. Verified independently against Rollup, which is what
|
|
774
|
+
Vite uses for production builds: **99 B** minified + gzipped under webpack,
|
|
775
|
+
and **156 B** minified (not gzipped) under Rollup — versus ~59 KB minified
|
|
776
|
+
for the same entry built for development. The Arabic translations exist only
|
|
777
|
+
in that development build.
|
|
735
778
|
- `<HydrationSnapshotScript>` also renders `null` outside development, so no
|
|
736
779
|
snapshot script is emitted into your production HTML.
|
|
737
780
|
|
|
@@ -802,6 +845,11 @@ to the rebuilt inspector rather than lost.
|
|
|
802
845
|
suspend `requestAnimationFrame` on hidden pages, so scheduling races a frame
|
|
803
846
|
against a 50 ms timer and no longer depends on the page being painted.
|
|
804
847
|
|
|
848
|
+
**The component name in a report was a tag like `<p>`.** Fixed. React's
|
|
849
|
+
component stacks list host elements first (`at p`, `at span`), and those were
|
|
850
|
+
being taken as the component. The nearest component you wrote is used instead,
|
|
851
|
+
and when there is none the report names no component rather than a tag.
|
|
852
|
+
|
|
805
853
|
**The "Learn more →" link 404s.** The links point at this README on GitHub
|
|
806
854
|
(`github.com/razan-aboushi/why-hydration#cause-…`). If you've forked the
|
|
807
855
|
package under a different name or repository, update `DOCS_BASE` in
|
|
@@ -823,16 +871,24 @@ production. It's dev-only, runs a bounded diff across roughly 1.5 seconds
|
|
|
823
871
|
right after hydration, then stops.
|
|
824
872
|
|
|
825
873
|
**Does it work with `<html dir="rtl">`?** Yes — see
|
|
826
|
-
[RTL and Arabic support](#rtl-and-arabic-support). The
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
874
|
+
[RTL and Arabic support](#rtl-and-arabic-support). The panel's language follows
|
|
875
|
+
`<html lang>`, not `dir`: an Arabic page gets the Arabic right-to-left panel,
|
|
876
|
+
and a right-to-left page in another language gets the English left-to-right
|
|
877
|
+
one. Detection covers Arabic-script formatting mismatches on both sides, not
|
|
878
|
+
just Arabic-vs-Latin.
|
|
879
|
+
|
|
880
|
+
**I want the English panel on my Arabic site (or the reverse).** Pass
|
|
881
|
+
`overlay={{ locale: 'en' }}` (or `'ar'`). The console and `onReport` are English
|
|
882
|
+
either way.
|
|
883
|
+
|
|
884
|
+
**My Arabic app reports a mismatch between two values that look the same.** They
|
|
885
|
+
differ by invisible bidirectional control characters — `Intl` adds LRM/RLM/isolate
|
|
832
886
|
marks around numbers and dates in RTL locales, and Node's ICU and the browser's
|
|
833
887
|
ICU do not always agree on which. The report names this explicitly under
|
|
834
|
-
[`locale-format`](#cause-locale-format)
|
|
835
|
-
|
|
888
|
+
[`locale-format`](#cause-locale-format), and the overlay draws each invisible
|
|
889
|
+
mark as a small labelled badge (`RLM`, `LRM`, …) in the value cell, so you can
|
|
890
|
+
see which side has it. Format the value in one place and pass the string down,
|
|
891
|
+
or add `suppressHydrationWarning` if the marks are harmless.
|
|
836
892
|
|
|
837
893
|
---
|
|
838
894
|
|