mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-02 11:47:23 +02:00
feat(v2): debug pages + debug layout + ability to debug content (#3229)
* improve debug plugin: - add multiple debug pages + debug layout - ability to debug plugin contentLoaded data * add missing dependency * fix broken test * improve content rendering a bit * create basic DebugJsonView * fix ReactJson SSR issues
This commit is contained in:
parent
be210a1bc4
commit
fe281a8ebe
30 changed files with 511 additions and 110 deletions
|
@ -12,6 +12,7 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^2.0.0-alpha.61",
|
||||
"@docusaurus/types": "^2.0.0-alpha.61",
|
||||
"@docusaurus/utils": "^2.0.0-alpha.61",
|
||||
"@hapi/joi": "^17.1.1",
|
||||
|
|
|
@ -39,6 +39,7 @@ describe('normalizePluginOptions', () => {
|
|||
redirects: [{from: '/x', to: '/y'}],
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'default',
|
||||
fromExtensions: ['exe', 'zip'],
|
||||
toExtensions: ['html'],
|
||||
createRedirects,
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
import {PluginOptions, RedirectOption, UserPluginOptions} from './types';
|
||||
import * as Joi from '@hapi/joi';
|
||||
import {PathnameValidator} from './redirectValidation';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
||||
export const DefaultPluginOptions: PluginOptions = {
|
||||
id: DEFAULT_PLUGIN_ID, // TODO temporary
|
||||
fromExtensions: [],
|
||||
toExtensions: [],
|
||||
redirects: [],
|
||||
|
@ -26,6 +28,7 @@ const RedirectPluginOptionValidation = Joi.object<RedirectOption>({
|
|||
const isString = Joi.string().required().not(null);
|
||||
|
||||
const UserOptionsSchema = Joi.object<UserPluginOptions>({
|
||||
id: Joi.string().optional(), // TODO remove once validation migrated to new system
|
||||
fromExtensions: Joi.array().items(isString),
|
||||
toExtensions: Joi.array().items(isString),
|
||||
redirects: Joi.array().items(RedirectPluginOptionValidation),
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import {Props} from '@docusaurus/types';
|
||||
|
||||
export type PluginOptions = {
|
||||
id: string;
|
||||
fromExtensions: string[];
|
||||
toExtensions: string[];
|
||||
redirects: RedirectOption[];
|
||||
|
|
|
@ -28,7 +28,6 @@ import {
|
|||
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||
import {
|
||||
LoadContext,
|
||||
PluginContentLoadedActions,
|
||||
ConfigureWebpackUtils,
|
||||
Props,
|
||||
Plugin,
|
||||
|
@ -195,13 +194,7 @@ export default function pluginContentBlog(
|
|||
};
|
||||
},
|
||||
|
||||
async contentLoaded({
|
||||
content: blogContents,
|
||||
actions,
|
||||
}: {
|
||||
content: BlogContent;
|
||||
actions: PluginContentLoadedActions;
|
||||
}) {
|
||||
async contentLoaded({content: blogContents, actions}) {
|
||||
if (!blogContents) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/types": "^2.0.0-alpha.61",
|
||||
"@docusaurus/utils": "^2.0.0-alpha.61"
|
||||
"@docusaurus/utils": "^2.0.0-alpha.61",
|
||||
"react-json-view": "^1.19.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@docusaurus/core": "^2.0.0",
|
||||
|
|
|
@ -6,13 +6,20 @@
|
|||
*/
|
||||
|
||||
import {LoadContext, Plugin} from '@docusaurus/types';
|
||||
import {normalizeUrl} from '@docusaurus/utils';
|
||||
|
||||
import {docuHash, normalizeUrl} from '@docusaurus/utils';
|
||||
import path from 'path';
|
||||
|
||||
export default function pluginContentPages({
|
||||
siteConfig: {baseUrl},
|
||||
generatedFilesDir,
|
||||
}: LoadContext): Plugin<void> {
|
||||
const pluginDataDirRoot = path.join(
|
||||
generatedFilesDir,
|
||||
'docusaurus-plugin-debug',
|
||||
);
|
||||
const aliasedSource = (source: string) =>
|
||||
`~debug/${path.relative(pluginDataDirRoot, source)}`;
|
||||
|
||||
return {
|
||||
name: 'docusaurus-plugin-debug',
|
||||
|
||||
|
@ -20,12 +27,63 @@ export default function pluginContentPages({
|
|||
return path.resolve(__dirname, '../src/theme');
|
||||
},
|
||||
|
||||
contentLoaded({actions: {addRoute}}) {
|
||||
async contentLoaded({actions: {createData, addRoute}, allContent}) {
|
||||
const allContentPath = await createData(
|
||||
// Note that this created data path must be in sync with
|
||||
// metadataPath provided to mdx-loader.
|
||||
`${docuHash('docusaurus-debug-allContent')}.json`,
|
||||
JSON.stringify(allContent, null, 2),
|
||||
);
|
||||
|
||||
// Home is config (duplicate for now)
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug']),
|
||||
component: '@theme/Debug',
|
||||
component: '@theme/DebugConfig',
|
||||
exact: true,
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug/config']),
|
||||
component: '@theme/DebugConfig',
|
||||
exact: true,
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug/metadata']),
|
||||
component: '@theme/DebugMetadata',
|
||||
exact: true,
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug/registry']),
|
||||
component: '@theme/DebugRegistry',
|
||||
exact: true,
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug/routes']),
|
||||
component: '@theme/DebugRoutes',
|
||||
exact: true,
|
||||
});
|
||||
|
||||
addRoute({
|
||||
path: normalizeUrl([baseUrl, '__docusaurus/debug/content']),
|
||||
component: '@theme/DebugContent',
|
||||
exact: true,
|
||||
modules: {
|
||||
allContent: aliasedSource(allContentPath),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
configureWebpack() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'~debug': pluginDataDirRoot,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import registry from '@generated/registry';
|
||||
import routes from '@generated/routes';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
function Debug() {
|
||||
const {siteMetadata} = useDocusaurusContext();
|
||||
return (
|
||||
<Layout permalink="__docusaurus/debug" title="Debug">
|
||||
<main className={styles.Container}>
|
||||
<section className={styles.Section}>
|
||||
<h2>Site Metadata</h2>
|
||||
<div>Docusaurus Version: {siteMetadata.docusaurusVersion}</div>
|
||||
<div>
|
||||
Site Version: {siteMetadata.siteVersion || 'No version specified'}
|
||||
</div>
|
||||
<h3>Plugins and themes:</h3>
|
||||
<ul>
|
||||
{Object.entries(siteMetadata.pluginVersions).map(
|
||||
([name, versionInformation]) => (
|
||||
<li key={name}>
|
||||
<div>Name: {name}</div>
|
||||
<div>Type: {versionInformation.type}</div>
|
||||
{versionInformation.version && (
|
||||
<div>Version: {versionInformation.version}</div>
|
||||
)}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
</section>
|
||||
<section className={styles.Section}>
|
||||
<h2>Registry</h2>
|
||||
<ul>
|
||||
{Object.values(registry).map(([, aliasedPath, resolved]) => (
|
||||
<li key={aliasedPath}>
|
||||
<div>Aliased Path: {aliasedPath}</div>
|
||||
<div>Resolved Path: {resolved}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
<section className={styles.Section}>
|
||||
<h2>Routes</h2>
|
||||
<ul>
|
||||
{routes.map(({path, exact}) => (
|
||||
<li key={path}>
|
||||
<div>Route: {path}</div>
|
||||
<div>Is exact: {String(Boolean(exact))}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default Debug;
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import DebugLayout from '../DebugLayout';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
function DebugMetadata() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<DebugLayout>
|
||||
<h2>Site config</h2>
|
||||
<div>{JSON.stringify(siteConfig, null, 2)}</div>
|
||||
</DebugLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugMetadata;
|
|
@ -5,13 +5,3 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.Container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.Section {
|
||||
width: 500px;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React, {useState} from 'react';
|
||||
|
||||
import DebugLayout from '../DebugLayout';
|
||||
import DebugJsonView from '../DebugJsonView';
|
||||
|
||||
const PluginInstanceContent = ({pluginId, pluginInstanceContent}) => (
|
||||
<section style={{marginBottom: 30}}>
|
||||
<h4>{`>> ${pluginId}`}</h4>
|
||||
<div
|
||||
style={{
|
||||
marginTop: 10,
|
||||
padding: 10,
|
||||
border: 'thin cyan solid',
|
||||
borderRadius: 5,
|
||||
backgroundColor: 'lightgrey',
|
||||
}}>
|
||||
<DebugJsonView src={pluginInstanceContent} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
const PluginContent = ({pluginName, pluginContent}) => {
|
||||
const [visible, setVisible] = useState(true);
|
||||
return (
|
||||
<section style={{marginBottom: 60}}>
|
||||
<h3 onClick={() => setVisible((v) => !v)} style={{cursor: 'pointer'}}>
|
||||
{pluginName}
|
||||
</h3>
|
||||
{visible && (
|
||||
<div>
|
||||
{Object.entries(pluginContent)
|
||||
// filter plugin instances with no content
|
||||
.filter(
|
||||
([_pluginId, pluginInstanceContent]) => !!pluginInstanceContent,
|
||||
)
|
||||
.map(([pluginId, pluginInstanceContent]) => {
|
||||
return (
|
||||
<PluginInstanceContent
|
||||
key={pluginId}
|
||||
pluginId={pluginId}
|
||||
pluginInstanceContent={pluginInstanceContent}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
function DebugContent({allContent}) {
|
||||
return (
|
||||
<DebugLayout>
|
||||
<h2>Plugin content</h2>
|
||||
<div>
|
||||
{Object.entries(allContent)
|
||||
// filter plugins with no content
|
||||
.filter(([_pluginName, pluginContent]) =>
|
||||
Object.values(pluginContent).some(
|
||||
(instanceContent) => !!instanceContent,
|
||||
),
|
||||
)
|
||||
.map(([pluginName, pluginContent]) => {
|
||||
return (
|
||||
<PluginContent
|
||||
key={pluginName}
|
||||
pluginName={pluginName}
|
||||
pluginContent={pluginContent}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</DebugLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugContent;
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
|
||||
// avoids "react-json-view" to display "root"
|
||||
const RootName = false;
|
||||
|
||||
// Seems ReactJson does not work with SSR
|
||||
// https://github.com/mac-s-g/react-json-view/issues/121
|
||||
const BrowserOnlyReactJson = (props) => {
|
||||
return (
|
||||
<BrowserOnly>
|
||||
{() => {
|
||||
const ReactJson = require('react-json-view').default;
|
||||
return <ReactJson {...props} />;
|
||||
}}
|
||||
</BrowserOnly>
|
||||
);
|
||||
};
|
||||
|
||||
function DebugJsonView({src}) {
|
||||
return (
|
||||
<BrowserOnlyReactJson
|
||||
src={src}
|
||||
name={RootName}
|
||||
shouldCollapse={(field) => {
|
||||
// By default, we collapse the json for performance reasons
|
||||
// See https://github.com/mac-s-g/react-json-view/issues/235
|
||||
// only the "root" is not collapsed
|
||||
return field.name !== RootName;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugJsonView;
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Link from '@docusaurus/Link';
|
||||
// import styles from './styles.module.css';
|
||||
|
||||
const DebugNavLink = ({to, children}) => (
|
||||
<Link
|
||||
style={{margin: 10}}
|
||||
className="button button--primary"
|
||||
isNavLink
|
||||
activeClassName="button--active"
|
||||
to={to}
|
||||
exact>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
|
||||
function DebugLayout({children}) {
|
||||
return (
|
||||
<div>
|
||||
<nav style={{width: '100%', padding: 10, border: 'solid'}}>
|
||||
<DebugNavLink to="/__docusaurus/debug">Config</DebugNavLink>
|
||||
<DebugNavLink to="/__docusaurus/debug/metadata">Metadata</DebugNavLink>
|
||||
<DebugNavLink to="/__docusaurus/debug/registry">Registry</DebugNavLink>
|
||||
<DebugNavLink to="/__docusaurus/debug/routes">Routes</DebugNavLink>
|
||||
<DebugNavLink to="/__docusaurus/debug/content">Content</DebugNavLink>
|
||||
</nav>
|
||||
<main style={{padding: 20}}>{children}</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugLayout;
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import DebugLayout from '../DebugLayout';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
function DebugMetadata() {
|
||||
const {siteMetadata} = useDocusaurusContext();
|
||||
return (
|
||||
<DebugLayout>
|
||||
<h2>Site Metadata</h2>
|
||||
<div>Docusaurus Version: {siteMetadata.docusaurusVersion}</div>
|
||||
<div>
|
||||
Site Version: {siteMetadata.siteVersion || 'No version specified'}
|
||||
</div>
|
||||
<h3>Plugins and themes:</h3>
|
||||
<ul>
|
||||
{Object.entries(siteMetadata.pluginVersions).map(
|
||||
([name, versionInformation]) => (
|
||||
<li key={name}>
|
||||
<div>Name: {name}</div>
|
||||
<div>Type: {versionInformation.type}</div>
|
||||
{versionInformation.version && (
|
||||
<div>Version: {versionInformation.version}</div>
|
||||
)}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
</DebugLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugMetadata;
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import DebugLayout from '../DebugLayout';
|
||||
import registry from '@generated/registry';
|
||||
|
||||
function DebugRegistry() {
|
||||
return (
|
||||
<DebugLayout>
|
||||
{' '}
|
||||
<h2>Registry</h2>
|
||||
<ul>
|
||||
{Object.values(registry).map(([, aliasedPath, resolved]) => (
|
||||
<li key={aliasedPath}>
|
||||
<div>Aliased Path: {aliasedPath}</div>
|
||||
<div>Resolved Path: {resolved}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</DebugLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugRegistry;
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import DebugLayout from '../DebugLayout';
|
||||
import routes from '@generated/routes';
|
||||
|
||||
function DebugRoutes() {
|
||||
return (
|
||||
<DebugLayout>
|
||||
<h2>Routes</h2>
|
||||
<ul>
|
||||
{routes.map(({path, exact}) => (
|
||||
<li key={path}>
|
||||
<div>Route: {path}</div>
|
||||
<div>Is exact: {String(Boolean(exact))}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</DebugLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebugRoutes;
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
|
@ -11,6 +11,9 @@ module.exports = function preset(context, opts = {}) {
|
|||
const {algolia, googleAnalytics, gtag} = themeConfig;
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
const debug =
|
||||
typeof opts.debug !== 'undefined' ? Boolean(opts.debug) : !isProd;
|
||||
|
||||
return {
|
||||
themes: [
|
||||
[require.resolve('@docusaurus/theme-classic'), opts.theme],
|
||||
|
@ -24,7 +27,7 @@ module.exports = function preset(context, opts = {}) {
|
|||
isProd &&
|
||||
googleAnalytics &&
|
||||
require.resolve('@docusaurus/plugin-google-analytics'),
|
||||
!isProd && require.resolve('@docusaurus/plugin-debug'),
|
||||
debug && require.resolve('@docusaurus/plugin-debug'),
|
||||
isProd && gtag && require.resolve('@docusaurus/plugin-google-gtag'),
|
||||
isProd && [require.resolve('@docusaurus/plugin-sitemap'), opts.sitemap],
|
||||
],
|
||||
|
|
12
packages/docusaurus-types/src/index.d.ts
vendored
12
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -126,8 +126,15 @@ export interface PluginContentLoadedActions {
|
|||
setGlobalData<T = unknown>(data: T): void;
|
||||
}
|
||||
|
||||
export type AllContent = Record<
|
||||
string, // plugin name
|
||||
Record<
|
||||
string, // plugin id
|
||||
unknown // plugin data
|
||||
>
|
||||
>;
|
||||
|
||||
export interface Plugin<T, U = unknown> {
|
||||
id?: string;
|
||||
name: string;
|
||||
loadContent?(): Promise<T>;
|
||||
validateOptions?(): ValidationResult<U>;
|
||||
|
@ -136,7 +143,8 @@ export interface Plugin<T, U = unknown> {
|
|||
content,
|
||||
actions,
|
||||
}: {
|
||||
content: T;
|
||||
content: T; // the content loaded by this plugin instance
|
||||
allContent: AllContent; // content loaded by ALL the plugins
|
||||
actions: PluginContentLoadedActions;
|
||||
}): void;
|
||||
routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60)
|
||||
|
|
|
@ -9,6 +9,7 @@ import {generate} from '@docusaurus/utils';
|
|||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import {
|
||||
AllContent,
|
||||
LoadContext,
|
||||
PluginConfig,
|
||||
PluginContentLoadedActions,
|
||||
|
@ -17,6 +18,7 @@ import {
|
|||
import initPlugins, {InitPlugin} from './init';
|
||||
import chalk from 'chalk';
|
||||
import {DEFAULT_PLUGIN_ID} from '../../constants';
|
||||
import {chain} from 'lodash';
|
||||
|
||||
export function sortConfig(routeConfigs: RouteConfig[]): void {
|
||||
// Sort the route config. This ensures that route with nested
|
||||
|
@ -68,23 +70,31 @@ export async function loadPlugins({
|
|||
// Currently plugins run lifecycle methods in parallel and are not order-dependent.
|
||||
// We could change this in future if there are plugins which need to
|
||||
// run in certain order or depend on others for data.
|
||||
const pluginsLoadedContent = await Promise.all(
|
||||
type ContentLoadedPlugin = {plugin: InitPlugin; content: unknown};
|
||||
const contentLoadedPlugins: ContentLoadedPlugin[] = await Promise.all(
|
||||
plugins.map(async (plugin) => {
|
||||
if (!plugin.loadContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return plugin.loadContent();
|
||||
const content = plugin.loadContent ? await plugin.loadContent() : null;
|
||||
return {plugin, content};
|
||||
}),
|
||||
);
|
||||
|
||||
const allContent: AllContent = chain(contentLoadedPlugins)
|
||||
.groupBy((item) => item.plugin.name)
|
||||
.mapValues((nameItems) => {
|
||||
return chain(nameItems)
|
||||
.groupBy((item) => item.plugin.options.id ?? DEFAULT_PLUGIN_ID)
|
||||
.mapValues((idItems) => idItems[0].content)
|
||||
.value();
|
||||
})
|
||||
.value();
|
||||
|
||||
// 3. Plugin Lifecycle - contentLoaded.
|
||||
const pluginsRouteConfigs: RouteConfig[] = [];
|
||||
|
||||
const globalData = {};
|
||||
|
||||
await Promise.all(
|
||||
plugins.map(async (plugin, index) => {
|
||||
contentLoadedPlugins.map(async ({plugin, content}) => {
|
||||
if (!plugin.contentLoaded) {
|
||||
return;
|
||||
}
|
||||
|
@ -100,11 +110,11 @@ export async function loadPlugins({
|
|||
|
||||
const createData: PluginContentLoadedActions['createData'] = async (
|
||||
name,
|
||||
content,
|
||||
data,
|
||||
) => {
|
||||
const modulePath = path.join(dataDir, name);
|
||||
await fs.ensureDir(path.dirname(modulePath));
|
||||
await generate(dataDir, name, content);
|
||||
await generate(dataDir, name, data);
|
||||
return modulePath;
|
||||
};
|
||||
|
||||
|
@ -125,8 +135,9 @@ export async function loadPlugins({
|
|||
};
|
||||
|
||||
await plugin.contentLoaded({
|
||||
content: pluginsLoadedContent[index],
|
||||
content,
|
||||
actions,
|
||||
allContent,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
PluginConfig,
|
||||
DocusaurusPluginVersionInformation,
|
||||
} from '@docusaurus/types';
|
||||
import {CONFIG_FILE_NAME} from '../../constants';
|
||||
import {CONFIG_FILE_NAME, DEFAULT_PLUGIN_ID} from '../../constants';
|
||||
import {getPluginVersion} from '../versions';
|
||||
import {ensureUniquePluginInstanceIds} from './pluginIds';
|
||||
import {
|
||||
|
@ -79,6 +79,13 @@ export default function initPlugins({
|
|||
options: pluginOptions,
|
||||
});
|
||||
pluginOptions = normalizedOptions;
|
||||
} else {
|
||||
// Important to ensure all plugins have an id
|
||||
// as we don't go through the Joi schema that adds it
|
||||
pluginOptions = {
|
||||
...pluginOptions,
|
||||
id: pluginOptions.id ?? DEFAULT_PLUGIN_ID,
|
||||
};
|
||||
}
|
||||
|
||||
// support both commonjs and ES modules
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
|
||||
/* Additional Checks */
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* Disabled on purpose (handled by ESLint, should not block compilation) */
|
||||
"noUnusedParameters": false,
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
|
|
@ -156,6 +156,7 @@ module.exports = {
|
|||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
debug: true, // force debug plugin usage
|
||||
docs: {
|
||||
// routeBasePath: '/',
|
||||
path: 'docs',
|
||||
|
|
66
yarn.lock
66
yarn.lock
|
@ -5440,6 +5440,11 @@ balanced-match@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base16@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
|
||||
integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
|
||||
|
||||
base64-js@^1.0.2:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||
|
@ -9642,7 +9647,14 @@ fb-watchman@^2.0.0:
|
|||
dependencies:
|
||||
bser "2.1.1"
|
||||
|
||||
fbjs@^0.8.0:
|
||||
fbemitter@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz#523e14fdaf5248805bb02f62efc33be703f51865"
|
||||
integrity sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=
|
||||
dependencies:
|
||||
fbjs "^0.8.4"
|
||||
|
||||
fbjs@^0.8.0, fbjs@^0.8.4:
|
||||
version "0.8.17"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
|
||||
integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
|
||||
|
@ -9956,6 +9968,14 @@ flush-write-stream@^2.0.0:
|
|||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
flux@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/flux/-/flux-3.1.3.tgz#d23bed515a79a22d933ab53ab4ada19d05b2f08a"
|
||||
integrity sha1-0jvtUVp5oi2TOrU6tK2hnQWy8Io=
|
||||
dependencies:
|
||||
fbemitter "^2.0.0"
|
||||
fbjs "^0.8.0"
|
||||
|
||||
fn.name@1.x.x:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
|
||||
|
@ -13541,6 +13561,11 @@ lodash.clonedeep@^4.5.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.curry@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
|
||||
integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
|
@ -13581,6 +13606,11 @@ lodash.flattendeep@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
|
||||
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
|
||||
|
||||
lodash.flow@^3.3.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
|
||||
integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
|
||||
|
||||
lodash.foreach@^4.3.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
|
||||
|
@ -17227,7 +17257,7 @@ prop-types-exact@^1.2.0:
|
|||
object.assign "^4.1.0"
|
||||
reflect.ownkeys "^0.2.0"
|
||||
|
||||
prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
|
@ -17355,6 +17385,11 @@ pupa@^2.0.1:
|
|||
dependencies:
|
||||
escape-goat "^2.0.0"
|
||||
|
||||
pure-color@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
|
||||
integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
|
||||
|
||||
q@^1.1.2, q@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
|
@ -17524,6 +17559,16 @@ react-attr-converter@^0.3.1:
|
|||
resolved "https://registry.yarnpkg.com/react-attr-converter/-/react-attr-converter-0.3.1.tgz#4a2abf6d907b7ddae4d862dfec80e489ce41ad6e"
|
||||
integrity sha512-dSxo2Mn6Zx4HajeCeQNLefwEO4kNtV/0E682R1+ZTyFRPqxDa5zYb5qM/ocqw9Bxr/kFQO0IUiqdV7wdHw+Cdg==
|
||||
|
||||
react-base16-styling@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
|
||||
integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
|
||||
dependencies:
|
||||
base16 "^1.0.0"
|
||||
lodash.curry "^4.0.1"
|
||||
lodash.flow "^3.3.0"
|
||||
pure-color "^1.2.0"
|
||||
|
||||
react-dev-utils@^10.2.1:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19"
|
||||
|
@ -17620,6 +17665,16 @@ react-is@^16.12.0, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-i
|
|||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-json-view@^1.19.1:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.19.1.tgz#95d8e59e024f08a25e5dc8f076ae304eed97cf5c"
|
||||
integrity sha512-u5e0XDLIs9Rj43vWkKvwL8G3JzvXSl6etuS5G42a8klMohZuYFQzSN6ri+/GiBptDqlrXPTdExJVU7x9rrlXhg==
|
||||
dependencies:
|
||||
flux "^3.1.3"
|
||||
react-base16-styling "^0.6.0"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
react-textarea-autosize "^6.1.0"
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
|
@ -17722,6 +17777,13 @@ react-test-renderer@^16.0.0-0:
|
|||
react-is "^16.8.6"
|
||||
scheduler "^0.19.1"
|
||||
|
||||
react-textarea-autosize@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5"
|
||||
integrity sha512-F6bI1dgib6fSvG8so1HuArPUv+iVEfPliuLWusLF+gAKz0FbB4jLrWUrTAeq1afnPT2c9toEZYUdz/y1uKMy4A==
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-toggle@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.1.1.tgz#2317f67bf918ea3508a96b09dd383efd9da572af"
|
||||
|
|
Loading…
Add table
Reference in a new issue