Skip to content

Commit

Permalink
Support for client only rendering (#263)
Browse files Browse the repository at this point in the history
  • Loading branch information
rohit-gohri authored Feb 9, 2023
1 parent a15e835 commit e222fec
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 92 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-rivers-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'docusaurus-theme-redoc': minor
---

Add support for client only rendering
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Rohit Gohri
Copyright (c) 2023 Rohit Gohri

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ See this issue, [https://github.com/facebook/docusaurus/issues/638](https://gith

## License

[MIT License. Copyright (c) 2022 Rohit Gohri](./LICENSE)
[MIT License. Copyright (c) 2023 Rohit Gohri](./LICENSE)
53 changes: 11 additions & 42 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/Redoc.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,37 @@
import React from 'react';
import clsx from 'clsx';
import '../../global';
import {
Redoc as RedocComponent,
RedocStandalone,
RedocRawOptions,
} from 'redoc';
import { RedocStandalone, RedocRawOptions } from 'redoc';
import { SpecProps } from '../../types/common';
import { useSpec } from '../../utils/useSpec';
import { ServerStyles } from './Styles';
import { useSpecOptions } from '../../utils/useSpecOptions';
import './styles.css';
import ServerRedoc from './ServerRedoc';

/*!
* Redocusaurus
* https://redocusaurus.vercel.app/
* (c) 2022 Rohit Gohri
* (c) 2023 Rohit Gohri
* Released under the MIT License
*/
function Redoc(
props: SpecProps & {
props: Partial<SpecProps> & {
className?: string;
optionsOverrides?: RedocRawOptions;
},
): JSX.Element {
const { className, optionsOverrides, ...specProps } = props;
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
specProps,
optionsOverrides,
);

const { className, optionsOverrides, spec, url, themeId, isSpecFile } = props;
const { options } = useSpecOptions(themeId, optionsOverrides);
const isDevMode = process.env.NODE_ENV === 'development';

if (isDevMode && specProps.isSpecFile === false) {
if ((isDevMode && isSpecFile === false) || !spec) {
return (
<div
className={clsx([
'redocusaurus',
hasLogo && 'redocusaurus-has-logo',
className,
])}
>
<RedocStandalone specUrl={specProps.url} options={store.rawOptions} />
<div className={clsx(['redocusaurus', className])}>
<RedocStandalone specUrl={url} options={options} />
</div>
);
}

return (
<>
<ServerStyles
specProps={specProps}
lightThemeOptions={lightThemeOptions}
darkThemeOptions={darkThemeOptions}
/>
<div
className={clsx([
'redocusaurus',
hasLogo && 'redocusaurus-has-logo',
className,
])}
>
<RedocComponent store={store} />
</div>
</>
);
return <ServerRedoc {...props} spec={spec} />;
}

export default Redoc;
48 changes: 48 additions & 0 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/ServerRedoc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import clsx from 'clsx';
import '../../global';
import { Redoc as RedocComponent, RedocRawOptions } from 'redoc';
import { SpecProps } from '../../types/common';
import { useSpec } from '../../utils/useSpec';
import { ServerStyles } from './Styles';
import './styles.css';

/*!
* Redocusaurus
* https://redocusaurus.vercel.app/
* (c) 2023 Rohit Gohri
* Released under the MIT License
*/
function ServerRedoc(
props: SpecProps & {
className?: string;
optionsOverrides?: RedocRawOptions;
},
): JSX.Element {
const { className, optionsOverrides, ...specProps } = props;
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
specProps,
optionsOverrides,
);

return (
<>
<ServerStyles
specProps={specProps}
lightThemeOptions={lightThemeOptions}
darkThemeOptions={darkThemeOptions}
/>
<div
className={clsx([
'redocusaurus',
hasLogo && 'redocusaurus-has-logo',
className,
])}
>
<RedocComponent store={store} />
</div>
</>
);
}

export default ServerRedoc;
54 changes: 7 additions & 47 deletions packages/docusaurus-theme-redoc/src/utils/useSpec.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,43 @@
import { useMemo, useEffect } from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useIsBrowser from '@docusaurus/useIsBrowser';
import { usePluginData } from '@docusaurus/useGlobalData';
import { useColorMode } from '@docusaurus/theme-common';
import merge from 'lodash/merge';
import '../global';
import { AppStore, RedocRawOptions } from 'redoc';
import { SpecProps } from '../types/common';
import { GlobalData } from '../types/options';
import { useSpecOptions } from './useSpecOptions';

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

/**
* Redocusaurus
* https://rohit-gohri.github.io/redocusaurus/
* (c) 2022 Rohit Gohri
* https://redocusaurus.vercel.app/
* (c) 2023 Rohit Gohri
* Released under the MIT License
*/
export function useSpec(
{ spec, url, themeId }: SpecProps,
optionsOverrides?: RedocRawOptions,
) {
const specOptions = useSpecOptions(themeId, optionsOverrides);
const fullUrl = useBaseUrl(url, { absolute: true });
const isBrowser = useIsBrowser();
const isDarkTheme = useColorMode().colorMode === 'dark';
const themeOptions = usePluginData(
'docusaurus-theme-redoc',
themeId,
) as GlobalData;

const result = useMemo(() => {
const { lightTheme, darkTheme, options: redocOptions } = themeOptions;

const commonOptions: Partial<RedocRawOptions> = {
// Disable offset when server rendering and set to selector
scrollYOffset:
!isBrowser && typeof redocOptions.scrollYOffset === 'string'
? 0
: redocOptions.scrollYOffset,
};

const lightThemeOptions: RedocRawOptions = merge(
{
...redocOptions,
...commonOptions,
theme: lightTheme,
},
optionsOverrides,
);

const darkThemeOptions: RedocRawOptions = merge(
{
...redocOptions,
...commonOptions,
theme: darkTheme,
},
optionsOverrides,
);

if (currentStore !== null && isBrowser) {
currentStore.dispose();
}

currentStore = new AppStore(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
spec as any,
fullUrl,
isBrowser && isDarkTheme ? darkThemeOptions : lightThemeOptions,
);
currentStore = new AppStore(spec, fullUrl, specOptions.options);

return {
darkThemeOptions,
lightThemeOptions,
...specOptions,
// @ts-expect-error extra prop
hasLogo: !!spec.info?.['x-logo'],
store: currentStore,
};
}, [isBrowser, spec, fullUrl, isDarkTheme, themeOptions, optionsOverrides]);
}, [isBrowser, spec, fullUrl, specOptions]);

useEffect(() => {
// to ensure that menu is properly loaded when theme gets changed
Expand Down
77 changes: 77 additions & 0 deletions packages/docusaurus-theme-redoc/src/utils/useSpecOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useMemo } from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser';
import {
usePluginData,
useAllPluginInstancesData,
} from '@docusaurus/useGlobalData';
import { useColorMode } from '@docusaurus/theme-common';
import merge from 'lodash/merge';
import '../global';
import { RedocRawOptions } from 'redoc';
import { SpecProps } from '../types/common';
import { GlobalData } from '../types/options';

/**
* Redocusaurus
* https://redocusaurus.vercel.app/
* (c) 2023 Rohit Gohri
* Released under the MIT License
*/
export function useSpecOptions(
themeId: SpecProps['themeId'] = 'theme-redoc',
optionsOverrides?: RedocRawOptions,
) {
const isBrowser = useIsBrowser();
const isDarkTheme = useColorMode().colorMode === 'dark';

const defaultThemeOptions = useAllPluginInstancesData(
'docusaurus-theme-redoc',
{
failfast: true,
},
);
const themeOptions =
(usePluginData('docusaurus-theme-redoc', themeId) as GlobalData) ||
Object.values(defaultThemeOptions)[0];

const result = useMemo(() => {
const { lightTheme, darkTheme, options: redocOptions } = themeOptions;

const commonOptions: Partial<RedocRawOptions> = {
// Disable offset when server rendering and set to selector
scrollYOffset:
!isBrowser && typeof redocOptions.scrollYOffset === 'string'
? 0
: redocOptions.scrollYOffset,
};

const lightThemeOptions: RedocRawOptions = merge(
{
...redocOptions,
...commonOptions,
theme: lightTheme,
},
optionsOverrides,
);

const darkThemeOptions: RedocRawOptions = merge(
{
...redocOptions,
...commonOptions,
theme: darkTheme,
},
optionsOverrides,
);

const options =
isBrowser && isDarkTheme ? darkThemeOptions : lightThemeOptions;

return {
options,
darkThemeOptions,
lightThemeOptions,
};
}, [isBrowser, isDarkTheme, themeOptions, optionsOverrides]);

return result;
}
4 changes: 4 additions & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ const config = {
label: 'Custom Layout',
to: '/examples/custom-layout/',
},
{
label: 'Client Only',
to: '/examples/client-only/',
},
],
},
{
Expand Down
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"clear": "docusaurus clear",
"dev": "docusaurus start",
"start": "docusaurus start",
"build": "docusaurus build",
"build": "NODE_OPTIONS='--inspect' docusaurus build",
"swizzle": "docusaurus swizzle",
"serve": "docusaurus serve",
"test": "percy snapshot snapshots.js"
Expand Down
18 changes: 18 additions & 0 deletions website/src/pages/examples/client-only/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import ApiDoc from '@theme/ApiDoc';

function ClientOnly() {
return (
<ApiDoc
layoutProps={{
title: `Client only page using url`,
description: 'Example showcasing client only loading of yaml',
}}
specProps={{
url: 'https://redocly.github.io/redoc/openapi.yaml',
}}
/>
);
}

export default ClientOnly;

1 comment on commit e222fec

@vercel
Copy link

@vercel vercel bot commented on e222fec Feb 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.