mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 10:20:09 +02:00
refactor(core): fix types for client code (#6064)
This commit is contained in:
parent
f96a051fbe
commit
b4ec7ec011
10 changed files with 48 additions and 58 deletions
|
@ -12,6 +12,7 @@
|
||||||
"directory": "packages/docusaurus-module-type-aliases"
|
"directory": "packages/docusaurus-module-type-aliases"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@docusaurus/types": "2.0.0-beta.9",
|
||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-helmet": "*",
|
"@types/react-helmet": "*",
|
||||||
"@types/react-router-config": "*",
|
"@types/react-router-config": "*",
|
||||||
|
|
|
@ -47,7 +47,9 @@ declare module '@generated/routes' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@generated/routesChunkNames' {
|
declare module '@generated/routesChunkNames' {
|
||||||
const routesChunkNames: Record<string, Record<string, string>>;
|
import type {RouteChunksTree} from '@docusaurus/types';
|
||||||
|
|
||||||
|
const routesChunkNames: Record<string, RouteChunksTree>;
|
||||||
export = routesChunkNames;
|
export = routesChunkNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
packages/docusaurus-types/src/index.d.ts
vendored
2
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -442,3 +442,5 @@ export interface TOCItem {
|
||||||
readonly children: TOCItem[];
|
readonly children: TOCItem[];
|
||||||
readonly level: number;
|
readonly level: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RouteChunksTree = {[x: string | number]: string | RouteChunksTree};
|
||||||
|
|
|
@ -72,6 +72,12 @@ function insertBanner() {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__DOCUSAURUS_INSERT_BASEURL_BANNER: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function BaseUrlIssueBannerEnabled() {
|
function BaseUrlIssueBannerEnabled() {
|
||||||
const {
|
const {
|
||||||
siteConfig: {baseUrl},
|
siteConfig: {baseUrl},
|
||||||
|
@ -80,8 +86,7 @@ function BaseUrlIssueBannerEnabled() {
|
||||||
// useLayoutEffect fires before DOMContentLoaded.
|
// useLayoutEffect fires before DOMContentLoaded.
|
||||||
// It gives the opportunity to avoid inserting the banner in the first place
|
// It gives the opportunity to avoid inserting the banner in the first place
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
window[InsertBannerWindowAttribute] = false;
|
||||||
(window as any)[InsertBannerWindowAttribute] = false;
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -5,19 +5,16 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// too dynamic
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
|
|
||||||
import clientModules from '@generated/client-modules';
|
import clientModules from '@generated/client-modules';
|
||||||
|
|
||||||
interface Dispatchers {
|
interface Dispatchers {
|
||||||
onRouteUpdate: (...args: any) => void;
|
onRouteUpdate: (...args: unknown[]) => void;
|
||||||
onRouteUpdateDelayed: (...args: any) => void;
|
onRouteUpdateDelayed: (...args: unknown[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dispatchLifecycleAction(
|
function dispatchLifecycleAction(
|
||||||
lifecycleAction: keyof Dispatchers,
|
lifecycleAction: keyof Dispatchers,
|
||||||
...args: any[]
|
...args: unknown[]
|
||||||
) {
|
) {
|
||||||
clientModules.forEach((clientModule) => {
|
clientModules.forEach((clientModule) => {
|
||||||
const lifecycleFunction =
|
const lifecycleFunction =
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {matchRoutes} from 'react-router-config';
|
import {matchRoutes} from 'react-router-config';
|
||||||
import routesChunkNames from '@generated/routesChunkNames';
|
import routesChunkNames from '@generated/routesChunkNames';
|
||||||
import routes from '@generated/routes';
|
import routes from '@generated/routes';
|
||||||
|
@ -22,18 +23,10 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSlowConnection = () => {
|
// If user is on slow or constrained connection.
|
||||||
// If user is on slow or constrained connection.
|
const isSlowConnection = () =>
|
||||||
if (`connection` in navigator) {
|
navigator.connection?.effectiveType.includes('2g') &&
|
||||||
if (
|
navigator.connection?.saveData;
|
||||||
(navigator.connection.effectiveType || ``).indexOf(`2g`) !== -1 &&
|
|
||||||
navigator.connection.saveData
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const canPrefetch = (routePath: string) =>
|
const canPrefetch = (routePath: string) =>
|
||||||
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
|
!isSlowConnection() && !loaded[routePath] && !fetched[routePath];
|
||||||
|
@ -41,25 +34,19 @@ const canPrefetch = (routePath: string) =>
|
||||||
const canPreload = (routePath: string) =>
|
const canPreload = (routePath: string) =>
|
||||||
!isSlowConnection() && !loaded[routePath];
|
!isSlowConnection() && !loaded[routePath];
|
||||||
|
|
||||||
const flatten = <T>(arrays: T[][]): T[] =>
|
|
||||||
Array.prototype.concat.apply([], arrays);
|
|
||||||
|
|
||||||
// Remove the last part containing the route hash
|
// Remove the last part containing the route hash
|
||||||
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
|
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
|
||||||
// output: /blog/2018/12/14/Happy-First-Birthday-Slash
|
// output: /blog/2018/12/14/Happy-First-Birthday-Slash
|
||||||
const removeRouteNameHash = (str: string) => str.replace(/(-[^-]+)$/, '');
|
const removeRouteNameHash = (str: string) => str.replace(/(-[^-]+)$/, '');
|
||||||
|
|
||||||
const getChunkNamesToLoad = (path: string): string[] =>
|
const getChunkNamesToLoad = (path: string): string[] =>
|
||||||
flatten(
|
|
||||||
Object.entries(routesChunkNames)
|
Object.entries(routesChunkNames)
|
||||||
.filter(
|
.filter(
|
||||||
([routeNameWithHash]) =>
|
([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path,
|
||||||
removeRouteNameHash(routeNameWithHash) === path,
|
|
||||||
)
|
)
|
||||||
.map(([, routeChunks]) =>
|
.flatMap(([, routeChunks]) =>
|
||||||
// flat() is useful for nested chunk names, it's not like array.flat()
|
// flat() is useful for nested chunk names, it's not like array.flat()
|
||||||
Object.values(flat(routeChunks)),
|
Object.values(flat(routeChunks)),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const docusaurus = {
|
const docusaurus = {
|
||||||
|
@ -73,8 +60,8 @@ const docusaurus = {
|
||||||
// Find all webpack chunk names needed.
|
// Find all webpack chunk names needed.
|
||||||
const matches = matchRoutes(routes, routePath);
|
const matches = matchRoutes(routes, routePath);
|
||||||
|
|
||||||
const chunkNamesNeeded = flatten(
|
const chunkNamesNeeded = matches.flatMap((match) =>
|
||||||
matches.map((match) => getChunkNamesToLoad(match.route.path as string)),
|
getChunkNamesToLoad(match.route.path),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prefetch all webpack chunk assets file needed.
|
// Prefetch all webpack chunk assets file needed.
|
||||||
|
|
|
@ -41,9 +41,9 @@ export function interpolate<Str extends string, Value extends ReactNode>(
|
||||||
|
|
||||||
const processedText = text.replace(ValueRegexp, (match: string) => {
|
const processedText = text.replace(ValueRegexp, (match: string) => {
|
||||||
// remove {{ and }} around the placeholder
|
// remove {{ and }} around the placeholder
|
||||||
const key = match.substr(
|
const key = match.substring(
|
||||||
1,
|
1,
|
||||||
match.length - 2,
|
match.length - 1,
|
||||||
) as ExtractInterpolatePlaceholders<Str>;
|
) as ExtractInterpolatePlaceholders<Str>;
|
||||||
|
|
||||||
const value = values?.[key];
|
const value = values?.[key];
|
||||||
|
|
|
@ -5,24 +5,25 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Too dynamic
|
import type {RouteChunksTree} from '@docusaurus/types';
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
function flat(target: unknown): Record<string, any> {
|
const isTree = (x: string | RouteChunksTree): x is RouteChunksTree =>
|
||||||
|
typeof x === 'object' && !!x && Object.keys(x).length > 0;
|
||||||
|
|
||||||
|
function flat(target: RouteChunksTree): Record<string, string> {
|
||||||
const delimiter = '.';
|
const delimiter = '.';
|
||||||
const output: Record<string, any> = {};
|
const output: Record<string, string> = {};
|
||||||
|
|
||||||
function step(object: any, prev?: string) {
|
function step(object: RouteChunksTree, prefix?: string | number) {
|
||||||
Object.keys(object).forEach((key) => {
|
Object.keys(object).forEach((key: string | number) => {
|
||||||
const value = object[key];
|
const value = object[key];
|
||||||
const type = typeof value;
|
const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
|
||||||
const isObject = type === 'object' && !!value;
|
|
||||||
const newKey = prev ? prev + delimiter + key : key;
|
|
||||||
|
|
||||||
if (isObject && Object.keys(value).length) {
|
if (isTree(value)) {
|
||||||
step(value, newKey);
|
step(value, newKey);
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
output[newKey] = value;
|
output[newKey] = value;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,5 @@ import {Plugin} from '@docusaurus/types';
|
||||||
export default function loadClientModules(
|
export default function loadClientModules(
|
||||||
plugins: Plugin<unknown>[],
|
plugins: Plugin<unknown>[],
|
||||||
): string[] {
|
): string[] {
|
||||||
return ([] as string[]).concat(
|
return plugins.flatMap((plugin) => plugin.getClientModules?.() ?? []);
|
||||||
...plugins
|
|
||||||
.map((plugin) => plugin.getClientModules?.() ?? [])
|
|
||||||
.filter(Boolean),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ function assertIsHtmlTagObject(val: unknown): asserts val is HtmlTagObject {
|
||||||
if (!isPlainObject(val)) {
|
if (!isPlainObject(val)) {
|
||||||
throw new Error(`"${val}" is not a valid HTML tag object.`);
|
throw new Error(`"${val}" is not a valid HTML tag object.`);
|
||||||
}
|
}
|
||||||
// @ts-expect-error: If tagName doesn't exist, it will throw.
|
if (typeof (val as HtmlTagObject).tagName !== 'string') {
|
||||||
if (typeof val.tagName !== 'string') {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${JSON.stringify(
|
`${JSON.stringify(
|
||||||
val,
|
val,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue