mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-06 12:52:31 +02:00
perf(v2): lazy collapsibles, reduce html output and build times (#5136)
* Allow collapsible to be lazy * cleanup comments * CollapsibleLazy little bug
This commit is contained in:
parent
04bcdbd3e1
commit
677e53d4db
4 changed files with 50 additions and 10 deletions
|
@ -141,7 +141,7 @@ function DocSidebarItemCategory({
|
||||||
{label}
|
{label}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<Collapsible as="ul" className="menu__list" collapsed={collapsed}>
|
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||||
<DocSidebarItems
|
<DocSidebarItems
|
||||||
items={items}
|
items={items}
|
||||||
tabIndex={collapsed ? -1 : 0}
|
tabIndex={collapsed ? -1 : 0}
|
||||||
|
|
|
@ -209,7 +209,8 @@ function NavItemMobile({
|
||||||
}}>
|
}}>
|
||||||
{props.children ?? props.label}
|
{props.children ?? props.label}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<Collapsible as="ul" className="menu__list" collapsed={collapsed}>
|
|
||||||
|
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||||
{items.map(({className: childItemClassName, ...childItemProps}, i) => (
|
{items.map(({className: childItemClassName, ...childItemProps}, i) => (
|
||||||
<li className="menu__list-item" key={i}>
|
<li className="menu__list-item" key={i}>
|
||||||
<NavLink
|
<NavLink
|
||||||
|
|
|
@ -40,6 +40,7 @@ export default function TOCCollapsible({toc, className}: TOCCollapsibleProps) {
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Collapsible
|
<Collapsible
|
||||||
|
lazy
|
||||||
className={styles.tocCollapsibleContent}
|
className={styles.tocCollapsibleContent}
|
||||||
collapsed={collapsed}>
|
collapsed={collapsed}>
|
||||||
<TOCHeadings toc={toc} />
|
<TOCHeadings toc={toc} />
|
||||||
|
|
|
@ -15,6 +15,7 @@ import React, {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
|
useLayoutEffect,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
const DefaultAnimationEasing = 'ease-in-out';
|
const DefaultAnimationEasing = 'ease-in-out';
|
||||||
|
@ -158,19 +159,21 @@ function getSSRStyle(collapsed: boolean) {
|
||||||
return collapsed ? CollapsedStyles : ExpandedStyles;
|
return collapsed ? CollapsedStyles : ExpandedStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Collapsible({
|
type CollapsibleBaseProps = {
|
||||||
|
as?: CollapsibleElementType;
|
||||||
|
collapsed: boolean;
|
||||||
|
children: ReactNode;
|
||||||
|
animation?: CollapsibleAnimationConfig;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CollapsibleBase({
|
||||||
as: As = 'div',
|
as: As = 'div',
|
||||||
collapsed,
|
collapsed,
|
||||||
children,
|
children,
|
||||||
animation,
|
animation,
|
||||||
className,
|
className,
|
||||||
}: {
|
}: CollapsibleBaseProps) {
|
||||||
as?: CollapsibleElementType; // TODO better typing, allow any html element (keyof JSX.IntrinsicElement => not working)
|
|
||||||
collapsed: boolean;
|
|
||||||
children: ReactNode;
|
|
||||||
animation?: CollapsibleAnimationConfig;
|
|
||||||
className?: string;
|
|
||||||
}) {
|
|
||||||
// any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
|
// any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
|
||||||
const collapsibleRef = useRef<any>(null);
|
const collapsibleRef = useRef<any>(null);
|
||||||
|
|
||||||
|
@ -205,3 +208,38 @@ export function Collapsible({
|
||||||
</As>
|
</As>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
|
||||||
|
const [mounted, setMounted] = useState(!collapsed);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!collapsed) {
|
||||||
|
setMounted(true);
|
||||||
|
}
|
||||||
|
}, [collapsed]);
|
||||||
|
|
||||||
|
// lazyCollapsed updated in effect so that the first expansion transition can work
|
||||||
|
const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (mounted) {
|
||||||
|
setLazyCollapsed(collapsed);
|
||||||
|
}
|
||||||
|
}, [mounted, collapsed]);
|
||||||
|
|
||||||
|
return mounted ? (
|
||||||
|
<CollapsibleBase {...props} collapsed={lazyCollapsed} />
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type CollapsibleProps = CollapsibleBaseProps & {
|
||||||
|
// Lazy allows to delay the rendering when collapsed => it will render children only after hydration, on first expansion
|
||||||
|
// Required prop: it forces to think if content should be server-rendered or not!
|
||||||
|
// This has perf impact on the SSR output and html file sizes
|
||||||
|
// See https://github.com/facebook/docusaurus/issues/4753
|
||||||
|
lazy: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Collapsible({lazy, ...props}: CollapsibleProps) {
|
||||||
|
const Comp = lazy ? CollapsibleLazy : CollapsibleBase;
|
||||||
|
return <Comp {...props} />;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue