mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-09 23:27:28 +02:00
feat(v2): allow home page for docs (#2652)
* feat(v2): allow home page for docs
* Refactor
* Remove debugging info 🤦♂️
* Add sort routes for first test case
* Sort child routes for consistency
This commit is contained in:
parent
393adc5324
commit
00a8e9e365
12 changed files with 264 additions and 61 deletions
|
@ -52,6 +52,15 @@ Object {
|
||||||
|
|
||||||
exports[`simple website content 2`] = `
|
exports[`simple website content 2`] = `
|
||||||
Array [
|
Array [
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"content": "@site/docs/hello.md",
|
||||||
|
"docsMetadata": "~docs/site-docs-hello-md-9df-base.json",
|
||||||
|
},
|
||||||
|
"path": "/docs",
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"component": "@theme/DocPage",
|
"component": "@theme/DocPage",
|
||||||
"modules": Object {
|
"modules": Object {
|
||||||
|
@ -107,6 +116,33 @@ Array [
|
||||||
|
|
||||||
exports[`versioned website content 1`] = `
|
exports[`versioned website content 1`] = `
|
||||||
Array [
|
Array [
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"content": "@site/versioned_docs/version-1.0.1/hello.md",
|
||||||
|
"docsMetadata": "~docs/site-versioned-docs-version-1-0-1-hello-md-0c7-base.json",
|
||||||
|
},
|
||||||
|
"path": "/docs",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"content": "@site/versioned_docs/version-1.0.0/hello.md",
|
||||||
|
"docsMetadata": "~docs/site-versioned-docs-version-1-0-0-hello-md-3ef-base.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/1.0.0",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"component": "@theme/DocPage",
|
||||||
|
"exact": true,
|
||||||
|
"modules": Object {
|
||||||
|
"content": "@site/docs/hello.md",
|
||||||
|
"docsMetadata": "~docs/site-docs-hello-md-9df-base.json",
|
||||||
|
},
|
||||||
|
"path": "/docs/next",
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"component": "@theme/DocPage",
|
"component": "@theme/DocPage",
|
||||||
"modules": Object {
|
"modules": Object {
|
||||||
|
|
|
@ -93,6 +93,7 @@ describe('simple website', () => {
|
||||||
const plugin = pluginContentDocs(context, {
|
const plugin = pluginContentDocs(context, {
|
||||||
path: pluginPath,
|
path: pluginPath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
|
homePageId: 'hello',
|
||||||
});
|
});
|
||||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||||
|
|
||||||
|
@ -203,6 +204,9 @@ describe('simple website', () => {
|
||||||
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
|
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
|
||||||
expect(baseMetadata.permalinkToSidebar).toEqual(permalinkToSidebar);
|
expect(baseMetadata.permalinkToSidebar).toEqual(permalinkToSidebar);
|
||||||
|
|
||||||
|
// Sort the route config like in src/server/plugins/index.ts for consistent snapshot ordering
|
||||||
|
sortConfig(routeConfigs);
|
||||||
|
|
||||||
expect(routeConfigs).not.toEqual([]);
|
expect(routeConfigs).not.toEqual([]);
|
||||||
expect(routeConfigs).toMatchSnapshot();
|
expect(routeConfigs).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -216,6 +220,7 @@ describe('versioned website', () => {
|
||||||
const plugin = pluginContentDocs(context, {
|
const plugin = pluginContentDocs(context, {
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
|
homePageId: 'hello',
|
||||||
});
|
});
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir);
|
||||||
const {docsDir: versionedDir} = env.versioning;
|
const {docsDir: versionedDir} = env.versioning;
|
||||||
|
|
|
@ -48,9 +48,12 @@ import {Configuration} from 'webpack';
|
||||||
import {docsVersion} from './version';
|
import {docsVersion} from './version';
|
||||||
import {VERSIONS_JSON_FILE} from './constants';
|
import {VERSIONS_JSON_FILE} from './constants';
|
||||||
|
|
||||||
|
const REVERSED_DOCS_HOME_PAGE_ID = '_index';
|
||||||
|
|
||||||
const DEFAULT_OPTIONS: PluginOptions = {
|
const DEFAULT_OPTIONS: PluginOptions = {
|
||||||
path: 'docs', // Path to data on filesystem, relative to site dir.
|
path: 'docs', // Path to data on filesystem, relative to site dir.
|
||||||
routeBasePath: 'docs', // URL Route.
|
routeBasePath: 'docs', // URL Route.
|
||||||
|
homePageId: REVERSED_DOCS_HOME_PAGE_ID, // Document id for docs home page.
|
||||||
include: ['**/*.{md,mdx}'], // Extensions to include.
|
include: ['**/*.{md,mdx}'], // Extensions to include.
|
||||||
sidebarPath: '', // Path to sidebar configuration for showing a list of markdown pages.
|
sidebarPath: '', // Path to sidebar configuration for showing a list of markdown pages.
|
||||||
docLayoutComponent: '@theme/DocPage',
|
docLayoutComponent: '@theme/DocPage',
|
||||||
|
@ -313,28 +316,96 @@ export default function pluginContentDocs(
|
||||||
const aliasedSource = (source: string) =>
|
const aliasedSource = (source: string) =>
|
||||||
`~docs/${path.relative(dataDir, source)}`;
|
`~docs/${path.relative(dataDir, source)}`;
|
||||||
|
|
||||||
|
const createDocsBaseMetadata = (version?: string): DocsBaseMetadata => {
|
||||||
|
const {docsSidebars, permalinkToSidebar, versionToSidebars} = content;
|
||||||
|
const neededSidebars: Set<string> =
|
||||||
|
versionToSidebars[version!] || new Set();
|
||||||
|
|
||||||
|
return {
|
||||||
|
docsSidebars: version
|
||||||
|
? pick(docsSidebars, Array.from(neededSidebars))
|
||||||
|
: docsSidebars,
|
||||||
|
permalinkToSidebar: version
|
||||||
|
? pickBy(permalinkToSidebar, (sidebar) =>
|
||||||
|
neededSidebars.has(sidebar),
|
||||||
|
)
|
||||||
|
: permalinkToSidebar,
|
||||||
|
version,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const genRoutes = async (
|
const genRoutes = async (
|
||||||
metadataItems: Metadata[],
|
metadataItems: Metadata[],
|
||||||
): Promise<RouteConfig[]> => {
|
): Promise<RouteConfig[]> => {
|
||||||
const routes = await Promise.all(
|
const routes: RouteConfig[] = [];
|
||||||
metadataItems.map(async (metadataItem) => {
|
|
||||||
await createData(
|
await metadataItems.forEach(async (metadataItem, i) => {
|
||||||
// Note that this created data path must be in sync with
|
const isDocsHomePage =
|
||||||
// metadataPath provided to mdx-loader.
|
metadataItem.id.substr(metadataItem.id.indexOf('/') + 1) ===
|
||||||
`${docuHash(metadataItem.source)}.json`,
|
options.homePageId;
|
||||||
JSON.stringify(metadataItem, null, 2),
|
|
||||||
|
if (isDocsHomePage) {
|
||||||
|
const homeDocsRoutePath =
|
||||||
|
routeBasePath === '' ? '/' : routeBasePath;
|
||||||
|
const versionDocsPathPrefix =
|
||||||
|
(metadataItem?.version === versioning.latestVersion
|
||||||
|
? ''
|
||||||
|
: metadataItem.version!) ?? '';
|
||||||
|
|
||||||
|
// To show the sidebar, get the sidebar key of available sibling item.
|
||||||
|
metadataItem.sidebar = (
|
||||||
|
metadataItems[i - 1] ?? metadataItems[i + 1]
|
||||||
|
).sidebar;
|
||||||
|
const docsBaseMetadata = createDocsBaseMetadata(
|
||||||
|
metadataItem.version!,
|
||||||
|
);
|
||||||
|
docsBaseMetadata.isHomePage = true;
|
||||||
|
docsBaseMetadata.homePagePath = normalizeUrl([
|
||||||
|
baseUrl,
|
||||||
|
homeDocsRoutePath,
|
||||||
|
versionDocsPathPrefix,
|
||||||
|
options.homePageId,
|
||||||
|
]);
|
||||||
|
const docsBaseMetadataPath = await createData(
|
||||||
|
`${docuHash(metadataItem.source)}-base.json`,
|
||||||
|
JSON.stringify(docsBaseMetadata, null, 2),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
// Add a route for docs home page.
|
||||||
|
addRoute({
|
||||||
|
path: normalizeUrl([
|
||||||
|
baseUrl,
|
||||||
|
homeDocsRoutePath,
|
||||||
|
versionDocsPathPrefix,
|
||||||
|
]),
|
||||||
|
component: docLayoutComponent,
|
||||||
|
exact: true,
|
||||||
|
modules: {
|
||||||
|
docsMetadata: aliasedSource(docsBaseMetadataPath),
|
||||||
|
content: metadataItem.source,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createData(
|
||||||
|
// Note that this created data path must be in sync with
|
||||||
|
// metadataPath provided to mdx-loader.
|
||||||
|
`${docuHash(metadataItem.source)}.json`,
|
||||||
|
JSON.stringify(metadataItem, null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Do not create a route for a page created specifically for docs home page.
|
||||||
|
if (metadataItem.id !== REVERSED_DOCS_HOME_PAGE_ID) {
|
||||||
|
routes.push({
|
||||||
path: metadataItem.permalink,
|
path: metadataItem.permalink,
|
||||||
component: docItemComponent,
|
component: docItemComponent,
|
||||||
exact: true,
|
exact: true,
|
||||||
modules: {
|
modules: {
|
||||||
content: metadataItem.source,
|
content: metadataItem.source,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}),
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
return routes.sort((a, b) =>
|
return routes.sort((a, b) =>
|
||||||
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
|
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
|
||||||
|
@ -383,19 +454,7 @@ export default function pluginContentDocs(
|
||||||
isLatestVersion ? '' : version,
|
isLatestVersion ? '' : version,
|
||||||
]);
|
]);
|
||||||
const docsBaseRoute = normalizeUrl([docsBasePermalink, ':route']);
|
const docsBaseRoute = normalizeUrl([docsBasePermalink, ':route']);
|
||||||
const neededSidebars: Set<string> =
|
const docsBaseMetadata = createDocsBaseMetadata(version);
|
||||||
content.versionToSidebars[version] || new Set();
|
|
||||||
const docsBaseMetadata: DocsBaseMetadata = {
|
|
||||||
docsSidebars: pick(
|
|
||||||
content.docsSidebars,
|
|
||||||
Array.from(neededSidebars),
|
|
||||||
),
|
|
||||||
permalinkToSidebar: pickBy(
|
|
||||||
content.permalinkToSidebar,
|
|
||||||
(sidebar) => neededSidebars.has(sidebar),
|
|
||||||
),
|
|
||||||
version,
|
|
||||||
};
|
|
||||||
|
|
||||||
// We want latest version route config to be placed last in the
|
// We want latest version route config to be placed last in the
|
||||||
// generated routeconfig. Otherwise, `/docs/next/foo` will match
|
// generated routeconfig. Otherwise, `/docs/next/foo` will match
|
||||||
|
@ -410,16 +469,31 @@ export default function pluginContentDocs(
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const routes = await genRoutes(Object.values(content.docsMetadata));
|
const routes = await genRoutes(Object.values(content.docsMetadata));
|
||||||
const docsBaseMetadata: DocsBaseMetadata = {
|
const docsBaseMetadata = createDocsBaseMetadata();
|
||||||
docsSidebars: content.docsSidebars,
|
|
||||||
permalinkToSidebar: content.permalinkToSidebar,
|
|
||||||
};
|
|
||||||
|
|
||||||
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath, ':route']);
|
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath, ':route']);
|
||||||
return addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
return addBaseRoute(docsBaseRoute, docsBaseMetadata, routes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async routesLoaded(routes) {
|
||||||
|
const normalizedHomeDocsRoutePath = `/${options.routeBasePath}`;
|
||||||
|
const homeDocsRoutes = routes.filter(
|
||||||
|
(routeConfig) => routeConfig.path === normalizedHomeDocsRoutePath,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the route for docs home page if there is a page with the same path (i.e. docs).
|
||||||
|
if (homeDocsRoutes.length > 1) {
|
||||||
|
const docsHomePageRouteIndex = routes.findIndex(
|
||||||
|
(route) =>
|
||||||
|
route.component === options.docLayoutComponent &&
|
||||||
|
route.path === normalizedHomeDocsRoutePath,
|
||||||
|
);
|
||||||
|
|
||||||
|
delete routes[docsHomePageRouteIndex!];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
configureWebpack(_config, isServer, utils) {
|
configureWebpack(_config, isServer, utils) {
|
||||||
const {getBabelLoader, getCacheLoader} = utils;
|
const {getBabelLoader, getCacheLoader} = utils;
|
||||||
const {rehypePlugins, remarkPlugins} = options;
|
const {rehypePlugins, remarkPlugins} = options;
|
||||||
|
|
|
@ -24,6 +24,7 @@ export interface PluginOptions extends MetadataOptions, PathOptions {
|
||||||
remarkPlugins: ([Function, object] | Function)[];
|
remarkPlugins: ([Function, object] | Function)[];
|
||||||
rehypePlugins: string[];
|
rehypePlugins: string[];
|
||||||
admonitions: any;
|
admonitions: any;
|
||||||
|
homePageId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SidebarItemDoc = {
|
export type SidebarItemDoc = {
|
||||||
|
@ -160,6 +161,8 @@ export type DocsBaseMetadata = Pick<
|
||||||
'docsSidebars' | 'permalinkToSidebar'
|
'docsSidebars' | 'permalinkToSidebar'
|
||||||
> & {
|
> & {
|
||||||
version?: string;
|
version?: string;
|
||||||
|
isHomePage?: boolean;
|
||||||
|
homePagePath?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VersioningEnv = {
|
export type VersioningEnv = {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {MDXProvider} from '@mdx-js/react';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import renderRoutes from '@docusaurus/renderRoutes';
|
import renderRoutes from '@docusaurus/renderRoutes';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
|
import DocItem from '@theme/DocItem';
|
||||||
import DocSidebar from '@theme/DocSidebar';
|
import DocSidebar from '@theme/DocSidebar';
|
||||||
import MDXComponents from '@theme/MDXComponents';
|
import MDXComponents from '@theme/MDXComponents';
|
||||||
import NotFound from '@theme/NotFound';
|
import NotFound from '@theme/NotFound';
|
||||||
|
@ -19,21 +20,31 @@ import {matchPath} from '@docusaurus/router';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function DocPage(props) {
|
function DocPage(props) {
|
||||||
const {route: baseRoute, docsMetadata, location} = props;
|
const {route: baseRoute, docsMetadata, location, content} = props;
|
||||||
// case-sensitive route such as it is defined in the sidebar
|
|
||||||
const currentRoute =
|
|
||||||
baseRoute.routes.find((route) => {
|
|
||||||
return matchPath(location.pathname, route);
|
|
||||||
}) || {};
|
|
||||||
const {permalinkToSidebar, docsSidebars, version} = docsMetadata;
|
|
||||||
const sidebar = permalinkToSidebar[currentRoute.path];
|
|
||||||
const {
|
const {
|
||||||
siteConfig: {themeConfig = {}} = {},
|
permalinkToSidebar,
|
||||||
|
docsSidebars,
|
||||||
|
version,
|
||||||
|
isHomePage,
|
||||||
|
homePagePath,
|
||||||
|
} = docsMetadata;
|
||||||
|
|
||||||
|
// Get case-sensitive route such as it is defined in the sidebar.
|
||||||
|
const currentRoute = !isHomePage
|
||||||
|
? baseRoute.routes.find((route) => {
|
||||||
|
return matchPath(location.pathname, route);
|
||||||
|
}) || {}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const sidebar = isHomePage
|
||||||
|
? content.metadata.sidebar
|
||||||
|
: permalinkToSidebar[currentRoute.path];
|
||||||
|
const {
|
||||||
|
siteConfig: {themeConfig: {sidebarCollapsible = true} = {}} = {},
|
||||||
isClient,
|
isClient,
|
||||||
} = useDocusaurusContext();
|
} = useDocusaurusContext();
|
||||||
const {sidebarCollapsible = true} = themeConfig;
|
|
||||||
|
|
||||||
if (Object.keys(currentRoute).length === 0) {
|
if (!isHomePage && Object.keys(currentRoute).length === 0) {
|
||||||
return <NotFound {...props} />;
|
return <NotFound {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +55,7 @@ function DocPage(props) {
|
||||||
<div className={styles.docSidebarContainer}>
|
<div className={styles.docSidebarContainer}>
|
||||||
<DocSidebar
|
<DocSidebar
|
||||||
docsSidebars={docsSidebars}
|
docsSidebars={docsSidebars}
|
||||||
path={currentRoute.path}
|
path={isHomePage ? homePagePath : currentRoute.path}
|
||||||
sidebar={sidebar}
|
sidebar={sidebar}
|
||||||
sidebarCollapsible={sidebarCollapsible}
|
sidebarCollapsible={sidebarCollapsible}
|
||||||
/>
|
/>
|
||||||
|
@ -52,7 +63,11 @@ function DocPage(props) {
|
||||||
)}
|
)}
|
||||||
<main className={styles.docMainContainer}>
|
<main className={styles.docMainContainer}>
|
||||||
<MDXProvider components={MDXComponents}>
|
<MDXProvider components={MDXComponents}>
|
||||||
{renderRoutes(baseRoute.routes)}
|
{isHomePage ? (
|
||||||
|
<DocItem content={content} />
|
||||||
|
) : (
|
||||||
|
renderRoutes(baseRoute.routes)
|
||||||
|
)}
|
||||||
</MDXProvider>
|
</MDXProvider>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,7 +17,13 @@ import styles from './styles.module.css';
|
||||||
|
|
||||||
const MOBILE_TOGGLE_SIZE = 24;
|
const MOBILE_TOGGLE_SIZE = 24;
|
||||||
|
|
||||||
function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
function DocSidebarItem({
|
||||||
|
item,
|
||||||
|
onItemClick,
|
||||||
|
collapsible,
|
||||||
|
activePath,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
const {items, href, label, type} = item;
|
const {items, href, label, type} = item;
|
||||||
const [collapsed, setCollapsed] = useState(item.collapsed);
|
const [collapsed, setCollapsed] = useState(item.collapsed);
|
||||||
const [prevCollapsedProp, setPreviousCollapsedProp] = useState(null);
|
const [prevCollapsedProp, setPreviousCollapsedProp] = useState(null);
|
||||||
|
@ -63,6 +69,7 @@ function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
||||||
item={childItem}
|
item={childItem}
|
||||||
onItemClick={onItemClick}
|
onItemClick={onItemClick}
|
||||||
collapsible={collapsible}
|
collapsible={collapsible}
|
||||||
|
activePath={activePath}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -75,7 +82,9 @@ function DocSidebarItem({item, onItemClick, collapsible, ...props}) {
|
||||||
return (
|
return (
|
||||||
<li className="menu__list-item" key={label}>
|
<li className="menu__list-item" key={label}>
|
||||||
<Link
|
<Link
|
||||||
className="menu__link"
|
className={classnames('menu__link', {
|
||||||
|
'menu__link--active': href === activePath,
|
||||||
|
})}
|
||||||
to={href}
|
to={href}
|
||||||
{...(isInternalUrl(href)
|
{...(isInternalUrl(href)
|
||||||
? {
|
? {
|
||||||
|
@ -219,6 +228,7 @@ function DocSidebar(props) {
|
||||||
setShowResponsiveSidebar(false);
|
setShowResponsiveSidebar(false);
|
||||||
}}
|
}}
|
||||||
collapsible={sidebarCollapsible}
|
collapsible={sidebarCollapsible}
|
||||||
|
activePath={path}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
1
packages/docusaurus-types/src/index.d.ts
vendored
1
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -105,6 +105,7 @@ export interface Plugin<T> {
|
||||||
content: T;
|
content: T;
|
||||||
actions: PluginContentLoadedActions;
|
actions: PluginContentLoadedActions;
|
||||||
}): void;
|
}): void;
|
||||||
|
routesLoaded?(routes: RouteConfig[]): void;
|
||||||
postBuild?(props: Props): void;
|
postBuild?(props: Props): void;
|
||||||
postStart?(props: Props): void;
|
postStart?(props: Props): void;
|
||||||
configureWebpack?(
|
configureWebpack?(
|
||||||
|
|
|
@ -40,6 +40,12 @@ export function sortConfig(routeConfigs: RouteConfig[]) {
|
||||||
|
|
||||||
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
routeConfigs.forEach((routeConfig) => {
|
||||||
|
routeConfig.routes?.sort((a, b) => {
|
||||||
|
return a.path > b.path ? 1 : b.path > a.path ? -1 : 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadPlugins({
|
export async function loadPlugins({
|
||||||
|
@ -100,6 +106,20 @@ export async function loadPlugins({
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 4. Plugin Lifecycle - routesLoaded.
|
||||||
|
// 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.
|
||||||
|
await Promise.all(
|
||||||
|
plugins.map(async (plugin) => {
|
||||||
|
if (!plugin.routesLoaded) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await plugin.routesLoaded(pluginsRouteConfigs);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Sort the route config. This ensures that route with nested
|
// Sort the route config. This ensures that route with nested
|
||||||
// routes are always placed last.
|
// routes are always placed last.
|
||||||
sortConfig(pluginsRouteConfigs);
|
sortConfig(pluginsRouteConfigs);
|
||||||
|
|
|
@ -29,6 +29,42 @@ id: part1
|
||||||
Lorem ipsum
|
Lorem ipsum
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Home page docs
|
||||||
|
|
||||||
|
Using the `homePageId` property, you can create a home page of your docs. To do this, you can create a new document, especially for this purpose with the id as `_index`, or you could specify an existing document id.
|
||||||
|
|
||||||
|
```js {8} title="docusaurus.config.js"
|
||||||
|
module.exports = {
|
||||||
|
// ...
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@docusaurus/preset-classic',
|
||||||
|
{
|
||||||
|
docs: {
|
||||||
|
homePageId: 'getting-started', // Defaults to `_index`
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Given the example above, now when you navigate to the path `/docs` you will see that the document content with id is `getting-started`. This functionality also works for docs with versioning enabled.
|
||||||
|
|
||||||
|
:::important
|
||||||
|
|
||||||
|
The document id of `_index` is reserved exclusively for the home doc page, so it will not work as a standalone route.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::note
|
||||||
|
|
||||||
|
The page `docs` that you created (eg. `src/pages/docs.js`) will take precedence over the route generated via the `homePageId` option.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## Sidebar
|
## Sidebar
|
||||||
|
|
||||||
To generate a sidebar to your Docusaurus site, you need to define a file that exports a sidebar object and pass that into the `@docusaurus/plugin-docs` plugin directly or via `@docusaurus/preset-classic`.
|
To generate a sidebar to your Docusaurus site, you need to define a file that exports a sidebar object and pass that into the `@docusaurus/plugin-docs` plugin directly or via `@docusaurus/preset-classic`.
|
||||||
|
@ -258,11 +294,17 @@ module.exports = {
|
||||||
|
|
||||||
## Docs-only mode
|
## Docs-only mode
|
||||||
|
|
||||||
If you just want the documentation feature, you can follow the instructions for a "docs-only mode":
|
If you just want the documentation feature, you can enable "docs-only mode".
|
||||||
|
|
||||||
1. Set the `routeBasePath` property of the `docs` object in `@docusaurus/preset-classic` in `docusaurus.config.js` to the root of your site:
|
To achieve this, set the `routeBasePath` property of the `docs` object in `@docusaurus/preset-classic` in `docusaurus.config.js` to the root of your site, and also in that object set the `homePageId` property with the value of the document ID that you show as root of the docs.
|
||||||
|
|
||||||
```js {8} title="docusaurus.config.js"
|
:::note
|
||||||
|
|
||||||
|
More details on functionality of home page for docs can be found in [appropriate section](#home-page-docs).
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
```js {8-9} title="docusaurus.config.js"
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// ...
|
// ...
|
||||||
presets: [
|
presets: [
|
||||||
|
@ -271,6 +313,7 @@ module.exports = {
|
||||||
{
|
{
|
||||||
docs: {
|
docs: {
|
||||||
routeBasePath: '/', // Set this value to '/'.
|
routeBasePath: '/', // Set this value to '/'.
|
||||||
|
homePageId: 'getting-started', // Set to existing document id.
|
||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -280,21 +323,6 @@ module.exports = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Set up a redirect to the initial document on the home page in `/src/pages/index.js`, e.g. for the document `getting-started`. This is needed because by default there's no page created for the root of the docs.
|
|
||||||
|
|
||||||
```jsx title="src/pages/index.js"
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import {Redirect} from '@docusaurus/router';
|
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
|
||||||
|
|
||||||
function Home() {
|
|
||||||
return <Redirect to={useBaseUrl('/getting-started')} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home;
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, when visiting your site, it will show your initial document instead of a landing page.
|
Now, when visiting your site, it will show your initial document instead of a landing page.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
|
|
@ -52,6 +52,10 @@ module.exports = function (context, options) {
|
||||||
|
|
||||||
Plugins should use the data loaded in `loadContent` and construct the pages/routes that consume the loaded data (optional).
|
Plugins should use the data loaded in `loadContent` and construct the pages/routes that consume the loaded data (optional).
|
||||||
|
|
||||||
|
## `async routesLoaded(routes)`
|
||||||
|
|
||||||
|
Plugins can modify the routes that were generated by all plugins. `routesLoaded` is called after `contentLoaded` hook.
|
||||||
|
|
||||||
### `content`
|
### `content`
|
||||||
|
|
||||||
`contentLoaded` will be called _after_ `loadContent` is done, the return value of `loadContent()` will be passed to `contentLoaded` as `content`.
|
`contentLoaded` will be called _after_ `loadContent` is done, the return value of `loadContent()` will be passed to `contentLoaded` as `content`.
|
||||||
|
@ -373,6 +377,11 @@ module.exports = function (context, opts) {
|
||||||
// actions are set of functional API provided by Docusaurus. e.g: addRoute
|
// actions are set of functional API provided by Docusaurus. e.g: addRoute
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async routesLoaded(routes) {
|
||||||
|
// routesLoaded hook is done after contentLoaded hook is done
|
||||||
|
// This can be useful if you need to change any route.
|
||||||
|
},
|
||||||
|
|
||||||
async postBuild(props) {
|
async postBuild(props) {
|
||||||
// after docusaurus <build> finish
|
// after docusaurus <build> finish
|
||||||
},
|
},
|
||||||
|
|
|
@ -236,6 +236,7 @@ module.exports = {
|
||||||
* do not include trailing slash
|
* do not include trailing slash
|
||||||
*/
|
*/
|
||||||
routeBasePath: 'docs',
|
routeBasePath: 'docs',
|
||||||
|
homePageId: '_index', // Document id for docs home page.
|
||||||
include: ['**/*.md', '**/*.mdx'], // Extensions to include.
|
include: ['**/*.md', '**/*.mdx'], // Extensions to include.
|
||||||
/**
|
/**
|
||||||
* Path to sidebar configuration for showing a list of markdown pages.
|
* Path to sidebar configuration for showing a list of markdown pages.
|
||||||
|
|
|
@ -36,6 +36,7 @@ module.exports = {
|
||||||
'@docusaurus/preset-classic',
|
'@docusaurus/preset-classic',
|
||||||
{
|
{
|
||||||
docs: {
|
docs: {
|
||||||
|
homePageId: 'introduction',
|
||||||
path: 'docs',
|
path: 'docs',
|
||||||
sidebarPath: require.resolve('./sidebars.js'),
|
sidebarPath: require.resolve('./sidebars.js'),
|
||||||
editUrl:
|
editUrl:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue