mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-21 13:06:58 +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,
|
||||
aliasedSitePath,
|
||||
docuHash,
|
||||
getFolderContainingFile,
|
||||
getPluginI18nPath,
|
||||
Globby,
|
||||
} from '@docusaurus/utils';
|
||||
import Yaml from 'js-yaml';
|
||||
|
||||
import {contentAuthorsSchema} from './options';
|
||||
import type {LoadContext, Plugin} from '@docusaurus/types';
|
||||
import type {
|
||||
PluginOptions,
|
||||
Content,
|
||||
ShowcaseMetadata,
|
||||
} from '@docusaurus/plugin-showcase';
|
||||
import type {PluginOptions, Content} from '@docusaurus/plugin-showcase';
|
||||
import type {ShowcaseContentPaths} from './types';
|
||||
|
||||
// https://stackoverflow.com/a/71166133
|
||||
const walk = async (dirPath: string): Promise<any[]> =>
|
||||
Promise.all(
|
||||
await fs.readdir(dirPath, {withFileTypes: true}).then((entries) =>
|
||||
entries.map((entry) => {
|
||||
const childPath = path.join(dirPath, entry.name);
|
||||
return entry.isDirectory() ? walk(childPath) : childPath;
|
||||
}),
|
||||
),
|
||||
);
|
||||
export function getContentPathList(
|
||||
contentPaths: ShowcaseContentPaths,
|
||||
): string[] {
|
||||
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
||||
}
|
||||
|
||||
export default function pluginContentShowcase(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Plugin<Content> {
|
||||
const {siteConfig, siteDir, generatedFilesDir} = context;
|
||||
): Plugin<Content | null> {
|
||||
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(
|
||||
generatedFilesDir,
|
||||
|
@ -48,35 +52,52 @@ export default function pluginContentShowcase(
|
|||
);
|
||||
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
||||
|
||||
const showcasePath = path.join(siteDir, options.path);
|
||||
|
||||
return {
|
||||
name: 'docusaurus-plugin-showcase',
|
||||
|
||||
// getPathsToWatch() {
|
||||
// return [path.join(siteDir, options.path, 'authors.yaml')];
|
||||
// },
|
||||
getPathsToWatch() {
|
||||
const {include} = options;
|
||||
return getContentPathList(contentPaths).flatMap((contentPath) =>
|
||||
include.map((pattern) => `${contentPath}/${pattern}`),
|
||||
);
|
||||
},
|
||||
|
||||
async loadContent(): Promise<Content> {
|
||||
const files: string[] = await walk(path.join(siteDir, options.path));
|
||||
const filteredFiles = files
|
||||
.flat(Number.POSITIVE_INFINITY)
|
||||
.filter((file) => file.endsWith('.yaml'));
|
||||
async loadContent() {
|
||||
const {include} = options;
|
||||
|
||||
const contentPromises = filteredFiles.map(async (file) => {
|
||||
const rawYaml = await fs.readFile(path.join(file), 'utf-8');
|
||||
const yaml = Yaml.load(rawYaml);
|
||||
const parsedYaml = contentAuthorsSchema.validate(yaml);
|
||||
if (!(await fs.pathExists(contentPaths.contentPath))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (parsedYaml.error) {
|
||||
throw new Error(`Validation failed: ${parsedYaml.error.message}`, {
|
||||
cause: parsedYaml.error,
|
||||
// const {baseUrl} = siteConfig;
|
||||
const showcaseFiles = await Globby(include, {
|
||||
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} =
|
||||
parsedYaml.value;
|
||||
|
||||
const {title, description, preview, website, source, tags} = yaml.value;
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
|
@ -85,11 +106,21 @@ export default function pluginContentShowcase(
|
|||
source,
|
||||
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 {
|
||||
website: content,
|
||||
website: await Promise.all(filteredFiles.map(doProcessPageSourceFile)),
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -134,17 +165,19 @@ export default function pluginContentShowcase(
|
|||
},
|
||||
|
||||
configureWebpack(_config, isServer, utils, content) {
|
||||
const contentDirs = getContentPathList(contentPaths);
|
||||
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'~blog': pluginDataDirRoot,
|
||||
'~showcase': pluginDataDirRoot,
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.mdx?$/i,
|
||||
include: [...showcasePath]
|
||||
include: contentDirs
|
||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||
.map(addTrailingPathSeparator),
|
||||
use: [
|
||||
|
@ -155,6 +188,10 @@ export default function pluginContentShowcase(
|
|||
path.resolve(siteDir, dir),
|
||||
),
|
||||
siteDir,
|
||||
// isMDXPartial: createAbsoluteFilePathMatcher(
|
||||
// options.exclude,
|
||||
// contentDirs,
|
||||
// ),
|
||||
metadataPath: (mdxPath: string) => {
|
||||
// Note that metadataPath must be the same/in-sync as
|
||||
// the path from createData for each MDX.
|
||||
|
@ -164,24 +201,15 @@ export default function pluginContentShowcase(
|
|||
`${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
|
||||
// require() calls
|
||||
// createAssets: ({
|
||||
// frontMatter,
|
||||
// metadata,
|
||||
// }: {
|
||||
// frontMatter: Content['website'][number];
|
||||
// metadata: ShowcaseMetadata;
|
||||
// }): Assets => ({
|
||||
// image: frontMatter.preview,
|
||||
// authorsImageUrls: metadata.frontMatter.preview.map(
|
||||
// (author) => author.imageURL,
|
||||
// ),
|
||||
// }),
|
||||
createAssets: ({
|
||||
frontMatter,
|
||||
}: {
|
||||
frontMatter: Content['website'][number];
|
||||
}) => ({
|
||||
image: frontMatter.preview,
|
||||
}),
|
||||
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 {GlobExcludeDefault} from '@docusaurus/utils';
|
||||
import type {OptionValidationContext} from '@docusaurus/types';
|
||||
import type {PluginOptions, Options} from '@docusaurus/plugin-showcase';
|
||||
|
||||
|
@ -13,11 +14,16 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
id: 'showcase',
|
||||
path: 'src/showcase/website', // Path to data on filesystem, relative to site dir.
|
||||
routeBasePath: '/', // URL Route.
|
||||
include: ['**/*.{yml,yaml,md,mdx}'], // Extensions to include.
|
||||
exclude: GlobExcludeDefault,
|
||||
};
|
||||
|
||||
const PluginOptionSchema = Joi.object<PluginOptions>({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
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({
|
||||
|
|
|
@ -16,6 +16,8 @@ declare module '@docusaurus/plugin-showcase' {
|
|||
id?: string;
|
||||
path: string;
|
||||
routeBasePath: string;
|
||||
include: string[];
|
||||
exclude: string[];
|
||||
};
|
||||
|
||||
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