From 677e53d4dbcaa148ee5ebed0de86443c3abe254b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Wed, 14 Jul 2021 16:18:52 +0200 Subject: [PATCH] perf(v2): lazy collapsibles, reduce html output and build times (#5136) * Allow collapsible to be lazy * cleanup comments * CollapsibleLazy little bug --- .../src/theme/DocSidebarItem/index.tsx | 2 +- .../theme/NavbarItem/DefaultNavbarItem.tsx | 3 +- .../src/theme/TOCCollapsible/index.tsx | 1 + .../src/utils/useCollapsible.tsx | 54 ++++++++++++++++--- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx index a5c1b2b936..117b6a57d1 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/index.tsx @@ -141,7 +141,7 @@ function DocSidebarItemCategory({ {label} - + {props.children ?? props.label} - + + {items.map(({className: childItemClassName, ...childItemProps}, i) => (
  • diff --git a/packages/docusaurus-theme-common/src/utils/useCollapsible.tsx b/packages/docusaurus-theme-common/src/utils/useCollapsible.tsx index a4efd49ab0..fd29fbc825 100644 --- a/packages/docusaurus-theme-common/src/utils/useCollapsible.tsx +++ b/packages/docusaurus-theme-common/src/utils/useCollapsible.tsx @@ -15,6 +15,7 @@ import React, { Dispatch, SetStateAction, ReactNode, + useLayoutEffect, } from 'react'; const DefaultAnimationEasing = 'ease-in-out'; @@ -158,19 +159,21 @@ function getSSRStyle(collapsed: boolean) { return collapsed ? CollapsedStyles : ExpandedStyles; } -export function Collapsible({ +type CollapsibleBaseProps = { + as?: CollapsibleElementType; + collapsed: boolean; + children: ReactNode; + animation?: CollapsibleAnimationConfig; + className?: string; +}; + +function CollapsibleBase({ as: As = 'div', collapsed, children, animation, className, -}: { - as?: CollapsibleElementType; // TODO better typing, allow any html element (keyof JSX.IntrinsicElement => not working) - collapsed: boolean; - children: ReactNode; - animation?: CollapsibleAnimationConfig; - className?: string; -}) { +}: CollapsibleBaseProps) { // any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914 const collapsibleRef = useRef(null); @@ -205,3 +208,38 @@ export function Collapsible({ ); } + +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 ? ( + + ) : 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 ; +}