mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-21 21:16:59 +02:00
wip use plugin page code logic
This commit is contained in:
parent
49b67463bd
commit
6e40a79b6f
5 changed files with 126 additions and 58 deletions
|
@ -14,33 +14,37 @@ import {
|
||||||
addTrailingPathSeparator,
|
addTrailingPathSeparator,
|
||||||
aliasedSitePath,
|
aliasedSitePath,
|
||||||
docuHash,
|
docuHash,
|
||||||
|
getFolderContainingFile,
|
||||||
|
getPluginI18nPath,
|
||||||
|
Globby,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
import Yaml from 'js-yaml';
|
import Yaml from 'js-yaml';
|
||||||
|
|
||||||
import {contentAuthorsSchema} from './options';
|
import {contentAuthorsSchema} from './options';
|
||||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||||
import type {
|
import type {PluginOptions, Content} from '@docusaurus/plugin-showcase';
|
||||||
PluginOptions,
|
import type {ShowcaseContentPaths} from './types';
|
||||||
Content,
|
|
||||||
ShowcaseMetadata,
|
|
||||||
} from '@docusaurus/plugin-showcase';
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/71166133
|
export function getContentPathList(
|
||||||
const walk = async (dirPath: string): Promise<any[]> =>
|
contentPaths: ShowcaseContentPaths,
|
||||||
Promise.all(
|
): string[] {
|
||||||
await fs.readdir(dirPath, {withFileTypes: true}).then((entries) =>
|
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
||||||
entries.map((entry) => {
|
}
|
||||||
const childPath = path.join(dirPath, entry.name);
|
|
||||||
return entry.isDirectory() ? walk(childPath) : childPath;
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function pluginContentShowcase(
|
export default function pluginContentShowcase(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin<Content> {
|
): Plugin<Content | null> {
|
||||||
const {siteConfig, siteDir, generatedFilesDir} = context;
|
const {siteConfig, siteDir, generatedFilesDir, localizationDir} = context;
|
||||||
|
|
||||||
|
const contentPaths: ShowcaseContentPaths = {
|
||||||
|
contentPath: path.resolve(siteDir, options.path),
|
||||||
|
contentPathLocalized: getPluginI18nPath({
|
||||||
|
localizationDir,
|
||||||
|
pluginName: 'docusaurus-plugin-content-pages',
|
||||||
|
pluginId: options.id,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
const pluginDataDirRoot = path.join(
|
const pluginDataDirRoot = path.join(
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
|
@ -48,35 +52,52 @@ export default function pluginContentShowcase(
|
||||||
);
|
);
|
||||||
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
||||||
|
|
||||||
const showcasePath = path.join(siteDir, options.path);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-showcase',
|
name: 'docusaurus-plugin-showcase',
|
||||||
|
|
||||||
// getPathsToWatch() {
|
getPathsToWatch() {
|
||||||
// return [path.join(siteDir, options.path, 'authors.yaml')];
|
const {include} = options;
|
||||||
// },
|
return getContentPathList(contentPaths).flatMap((contentPath) =>
|
||||||
|
include.map((pattern) => `${contentPath}/${pattern}`),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
async loadContent(): Promise<Content> {
|
async loadContent() {
|
||||||
const files: string[] = await walk(path.join(siteDir, options.path));
|
const {include} = options;
|
||||||
const filteredFiles = files
|
|
||||||
.flat(Number.POSITIVE_INFINITY)
|
|
||||||
.filter((file) => file.endsWith('.yaml'));
|
|
||||||
|
|
||||||
const contentPromises = filteredFiles.map(async (file) => {
|
if (!(await fs.pathExists(contentPaths.contentPath))) {
|
||||||
const rawYaml = await fs.readFile(path.join(file), 'utf-8');
|
return null;
|
||||||
const yaml = Yaml.load(rawYaml);
|
}
|
||||||
const parsedYaml = contentAuthorsSchema.validate(yaml);
|
|
||||||
|
|
||||||
if (parsedYaml.error) {
|
// const {baseUrl} = siteConfig;
|
||||||
throw new Error(`Validation failed: ${parsedYaml.error.message}`, {
|
const showcaseFiles = await Globby(include, {
|
||||||
cause: parsedYaml.error,
|
cwd: contentPaths.contentPath,
|
||||||
|
ignore: options.exclude,
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredFiles = showcaseFiles.filter((file) =>
|
||||||
|
file.endsWith('.yaml'),
|
||||||
|
);
|
||||||
|
|
||||||
|
async function processPageSourceFile(relativeSource: string) {
|
||||||
|
// Lookup in localized folder in priority
|
||||||
|
const contentPath = await getFolderContainingFile(
|
||||||
|
getContentPathList(contentPaths),
|
||||||
|
relativeSource,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sourcePath = path.join(contentPath, relativeSource);
|
||||||
|
const aliasedSourcePath = aliasedSitePath(sourcePath, siteDir);
|
||||||
|
const rawYaml = await fs.readFile(sourcePath, 'utf-8');
|
||||||
|
const unsafeYaml = Yaml.load(rawYaml);
|
||||||
|
const yaml = contentAuthorsSchema.validate(unsafeYaml);
|
||||||
|
if (yaml.error) {
|
||||||
|
throw new Error(`Validation failed: ${yaml.error.message}`, {
|
||||||
|
cause: yaml.error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {title, description, preview, website, source, tags} =
|
const {title, description, preview, website, source, tags} = yaml.value;
|
||||||
parsedYaml.value;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
@ -85,11 +106,21 @@ export default function pluginContentShowcase(
|
||||||
source,
|
source,
|
||||||
tags,
|
tags,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
|
||||||
|
async function doProcessPageSourceFile(relativeSource: string) {
|
||||||
|
try {
|
||||||
|
return await processPageSourceFile(relativeSource);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`Processing of page source file path=${relativeSource} failed.`,
|
||||||
|
{cause: err as Error},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const content = await Promise.all(contentPromises);
|
|
||||||
return {
|
return {
|
||||||
website: content,
|
website: await Promise.all(filteredFiles.map(doProcessPageSourceFile)),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -134,17 +165,19 @@ export default function pluginContentShowcase(
|
||||||
},
|
},
|
||||||
|
|
||||||
configureWebpack(_config, isServer, utils, content) {
|
configureWebpack(_config, isServer, utils, content) {
|
||||||
|
const contentDirs = getContentPathList(contentPaths);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~blog': pluginDataDirRoot,
|
'~showcase': pluginDataDirRoot,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.mdx?$/i,
|
test: /\.mdx?$/i,
|
||||||
include: [...showcasePath]
|
include: contentDirs
|
||||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||||
.map(addTrailingPathSeparator),
|
.map(addTrailingPathSeparator),
|
||||||
use: [
|
use: [
|
||||||
|
@ -155,6 +188,10 @@ export default function pluginContentShowcase(
|
||||||
path.resolve(siteDir, dir),
|
path.resolve(siteDir, dir),
|
||||||
),
|
),
|
||||||
siteDir,
|
siteDir,
|
||||||
|
// isMDXPartial: createAbsoluteFilePathMatcher(
|
||||||
|
// options.exclude,
|
||||||
|
// contentDirs,
|
||||||
|
// ),
|
||||||
metadataPath: (mdxPath: string) => {
|
metadataPath: (mdxPath: string) => {
|
||||||
// Note that metadataPath must be the same/in-sync as
|
// Note that metadataPath must be the same/in-sync as
|
||||||
// the path from createData for each MDX.
|
// the path from createData for each MDX.
|
||||||
|
@ -164,24 +201,15 @@ export default function pluginContentShowcase(
|
||||||
`${docuHash(aliasedPath)}.json`,
|
`${docuHash(aliasedPath)}.json`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
// For blog posts a title in markdown is always removed
|
|
||||||
// Blog posts title are rendered separately
|
|
||||||
removeContentTitle: true,
|
|
||||||
|
|
||||||
// Assets allow to convert some relative images paths to
|
// Assets allow to convert some relative images paths to
|
||||||
// require() calls
|
// require() calls
|
||||||
// createAssets: ({
|
createAssets: ({
|
||||||
// frontMatter,
|
frontMatter,
|
||||||
// metadata,
|
}: {
|
||||||
// }: {
|
frontMatter: Content['website'][number];
|
||||||
// frontMatter: Content['website'][number];
|
}) => ({
|
||||||
// metadata: ShowcaseMetadata;
|
image: frontMatter.preview,
|
||||||
// }): Assets => ({
|
}),
|
||||||
// image: frontMatter.preview,
|
|
||||||
// authorsImageUrls: metadata.frontMatter.preview.map(
|
|
||||||
// (author) => author.imageURL,
|
|
||||||
// ),
|
|
||||||
// }),
|
|
||||||
markdownConfig: siteConfig.markdown,
|
markdownConfig: siteConfig.markdown,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
22
packages/docusaurus-plugin-showcase/src/markdownLoader.ts
Normal file
22
packages/docusaurus-plugin-showcase/src/markdownLoader.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* 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 type {LoaderContext} from 'webpack';
|
||||||
|
|
||||||
|
export default function markdownLoader(
|
||||||
|
this: LoaderContext<undefined>,
|
||||||
|
fileString: string,
|
||||||
|
): void {
|
||||||
|
const callback = this.async();
|
||||||
|
|
||||||
|
// const options = this.getOptions();
|
||||||
|
|
||||||
|
// TODO provide additional md processing here? like interlinking pages?
|
||||||
|
// fileString = linkify(fileString)
|
||||||
|
|
||||||
|
return callback(null, fileString);
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Joi, RouteBasePathSchema} from '@docusaurus/utils-validation';
|
import {Joi, RouteBasePathSchema} from '@docusaurus/utils-validation';
|
||||||
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
||||||
import type {OptionValidationContext} from '@docusaurus/types';
|
import type {OptionValidationContext} from '@docusaurus/types';
|
||||||
import type {PluginOptions, Options} from '@docusaurus/plugin-showcase';
|
import type {PluginOptions, Options} from '@docusaurus/plugin-showcase';
|
||||||
|
|
||||||
|
@ -13,11 +14,16 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
||||||
id: 'showcase',
|
id: 'showcase',
|
||||||
path: 'src/showcase/website', // Path to data on filesystem, relative to site dir.
|
path: 'src/showcase/website', // Path to data on filesystem, relative to site dir.
|
||||||
routeBasePath: '/', // URL Route.
|
routeBasePath: '/', // URL Route.
|
||||||
|
include: ['**/*.{yml,yaml,md,mdx}'], // Extensions to include.
|
||||||
|
exclude: GlobExcludeDefault,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PluginOptionSchema = Joi.object<PluginOptions>({
|
const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||||
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
||||||
|
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
||||||
|
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
||||||
|
id: Joi.string().default(DEFAULT_OPTIONS.id),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const contentAuthorsSchema = Joi.object({
|
export const contentAuthorsSchema = Joi.object({
|
||||||
|
|
|
@ -16,6 +16,8 @@ declare module '@docusaurus/plugin-showcase' {
|
||||||
id?: string;
|
id?: string;
|
||||||
path: string;
|
path: string;
|
||||||
routeBasePath: string;
|
routeBasePath: string;
|
||||||
|
include: string[];
|
||||||
|
exclude: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TagType =
|
export type TagType =
|
||||||
|
|
10
packages/docusaurus-plugin-showcase/src/types.ts
Normal file
10
packages/docusaurus-plugin-showcase/src/types.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export type ShowcaseContentPaths = {
|
||||||
|
contentPath: string;
|
||||||
|
contentPathLocalized: string;
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue