Skip to content

Commit 2e2f803

Browse files
committed
docs: Fix blog hydration error
1 parent 751c63a commit 2e2f803

File tree

10 files changed

+85
-38
lines changed

10 files changed

+85
-38
lines changed

docs/core/concepts/normalization.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ library, which has less features, but similar schema definitions.
385385
Memoization is done at every entity level - no matter how nested, ensuring global referential equality guarantees
386386
and up to 20x performance even after [mutation operations](../getting-started/mutations.md) like Create, Update and Delete.
387387

388+
<center>
389+
388390
<Grid>
389391

390392
```mermaid
@@ -405,8 +407,6 @@ xychart-beta
405407

406408
</Grid>
407409

408-
<center>
409-
410410
[View benchmark](https://github.com/reactive/data-client/blob/master/examples/benchmark)
411411

412412
</center>

website/blog/.cursor/rules/blog-posts.mdc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ When documenting performance gains:
113113
3. **Link evidence** - Reference the PR implementing the optimization and relevant docs
114114
4. **Visualize with mermaid chart** - Use `xychart-beta` bar chart comparing operations:
115115

116+
<div style={{maxWidth:'600px'}}>
116117
```mermaid
117118
xychart-beta
118119
title "Performance vs vX.Y"
@@ -121,6 +122,7 @@ xychart-beta
121122
bar [new_values]
122123
bar [baseline_100s]
123124
```
125+
</div>
124126

125127
5. **Include benchmark links** - End with centered links to live benchmarks and source:
126128

website/blog/2024-04-08-v0.11-queries-querable-usequery.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ image: /img/social/0.11-card.png
66
description: 0.11 of Data Client brings new memoized direct schema access to the store with any Queryable Schema with the useQuery hook
77
---
88

9-
import Grid from '@site/src/components/Grid';
109
import Link from '@docusaurus/Link';
1110

1211
Besides the performance and data integrity benefits of [normalizing the state](https://react.dev/learn/choosing-the-state-structure),
@@ -256,6 +255,9 @@ decent boost of 2x to the most common operations. With the addition of [query ca
256255

257256
These adds to the existing (up to 23x) [lead over the legacy normalizr](/docs/concepts/normalization#benchmarks) library.
258257

258+
<center>
259+
<div style={{maxWidth:'600px'}}>
260+
259261
```mermaid
260262
xychart-beta
261263
title "Performance vs v0.10"
@@ -265,7 +267,7 @@ xychart-beta
265267
bar [100, 100, 100, 100, 100]
266268
```
267269

268-
<center>
270+
</div>
269271

270272
[Benchmarks over time](https://reactive.github.io/data-client/dev/bench/) | [View benchmark](https://github.com/reactive/data-client/tree/master/examples/benchmark)
271273

website/blog/2024-07-13-v0.14-release-announcement.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ Internal schema interface changes provide a **10% normalization performance boos
207207

208208
Using `Map` instead of plain objects for entity storage provides up to **32% faster lookups** for large datasets. [#3390](https://github.com/reactive/data-client/pull/3390)
209209

210+
<center>
211+
<div style={{maxWidth:'500px'}}>
212+
210213
```mermaid
211214
xychart-beta
212215
title "Performance vs v0.13"
@@ -216,7 +219,7 @@ xychart-beta
216219
bar [100, 100, 100]
217220
```
218221

219-
<center>
222+
</div>
220223

221224
[Benchmarks over time](https://reactive.github.io/data-client/dev/bench/) | [View benchmark](https://github.com/reactive/data-client/tree/master/examples/benchmark)
222225

website/blog/2025-01-XX-v0.15-vue-support-collection-remove.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ import {
228228

229229
Removing ImmutableJS auto-detection overhead and optimizing denormalization code paths provides a **10-20% improvement** for get/denormalize operations. [#3421](https://github.com/reactive/data-client/pull/3421), [#3468](https://github.com/reactive/data-client/pull/3468)
230230

231+
<center>
232+
<div style={{maxWidth:'500px'}}>
233+
231234
```mermaid
232235
xychart-beta
233236
title "Performance vs v0.14"
@@ -237,7 +240,7 @@ xychart-beta
237240
bar [100, 100, 100]
238241
```
239242

240-
<center>
243+
</div>
241244

242245
[Benchmarks over time](https://reactive.github.io/data-client/dev/bench/) | [View benchmark](https://github.com/reactive/data-client/tree/master/examples/benchmark)
243246

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import DiffEditorMonaco, { type DiffMonacoProps } from './DiffEditorMonaco';
2-
import usingMonaco from './Playground/usingMonaco';
1+
import DiffEditorMonaco from './DiffEditorMonaco';
32

4-
const DiffEditorChooser =
5-
usingMonaco ? DiffEditorMonaco : ({ fallback }: DiffMonacoProps) => fallback;
3+
// Always use DiffEditorMonaco which handles SSR via <BrowserOnly>
4+
// The mobile/bot detection is handled inside DiffEditorMonaco
5+
const DiffEditorChooser = DiffEditorMonaco;
66
export default DiffEditorChooser;

website/src/components/DiffEditorMonaco.tsx

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type editor } from 'monaco-editor';
55
import { useMemo } from 'react';
66

77
import { extensionToMonacoLanguage } from './Playground/extensionToMonacoLanguage';
8+
import { isMobileOrBot } from './Playground/isMobileOrBot';
89
import { options } from './Playground/monacoOptions';
910
import MonacoPreloads from './Playground/MonacoPreloads';
1011
import styles from './Playground/styles.module.css';
@@ -30,37 +31,43 @@ export default function DiffEditor({
3031
return (
3132
<>
3233
<BrowserOnly fallback={fallback}>
33-
{() => (
34-
<div
35-
className={clsx(
36-
styles.playgroundContainer,
37-
styles.standaloneEditor,
38-
)}
39-
>
40-
<div className={styles.playgroundTextEdit}>
41-
<div className={clsx(styles.playgroundEditor)}>
42-
<BaseDiffEditor
43-
language={extensionToMonacoLanguage(codeTabs[0].language)}
44-
original={original}
45-
modified={modified}
46-
options={DIFF_OPTIONS}
47-
onMount={handleMount}
48-
height={height}
49-
theme="prism"
50-
loading={fallback}
51-
/>
34+
{() => {
35+
// Skip Monaco for mobile/bots - use static fallback
36+
if (isMobileOrBot()) {
37+
return fallback;
38+
}
39+
return (
40+
<div
41+
className={clsx(
42+
styles.playgroundContainer,
43+
styles.standaloneEditor,
44+
)}
45+
>
46+
<div className={styles.playgroundTextEdit}>
47+
<div className={clsx(styles.playgroundEditor)}>
48+
<BaseDiffEditor
49+
language={extensionToMonacoLanguage(codeTabs[0].language)}
50+
original={original}
51+
modified={modified}
52+
options={DIFF_OPTIONS}
53+
onMount={handleMount}
54+
height={height}
55+
theme="prism"
56+
loading={fallback}
57+
/>
58+
</div>
5259
</div>
5360
</div>
54-
</div>
55-
)}
61+
);
62+
}}
5663
</BrowserOnly>
5764
<MonacoPreloads />
5865
</>
5966
);
6067
}
6168

6269
export type DiffMonacoProps = {
63-
fallback: JSX.Element;
70+
fallback: React.ReactNode;
6471
codes: string[];
6572
codeTabs: {
6673
[k: string]: any;
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import PlaygroundLiveEditor from './PlaygroundLiveEditor';
22
import PlaygroundMonacoEditor from './PlaygroundMonacoEditor';
3-
import usingMonaco from './usingMonaco';
43

5-
const PlaygroundEditor =
6-
usingMonaco ? PlaygroundMonacoEditor : PlaygroundLiveEditor;
4+
// Always use Monaco editor wrapper - mobile/bot check happens inside
5+
// This avoids hydration mismatch from module-level navigator checks
6+
const PlaygroundEditor = PlaygroundMonacoEditor;
77
export default PlaygroundEditor;
8+
9+
// Re-export for use as fallback inside Monaco editor
10+
export { PlaygroundLiveEditor };

website/src/components/Playground/PlaygroundMonacoEditor.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import { LiveEditor } from 'react-live';
77
import './monaco-init';
88

99
import { extensionToMonacoLanguage } from './extensionToMonacoLanguage';
10+
import { isMobileOrBot } from './isMobileOrBot';
1011
import { largeOptions, options } from './monacoOptions';
12+
import PlaygroundLiveEditor from './PlaygroundLiveEditor';
1113
import useAutoHeight from './useAutoHeight';
1214

1315
export default function PlaygroundMonacoEditor({
@@ -22,7 +24,18 @@ export default function PlaygroundMonacoEditor({
2224
isFocused = false,
2325
language = 'tsx',
2426
readOnly = false,
25-
...rest
27+
}: {
28+
onChange: (value: string | undefined) => void;
29+
code: string;
30+
path?: string;
31+
onFocus: (tabIndex: number) => void;
32+
tabIndex: number;
33+
highlights?: string;
34+
autoFocus?: boolean;
35+
large?: boolean;
36+
isFocused?: boolean;
37+
language?: string;
38+
readOnly?: boolean;
2639
}) {
2740
const editorOptions = useMemo(
2841
() => ({ ...(large ? largeOptions : options), readOnly }),
@@ -43,14 +56,15 @@ export default function PlaygroundMonacoEditor({
4356
isFocused,
4457
lineHeight: editorOptions.lineHeight,
4558
});
59+
4660
const handleMount = useCallback(
4761
(editor: Monaco.editor.ICodeEditor, monaco: typeof Monaco) => {
4862
// autofocus
4963
if (autoFocus) editor.focus();
5064
// autohighlight
51-
const myhighlights = highlights && rangeParser(highlights);
65+
const myhighlights = highlights ? rangeParser(highlights) : undefined;
5266

53-
if (highlights) {
67+
if (myhighlights) {
5468
let selectionStartLineNumber = myhighlights[0];
5569
let positionLineNumber = selectionStartLineNumber;
5670
const selections: ISelection[] = [];
@@ -88,6 +102,13 @@ export default function PlaygroundMonacoEditor({
88102
[],
89103
);
90104

105+
// Use lightweight editor for mobile/bots
106+
// This runs inside BrowserOnly, so navigator is always defined
107+
// Check must be after hooks to satisfy React's rules of hooks
108+
if (isMobileOrBot()) {
109+
return <PlaygroundLiveEditor onChange={onChange} code={code} />;
110+
}
111+
91112
return (
92113
<Editor
93114
path={path}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** Check if current browser is mobile or a bot - must be called client-side only */
2+
export function isMobileOrBot(): boolean {
3+
return /bot|googlebot|crawler|spider|robot|crawling|Mobile|Android|BlackBerry/i.test(
4+
navigator.userAgent,
5+
);
6+
}

0 commit comments

Comments
 (0)