feat(core): use react-helmet-async (#6306)

* Use React Strict Mode

Even though Strict Mode is not required a WARNING icon now displays
on all components that do not use React.StrictMode on React DevTools extension.

Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com>

* Utilize react-helmet-async instead of react-helmet

react-helmet is NOT thread safe, as explained in https://open.nytimes.com/the-future-of-meta-tag-management-for-modern-react-development-ec26a7dc9183#fdc2

Therefore, it's better if react-helmet-async is utilized instead of react-helmet.

Even though react-helmet-async is being utilized, most users will not require any code changes to @docusaurus/Head since it uses the same API as react-helmet.

Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com>

* Include HelmetProvider inside client entry

I forgot to do this before.

Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com>

* format

* fix TS

* address reviews

* Remove forked react-loadable package in favor of @react-loadable/revised

Both unforked react-loadable and @docusaurus/react-loadable uses legacy React APIs.

However, @react-loadable/revised (https://github.com/react-loadable/revised) is actively maintained and widely used in production, thus replaced with this package.

Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com>

* remove unused comma

* Address reviews from https://github.com/facebook/docusaurus/pull/6306#pullrequestreview-864745191

Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com>

Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
seyoon20087 2022-02-02 15:52:44 +09:00 committed by GitHub
parent 94135ac71a
commit a615ab3999
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 27 deletions

View file

@ -81,7 +81,7 @@
"postcss-loader": "^6.1.1",
"prompts": "^2.4.1",
"react-dev-utils": "^12.0.0",
"react-helmet": "^6.1.0",
"react-helmet-async": "^1.2.2",
"react-loadable": "npm:@docusaurus/react-loadable@5.5.2",
"react-loadable-ssr-addon-v5-slorber": "^1.0.1",
"react-router": "^5.2.0",
@ -111,7 +111,6 @@
"@types/mini-css-extract-plugin": "^2.5.1",
"@types/nprogress": "^0.2.0",
"@types/react-dom": "^17.0.9",
"@types/react-helmet": "^6.0.0",
"@types/react-router-config": "^5.0.1",
"@types/rtl-detect": "^1.0.0",
"@types/serve-handler": "^6.1.1",

View file

@ -8,6 +8,7 @@
import React from 'react';
import {hydrate, render} from 'react-dom';
import {BrowserRouter} from 'react-router-dom';
import {HelmetProvider} from 'react-helmet-async';
import routes from '@generated/routes';
import ExecutionEnvironment from './exports/ExecutionEnvironment';
@ -32,9 +33,11 @@ if (ExecutionEnvironment.canUseDOM) {
const renderMethod = process.env.NODE_ENV === 'production' ? hydrate : render;
preload(routes, window.location.pathname).then(() => {
renderMethod(
<BrowserRouter>
<App />
</BrowserRouter>,
<HelmetProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</HelmetProvider>,
document.getElementById('__docusaurus'),
);
});

View file

@ -6,7 +6,7 @@
*/
import React from 'react';
import {Helmet} from 'react-helmet';
import {Helmet} from 'react-helmet-async';
import type {HeadProps} from '@docusaurus/Head';
function Head(props: HeadProps): JSX.Element {

View file

@ -9,7 +9,7 @@ import * as eta from 'eta';
import React from 'react';
import {StaticRouter} from 'react-router-dom';
import ReactDOMServer from 'react-dom/server';
import {Helmet} from 'react-helmet';
import {HelmetProvider, type FilledContext} from 'react-helmet-async';
import {getBundles, type Manifest} from 'react-loadable-ssr-addon-v5-slorber';
import Loadable from 'react-loadable';
@ -82,20 +82,23 @@ async function doRender(locals: Locals & {path: string}) {
await preload(routes, location);
const modules = new Set<string>();
const context = {};
const helmetContext = {};
const linksCollector = createStatefulLinksCollector();
const appHtml = ReactDOMServer.renderToString(
<Loadable.Capture report={(moduleName) => modules.add(moduleName)}>
<StaticRouter location={location} context={context}>
<ProvideLinksCollector linksCollector={linksCollector}>
<App />
</ProvideLinksCollector>
</StaticRouter>
<HelmetProvider context={helmetContext}>
<StaticRouter location={location} context={context}>
<ProvideLinksCollector linksCollector={linksCollector}>
<App />
</ProvideLinksCollector>
</StaticRouter>
</HelmetProvider>
</Loadable.Capture>,
);
onLinksCollected(location, linksCollector.getCollectedLinks());
const helmet = Helmet.renderStatic();
const {helmet} = helmetContext as FilledContext;
const htmlAttributes = helmet.htmlAttributes.toString();
const bodyAttributes = helmet.bodyAttributes.toString();
const metaStrings = [