mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-06 21:57:14 +02:00
fix(core): fix React hydration errors, change html minifier settings (#10786)
This commit is contained in:
parent
2565601af3
commit
f196a1eb29
4 changed files with 27 additions and 34 deletions
|
@ -131,21 +131,11 @@ function throwOnConsole(page: Page) {
|
||||||
const typesToCheck = ['error', 'warning'];
|
const typesToCheck = ['error', 'warning'];
|
||||||
|
|
||||||
const ignoreMessages = [
|
const ignoreMessages = [
|
||||||
// This mismatch warning looks like a React 18 bug to me
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s className "null" ""',
|
|
||||||
|
|
||||||
// TODO this fetch error message is unexpected and should be fixed
|
// TODO this fetch error message is unexpected and should be fixed
|
||||||
// it's already happening in main branch
|
// it's already happening in main branch
|
||||||
'Failed to load resource: the server responded with a status of 404 (Not Found)',
|
'Failed to load resource: the server responded with a status of 404 (Not Found)',
|
||||||
|
|
||||||
// TODO looks like a legit hydration bug to fix
|
// TODO looks like legit hydration bugs to fix
|
||||||
// on /blog/releases/2.4
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs" "/docs?docusaurus-theme=light"',
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs" "/docs?docusaurus-theme=dark"',
|
|
||||||
// on /blog/releases/3.0
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs" "/docs?docusaurus-data-navbar=false&docusaurus-data-red-border"',
|
|
||||||
// on /docs/styling-layout
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs" "/docs?docusaurus-data-navbar=false&docusaurus-data-red-border"',
|
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs/configuration" "/docs/configuration?docusaurus-theme=light"',
|
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs/configuration" "/docs/configuration?docusaurus-theme=light"',
|
||||||
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs/configuration" "/docs/configuration?docusaurus-theme=dark"',
|
'Warning: Prop `%s` did not match. Server: %s Client: %s%s href "/docs/configuration" "/docs/configuration?docusaurus-theme=dark"',
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,13 @@ async function getTerserMinifier(): Promise<HtmlMinifier> {
|
||||||
minify: async function minifyHtmlWithTerser(html) {
|
minify: async function minifyHtmlWithTerser(html) {
|
||||||
try {
|
try {
|
||||||
const code = await terserHtmlMinifier(html, {
|
const code = await terserHtmlMinifier(html, {
|
||||||
|
// When enabled => React hydration errors
|
||||||
removeComments: false,
|
removeComments: false,
|
||||||
removeRedundantAttributes: true,
|
removeRedundantAttributes: false,
|
||||||
removeEmptyAttributes: true,
|
removeEmptyAttributes: false,
|
||||||
|
sortAttributes: false,
|
||||||
|
sortClassName: false,
|
||||||
|
|
||||||
removeScriptTypeAttributes: true,
|
removeScriptTypeAttributes: true,
|
||||||
removeStyleLinkTypeAttributes: true,
|
removeStyleLinkTypeAttributes: true,
|
||||||
useShortDoctype: true,
|
useShortDoctype: true,
|
||||||
|
@ -84,8 +88,13 @@ async function getSwcMinifier(): Promise<HtmlMinifier> {
|
||||||
sortSpaceSeparatedAttributeValues: false,
|
sortSpaceSeparatedAttributeValues: false,
|
||||||
sortAttributes: false,
|
sortAttributes: false,
|
||||||
|
|
||||||
removeRedundantAttributes: 'all',
|
// When enabled => hydration error for className={"yt-lite "}
|
||||||
removeEmptyAttributes: true,
|
normalizeAttributes: false,
|
||||||
|
// When enabled => hydration error for className=""
|
||||||
|
removeEmptyAttributes: false,
|
||||||
|
// When enabled => hydration error for <a target="_self">
|
||||||
|
removeRedundantAttributes: 'none',
|
||||||
|
|
||||||
minifyJs: true,
|
minifyJs: true,
|
||||||
minifyJson: true,
|
minifyJson: true,
|
||||||
minifyCss: true,
|
minifyCss: true,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import React, {
|
||||||
type SetStateAction,
|
type SetStateAction,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import useIsomorphicLayoutEffect from '@docusaurus/useIsomorphicLayoutEffect';
|
import useIsomorphicLayoutEffect from '@docusaurus/useIsomorphicLayoutEffect';
|
||||||
import {prefersReducedMotion} from '../../utils/accessibilityUtils';
|
import {prefersReducedMotion} from '../../utils/accessibilityUtils';
|
||||||
|
|
||||||
|
@ -161,8 +161,15 @@ type CollapsibleElementType = React.ElementType<
|
||||||
* Prevent hydration layout shift before animations are handled imperatively
|
* Prevent hydration layout shift before animations are handled imperatively
|
||||||
* with JS
|
* with JS
|
||||||
*/
|
*/
|
||||||
function getSSRStyle(collapsed: boolean) {
|
function getSSRStyle({
|
||||||
if (ExecutionEnvironment.canUseDOM) {
|
collapsed,
|
||||||
|
isBrowser,
|
||||||
|
}: {
|
||||||
|
collapsed: boolean;
|
||||||
|
isBrowser: boolean;
|
||||||
|
}) {
|
||||||
|
// After hydration, styles are applied
|
||||||
|
if (isBrowser) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return collapsed ? CollapsedStyles : ExpandedStyles;
|
return collapsed ? CollapsedStyles : ExpandedStyles;
|
||||||
|
@ -202,6 +209,7 @@ function CollapsibleBase({
|
||||||
className,
|
className,
|
||||||
disableSSRStyle,
|
disableSSRStyle,
|
||||||
}: CollapsibleBaseProps) {
|
}: CollapsibleBaseProps) {
|
||||||
|
const isBrowser = useIsBrowser();
|
||||||
const collapsibleRef = useRef<HTMLElement>(null);
|
const collapsibleRef = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
useCollapseAnimation({collapsibleRef, collapsed, animation});
|
useCollapseAnimation({collapsibleRef, collapsed, animation});
|
||||||
|
@ -211,7 +219,8 @@ function CollapsibleBase({
|
||||||
// @ts-expect-error: the "too complicated type" is produced from
|
// @ts-expect-error: the "too complicated type" is produced from
|
||||||
// "CollapsibleElementType" being a huge union
|
// "CollapsibleElementType" being a huge union
|
||||||
ref={collapsibleRef as RefObject<never>} // Refs are contravariant, which is not expressible in TS
|
ref={collapsibleRef as RefObject<never>} // Refs are contravariant, which is not expressible in TS
|
||||||
style={disableSSRStyle ? undefined : getSSRStyle(collapsed)}
|
// Not even sure we need this SSRStyle anymore, try to remove it?
|
||||||
|
style={disableSSRStyle ? undefined : getSSRStyle({collapsed, isBrowser})}
|
||||||
onTransitionEnd={(e: React.TransitionEvent) => {
|
onTransitionEnd={(e: React.TransitionEvent) => {
|
||||||
if (e.propertyName !== 'height') {
|
if (e.propertyName !== 'height') {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -6,21 +6,6 @@ import Tabs from '@theme/Tabs';
|
||||||
import TabItem from '@theme/TabItem';
|
import TabItem from '@theme/TabItem';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tabs with dynamic default value
|
|
||||||
|
|
||||||
This can cause [bugs](https://github.com/facebook/react-native-website/issues/2771) when default value is different between SSR and client:
|
|
||||||
|
|
||||||
```mdx-code-block
|
|
||||||
export const isMacOS = typeof window !== 'undefined' && navigator.platform.startsWith('Mac');
|
|
||||||
|
|
||||||
<BrowserWindow>
|
|
||||||
<Tabs defaultValue={isMacOS ? "ios" : "android"}>
|
|
||||||
<TabItem value="android" label="Android">Android content</TabItem>
|
|
||||||
<TabItem value="ios" label="iOS">iOS content</TabItem>
|
|
||||||
</Tabs>
|
|
||||||
</BrowserWindow>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tabs sync with different heights
|
## Tabs sync with different heights
|
||||||
|
|
||||||
```mdx-code-block
|
```mdx-code-block
|
||||||
|
|
Loading…
Add table
Reference in a new issue