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:
Alexey Pyltsyn 2020-05-17 12:48:02 +03:00 committed by GitHub
parent 393adc5324
commit 00a8e9e365
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 264 additions and 61 deletions

View file

@ -52,6 +52,15 @@ Object {
exports[`simple website content 2`] = `
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 {
"component": "@theme/DocPage",
"modules": Object {
@ -107,6 +116,33 @@ Array [
exports[`versioned website content 1`] = `
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 {
"component": "@theme/DocPage",
"modules": Object {

View file

@ -93,6 +93,7 @@ describe('simple website', () => {
const plugin = pluginContentDocs(context, {
path: pluginPath,
sidebarPath,
homePageId: 'hello',
});
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
@ -203,6 +204,9 @@ describe('simple website', () => {
expect(baseMetadata.docsSidebars).toEqual(docsSidebars);
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).toMatchSnapshot();
});
@ -216,6 +220,7 @@ describe('versioned website', () => {
const plugin = pluginContentDocs(context, {
routeBasePath,
sidebarPath,
homePageId: 'hello',
});
const env = loadEnv(siteDir);
const {docsDir: versionedDir} = env.versioning;

View file

@ -48,9 +48,12 @@ import {Configuration} from 'webpack';
import {docsVersion} from './version';
import {VERSIONS_JSON_FILE} from './constants';
const REVERSED_DOCS_HOME_PAGE_ID = '_index';
const DEFAULT_OPTIONS: PluginOptions = {
path: 'docs', // Path to data on filesystem, relative to site dir.
routeBasePath: 'docs', // URL Route.
homePageId: REVERSED_DOCS_HOME_PAGE_ID, // Document id for docs home page.
include: ['**/*.{md,mdx}'], // Extensions to include.
sidebarPath: '', // Path to sidebar configuration for showing a list of markdown pages.
docLayoutComponent: '@theme/DocPage',
@ -313,28 +316,96 @@ export default function pluginContentDocs(
const aliasedSource = (source: string) =>
`~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 (
metadataItems: Metadata[],
): Promise<RouteConfig[]> => {
const routes = await Promise.all(
metadataItems.map(async (metadataItem) => {
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),
const routes: RouteConfig[] = [];
await metadataItems.forEach(async (metadataItem, i) => {
const isDocsHomePage =
metadataItem.id.substr(metadataItem.id.indexOf('/') + 1) ===
options.homePageId;
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,
component: docItemComponent,
exact: true,
modules: {
content: metadataItem.source,
},
};
}),
);
});
}
});
return routes.sort((a, b) =>
a.path > b.path ? 1 : b.path > a.path ? -1 : 0,
@ -383,19 +454,7 @@ export default function pluginContentDocs(
isLatestVersion ? '' : version,
]);
const docsBaseRoute = normalizeUrl([docsBasePermalink, ':route']);
const neededSidebars: Set<string> =
content.versionToSidebars[version] || new Set();
const docsBaseMetadata: DocsBaseMetadata = {
docsSidebars: pick(
content.docsSidebars,
Array.from(neededSidebars),
),
permalinkToSidebar: pickBy(
content.permalinkToSidebar,
(sidebar) => neededSidebars.has(sidebar),
),
version,
};
const docsBaseMetadata = createDocsBaseMetadata(version);
// We want latest version route config to be placed last in the
// generated routeconfig. Otherwise, `/docs/next/foo` will match
@ -410,16 +469,31 @@ export default function pluginContentDocs(
);
} else {
const routes = await genRoutes(Object.values(content.docsMetadata));
const docsBaseMetadata: DocsBaseMetadata = {
docsSidebars: content.docsSidebars,
permalinkToSidebar: content.permalinkToSidebar,
};
const docsBaseMetadata = createDocsBaseMetadata();
const docsBaseRoute = normalizeUrl([baseUrl, routeBasePath, ':route']);
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) {
const {getBabelLoader, getCacheLoader} = utils;
const {rehypePlugins, remarkPlugins} = options;

View file

@ -24,6 +24,7 @@ export interface PluginOptions extends MetadataOptions, PathOptions {
remarkPlugins: ([Function, object] | Function)[];
rehypePlugins: string[];
admonitions: any;
homePageId: string;
}
export type SidebarItemDoc = {
@ -160,6 +161,8 @@ export type DocsBaseMetadata = Pick<
'docsSidebars' | 'permalinkToSidebar'
> & {
version?: string;
isHomePage?: boolean;
homePagePath?: string;
};
export type VersioningEnv = {