Skip to content

Commit e222fec

Browse files
authored
Support for client only rendering (#263)
1 parent a15e835 commit e222fec

File tree

10 files changed

+173
-92
lines changed

10 files changed

+173
-92
lines changed

.changeset/late-rivers-kick.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'docusaurus-theme-redoc': minor
3+
---
4+
5+
Add support for client only rendering

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2022 Rohit Gohri
3+
Copyright (c) 2023 Rohit Gohri
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@ See this issue, [https://github.com/facebook/docusaurus/issues/638](https://gith
5252

5353
## License
5454

55-
[MIT License. Copyright (c) 2022 Rohit Gohri](./LICENSE)
55+
[MIT License. Copyright (c) 2023 Rohit Gohri](./LICENSE)
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,37 @@
11
import React from 'react';
22
import clsx from 'clsx';
33
import '../../global';
4-
import {
5-
Redoc as RedocComponent,
6-
RedocStandalone,
7-
RedocRawOptions,
8-
} from 'redoc';
4+
import { RedocStandalone, RedocRawOptions } from 'redoc';
95
import { SpecProps } from '../../types/common';
10-
import { useSpec } from '../../utils/useSpec';
11-
import { ServerStyles } from './Styles';
6+
import { useSpecOptions } from '../../utils/useSpecOptions';
127
import './styles.css';
8+
import ServerRedoc from './ServerRedoc';
139

1410
/*!
1511
* Redocusaurus
1612
* https://redocusaurus.vercel.app/
17-
* (c) 2022 Rohit Gohri
13+
* (c) 2023 Rohit Gohri
1814
* Released under the MIT License
1915
*/
2016
function Redoc(
21-
props: SpecProps & {
17+
props: Partial<SpecProps> & {
2218
className?: string;
2319
optionsOverrides?: RedocRawOptions;
2420
},
2521
): JSX.Element {
26-
const { className, optionsOverrides, ...specProps } = props;
27-
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
28-
specProps,
29-
optionsOverrides,
30-
);
31-
22+
const { className, optionsOverrides, spec, url, themeId, isSpecFile } = props;
23+
const { options } = useSpecOptions(themeId, optionsOverrides);
3224
const isDevMode = process.env.NODE_ENV === 'development';
3325

34-
if (isDevMode && specProps.isSpecFile === false) {
26+
if ((isDevMode && isSpecFile === false) || !spec) {
3527
return (
36-
<div
37-
className={clsx([
38-
'redocusaurus',
39-
hasLogo && 'redocusaurus-has-logo',
40-
className,
41-
])}
42-
>
43-
<RedocStandalone specUrl={specProps.url} options={store.rawOptions} />
28+
<div className={clsx(['redocusaurus', className])}>
29+
<RedocStandalone specUrl={url} options={options} />
4430
</div>
4531
);
4632
}
4733

48-
return (
49-
<>
50-
<ServerStyles
51-
specProps={specProps}
52-
lightThemeOptions={lightThemeOptions}
53-
darkThemeOptions={darkThemeOptions}
54-
/>
55-
<div
56-
className={clsx([
57-
'redocusaurus',
58-
hasLogo && 'redocusaurus-has-logo',
59-
className,
60-
])}
61-
>
62-
<RedocComponent store={store} />
63-
</div>
64-
</>
65-
);
34+
return <ServerRedoc {...props} spec={spec} />;
6635
}
6736

6837
export default Redoc;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import clsx from 'clsx';
3+
import '../../global';
4+
import { Redoc as RedocComponent, RedocRawOptions } from 'redoc';
5+
import { SpecProps } from '../../types/common';
6+
import { useSpec } from '../../utils/useSpec';
7+
import { ServerStyles } from './Styles';
8+
import './styles.css';
9+
10+
/*!
11+
* Redocusaurus
12+
* https://redocusaurus.vercel.app/
13+
* (c) 2023 Rohit Gohri
14+
* Released under the MIT License
15+
*/
16+
function ServerRedoc(
17+
props: SpecProps & {
18+
className?: string;
19+
optionsOverrides?: RedocRawOptions;
20+
},
21+
): JSX.Element {
22+
const { className, optionsOverrides, ...specProps } = props;
23+
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
24+
specProps,
25+
optionsOverrides,
26+
);
27+
28+
return (
29+
<>
30+
<ServerStyles
31+
specProps={specProps}
32+
lightThemeOptions={lightThemeOptions}
33+
darkThemeOptions={darkThemeOptions}
34+
/>
35+
<div
36+
className={clsx([
37+
'redocusaurus',
38+
hasLogo && 'redocusaurus-has-logo',
39+
className,
40+
])}
41+
>
42+
<RedocComponent store={store} />
43+
</div>
44+
</>
45+
);
46+
}
47+
48+
export default ServerRedoc;

packages/docusaurus-theme-redoc/src/utils/useSpec.ts

+7-47
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,43 @@
11
import { useMemo, useEffect } from 'react';
22
import useBaseUrl from '@docusaurus/useBaseUrl';
33
import useIsBrowser from '@docusaurus/useIsBrowser';
4-
import { usePluginData } from '@docusaurus/useGlobalData';
54
import { useColorMode } from '@docusaurus/theme-common';
6-
import merge from 'lodash/merge';
75
import '../global';
86
import { AppStore, RedocRawOptions } from 'redoc';
97
import { SpecProps } from '../types/common';
10-
import { GlobalData } from '../types/options';
8+
import { useSpecOptions } from './useSpecOptions';
119

1210
// the current store singleton in the app's instance
1311
let currentStore: AppStore | null = null;
1412

1513
/**
1614
* Redocusaurus
17-
* https://rohit-gohri.github.io/redocusaurus/
18-
* (c) 2022 Rohit Gohri
15+
* https://redocusaurus.vercel.app/
16+
* (c) 2023 Rohit Gohri
1917
* Released under the MIT License
2018
*/
2119
export function useSpec(
2220
{ spec, url, themeId }: SpecProps,
2321
optionsOverrides?: RedocRawOptions,
2422
) {
23+
const specOptions = useSpecOptions(themeId, optionsOverrides);
2524
const fullUrl = useBaseUrl(url, { absolute: true });
2625
const isBrowser = useIsBrowser();
2726
const isDarkTheme = useColorMode().colorMode === 'dark';
28-
const themeOptions = usePluginData(
29-
'docusaurus-theme-redoc',
30-
themeId,
31-
) as GlobalData;
3227

3328
const result = useMemo(() => {
34-
const { lightTheme, darkTheme, options: redocOptions } = themeOptions;
35-
36-
const commonOptions: Partial<RedocRawOptions> = {
37-
// Disable offset when server rendering and set to selector
38-
scrollYOffset:
39-
!isBrowser && typeof redocOptions.scrollYOffset === 'string'
40-
? 0
41-
: redocOptions.scrollYOffset,
42-
};
43-
44-
const lightThemeOptions: RedocRawOptions = merge(
45-
{
46-
...redocOptions,
47-
...commonOptions,
48-
theme: lightTheme,
49-
},
50-
optionsOverrides,
51-
);
52-
53-
const darkThemeOptions: RedocRawOptions = merge(
54-
{
55-
...redocOptions,
56-
...commonOptions,
57-
theme: darkTheme,
58-
},
59-
optionsOverrides,
60-
);
61-
6229
if (currentStore !== null && isBrowser) {
6330
currentStore.dispose();
6431
}
65-
66-
currentStore = new AppStore(
67-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
68-
spec as any,
69-
fullUrl,
70-
isBrowser && isDarkTheme ? darkThemeOptions : lightThemeOptions,
71-
);
32+
currentStore = new AppStore(spec, fullUrl, specOptions.options);
7233

7334
return {
74-
darkThemeOptions,
75-
lightThemeOptions,
35+
...specOptions,
7636
// @ts-expect-error extra prop
7737
hasLogo: !!spec.info?.['x-logo'],
7838
store: currentStore,
7939
};
80-
}, [isBrowser, spec, fullUrl, isDarkTheme, themeOptions, optionsOverrides]);
40+
}, [isBrowser, spec, fullUrl, specOptions]);
8141

8242
useEffect(() => {
8343
// to ensure that menu is properly loaded when theme gets changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useMemo } from 'react';
2+
import useIsBrowser from '@docusaurus/useIsBrowser';
3+
import {
4+
usePluginData,
5+
useAllPluginInstancesData,
6+
} from '@docusaurus/useGlobalData';
7+
import { useColorMode } from '@docusaurus/theme-common';
8+
import merge from 'lodash/merge';
9+
import '../global';
10+
import { RedocRawOptions } from 'redoc';
11+
import { SpecProps } from '../types/common';
12+
import { GlobalData } from '../types/options';
13+
14+
/**
15+
* Redocusaurus
16+
* https://redocusaurus.vercel.app/
17+
* (c) 2023 Rohit Gohri
18+
* Released under the MIT License
19+
*/
20+
export function useSpecOptions(
21+
themeId: SpecProps['themeId'] = 'theme-redoc',
22+
optionsOverrides?: RedocRawOptions,
23+
) {
24+
const isBrowser = useIsBrowser();
25+
const isDarkTheme = useColorMode().colorMode === 'dark';
26+
27+
const defaultThemeOptions = useAllPluginInstancesData(
28+
'docusaurus-theme-redoc',
29+
{
30+
failfast: true,
31+
},
32+
);
33+
const themeOptions =
34+
(usePluginData('docusaurus-theme-redoc', themeId) as GlobalData) ||
35+
Object.values(defaultThemeOptions)[0];
36+
37+
const result = useMemo(() => {
38+
const { lightTheme, darkTheme, options: redocOptions } = themeOptions;
39+
40+
const commonOptions: Partial<RedocRawOptions> = {
41+
// Disable offset when server rendering and set to selector
42+
scrollYOffset:
43+
!isBrowser && typeof redocOptions.scrollYOffset === 'string'
44+
? 0
45+
: redocOptions.scrollYOffset,
46+
};
47+
48+
const lightThemeOptions: RedocRawOptions = merge(
49+
{
50+
...redocOptions,
51+
...commonOptions,
52+
theme: lightTheme,
53+
},
54+
optionsOverrides,
55+
);
56+
57+
const darkThemeOptions: RedocRawOptions = merge(
58+
{
59+
...redocOptions,
60+
...commonOptions,
61+
theme: darkTheme,
62+
},
63+
optionsOverrides,
64+
);
65+
66+
const options =
67+
isBrowser && isDarkTheme ? darkThemeOptions : lightThemeOptions;
68+
69+
return {
70+
options,
71+
darkThemeOptions,
72+
lightThemeOptions,
73+
};
74+
}, [isBrowser, isDarkTheme, themeOptions, optionsOverrides]);
75+
76+
return result;
77+
}

website/docusaurus.config.js

+4
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ const config = {
132132
label: 'Custom Layout',
133133
to: '/examples/custom-layout/',
134134
},
135+
{
136+
label: 'Client Only',
137+
to: '/examples/client-only/',
138+
},
135139
],
136140
},
137141
{

website/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"clear": "docusaurus clear",
1717
"dev": "docusaurus start",
1818
"start": "docusaurus start",
19-
"build": "docusaurus build",
19+
"build": "NODE_OPTIONS='--inspect' docusaurus build",
2020
"swizzle": "docusaurus swizzle",
2121
"serve": "docusaurus serve",
2222
"test": "percy snapshot snapshots.js"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import ApiDoc from '@theme/ApiDoc';
3+
4+
function ClientOnly() {
5+
return (
6+
<ApiDoc
7+
layoutProps={{
8+
title: `Client only page using url`,
9+
description: 'Example showcasing client only loading of yaml',
10+
}}
11+
specProps={{
12+
url: 'https://redocly.github.io/redoc/openapi.yaml',
13+
}}
14+
/>
15+
);
16+
}
17+
18+
export default ClientOnly;

0 commit comments

Comments
 (0)