docusaurus/packages/docusaurus-plugin-content-pages/src/index.ts
Anshul Goyal f234c407f1
feat(v2): add support to ignore files in pages plugin (#3196)
* add support to ignore pages

* fix import problem

* Update website/docs/guides/creating-pages.md

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>

* Revert "fix import problem"

This reverts commit 4457a2e938.

* revert

* fix slash

* forbid frontmatter

* fix formatting

* Update website/docs/guides/creating-pages.md

* Update website/src/pages/examples/_chapter1.md

* Update website/src/pages/examples/_chapter2.mdx

* Update website/src/pages/examples/markdownPageExample.md

* Update website/src/pages/examples/markdownPageExample.md

* Update website/src/pages/examples/markdownPageExample.md

* Update website/src/pages/examples/markdownPageExample.md

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
2020-08-05 21:35:55 +02:00

222 lines
6.2 KiB
TypeScript

/**
* 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 globby from 'globby';
import fs from 'fs';
import path from 'path';
import minimatch from 'minimatch';
import slash from 'slash';
import {
encodePath,
fileToPath,
aliasedSitePath,
docuHash,
} from '@docusaurus/utils';
import {
LoadContext,
Plugin,
OptionValidationContext,
ValidationResult,
ConfigureWebpackUtils,
} from '@docusaurus/types';
import {Configuration, Loader} from 'webpack';
import admonitions from 'remark-admonitions';
import {PluginOptionSchema} from './pluginOptionSchema';
import {ValidationError} from '@hapi/joi';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
import {PluginOptions, LoadedContent, Metadata} from './types';
const isMarkdownSource = (source: string) =>
source.endsWith('.md') || source.endsWith('.mdx');
export default function pluginContentPages(
context: LoadContext,
options: PluginOptions,
): Plugin<LoadedContent | null, typeof PluginOptionSchema> {
if (options.admonitions) {
options.remarkPlugins = options.remarkPlugins.concat([
[admonitions, options.admonitions || {}],
]);
}
const {siteConfig, siteDir, generatedFilesDir} = context;
const contentPath = path.resolve(siteDir, options.path);
const pluginDataDirRoot = path.join(
generatedFilesDir,
'docusaurus-plugin-content-pages',
);
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
const excludeRegex = new RegExp(
options.exclude
.map((pattern) => minimatch.makeRe(pattern).source)
.join('|'),
);
return {
name: 'docusaurus-plugin-content-pages',
getPathsToWatch() {
const {include = []} = options;
const globPattern = include.map((pattern) => `${contentPath}/${pattern}`);
return [...globPattern];
},
getClientModules() {
const modules = [];
if (options.admonitions) {
modules.push(require.resolve('remark-admonitions/styles/infima.css'));
}
return modules;
},
async loadContent() {
const {include} = options;
const pagesDir = contentPath;
if (!fs.existsSync(pagesDir)) {
return null;
}
const {baseUrl} = siteConfig;
const pagesFiles = await globby(include, {
cwd: pagesDir,
ignore: options.exclude,
});
function toMetadata(relativeSource: string): Metadata {
const source = path.join(pagesDir, relativeSource);
const aliasedSourcePath = aliasedSitePath(source, siteDir);
const pathName = encodePath(fileToPath(relativeSource));
const permalink = pathName.replace(/^\//, baseUrl || '');
if (isMarkdownSource(relativeSource)) {
return {
type: 'mdx',
permalink,
source: aliasedSourcePath,
};
} else {
return {
type: 'jsx',
permalink,
source: aliasedSourcePath,
};
}
}
return pagesFiles.map(toMetadata);
},
async contentLoaded({content, actions}) {
if (!content) {
return;
}
const {addRoute, createData} = actions;
await Promise.all(
content.map(async (metadata) => {
const {permalink, source} = metadata;
if (metadata.type === 'mdx') {
await createData(
// Note that this created data path must be in sync with
// metadataPath provided to mdx-loader.
`${docuHash(metadata.source)}.json`,
JSON.stringify(metadata, null, 2),
);
addRoute({
path: permalink,
component: options.mdxPageComponent,
exact: true,
modules: {
content: source,
},
});
} else {
addRoute({
path: permalink,
component: source,
exact: true,
modules: {
config: `@generated/docusaurus.config`,
},
});
}
}),
);
},
configureWebpack(
_config: Configuration,
isServer: boolean,
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
) {
const {rehypePlugins, remarkPlugins} = options;
return {
resolve: {
alias: {
'~pages': pluginDataDirRoot,
},
},
module: {
rules: [
{
test: /(\.mdx?)$/,
include: [contentPath],
use: [
getCacheLoader(isServer),
getBabelLoader(isServer),
{
loader: require.resolve('@docusaurus/mdx-loader'),
options: {
remarkPlugins,
rehypePlugins,
// Note that metadataPath must be the same/in-sync as
// the path from createData for each MDX.
metadataPath: (mdxPath: string) => {
if (excludeRegex.test(slash(mdxPath))) {
return null;
}
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
return path.join(
dataDir,
`${docuHash(aliasedSource)}.json`,
);
},
forbidFrontMatter: (mdxPath: string) =>
excludeRegex.test(slash(mdxPath)),
},
},
{
loader: path.resolve(__dirname, './markdownLoader.js'),
options: {
// siteDir,
// contentPath,
},
},
].filter(Boolean) as Loader[],
},
],
},
};
},
};
}
export function validateOptions({
validate,
options,
}: OptionValidationContext<PluginOptions, ValidationError>): ValidationResult<
PluginOptions,
ValidationError
> {
const validatedOptions = validate(PluginOptionSchema, options);
return validatedOptions;
}