mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-11 08:07:26 +02:00
feat(v2): blog + docs multi-instance plugins (#3204)
* stable createData namespacing + second-blog dogfooding * Docs: support multi-instance + make community docs a separate instance * tests: add 2nd docs instance to versioned site * fix docs version cli tests * fix docs versioning cli * typo * team: add link to my site * better extendCli integration * fix metadata tests * tests for versioned site with second docs instance * move some validation code to utils-validation * fix missing dependency * fix bad compiled output due to importing constants in ./client folder * make docs tests easier to maintain * refactors * prevent lodash imports in client bundle * redirect old community docs to new urls
This commit is contained in:
parent
e944f35640
commit
59f705ee66
67 changed files with 2025 additions and 2059 deletions
|
@ -10,7 +10,10 @@ import kebabCase from 'lodash.kebabcase';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {normalizeUrl, docuHash, aliasedSitePath} from '@docusaurus/utils';
|
import {normalizeUrl, docuHash, aliasedSitePath} from '@docusaurus/utils';
|
||||||
import {STATIC_DIR_NAME} from '@docusaurus/core/lib/constants';
|
import {
|
||||||
|
STATIC_DIR_NAME,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
} from '@docusaurus/core/lib/constants';
|
||||||
import {ValidationError} from '@hapi/joi';
|
import {ValidationError} from '@hapi/joi';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -48,11 +51,15 @@ export default function pluginContentBlog(
|
||||||
|
|
||||||
const {siteDir, generatedFilesDir} = context;
|
const {siteDir, generatedFilesDir} = context;
|
||||||
const contentPath = path.resolve(siteDir, options.path);
|
const contentPath = path.resolve(siteDir, options.path);
|
||||||
const dataDir = path.join(
|
|
||||||
|
const pluginDataDirRoot = path.join(
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
'docusaurus-plugin-content-blog',
|
'docusaurus-plugin-content-blog',
|
||||||
// options.id ?? 'default', // TODO support multi-instance
|
|
||||||
);
|
);
|
||||||
|
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
||||||
|
const aliasedSource = (source: string) =>
|
||||||
|
`~blog/${path.relative(pluginDataDirRoot, source)}`;
|
||||||
|
|
||||||
let blogPosts: BlogPost[] = [];
|
let blogPosts: BlogPost[] = [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -206,8 +213,6 @@ export default function pluginContentBlog(
|
||||||
blogTagsPostsComponent,
|
blogTagsPostsComponent,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const aliasedSource = (source: string) =>
|
|
||||||
`~blog/${path.relative(dataDir, source)}`;
|
|
||||||
const {addRoute, createData} = actions;
|
const {addRoute, createData} = actions;
|
||||||
const {
|
const {
|
||||||
blogPosts: loadedBlogPosts,
|
blogPosts: loadedBlogPosts,
|
||||||
|
@ -349,7 +354,7 @@ export default function pluginContentBlog(
|
||||||
return {
|
return {
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~blog': dataDir,
|
'~blog': pluginDataDirRoot,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
@ -369,10 +374,10 @@ export default function pluginContentBlog(
|
||||||
// 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.
|
||||||
metadataPath: (mdxPath: string) => {
|
metadataPath: (mdxPath: string) => {
|
||||||
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
|
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
||||||
return path.join(
|
return path.join(
|
||||||
dataDir,
|
dataDir,
|
||||||
`${docuHash(aliasedSource)}.json`,
|
`${docuHash(aliasedPath)}.json`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Team current version
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"community": ["team"]
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Team 1.0.0
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"version-1.0.0/community": ["version-1.0.0/team"]
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
["1.0.0"]
|
File diff suppressed because it is too large
Load diff
|
@ -77,3 +77,14 @@ Object {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`docsVersion second docs instance versioning 1`] = `
|
||||||
|
Object {
|
||||||
|
"version-2.0.0/community": Array [
|
||||||
|
Object {
|
||||||
|
"id": "version-2.0.0/team",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import loadEnv from '../env';
|
import loadEnv from '../env';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
describe('loadEnv', () => {
|
describe('loadEnv', () => {
|
||||||
test('website with versioning disabled', () => {
|
test('website with versioning disabled', () => {
|
||||||
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
const siteDir = path.join(__dirname, '__fixtures__', 'simple-site');
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
expect(env.versioning.enabled).toBe(false);
|
expect(env.versioning.enabled).toBe(false);
|
||||||
expect(env.versioning.versions).toStrictEqual([]);
|
expect(env.versioning.versions).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('website with versioning enabled', () => {
|
test('website with versioning enabled', () => {
|
||||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
expect(env.versioning.enabled).toBe(true);
|
expect(env.versioning.enabled).toBe(true);
|
||||||
expect(env.versioning.latestVersion).toBe('1.0.1');
|
expect(env.versioning.latestVersion).toBe('1.0.1');
|
||||||
expect(env.versioning.versions).toStrictEqual([
|
expect(env.versioning.versions).toStrictEqual([
|
||||||
|
@ -28,9 +29,17 @@ describe('loadEnv', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('website with versioning enabled, 2nd docs plugin instance', () => {
|
||||||
|
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||||
|
const env = loadEnv(siteDir, 'community');
|
||||||
|
expect(env.versioning.enabled).toBe(true);
|
||||||
|
expect(env.versioning.latestVersion).toBe('1.0.0');
|
||||||
|
expect(env.versioning.versions).toStrictEqual(['1.0.0']);
|
||||||
|
});
|
||||||
|
|
||||||
test('website with versioning but disabled', () => {
|
test('website with versioning but disabled', () => {
|
||||||
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||||
const env = loadEnv(siteDir, {disableVersioning: true});
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID, {disableVersioning: true});
|
||||||
expect(env.versioning.enabled).toBe(false);
|
expect(env.versioning.enabled).toBe(false);
|
||||||
expect(env.versioning.versions).toStrictEqual([]);
|
expect(env.versioning.versions).toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
@ -42,7 +51,7 @@ describe('loadEnv', () => {
|
||||||
invalid: 'json',
|
invalid: 'json',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
expect(env.versioning.enabled).toBe(false);
|
expect(env.versioning.enabled).toBe(false);
|
||||||
mock.mockRestore();
|
mock.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,35 +12,65 @@ import commander from 'commander';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import pluginContentDocs from '../index';
|
import pluginContentDocs from '../index';
|
||||||
import loadEnv from '../env';
|
import loadEnv from '../env';
|
||||||
import normalizePluginOptions from './pluginOptionSchema.test';
|
|
||||||
import {loadContext} from '@docusaurus/core/src/server/index';
|
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||||
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils';
|
||||||
import {RouteConfig} from '@docusaurus/types';
|
import {RouteConfig} from '@docusaurus/types';
|
||||||
import {posixPath} from '@docusaurus/utils';
|
import {posixPath} from '@docusaurus/utils';
|
||||||
import {sortConfig} from '@docusaurus/core/src/server/plugins';
|
import {sortConfig} from '@docusaurus/core/src/server/plugins';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
import * as version from '../version';
|
import * as version from '../version';
|
||||||
|
import {PluginOptionSchema} from '../pluginOptionSchema';
|
||||||
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
|
|
||||||
const createFakeActions = (
|
const createFakeActions = (contentDir: string) => {
|
||||||
routeConfigs: RouteConfig[],
|
const routeConfigs: RouteConfig[] = [];
|
||||||
contentDir,
|
const dataContainer: any = {};
|
||||||
dataContainer?,
|
const globalDataContainer: any = {};
|
||||||
globalDataContainer?,
|
|
||||||
) => {
|
const actions = {
|
||||||
return {
|
|
||||||
addRoute: (config: RouteConfig) => {
|
addRoute: (config: RouteConfig) => {
|
||||||
routeConfigs.push(config);
|
routeConfigs.push(config);
|
||||||
},
|
},
|
||||||
createData: async (name, content) => {
|
createData: async (name: string, content: unknown) => {
|
||||||
if (dataContainer) {
|
dataContainer[name] = content;
|
||||||
dataContainer[name] = content;
|
|
||||||
}
|
|
||||||
return path.join(contentDir, name);
|
return path.join(contentDir, name);
|
||||||
},
|
},
|
||||||
setGlobalData: (data) => {
|
setGlobalData: (data: any) => {
|
||||||
globalDataContainer.pluginName = {pluginId: data};
|
globalDataContainer.pluginName = {pluginId: data};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Extra fns useful for tests!
|
||||||
|
const utils = {
|
||||||
|
getGlobalData: () => globalDataContainer,
|
||||||
|
getRouteConfigs: () => routeConfigs,
|
||||||
|
// query by prefix, because files have a hash at the end
|
||||||
|
// so it's not convenient to query by full filename
|
||||||
|
getCreatedDataByPrefix: (prefix: string) => {
|
||||||
|
const entry = Object.entries(dataContainer).find(([key]) =>
|
||||||
|
key.startsWith(prefix),
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
throw new Error(`No entry found for prefix=${prefix}`);
|
||||||
|
}
|
||||||
|
return JSON.parse(entry[1] as string);
|
||||||
|
},
|
||||||
|
|
||||||
|
expectSnapshot: () => {
|
||||||
|
// Sort the route config like in src/server/plugins/index.ts for consistent snapshot ordering
|
||||||
|
sortConfig(routeConfigs);
|
||||||
|
expect(routeConfigs).not.toEqual([]);
|
||||||
|
expect(routeConfigs).toMatchSnapshot('route config');
|
||||||
|
expect(dataContainer).toMatchSnapshot('data');
|
||||||
|
expect(globalDataContainer).toMatchSnapshot('global data');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
actions,
|
||||||
|
utils,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
test('site with wrong sidebar file', async () => {
|
test('site with wrong sidebar file', async () => {
|
||||||
|
@ -49,7 +79,7 @@ test('site with wrong sidebar file', async () => {
|
||||||
const sidebarPath = path.join(siteDir, 'wrong-sidebars.json');
|
const sidebarPath = path.join(siteDir, 'wrong-sidebars.json');
|
||||||
const plugin = pluginContentDocs(
|
const plugin = pluginContentDocs(
|
||||||
context,
|
context,
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -62,28 +92,30 @@ describe('empty/no docs website', () => {
|
||||||
|
|
||||||
test('no files in docs folder', async () => {
|
test('no files in docs folder', async () => {
|
||||||
await fs.ensureDir(path.join(siteDir, 'docs'));
|
await fs.ensureDir(path.join(siteDir, 'docs'));
|
||||||
const plugin = pluginContentDocs(context, normalizePluginOptions({}));
|
const plugin = pluginContentDocs(
|
||||||
|
context,
|
||||||
|
normalizePluginOptions(PluginOptionSchema, {}),
|
||||||
|
);
|
||||||
const content = await plugin.loadContent();
|
const content = await plugin.loadContent();
|
||||||
const {docsMetadata, docsSidebars} = content;
|
const {docsMetadata, docsSidebars} = content;
|
||||||
expect(docsMetadata).toMatchInlineSnapshot(`Object {}`);
|
expect(docsMetadata).toMatchInlineSnapshot(`Object {}`);
|
||||||
expect(docsSidebars).toMatchInlineSnapshot(`Object {}`);
|
expect(docsSidebars).toMatchInlineSnapshot(`Object {}`);
|
||||||
|
|
||||||
const routeConfigs = [];
|
|
||||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||||
const actions = createFakeActions(routeConfigs, pluginContentDir);
|
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||||
|
|
||||||
await plugin.contentLoaded({
|
await plugin.contentLoaded({
|
||||||
content,
|
content,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(routeConfigs).toEqual([]);
|
expect(utils.getRouteConfigs()).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('docs folder does not exist', async () => {
|
test('docs folder does not exist', async () => {
|
||||||
const plugin = pluginContentDocs(
|
const plugin = pluginContentDocs(
|
||||||
context,
|
context,
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
path: '/path/does/not/exist/',
|
path: '/path/does/not/exist/',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -99,7 +131,7 @@ describe('simple website', () => {
|
||||||
const pluginPath = 'docs';
|
const pluginPath = 'docs';
|
||||||
const plugin = pluginContentDocs(
|
const plugin = pluginContentDocs(
|
||||||
context,
|
context,
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
path: pluginPath,
|
path: pluginPath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
homePageId: 'hello',
|
homePageId: 'hello',
|
||||||
|
@ -112,7 +144,7 @@ describe('simple website', () => {
|
||||||
const cli = new commander.Command();
|
const cli = new commander.Command();
|
||||||
plugin.extendCli(cli);
|
plugin.extendCli(cli);
|
||||||
cli.parse(['node', 'test', 'docs:version', '1.0.0']);
|
cli.parse(['node', 'test', 'docs:version', '1.0.0']);
|
||||||
expect(mock).toHaveBeenCalledWith('1.0.0', siteDir, {
|
expect(mock).toHaveBeenCalledWith('1.0.0', siteDir, DEFAULT_PLUGIN_ID, {
|
||||||
path: pluginPath,
|
path: pluginPath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
});
|
});
|
||||||
|
@ -200,15 +232,7 @@ describe('simple website', () => {
|
||||||
|
|
||||||
expect(docsSidebars).toMatchSnapshot();
|
expect(docsSidebars).toMatchSnapshot();
|
||||||
|
|
||||||
const routeConfigs = [];
|
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||||
const dataContainer = {};
|
|
||||||
const globalDataContainer = {};
|
|
||||||
const actions = createFakeActions(
|
|
||||||
routeConfigs,
|
|
||||||
pluginContentDir,
|
|
||||||
dataContainer,
|
|
||||||
globalDataContainer,
|
|
||||||
);
|
|
||||||
|
|
||||||
await plugin.contentLoaded({
|
await plugin.contentLoaded({
|
||||||
content,
|
content,
|
||||||
|
@ -216,16 +240,12 @@ describe('simple website', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// There is only one nested docs route for simple site
|
// There is only one nested docs route for simple site
|
||||||
const baseMetadata = JSON.parse(dataContainer['docs-route-ff2.json']);
|
const baseMetadata = utils.getCreatedDataByPrefix('docs-route-');
|
||||||
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
|
utils.expectSnapshot();
|
||||||
sortConfig(routeConfigs);
|
expect(utils.getGlobalData()).toMatchSnapshot();
|
||||||
|
|
||||||
expect(routeConfigs).not.toEqual([]);
|
|
||||||
expect(routeConfigs).toMatchSnapshot();
|
|
||||||
expect(globalDataContainer).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,22 +256,26 @@ describe('versioned website', () => {
|
||||||
const routeBasePath = 'docs';
|
const routeBasePath = 'docs';
|
||||||
const plugin = pluginContentDocs(
|
const plugin = pluginContentDocs(
|
||||||
context,
|
context,
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
routeBasePath,
|
routeBasePath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
homePageId: 'hello',
|
homePageId: 'hello',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
const {docsDir: versionedDir} = env.versioning;
|
const {docsDir: versionedDir} = env.versioning;
|
||||||
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||||
|
|
||||||
|
test('isVersioned', () => {
|
||||||
|
expect(env.versioning.enabled).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('extendCli - docsVersion', () => {
|
test('extendCli - docsVersion', () => {
|
||||||
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||||
const cli = new commander.Command();
|
const cli = new commander.Command();
|
||||||
plugin.extendCli(cli);
|
plugin.extendCli(cli);
|
||||||
cli.parse(['node', 'test', 'docs:version', '2.0.0']);
|
cli.parse(['node', 'test', 'docs:version', '2.0.0']);
|
||||||
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, {
|
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, DEFAULT_PLUGIN_ID, {
|
||||||
path: routeBasePath,
|
path: routeBasePath,
|
||||||
sidebarPath,
|
sidebarPath,
|
||||||
});
|
});
|
||||||
|
@ -401,23 +425,15 @@ describe('versioned website', () => {
|
||||||
expect(versionToSidebars).toMatchSnapshot(
|
expect(versionToSidebars).toMatchSnapshot(
|
||||||
'sidebars needed for each version',
|
'sidebars needed for each version',
|
||||||
);
|
);
|
||||||
const routeConfigs = [];
|
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||||
const dataContainer = {};
|
|
||||||
const globalDataContainer = {};
|
|
||||||
const actions = createFakeActions(
|
|
||||||
routeConfigs,
|
|
||||||
pluginContentDir,
|
|
||||||
dataContainer,
|
|
||||||
globalDataContainer,
|
|
||||||
);
|
|
||||||
await plugin.contentLoaded({
|
await plugin.contentLoaded({
|
||||||
content,
|
content,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
|
||||||
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
||||||
const latestVersionBaseMetadata = JSON.parse(
|
const latestVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||||
dataContainer['docs-route-ff2.json'],
|
'docs-route-',
|
||||||
);
|
);
|
||||||
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
||||||
'base metadata for latest version',
|
'base metadata for latest version',
|
||||||
|
@ -426,8 +442,8 @@ describe('versioned website', () => {
|
||||||
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||||
permalinkToSidebar,
|
permalinkToSidebar,
|
||||||
);
|
);
|
||||||
const nextVersionBaseMetadata = JSON.parse(
|
const nextVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||||
dataContainer['docs-next-route-1c8.json'],
|
'docs-next-route-',
|
||||||
);
|
);
|
||||||
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
||||||
'base metadata for next version',
|
'base metadata for next version',
|
||||||
|
@ -436,8 +452,8 @@ describe('versioned website', () => {
|
||||||
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||||
permalinkToSidebar,
|
permalinkToSidebar,
|
||||||
);
|
);
|
||||||
const firstVersionBaseMetadata = JSON.parse(
|
const firstVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||||
dataContainer['docs-1-0-0-route-660.json'],
|
'docs-1-0-0-route-',
|
||||||
);
|
);
|
||||||
expect(firstVersionBaseMetadata).toMatchSnapshot(
|
expect(firstVersionBaseMetadata).toMatchSnapshot(
|
||||||
'base metadata for first version',
|
'base metadata for first version',
|
||||||
|
@ -447,11 +463,151 @@ describe('versioned website', () => {
|
||||||
permalinkToSidebar,
|
permalinkToSidebar,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort the route config like in src/server/plugins/index.ts for consistent snapshot ordering
|
utils.expectSnapshot();
|
||||||
sortConfig(routeConfigs);
|
});
|
||||||
|
});
|
||||||
expect(routeConfigs).not.toEqual([]);
|
|
||||||
expect(routeConfigs).toMatchSnapshot();
|
describe('versioned website (community)', () => {
|
||||||
expect(globalDataContainer).toMatchSnapshot();
|
const siteDir = path.join(__dirname, '__fixtures__', 'versioned-site');
|
||||||
|
const context = loadContext(siteDir);
|
||||||
|
const sidebarPath = path.join(siteDir, 'community_sidebars.json');
|
||||||
|
const routeBasePath = 'community';
|
||||||
|
const pluginId = 'community';
|
||||||
|
const plugin = pluginContentDocs(
|
||||||
|
context,
|
||||||
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
|
id: 'community',
|
||||||
|
path: 'community',
|
||||||
|
routeBasePath,
|
||||||
|
sidebarPath,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const env = loadEnv(siteDir, pluginId);
|
||||||
|
const {docsDir: versionedDir} = env.versioning;
|
||||||
|
const pluginContentDir = path.join(context.generatedFilesDir, plugin.name);
|
||||||
|
|
||||||
|
test('isVersioned', () => {
|
||||||
|
expect(env.versioning.enabled).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extendCli - docsVersion', () => {
|
||||||
|
const mock = jest.spyOn(version, 'docsVersion').mockImplementation();
|
||||||
|
const cli = new commander.Command();
|
||||||
|
plugin.extendCli(cli);
|
||||||
|
cli.parse(['node', 'test', `docs:version:${pluginId}`, '2.0.0']);
|
||||||
|
expect(mock).toHaveBeenCalledWith('2.0.0', siteDir, pluginId, {
|
||||||
|
path: routeBasePath,
|
||||||
|
sidebarPath,
|
||||||
|
});
|
||||||
|
mock.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getPathToWatch', () => {
|
||||||
|
const pathToWatch = plugin.getPathsToWatch();
|
||||||
|
const matchPattern = pathToWatch.map((filepath) =>
|
||||||
|
posixPath(path.relative(siteDir, filepath)),
|
||||||
|
);
|
||||||
|
expect(matchPattern).not.toEqual([]);
|
||||||
|
expect(matchPattern).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
"community/**/*.{md,mdx}",
|
||||||
|
"community_versioned_sidebars/version-1.0.0-sidebars.json",
|
||||||
|
"community_versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||||
|
"community_sidebars.json",
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(isMatch('community/team.md', matchPattern)).toEqual(true);
|
||||||
|
expect(
|
||||||
|
isMatch('community_versioned_docs/version-1.0.0/team.md', matchPattern),
|
||||||
|
).toEqual(true);
|
||||||
|
|
||||||
|
// Non existing version
|
||||||
|
expect(
|
||||||
|
isMatch('community_versioned_docs/version-2.0.0/team.md', matchPattern),
|
||||||
|
).toEqual(false);
|
||||||
|
expect(
|
||||||
|
isMatch(
|
||||||
|
'community_versioned_sidebars/version-2.0.0-sidebars.json',
|
||||||
|
matchPattern,
|
||||||
|
),
|
||||||
|
).toEqual(false);
|
||||||
|
|
||||||
|
expect(isMatch('community/team.js', matchPattern)).toEqual(false);
|
||||||
|
expect(
|
||||||
|
isMatch('community_versioned_docs/version-1.0.0/team.js', matchPattern),
|
||||||
|
).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('content', async () => {
|
||||||
|
const content = await plugin.loadContent();
|
||||||
|
const {
|
||||||
|
docsMetadata,
|
||||||
|
docsSidebars,
|
||||||
|
versionToSidebars,
|
||||||
|
permalinkToSidebar,
|
||||||
|
} = content;
|
||||||
|
|
||||||
|
expect(docsMetadata.team).toEqual({
|
||||||
|
id: 'team',
|
||||||
|
unversionedId: 'team',
|
||||||
|
isDocsHomePage: false,
|
||||||
|
permalink: '/community/next/team',
|
||||||
|
source: path.join('@site', routeBasePath, 'team.md'),
|
||||||
|
title: 'team',
|
||||||
|
description: 'Team current version',
|
||||||
|
version: 'next',
|
||||||
|
sidebar: 'community',
|
||||||
|
});
|
||||||
|
expect(docsMetadata['version-1.0.0/team']).toEqual({
|
||||||
|
id: 'version-1.0.0/team',
|
||||||
|
unversionedId: 'team',
|
||||||
|
isDocsHomePage: false,
|
||||||
|
permalink: '/community/team',
|
||||||
|
source: path.join(
|
||||||
|
'@site',
|
||||||
|
path.relative(siteDir, versionedDir),
|
||||||
|
'version-1.0.0',
|
||||||
|
'team.md',
|
||||||
|
),
|
||||||
|
title: 'team',
|
||||||
|
description: 'Team 1.0.0',
|
||||||
|
version: '1.0.0',
|
||||||
|
sidebar: 'version-1.0.0/community',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(docsSidebars).toMatchSnapshot('all sidebars');
|
||||||
|
expect(versionToSidebars).toMatchSnapshot(
|
||||||
|
'sidebars needed for each version',
|
||||||
|
);
|
||||||
|
|
||||||
|
const {actions, utils} = createFakeActions(pluginContentDir);
|
||||||
|
await plugin.contentLoaded({
|
||||||
|
content,
|
||||||
|
actions,
|
||||||
|
});
|
||||||
|
|
||||||
|
// The created base metadata for each nested docs route is smartly chunked/ splitted across version
|
||||||
|
const latestVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||||
|
'community-route-',
|
||||||
|
);
|
||||||
|
expect(latestVersionBaseMetadata).toMatchSnapshot(
|
||||||
|
'base metadata for latest version',
|
||||||
|
);
|
||||||
|
expect(latestVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||||
|
expect(latestVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||||
|
permalinkToSidebar,
|
||||||
|
);
|
||||||
|
const nextVersionBaseMetadata = utils.getCreatedDataByPrefix(
|
||||||
|
'community-next-route-',
|
||||||
|
);
|
||||||
|
expect(nextVersionBaseMetadata).toMatchSnapshot(
|
||||||
|
'base metadata for next version',
|
||||||
|
);
|
||||||
|
expect(nextVersionBaseMetadata.docsSidebars).not.toEqual(docsSidebars);
|
||||||
|
expect(nextVersionBaseMetadata.permalinkToSidebar).not.toEqual(
|
||||||
|
permalinkToSidebar,
|
||||||
|
);
|
||||||
|
|
||||||
|
utils.expectSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ import processMetadata from '../metadata';
|
||||||
import loadEnv from '../env';
|
import loadEnv from '../env';
|
||||||
import {MetadataRaw, Env, MetadataOptions} from '../types';
|
import {MetadataRaw, Env, MetadataOptions} from '../types';
|
||||||
import {LoadContext} from '@docusaurus/types';
|
import {LoadContext} from '@docusaurus/types';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ describe('simple site', () => {
|
||||||
const context = loadContext(siteDir);
|
const context = loadContext(siteDir);
|
||||||
const routeBasePath = 'docs';
|
const routeBasePath = 'docs';
|
||||||
const docsDir = path.resolve(siteDir, routeBasePath);
|
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
const options = {routeBasePath};
|
const options = {routeBasePath};
|
||||||
|
|
||||||
const {testMeta, testSlug} = createTestHelpers({
|
const {testMeta, testSlug} = createTestHelpers({
|
||||||
|
@ -309,7 +310,7 @@ describe('versioned site', () => {
|
||||||
const context = loadContext(siteDir);
|
const context = loadContext(siteDir);
|
||||||
const routeBasePath = 'docs';
|
const routeBasePath = 'docs';
|
||||||
const docsDir = path.resolve(siteDir, routeBasePath);
|
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||||
const env = loadEnv(siteDir);
|
const env = loadEnv(siteDir, DEFAULT_PLUGIN_ID);
|
||||||
const {docsDir: versionedDir} = env.versioning;
|
const {docsDir: versionedDir} = env.versioning;
|
||||||
const options = {routeBasePath};
|
const options = {routeBasePath};
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
|
||||||
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
export default function normalizePluginOptions(options) {
|
|
||||||
const {value, error} = PluginOptionSchema.validate(options, {
|
|
||||||
convert: false,
|
|
||||||
});
|
|
||||||
if (error) {
|
|
||||||
throw error;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the type of remark/rehype plugins is function
|
// the type of remark/rehype plugins is function
|
||||||
const remarkRehypePluginStub = () => {};
|
const remarkRehypePluginStub = () => {};
|
||||||
|
@ -63,7 +53,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
|
|
||||||
test('should reject bad path inputs', () => {
|
test('should reject bad path inputs', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
path: 2,
|
path: 2,
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`);
|
}).toThrowErrorMatchingInlineSnapshot(`"\\"path\\" must be a string"`);
|
||||||
|
@ -71,7 +61,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
|
|
||||||
test('should reject bad include inputs', () => {
|
test('should reject bad include inputs', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
include: '**/*.{md,mdx}',
|
include: '**/*.{md,mdx}',
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`);
|
}).toThrowErrorMatchingInlineSnapshot(`"\\"include\\" must be an array"`);
|
||||||
|
@ -79,7 +69,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
|
|
||||||
test('should reject bad showLastUpdateTime inputs', () => {
|
test('should reject bad showLastUpdateTime inputs', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
showLastUpdateTime: 'true',
|
showLastUpdateTime: 'true',
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingInlineSnapshot(
|
}).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
@ -89,7 +79,7 @@ describe('normalizeDocsPluginOptions', () => {
|
||||||
|
|
||||||
test('should reject bad remarkPlugins input', () => {
|
test('should reject bad remarkPlugins input', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
normalizePluginOptions({
|
normalizePluginOptions(PluginOptionSchema, {
|
||||||
remarkPlugins: 'remark-math',
|
remarkPlugins: 'remark-math',
|
||||||
});
|
});
|
||||||
}).toThrowErrorMatchingInlineSnapshot(
|
}).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
getVersionsJSONFile,
|
getVersionsJSONFile,
|
||||||
getVersionedSidebarsDir,
|
getVersionedSidebarsDir,
|
||||||
} from '../env';
|
} from '../env';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||||
|
|
||||||
|
@ -27,87 +28,114 @@ describe('docsVersion', () => {
|
||||||
|
|
||||||
test('no version tag provided', () => {
|
test('no version tag provided', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion(null, simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(null, simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion(undefined, simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(undefined, simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion('', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
`"[docs] No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version tag should not have slash', () => {
|
test('version tag should not have slash', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('foo/bar', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion('foo/bar', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('foo\\bar', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(
|
||||||
|
'foo\\bar',
|
||||||
|
simpleSiteDir,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Do not include slash (/) or (\\\\). Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version tag should not be too long', () => {
|
test('version tag should not be too long', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('a'.repeat(255), simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(
|
||||||
|
'a'.repeat(255),
|
||||||
|
simpleSiteDir,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version tag should not be a dot or two dots', () => {
|
test('version tag should not be a dot or two dots', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('..', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion('..', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('.', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion('.', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Do not name your version \\".\\" or \\"..\\". Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version tag should be a valid pathname', () => {
|
test('version tag should be a valid pathname', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('<foo|bar>', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(
|
||||||
|
'<foo|bar>',
|
||||||
|
simpleSiteDir,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('foo\x00bar', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion(
|
||||||
|
'foo\x00bar',
|
||||||
|
simpleSiteDir,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('foo:bar', simpleSiteDir, DEFAULT_OPTIONS),
|
docsVersion('foo:bar', simpleSiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
`"[docs] Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0"`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('version tag already exist', () => {
|
test('version tag already exist', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('1.0.0', versionedSiteDir, DEFAULT_OPTIONS),
|
docsVersion(
|
||||||
|
'1.0.0',
|
||||||
|
versionedSiteDir,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
DEFAULT_OPTIONS,
|
||||||
|
),
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"This version already exists!. Use a version tag that does not already exist."`,
|
`"[docs] This version already exists!. Use a version tag that does not already exist."`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('no docs file to version', () => {
|
test('no docs file to version', () => {
|
||||||
const emptySiteDir = path.join(fixtureDir, 'empty-site');
|
const emptySiteDir = path.join(fixtureDir, 'empty-site');
|
||||||
expect(() =>
|
expect(() =>
|
||||||
docsVersion('1.0.0', emptySiteDir, DEFAULT_OPTIONS),
|
docsVersion('1.0.0', emptySiteDir, DEFAULT_PLUGIN_ID, DEFAULT_OPTIONS),
|
||||||
).toThrowErrorMatchingInlineSnapshot(`"There is no docs to version !"`);
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"[docs] There is no docs to version !"`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('first time versioning', () => {
|
test('first time versioning', () => {
|
||||||
|
@ -131,21 +159,26 @@ describe('docsVersion', () => {
|
||||||
path: 'docs',
|
path: 'docs',
|
||||||
sidebarPath: path.join(simpleSiteDir, 'sidebars.json'),
|
sidebarPath: path.join(simpleSiteDir, 'sidebars.json'),
|
||||||
};
|
};
|
||||||
docsVersion('1.0.0', simpleSiteDir, options);
|
docsVersion('1.0.0', simpleSiteDir, DEFAULT_PLUGIN_ID, options);
|
||||||
expect(copyMock).toHaveBeenCalledWith(
|
expect(copyMock).toHaveBeenCalledWith(
|
||||||
path.join(simpleSiteDir, options.path),
|
path.join(simpleSiteDir, options.path),
|
||||||
path.join(getVersionedDocsDir(simpleSiteDir), 'version-1.0.0'),
|
path.join(
|
||||||
|
getVersionedDocsDir(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
|
'version-1.0.0',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(versionedSidebar).toMatchSnapshot();
|
expect(versionedSidebar).toMatchSnapshot();
|
||||||
expect(versionedSidebarPath).toEqual(
|
expect(versionedSidebarPath).toEqual(
|
||||||
path.join(
|
path.join(
|
||||||
getVersionedSidebarsDir(simpleSiteDir),
|
getVersionedSidebarsDir(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
'version-1.0.0-sidebars.json',
|
'version-1.0.0-sidebars.json',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(versionsPath).toEqual(getVersionsJSONFile(simpleSiteDir));
|
expect(versionsPath).toEqual(
|
||||||
|
getVersionsJSONFile(simpleSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
|
);
|
||||||
expect(versions).toEqual(['1.0.0']);
|
expect(versions).toEqual(['1.0.0']);
|
||||||
expect(consoleMock).toHaveBeenCalledWith('Version 1.0.0 created!');
|
expect(consoleMock).toHaveBeenCalledWith('[docs] Version 1.0.0 created!');
|
||||||
|
|
||||||
copyMock.mockRestore();
|
copyMock.mockRestore();
|
||||||
writeMock.mockRestore();
|
writeMock.mockRestore();
|
||||||
|
@ -174,21 +207,78 @@ describe('docsVersion', () => {
|
||||||
path: 'docs',
|
path: 'docs',
|
||||||
sidebarPath: path.join(versionedSiteDir, 'sidebars.json'),
|
sidebarPath: path.join(versionedSiteDir, 'sidebars.json'),
|
||||||
};
|
};
|
||||||
docsVersion('2.0.0', versionedSiteDir, options);
|
docsVersion('2.0.0', versionedSiteDir, DEFAULT_PLUGIN_ID, options);
|
||||||
expect(copyMock).toHaveBeenCalledWith(
|
expect(copyMock).toHaveBeenCalledWith(
|
||||||
path.join(versionedSiteDir, options.path),
|
path.join(versionedSiteDir, options.path),
|
||||||
path.join(getVersionedDocsDir(versionedSiteDir), 'version-2.0.0'),
|
path.join(
|
||||||
|
getVersionedDocsDir(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
|
'version-2.0.0',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
expect(versionedSidebar).toMatchSnapshot();
|
expect(versionedSidebar).toMatchSnapshot();
|
||||||
expect(versionedSidebarPath).toEqual(
|
expect(versionedSidebarPath).toEqual(
|
||||||
path.join(
|
path.join(
|
||||||
getVersionedSidebarsDir(versionedSiteDir),
|
getVersionedSidebarsDir(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
'version-2.0.0-sidebars.json',
|
'version-2.0.0-sidebars.json',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(versionsPath).toEqual(getVersionsJSONFile(versionedSiteDir));
|
expect(versionsPath).toEqual(
|
||||||
|
getVersionsJSONFile(versionedSiteDir, DEFAULT_PLUGIN_ID),
|
||||||
|
);
|
||||||
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']);
|
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']);
|
||||||
expect(consoleMock).toHaveBeenCalledWith('Version 2.0.0 created!');
|
expect(consoleMock).toHaveBeenCalledWith('[docs] Version 2.0.0 created!');
|
||||||
|
|
||||||
|
copyMock.mockRestore();
|
||||||
|
writeMock.mockRestore();
|
||||||
|
consoleMock.mockRestore();
|
||||||
|
ensureMock.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('second docs instance versioning', () => {
|
||||||
|
const pluginId = 'community';
|
||||||
|
|
||||||
|
const copyMock = jest.spyOn(fs, 'copySync').mockImplementation();
|
||||||
|
const ensureMock = jest.spyOn(fs, 'ensureDirSync').mockImplementation();
|
||||||
|
const writeMock = jest.spyOn(fs, 'writeFileSync');
|
||||||
|
let versionedSidebar;
|
||||||
|
let versionedSidebarPath;
|
||||||
|
writeMock.mockImplementationOnce((filepath, content) => {
|
||||||
|
versionedSidebarPath = filepath;
|
||||||
|
versionedSidebar = JSON.parse(content);
|
||||||
|
});
|
||||||
|
let versionsPath;
|
||||||
|
let versions;
|
||||||
|
writeMock.mockImplementationOnce((filepath, content) => {
|
||||||
|
versionsPath = filepath;
|
||||||
|
versions = JSON.parse(content);
|
||||||
|
});
|
||||||
|
const consoleMock = jest.spyOn(console, 'log').mockImplementation();
|
||||||
|
const options = {
|
||||||
|
path: 'community',
|
||||||
|
sidebarPath: path.join(versionedSiteDir, 'community_sidebars.json'),
|
||||||
|
};
|
||||||
|
docsVersion('2.0.0', versionedSiteDir, pluginId, options);
|
||||||
|
expect(copyMock).toHaveBeenCalledWith(
|
||||||
|
path.join(versionedSiteDir, options.path),
|
||||||
|
path.join(
|
||||||
|
getVersionedDocsDir(versionedSiteDir, pluginId),
|
||||||
|
'version-2.0.0',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(versionedSidebar).toMatchSnapshot();
|
||||||
|
expect(versionedSidebarPath).toEqual(
|
||||||
|
path.join(
|
||||||
|
getVersionedSidebarsDir(versionedSiteDir, pluginId),
|
||||||
|
'version-2.0.0-sidebars.json',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(versionsPath).toEqual(
|
||||||
|
getVersionsJSONFile(versionedSiteDir, pluginId),
|
||||||
|
);
|
||||||
|
expect(versions).toEqual(['2.0.0', '1.0.0']);
|
||||||
|
expect(consoleMock).toHaveBeenCalledWith(
|
||||||
|
'[community] Version 2.0.0 created!',
|
||||||
|
);
|
||||||
|
|
||||||
copyMock.mockRestore();
|
copyMock.mockRestore();
|
||||||
writeMock.mockRestore();
|
writeMock.mockRestore();
|
||||||
|
|
|
@ -14,24 +14,49 @@ import {
|
||||||
VERSIONED_SIDEBARS_DIR,
|
VERSIONED_SIDEBARS_DIR,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export function getVersionedDocsDir(siteDir: string): string {
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
return path.join(siteDir, VERSIONED_DOCS_DIR);
|
|
||||||
|
// retro-compatibility: no prefix for the default plugin id
|
||||||
|
function addPluginIdPrefix(fileOrDir: string, pluginId: string): string {
|
||||||
|
if (pluginId === DEFAULT_PLUGIN_ID) {
|
||||||
|
return fileOrDir;
|
||||||
|
} else {
|
||||||
|
return `${pluginId}_${fileOrDir}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVersionedSidebarsDir(siteDir: string): string {
|
export function getVersionedDocsDir(siteDir: string, pluginId: string): string {
|
||||||
return path.join(siteDir, VERSIONED_SIDEBARS_DIR);
|
return path.join(siteDir, addPluginIdPrefix(VERSIONED_DOCS_DIR, pluginId));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVersionsJSONFile(siteDir: string): string {
|
export function getVersionedSidebarsDir(
|
||||||
return path.join(siteDir, VERSIONS_JSON_FILE);
|
siteDir: string,
|
||||||
|
pluginId: string,
|
||||||
|
): string {
|
||||||
|
return path.join(
|
||||||
|
siteDir,
|
||||||
|
addPluginIdPrefix(VERSIONED_SIDEBARS_DIR, pluginId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVersionsJSONFile(siteDir: string, pluginId: string): string {
|
||||||
|
return path.join(siteDir, addPluginIdPrefix(VERSIONS_JSON_FILE, pluginId));
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnvOptions = Partial<{disableVersioning: boolean}>;
|
type EnvOptions = Partial<{disableVersioning: boolean}>;
|
||||||
|
|
||||||
export default function (
|
export default function (
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
|
pluginId: string,
|
||||||
options: EnvOptions = {disableVersioning: false},
|
options: EnvOptions = {disableVersioning: false},
|
||||||
): Env {
|
): Env {
|
||||||
|
if (!siteDir) {
|
||||||
|
throw new Error('unexpected, missing siteDir');
|
||||||
|
}
|
||||||
|
if (!pluginId) {
|
||||||
|
throw new Error('unexpected, missing pluginId');
|
||||||
|
}
|
||||||
|
|
||||||
const versioning: VersioningEnv = {
|
const versioning: VersioningEnv = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
versions: [],
|
versions: [],
|
||||||
|
@ -40,7 +65,7 @@ export default function (
|
||||||
sidebarsDir: '',
|
sidebarsDir: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const versionsJSONFile = getVersionsJSONFile(siteDir);
|
const versionsJSONFile = getVersionsJSONFile(siteDir, pluginId);
|
||||||
if (fs.existsSync(versionsJSONFile)) {
|
if (fs.existsSync(versionsJSONFile)) {
|
||||||
if (!options.disableVersioning) {
|
if (!options.disableVersioning) {
|
||||||
const parsedVersions = JSON.parse(
|
const parsedVersions = JSON.parse(
|
||||||
|
@ -51,8 +76,8 @@ export default function (
|
||||||
versioning.latestVersion = parsedVersions[0];
|
versioning.latestVersion = parsedVersions[0];
|
||||||
versioning.enabled = true;
|
versioning.enabled = true;
|
||||||
versioning.versions = parsedVersions;
|
versioning.versions = parsedVersions;
|
||||||
versioning.docsDir = getVersionedDocsDir(siteDir);
|
versioning.docsDir = getVersionedDocsDir(siteDir, pluginId);
|
||||||
versioning.sidebarsDir = getVersionedSidebarsDir(siteDir);
|
versioning.sidebarsDir = getVersionedSidebarsDir(siteDir, pluginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@ import path from 'path';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {STATIC_DIR_NAME} from '@docusaurus/core/lib/constants';
|
import {
|
||||||
|
STATIC_DIR_NAME,
|
||||||
|
DEFAULT_PLUGIN_ID,
|
||||||
|
} from '@docusaurus/core/lib/constants';
|
||||||
import {
|
import {
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
docuHash,
|
docuHash,
|
||||||
|
@ -77,15 +80,21 @@ export default function pluginContentDocs(
|
||||||
const {siteDir, generatedFilesDir, baseUrl} = context;
|
const {siteDir, generatedFilesDir, baseUrl} = context;
|
||||||
const docsDir = path.resolve(siteDir, options.path);
|
const docsDir = path.resolve(siteDir, options.path);
|
||||||
const sourceToPermalink: SourceToPermalink = {};
|
const sourceToPermalink: SourceToPermalink = {};
|
||||||
|
const pluginId = options.id ?? DEFAULT_PLUGIN_ID;
|
||||||
|
const isDefaultPluginId = pluginId === DEFAULT_PLUGIN_ID;
|
||||||
|
|
||||||
const dataDir = path.join(
|
const pluginDataDirRoot = path.join(
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
'docusaurus-plugin-content-docs',
|
'docusaurus-plugin-content-docs',
|
||||||
// options.id ?? 'default', // TODO support multi-instance
|
|
||||||
);
|
);
|
||||||
|
const dataDir = path.join(pluginDataDirRoot, pluginId);
|
||||||
|
const aliasedSource = (source: string) =>
|
||||||
|
`~docs/${path.relative(pluginDataDirRoot, source)}`;
|
||||||
|
|
||||||
// Versioning.
|
// Versioning.
|
||||||
const env = loadEnv(siteDir, {disableVersioning: options.disableVersioning});
|
const env = loadEnv(siteDir, pluginId, {
|
||||||
|
disableVersioning: options.disableVersioning,
|
||||||
|
});
|
||||||
const {versioning} = env;
|
const {versioning} = env;
|
||||||
const {
|
const {
|
||||||
versions,
|
versions,
|
||||||
|
@ -102,12 +111,19 @@ export default function pluginContentDocs(
|
||||||
},
|
},
|
||||||
|
|
||||||
extendCli(cli) {
|
extendCli(cli) {
|
||||||
|
const command = isDefaultPluginId
|
||||||
|
? 'docs:version'
|
||||||
|
: `docs:version:${pluginId}`;
|
||||||
|
const commandDescription = isDefaultPluginId
|
||||||
|
? 'Tag a new docs version'
|
||||||
|
: `Tag a new docs version (${pluginId})`;
|
||||||
|
|
||||||
cli
|
cli
|
||||||
.command('docs:version')
|
.command(command)
|
||||||
.arguments('<version>')
|
.arguments('<version>')
|
||||||
.description('Tag a new version for docs')
|
.description(commandDescription)
|
||||||
.action((version) => {
|
.action((version) => {
|
||||||
docsVersion(version, siteDir, {
|
docsVersion(version, siteDir, pluginId, {
|
||||||
path: options.path,
|
path: options.path,
|
||||||
sidebarPath: options.sidebarPath,
|
sidebarPath: options.sidebarPath,
|
||||||
});
|
});
|
||||||
|
@ -335,9 +351,6 @@ Available document ids=
|
||||||
|
|
||||||
setGlobalData<GlobalPluginData>(pluginInstanceGlobalData);
|
setGlobalData<GlobalPluginData>(pluginInstanceGlobalData);
|
||||||
|
|
||||||
const aliasedSource = (source: string) =>
|
|
||||||
`~docs/${path.relative(dataDir, source)}`;
|
|
||||||
|
|
||||||
const createDocsBaseMetadata = (
|
const createDocsBaseMetadata = (
|
||||||
version: DocsVersion,
|
version: DocsVersion,
|
||||||
): DocsBaseMetadata => {
|
): DocsBaseMetadata => {
|
||||||
|
@ -499,7 +512,7 @@ Available document ids=
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~docs': dataDir,
|
'~docs': pluginDataDirRoot,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
@ -519,10 +532,10 @@ Available document ids=
|
||||||
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.
|
||||||
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
|
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
||||||
return path.join(
|
return path.join(
|
||||||
dataDir,
|
dataDir,
|
||||||
`${docuHash(aliasedSource)}.json`,
|
`${docuHash(aliasedPath)}.json`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,29 +14,36 @@ import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {Sidebar, PathOptions, SidebarItem} from './types';
|
import {Sidebar, PathOptions, SidebarItem} from './types';
|
||||||
import loadSidebars from './sidebars';
|
import loadSidebars from './sidebars';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
// Tests depend on non-default export for mocking.
|
// Tests depend on non-default export for mocking.
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export function docsVersion(
|
export function docsVersion(
|
||||||
version: string | null | undefined,
|
version: string | null | undefined,
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
|
pluginId: string,
|
||||||
options: PathOptions,
|
options: PathOptions,
|
||||||
): void {
|
): void {
|
||||||
|
// It wouldn't be very user-friendly to show a [default] log prefix,
|
||||||
|
// so we use [docs] instead of [default]
|
||||||
|
const pluginIdLogPrefix =
|
||||||
|
pluginId === DEFAULT_PLUGIN_ID ? '[docs] ' : `[${pluginId}] `;
|
||||||
|
|
||||||
if (!version) {
|
if (!version) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0',
|
`${pluginIdLogPrefix}No version tag specified!. Pass the version you wish to create as an argument. Ex: 1.0.0`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version.includes('/') || version.includes('\\')) {
|
if (version.includes('/') || version.includes('\\')) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid version tag specified! Do not include slash (/) or (\\). Try something like: 1.0.0`,
|
`${pluginIdLogPrefix}Invalid version tag specified! Do not include slash (/) or (\\). Try something like: 1.0.0`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version.length > 32) {
|
if (version.length > 32) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0',
|
`${pluginIdLogPrefix}Invalid version tag specified! Length must <= 32 characters. Try something like: 1.0.0`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,19 +51,19 @@ export function docsVersion(
|
||||||
// sure it's a valid pathname.
|
// sure it's a valid pathname.
|
||||||
if (/[<>:"\/\\|?*\x00-\x1F]/g.test(version)) {
|
if (/[<>:"\/\\|?*\x00-\x1F]/g.test(version)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0',
|
`${pluginIdLogPrefix}Invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/^\.\.?$/.test(version)) {
|
if (/^\.\.?$/.test(version)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0',
|
`${pluginIdLogPrefix}Invalid version tag specified! Do not name your version "." or "..". Try something like: 1.0.0`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load existing versions.
|
// Load existing versions.
|
||||||
let versions = [];
|
let versions = [];
|
||||||
const versionsJSONFile = getVersionsJSONFile(siteDir);
|
const versionsJSONFile = getVersionsJSONFile(siteDir, pluginId);
|
||||||
if (fs.existsSync(versionsJSONFile)) {
|
if (fs.existsSync(versionsJSONFile)) {
|
||||||
versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8'));
|
versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8'));
|
||||||
}
|
}
|
||||||
|
@ -64,7 +71,7 @@ export function docsVersion(
|
||||||
// Check if version already exists.
|
// Check if version already exists.
|
||||||
if (versions.includes(version)) {
|
if (versions.includes(version)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'This version already exists!. Use a version tag that does not already exist.',
|
`${pluginIdLogPrefix}This version already exists!. Use a version tag that does not already exist.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,11 +80,11 @@ export function docsVersion(
|
||||||
// Copy docs files.
|
// Copy docs files.
|
||||||
const docsDir = path.join(siteDir, docsPath);
|
const docsDir = path.join(siteDir, docsPath);
|
||||||
if (fs.existsSync(docsDir) && fs.readdirSync(docsDir).length > 0) {
|
if (fs.existsSync(docsDir) && fs.readdirSync(docsDir).length > 0) {
|
||||||
const versionedDir = getVersionedDocsDir(siteDir);
|
const versionedDir = getVersionedDocsDir(siteDir, pluginId);
|
||||||
const newVersionDir = path.join(versionedDir, `version-${version}`);
|
const newVersionDir = path.join(versionedDir, `version-${version}`);
|
||||||
fs.copySync(docsDir, newVersionDir);
|
fs.copySync(docsDir, newVersionDir);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('There is no docs to version !');
|
throw new Error(`${pluginIdLogPrefix}There is no docs to version !`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load current sidebar and create a new versioned sidebars file.
|
// Load current sidebar and create a new versioned sidebars file.
|
||||||
|
@ -109,7 +116,7 @@ export function docsVersion(
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
const versionedSidebarsDir = getVersionedSidebarsDir(siteDir);
|
const versionedSidebarsDir = getVersionedSidebarsDir(siteDir, pluginId);
|
||||||
const newSidebarFile = path.join(
|
const newSidebarFile = path.join(
|
||||||
versionedSidebarsDir,
|
versionedSidebarsDir,
|
||||||
`version-${version}-sidebars.json`,
|
`version-${version}-sidebars.json`,
|
||||||
|
@ -127,5 +134,5 @@ export function docsVersion(
|
||||||
fs.ensureDirSync(path.dirname(versionsJSONFile));
|
fs.ensureDirSync(path.dirname(versionsJSONFile));
|
||||||
fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
|
fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
|
||||||
|
|
||||||
console.log(`Version ${version} created!`);
|
console.log(`${pluginIdLogPrefix}Version ${version} created!`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"@types/hapi__joi": "^17.1.2"
|
"@types/hapi__joi": "^17.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@docusaurus/core": "^2.0.0-alpha.61",
|
||||||
"@docusaurus/mdx-loader": "^2.0.0-alpha.61",
|
"@docusaurus/mdx-loader": "^2.0.0-alpha.61",
|
||||||
"@docusaurus/types": "^2.0.0-alpha.61",
|
"@docusaurus/types": "^2.0.0-alpha.61",
|
||||||
"@docusaurus/utils": "^2.0.0-alpha.61",
|
"@docusaurus/utils": "^2.0.0-alpha.61",
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {Configuration, Loader} from 'webpack';
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||||
import {ValidationError} from '@hapi/joi';
|
import {ValidationError} from '@hapi/joi';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
|
|
||||||
import {PluginOptions, LoadedContent, Metadata} from './types';
|
import {PluginOptions, LoadedContent, Metadata} from './types';
|
||||||
|
|
||||||
|
@ -44,10 +45,11 @@ export default function pluginContentPages(
|
||||||
|
|
||||||
const contentPath = path.resolve(siteDir, options.path);
|
const contentPath = path.resolve(siteDir, options.path);
|
||||||
|
|
||||||
const dataDir = path.join(
|
const pluginDataDirRoot = path.join(
|
||||||
generatedFilesDir,
|
generatedFilesDir,
|
||||||
'docusaurus-plugin-content-pages',
|
'docusaurus-plugin-content-pages',
|
||||||
);
|
);
|
||||||
|
const dataDir = path.join(pluginDataDirRoot, options.id ?? DEFAULT_PLUGIN_ID);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-content-pages',
|
name: 'docusaurus-plugin-content-pages',
|
||||||
|
@ -83,20 +85,20 @@ export default function pluginContentPages(
|
||||||
|
|
||||||
function toMetadata(relativeSource: string): Metadata {
|
function toMetadata(relativeSource: string): Metadata {
|
||||||
const source = path.join(pagesDir, relativeSource);
|
const source = path.join(pagesDir, relativeSource);
|
||||||
const aliasedSource = aliasedSitePath(source, siteDir);
|
const aliasedSourcePath = aliasedSitePath(source, siteDir);
|
||||||
const pathName = encodePath(fileToPath(relativeSource));
|
const pathName = encodePath(fileToPath(relativeSource));
|
||||||
const permalink = pathName.replace(/^\//, baseUrl || '');
|
const permalink = pathName.replace(/^\//, baseUrl || '');
|
||||||
if (isMarkdownSource(relativeSource)) {
|
if (isMarkdownSource(relativeSource)) {
|
||||||
return {
|
return {
|
||||||
type: 'mdx',
|
type: 'mdx',
|
||||||
permalink,
|
permalink,
|
||||||
source: aliasedSource,
|
source: aliasedSourcePath,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
type: 'jsx',
|
type: 'jsx',
|
||||||
permalink,
|
permalink,
|
||||||
source: aliasedSource,
|
source: aliasedSourcePath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +154,7 @@ export default function pluginContentPages(
|
||||||
return {
|
return {
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~pages': dataDir,
|
'~pages': pluginDataDirRoot,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
@ -171,10 +173,10 @@ export default function pluginContentPages(
|
||||||
// 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.
|
||||||
metadataPath: (mdxPath: string) => {
|
metadataPath: (mdxPath: string) => {
|
||||||
const aliasedSource = aliasedSitePath(mdxPath, siteDir);
|
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
||||||
return path.join(
|
return path.join(
|
||||||
dataDir,
|
dataDir,
|
||||||
`${docuHash(aliasedSource)}.json`,
|
`${docuHash(aliasedPath)}.json`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface PluginOptions {
|
export interface PluginOptions {
|
||||||
|
id?: string;
|
||||||
path: string;
|
path: string;
|
||||||
routeBasePath: string;
|
routeBasePath: string;
|
||||||
include: string[];
|
include: string[];
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"@types/hapi__joi": "^17.1.2"
|
"@types/hapi__joi": "^17.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/joi": "17.1.1"
|
"@hapi/joi": "17.1.1",
|
||||||
|
"chalk": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.15.1"
|
"node": ">=10.15.1"
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`validation schemas AdmonitionsSchema 1`] = `"\\"value\\" must be of type object"`;
|
|
||||||
|
|
||||||
exports[`validation schemas AdmonitionsSchema 2`] = `"\\"value\\" must be of type object"`;
|
|
||||||
|
|
||||||
exports[`validation schemas AdmonitionsSchema 3`] = `"\\"value\\" must be of type object"`;
|
|
||||||
|
|
||||||
exports[`validation schemas AdmonitionsSchema 4`] = `"\\"value\\" must be of type object"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 1`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 2`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 3`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 4`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 5`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 6`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 7`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 8`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RehypePluginsSchema 9`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 1`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 2`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 3`] = `"\\"value\\" must be an array"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 4`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 5`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 6`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 7`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 8`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
||||||
|
|
||||||
exports[`validation schemas RemarkPluginsSchema 9`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`validation schemas AdmonitionsSchema: for value=[] 1`] = `"\\"value\\" must be of type object"`;
|
||||||
|
|
||||||
|
exports[`validation schemas AdmonitionsSchema: for value=3 1`] = `"\\"value\\" must be of type object"`;
|
||||||
|
|
||||||
|
exports[`validation schemas AdmonitionsSchema: for value=null 1`] = `"\\"value\\" must be of type object"`;
|
||||||
|
|
||||||
|
exports[`validation schemas AdmonitionsSchema: for value=true 1`] = `"\\"value\\" must be of type object"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value="/docs" 1`] = `"\\"value\\" with value \\"/docs\\" fails to match the required pattern: /^[a-zA-Z_\\\\-]+$/"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value="do cs" 1`] = `"\\"value\\" with value \\"do cs\\" fails to match the required pattern: /^[a-zA-Z_\\\\-]+$/"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value="do/cs" 1`] = `"\\"value\\" with value \\"do/cs\\" fails to match the required pattern: /^[a-zA-Z_\\\\-]+$/"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value="docs/" 1`] = `"\\"value\\" with value \\"docs/\\" fails to match the required pattern: /^[a-zA-Z_\\\\-]+$/"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value=[] 1`] = `"\\"value\\" must be a string"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value=3 1`] = `"\\"value\\" must be a string"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value=null 1`] = `"\\"value\\" must be a string"`;
|
||||||
|
|
||||||
|
exports[`validation schemas PluginIdSchema: for value=true 1`] = `"\\"value\\" must be a string"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RehypePluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[[]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[[null,null]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[[null,true]] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[3] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[false] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=[null] 1`] = `"\\"[0]\\" does not match any of the allowed types"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=3 1`] = `"\\"value\\" must be an array"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=false 1`] = `"\\"value\\" must be an array"`;
|
||||||
|
|
||||||
|
exports[`validation schemas RemarkPluginsSchema: for value=null 1`] = `"\\"value\\" must be an array"`;
|
|
@ -11,7 +11,8 @@ import {
|
||||||
AdmonitionsSchema,
|
AdmonitionsSchema,
|
||||||
RehypePluginsSchema,
|
RehypePluginsSchema,
|
||||||
RemarkPluginsSchema,
|
RemarkPluginsSchema,
|
||||||
} from '../index';
|
PluginIdSchema,
|
||||||
|
} from '../validationSchemas';
|
||||||
|
|
||||||
function createTestHelpers({
|
function createTestHelpers({
|
||||||
schema,
|
schema,
|
||||||
|
@ -25,7 +26,10 @@ function createTestHelpers({
|
||||||
}
|
}
|
||||||
|
|
||||||
function testFail(value: unknown) {
|
function testFail(value: unknown) {
|
||||||
expect(() => Joi.attempt(value, schema)).toThrowErrorMatchingSnapshot();
|
expect(() => Joi.attempt(value, schema)).toThrowErrorMatchingSnapshot(
|
||||||
|
// @ts-expect-error: seems ok at runtime, but bad typedef
|
||||||
|
`for value=${JSON.stringify(value)}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {testOK, testFail};
|
return {testOK, testFail};
|
||||||
|
@ -58,6 +62,27 @@ function testMarkdownPluginSchemas(schema: Joi.SchemaLike) {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('validation schemas', () => {
|
describe('validation schemas', () => {
|
||||||
|
test('PluginIdSchema', () => {
|
||||||
|
const {testOK, testFail} = createTestHelpers({
|
||||||
|
schema: PluginIdSchema,
|
||||||
|
defaultValue: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
testOK(undefined);
|
||||||
|
testOK('docs');
|
||||||
|
testOK('default');
|
||||||
|
testOK('plugin-id_with-simple-special-chars');
|
||||||
|
|
||||||
|
testFail('/docs');
|
||||||
|
testFail('docs/');
|
||||||
|
testFail('do/cs');
|
||||||
|
testFail('do cs');
|
||||||
|
testFail(null);
|
||||||
|
testFail(3);
|
||||||
|
testFail(true);
|
||||||
|
testFail([]);
|
||||||
|
});
|
||||||
|
|
||||||
test('AdmonitionsSchema', () => {
|
test('AdmonitionsSchema', () => {
|
||||||
const {testOK, testFail} = createTestHelpers({
|
const {testOK, testFail} = createTestHelpers({
|
||||||
schema: AdmonitionsSchema,
|
schema: AdmonitionsSchema,
|
|
@ -4,19 +4,6 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
import * as Joi from '@hapi/joi';
|
|
||||||
|
|
||||||
const MarkdownPluginsSchema = Joi.array()
|
export * from './validationUtils';
|
||||||
.items(
|
export * from './validationSchemas';
|
||||||
Joi.array()
|
|
||||||
// TODO, this allows [config,fn] too?
|
|
||||||
.items(Joi.function().required(), Joi.object().required())
|
|
||||||
.length(2),
|
|
||||||
Joi.function(),
|
|
||||||
)
|
|
||||||
.default([]);
|
|
||||||
|
|
||||||
export const RemarkPluginsSchema = MarkdownPluginsSchema;
|
|
||||||
export const RehypePluginsSchema = MarkdownPluginsSchema;
|
|
||||||
|
|
||||||
export const AdmonitionsSchema = Joi.object().default({});
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* 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 * as Joi from '@hapi/joi';
|
||||||
|
|
||||||
|
export const PluginIdSchema = Joi.string()
|
||||||
|
.regex(/^[a-zA-Z_\-]+$/)
|
||||||
|
// duplicate core constant, otherwise cyclic dependency is created :(
|
||||||
|
.default('default');
|
||||||
|
|
||||||
|
const MarkdownPluginsSchema = Joi.array()
|
||||||
|
.items(
|
||||||
|
Joi.array()
|
||||||
|
// TODO, this allows [config,fn] too?
|
||||||
|
.items(Joi.function().required(), Joi.object().required())
|
||||||
|
.length(2),
|
||||||
|
Joi.function(),
|
||||||
|
)
|
||||||
|
.default([]);
|
||||||
|
|
||||||
|
export const RemarkPluginsSchema = MarkdownPluginsSchema;
|
||||||
|
export const RehypePluginsSchema = MarkdownPluginsSchema;
|
||||||
|
|
||||||
|
export const AdmonitionsSchema = Joi.object().default({});
|
85
packages/docusaurus-utils-validation/src/validationUtils.ts
Normal file
85
packages/docusaurus-utils-validation/src/validationUtils.ts
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
* 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 * as Joi from '@hapi/joi';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import {PluginIdSchema} from './validationSchemas';
|
||||||
|
|
||||||
|
// TODO temporary escape hatch for alpha-60: to be removed soon
|
||||||
|
// Our validation schemas might be buggy at first
|
||||||
|
// will permit users to bypass validation until we fix all validation errors
|
||||||
|
// see for example: https://github.com/facebook/docusaurus/pull/3120
|
||||||
|
// Undocumented on purpose, as we don't want users to keep using it over time
|
||||||
|
// Maybe we'll make this escape hatch official some day, with a better api?
|
||||||
|
export const isValidationDisabledEscapeHatch =
|
||||||
|
process.env.DISABLE_DOCUSAURUS_VALIDATION === 'true';
|
||||||
|
|
||||||
|
if (isValidationDisabledEscapeHatch) {
|
||||||
|
console.error(
|
||||||
|
chalk.red(
|
||||||
|
'You should avoid using DISABLE_DOCUSAURUS_VALIDATION escape hatch, this will be removed',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logValidationBugReportHint = () => {
|
||||||
|
console.log(
|
||||||
|
`\n${chalk.red('A validation error occured.')}${chalk.cyanBright(
|
||||||
|
'\nThe validation system was added recently to Docusaurus as an attempt to avoid user configuration errors.' +
|
||||||
|
'\nWe may have made some mistakes.' +
|
||||||
|
'\nIf you think your configuration is valid and should keep working, please open a bug report.',
|
||||||
|
)}\n`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function normalizePluginOptions<T extends {id?: string}>(
|
||||||
|
schema: Joi.ObjectSchema<T>,
|
||||||
|
options: unknown,
|
||||||
|
) {
|
||||||
|
// All plugins can be provided an "id" option (multi-instance support)
|
||||||
|
// we add schema validation automatically
|
||||||
|
const finalSchema = schema.append({
|
||||||
|
id: PluginIdSchema,
|
||||||
|
});
|
||||||
|
const {error, value} = finalSchema.validate(options, {
|
||||||
|
convert: false,
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
logValidationBugReportHint();
|
||||||
|
if (isValidationDisabledEscapeHatch) {
|
||||||
|
console.error(error);
|
||||||
|
return options;
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeThemeConfig<T>(
|
||||||
|
schema: Joi.ObjectSchema<T>,
|
||||||
|
themeConfig: unknown,
|
||||||
|
) {
|
||||||
|
// A theme should only validate his "slice" of the full themeConfig,
|
||||||
|
// not the whole object, so we allow unknown attributes
|
||||||
|
// otherwise one theme would fail validating the data of another theme
|
||||||
|
const finalSchema = schema.unknown();
|
||||||
|
|
||||||
|
const {error, value} = finalSchema.validate(themeConfig, {
|
||||||
|
convert: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
logValidationBugReportHint();
|
||||||
|
if (isValidationDisabledEscapeHatch) {
|
||||||
|
console.error(error);
|
||||||
|
return themeConfig;
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
|
@ -47,6 +47,7 @@
|
||||||
"@babel/runtime-corejs3": "^7.10.4",
|
"@babel/runtime-corejs3": "^7.10.4",
|
||||||
"@docusaurus/types": "^2.0.0-alpha.61",
|
"@docusaurus/types": "^2.0.0-alpha.61",
|
||||||
"@docusaurus/utils": "^2.0.0-alpha.61",
|
"@docusaurus/utils": "^2.0.0-alpha.61",
|
||||||
|
"@docusaurus/utils-validation": "^2.0.0-alpha.61",
|
||||||
"@endiliey/static-site-generator-webpack-plugin": "^4.0.0",
|
"@endiliey/static-site-generator-webpack-plugin": "^4.0.0",
|
||||||
"@hapi/joi": "^17.1.1",
|
"@hapi/joi": "^17.1.1",
|
||||||
"@svgr/webpack": "^5.4.0",
|
"@svgr/webpack": "^5.4.0",
|
||||||
|
|
29
packages/docusaurus/src/client/.eslintrc.js
Normal file
29
packages/docusaurus/src/client/.eslintrc.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
rules: {
|
||||||
|
'no-restricted-imports': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
// prevent importing lodash in client bundle
|
||||||
|
// prefer shipping vanilla JS
|
||||||
|
'lodash',
|
||||||
|
'lodash.**',
|
||||||
|
'lodash/**',
|
||||||
|
// prevent importing server code in client bundle
|
||||||
|
'**/../babel/**',
|
||||||
|
'**/../server/**',
|
||||||
|
'**/../commands/**',
|
||||||
|
'**/../webpack/**',
|
||||||
|
'**/../constants',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
|
@ -7,6 +7,12 @@
|
||||||
|
|
||||||
import useDocusaurusContext from './useDocusaurusContext';
|
import useDocusaurusContext from './useDocusaurusContext';
|
||||||
|
|
||||||
|
// TODO annoying constant duplication
|
||||||
|
// if we import something from outside the /client folder,
|
||||||
|
// the tsc directory structure is affected
|
||||||
|
// import {DEFAULT_PLUGIN_ID} from '../../constants';
|
||||||
|
const DEFAULT_PLUGIN_ID = 'default';
|
||||||
|
|
||||||
export default function useGlobalData() {
|
export default function useGlobalData() {
|
||||||
const {globalData} = useDocusaurusContext();
|
const {globalData} = useDocusaurusContext();
|
||||||
if (!globalData) {
|
if (!globalData) {
|
||||||
|
@ -30,7 +36,7 @@ export function useAllPluginInstancesData<T = unknown>(
|
||||||
|
|
||||||
export function usePluginData<T = unknown>(
|
export function usePluginData<T = unknown>(
|
||||||
pluginName: string,
|
pluginName: string,
|
||||||
pluginId: string = 'default',
|
pluginId: string = DEFAULT_PLUGIN_ID,
|
||||||
): T {
|
): T {
|
||||||
const pluginGlobalData = useAllPluginInstancesData(pluginName);
|
const pluginGlobalData = useAllPluginInstancesData(pluginName);
|
||||||
const pluginInstanceGlobalData = pluginGlobalData[pluginId];
|
const pluginInstanceGlobalData = pluginGlobalData[pluginId];
|
||||||
|
|
|
@ -14,3 +14,4 @@ export const STATIC_DIR_NAME = 'static';
|
||||||
export const STATIC_ASSETS_DIR_NAME = 'assets'; // files handled by webpack
|
export const STATIC_ASSETS_DIR_NAME = 'assets'; // files handled by webpack
|
||||||
export const THEME_PATH = `${SRC_DIR_NAME}/theme`;
|
export const THEME_PATH = `${SRC_DIR_NAME}/theme`;
|
||||||
export const DEFAULT_PORT = 3000;
|
export const DEFAULT_PORT = 3000;
|
||||||
|
export const DEFAULT_PLUGIN_ID = 'default';
|
||||||
|
|
|
@ -9,9 +9,9 @@ import {DocusaurusConfig} from '@docusaurus/types';
|
||||||
import {CONFIG_FILE_NAME} from '../constants';
|
import {CONFIG_FILE_NAME} from '../constants';
|
||||||
import Joi from '@hapi/joi';
|
import Joi from '@hapi/joi';
|
||||||
import {
|
import {
|
||||||
isValidationDisabledEscapeHatch,
|
|
||||||
logValidationBugReportHint,
|
logValidationBugReportHint,
|
||||||
} from './utils';
|
isValidationDisabledEscapeHatch,
|
||||||
|
} from '@docusaurus/utils-validation';
|
||||||
|
|
||||||
export const DEFAULT_CONFIG: Pick<
|
export const DEFAULT_CONFIG: Pick<
|
||||||
DocusaurusConfig,
|
DocusaurusConfig,
|
||||||
|
@ -47,6 +47,7 @@ const PresetSchema = Joi.alternatives().try(
|
||||||
Joi.array().items(Joi.string().required(), Joi.object().required()).length(2),
|
Joi.array().items(Joi.string().required(), Joi.object().required()).length(2),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO move to @docusaurus/utils-validation
|
||||||
const ConfigSchema = Joi.object({
|
const ConfigSchema = Joi.object({
|
||||||
baseUrl: Joi.string()
|
baseUrl: Joi.string()
|
||||||
.required()
|
.required()
|
||||||
|
@ -87,6 +88,7 @@ const ConfigSchema = Joi.object({
|
||||||
tagline: Joi.string().allow(''),
|
tagline: Joi.string().allow(''),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO move to @docusaurus/utils-validation
|
||||||
export function validateConfig(
|
export function validateConfig(
|
||||||
config: Partial<DocusaurusConfig>,
|
config: Partial<DocusaurusConfig>,
|
||||||
): DocusaurusConfig {
|
): DocusaurusConfig {
|
||||||
|
|
|
@ -16,8 +16,7 @@ import {
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import initPlugins, {InitPlugin} from './init';
|
import initPlugins, {InitPlugin} from './init';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '../../constants';
|
||||||
const DefaultPluginId = 'default';
|
|
||||||
|
|
||||||
export function sortConfig(routeConfigs: RouteConfig[]): void {
|
export function sortConfig(routeConfigs: RouteConfig[]): void {
|
||||||
// Sort the route config. This ensures that route with nested
|
// Sort the route config. This ensures that route with nested
|
||||||
|
@ -90,14 +89,11 @@ export async function loadPlugins({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pluginId = plugin.options.id ?? DefaultPluginId;
|
const pluginId = plugin.options.id ?? DEFAULT_PLUGIN_ID;
|
||||||
|
|
||||||
const pluginContentDir = path.join(
|
// plugins data files are namespaced by pluginName/pluginId
|
||||||
context.generatedFilesDir,
|
const dataDirRoot = path.join(context.generatedFilesDir, plugin.name);
|
||||||
plugin.name,
|
const dataDir = path.join(dataDirRoot, pluginId);
|
||||||
// TODO each plugin instance should have its folder
|
|
||||||
// pluginId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const addRoute: PluginContentLoadedActions['addRoute'] = (config) =>
|
const addRoute: PluginContentLoadedActions['addRoute'] = (config) =>
|
||||||
pluginsRouteConfigs.push(config);
|
pluginsRouteConfigs.push(config);
|
||||||
|
@ -106,9 +102,9 @@ export async function loadPlugins({
|
||||||
name,
|
name,
|
||||||
content,
|
content,
|
||||||
) => {
|
) => {
|
||||||
const modulePath = path.join(pluginContentDir, name);
|
const modulePath = path.join(dataDir, name);
|
||||||
await fs.ensureDir(path.dirname(modulePath));
|
await fs.ensureDir(path.dirname(modulePath));
|
||||||
await generate(pluginContentDir, name, content);
|
await generate(dataDir, name, content);
|
||||||
return modulePath;
|
return modulePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,65 +13,15 @@ import {
|
||||||
Plugin,
|
Plugin,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
PluginConfig,
|
PluginConfig,
|
||||||
ValidationSchema,
|
|
||||||
DocusaurusPluginVersionInformation,
|
DocusaurusPluginVersionInformation,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {CONFIG_FILE_NAME} from '../../constants';
|
import {CONFIG_FILE_NAME} from '../../constants';
|
||||||
import {getPluginVersion} from '../versions';
|
import {getPluginVersion} from '../versions';
|
||||||
import {ensureUniquePluginInstanceIds} from './pluginIds';
|
import {ensureUniquePluginInstanceIds} from './pluginIds';
|
||||||
import * as Joi from '@hapi/joi';
|
|
||||||
import {
|
import {
|
||||||
isValidationDisabledEscapeHatch,
|
normalizePluginOptions,
|
||||||
logValidationBugReportHint,
|
normalizeThemeConfig,
|
||||||
} from '../utils';
|
} from '@docusaurus/utils-validation';
|
||||||
|
|
||||||
function pluginOptionsValidator<T>(
|
|
||||||
schema: ValidationSchema<T>,
|
|
||||||
options: Partial<T>,
|
|
||||||
) {
|
|
||||||
// All plugins can be provided an "id" for multi-instance support
|
|
||||||
// we don't ask the user to implement id validation, we add it automatically
|
|
||||||
const finalSchema = schema.append({
|
|
||||||
id: Joi.string(),
|
|
||||||
});
|
|
||||||
const {error, value} = finalSchema.validate(options, {
|
|
||||||
convert: false,
|
|
||||||
});
|
|
||||||
if (error) {
|
|
||||||
logValidationBugReportHint();
|
|
||||||
if (isValidationDisabledEscapeHatch) {
|
|
||||||
console.error(error);
|
|
||||||
return options;
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function themeConfigValidator<T>(
|
|
||||||
schema: ValidationSchema<T>,
|
|
||||||
themeConfig: Partial<T>,
|
|
||||||
) {
|
|
||||||
// A theme should only validate his "slice" of the full themeConfig,
|
|
||||||
// not the whole object, so we allow unknown attributes to pass a theme validation
|
|
||||||
const finalSchema = schema.unknown();
|
|
||||||
|
|
||||||
const {error, value} = finalSchema.validate(themeConfig, {
|
|
||||||
convert: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
logValidationBugReportHint();
|
|
||||||
if (isValidationDisabledEscapeHatch) {
|
|
||||||
console.error(error);
|
|
||||||
return themeConfig;
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InitPlugin = Plugin<unknown> & {
|
export type InitPlugin = Plugin<unknown> & {
|
||||||
readonly options: PluginOptions;
|
readonly options: PluginOptions;
|
||||||
|
@ -125,7 +75,7 @@ export default function initPlugins({
|
||||||
|
|
||||||
if (validateOptions) {
|
if (validateOptions) {
|
||||||
const normalizedOptions = validateOptions({
|
const normalizedOptions = validateOptions({
|
||||||
validate: pluginOptionsValidator,
|
validate: normalizePluginOptions,
|
||||||
options: pluginOptions,
|
options: pluginOptions,
|
||||||
});
|
});
|
||||||
pluginOptions = normalizedOptions;
|
pluginOptions = normalizedOptions;
|
||||||
|
@ -138,7 +88,7 @@ export default function initPlugins({
|
||||||
|
|
||||||
if (validateThemeConfig) {
|
if (validateThemeConfig) {
|
||||||
const normalizedThemeConfig = validateThemeConfig({
|
const normalizedThemeConfig = validateThemeConfig({
|
||||||
validate: themeConfigValidator,
|
validate: normalizeThemeConfig,
|
||||||
themeConfig: context.siteConfig.themeConfig,
|
themeConfig: context.siteConfig.themeConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import {groupBy} from 'lodash';
|
import {groupBy} from 'lodash';
|
||||||
import {InitPlugin} from './init';
|
import {InitPlugin} from './init';
|
||||||
|
import {DEFAULT_PLUGIN_ID} from '../../constants';
|
||||||
|
|
||||||
// It is forbidden to have 2 plugins of the same name sharind the same id
|
// It is forbidden to have 2 plugins of the same name sharind the same id
|
||||||
// this is required to support multi-instance plugins without conflict
|
// this is required to support multi-instance plugins without conflict
|
||||||
|
@ -15,7 +16,7 @@ export function ensureUniquePluginInstanceIds(plugins: InitPlugin[]) {
|
||||||
Object.entries(pluginsByName).forEach(([pluginName, pluginInstances]) => {
|
Object.entries(pluginsByName).forEach(([pluginName, pluginInstances]) => {
|
||||||
const pluginInstancesById = groupBy(
|
const pluginInstancesById = groupBy(
|
||||||
pluginInstances,
|
pluginInstances,
|
||||||
(p) => p.options.id ?? 'default',
|
(p) => p.options.id ?? DEFAULT_PLUGIN_ID,
|
||||||
);
|
);
|
||||||
Object.entries(pluginInstancesById).forEach(
|
Object.entries(pluginInstancesById).forEach(
|
||||||
([pluginId, pluginInstancesWithId]) => {
|
([pluginId, pluginInstancesWithId]) => {
|
||||||
|
|
|
@ -8,32 +8,6 @@ import chalk from 'chalk';
|
||||||
import flatMap from 'lodash.flatmap';
|
import flatMap from 'lodash.flatmap';
|
||||||
import {RouteConfig, ReportingSeverity} from '@docusaurus/types';
|
import {RouteConfig, ReportingSeverity} from '@docusaurus/types';
|
||||||
|
|
||||||
// TODO temporary escape hatch for alpha-60: to be removed soon
|
|
||||||
// Our validation schemas might be buggy at first
|
|
||||||
// will permit users to bypass validation until we fix all validation errors
|
|
||||||
// see for example: https://github.com/facebook/docusaurus/pull/3120
|
|
||||||
// Undocumented on purpose, as we don't want users to keep using it over time
|
|
||||||
// Maybe we'll make this escape hatch official some day, with a better api?
|
|
||||||
export const isValidationDisabledEscapeHatch =
|
|
||||||
process.env.DISABLE_DOCUSAURUS_VALIDATION === 'true';
|
|
||||||
|
|
||||||
isValidationDisabledEscapeHatch &&
|
|
||||||
console.error(
|
|
||||||
chalk.red(
|
|
||||||
'You should avoid using DISABLE_DOCUSAURUS_VALIDATION escape hatch, this will be removed',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const logValidationBugReportHint = () => {
|
|
||||||
console.log(
|
|
||||||
`\n${chalk.red('A validation error occured.')}${chalk.cyanBright(
|
|
||||||
'\nThe validation system was added recently to Docusaurus as an attempt to avoid user configuration errors.' +
|
|
||||||
'\nWe may have made some mistakes.' +
|
|
||||||
'\nIf you think your configuration is valid and should keep working, please open a bug report.',
|
|
||||||
)}\n`,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Recursively get the final routes (routes with no subroutes)
|
// Recursively get the final routes (routes with no subroutes)
|
||||||
export function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[] {
|
export function getAllFinalRoutes(routeConfig: RouteConfig[]): RouteConfig[] {
|
||||||
function getFinalRoutes(route: RouteConfig): RouteConfig[] {
|
function getFinalRoutes(route: RouteConfig): RouteConfig[] {
|
||||||
|
|
|
@ -20,13 +20,13 @@ See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase
|
||||||
|
|
||||||
## Official plugins
|
## Official plugins
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
- [@docusaurus/plugin-content-blog](/docs/using-plugins#docusaurusplugin-content-blog)
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
- [@docusaurus/plugin-content-docs](/docs/using-plugins#docusaurusplugin-content-docs)
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
- [@docusaurus/plugin-content-pages](/docs/using-plugins#docusaurusplugin-content-pages)
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
- [@docusaurus/plugin-google-analytics](/docs/using-plugins#docusaurusplugin-google-analytics)
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
- [@docusaurus/plugin-google-gtag](/docs/using-plugins#docusaurusplugin-google-gtag)
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
- [@docusaurus/plugin-sitemap](/docs/using-plugins#docusaurusplugin-sitemap)
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
- [@docusaurus/plugin-ideal-image](/docs/using-plugins#docusaurusplugin-ideal-image)
|
||||||
|
|
||||||
## Community plugins
|
## Community plugins
|
||||||
|
|
|
@ -36,7 +36,7 @@ export function TeamProfileCardCol(props) { return <TeamProfileCard {...props} c
|
||||||
githubUrl="https://github.com/slorber"
|
githubUrl="https://github.com/slorber"
|
||||||
twitterUrl="https://twitter.com/sebastienlorber"
|
twitterUrl="https://twitter.com/sebastienlorber"
|
||||||
>
|
>
|
||||||
React lover since 2014. Freelance, helping Facebook ship Docusaurus v2.
|
React lover since 2014. Freelance, helping Facebook ship Docusaurus v2. He writes regularly, on his <a href="https://sebastienlorber.com/" target="_blank">website</a> and <a href="https://dev.to/sebastienlorber" target="_blank">Dev.to</a>.
|
||||||
</TeamProfileCardCol>
|
</TeamProfileCardCol>
|
||||||
<TeamProfileCardCol
|
<TeamProfileCardCol
|
||||||
name="Yangshun Tay"
|
name="Yangshun Tay"
|
|
@ -187,6 +187,8 @@ By default, the classic theme assumes only one blog per website and hence includ
|
||||||
|
|
||||||
Set the `routeBasePath` to the URL route that you want your second blog to be accessed on. Note that the `routeBasePath` here has to be different from the first blog or else there could be a collision of paths! Also, set `path` to the path to the directory containing your second blog's entries.
|
Set the `routeBasePath` to the URL route that you want your second blog to be accessed on. Note that the `routeBasePath` here has to be different from the first blog or else there could be a collision of paths! Also, set `path` to the path to the directory containing your second blog's entries.
|
||||||
|
|
||||||
|
As documented for [multi-instance plugins](./using-plugins.md#multi-instance-plugins-and-plugin-ids), you need to assign a unique id to the plugins.
|
||||||
|
|
||||||
```js title="docusaurus.config.js"
|
```js title="docusaurus.config.js"
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// ...
|
// ...
|
||||||
|
@ -194,6 +196,10 @@ module.exports = {
|
||||||
[
|
[
|
||||||
'@docusaurus/plugin-content-blog',
|
'@docusaurus/plugin-content-blog',
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Required for any multi-instance plugin
|
||||||
|
*/
|
||||||
|
id: 'second-blog',
|
||||||
/**
|
/**
|
||||||
* URL route for the blog section of your site.
|
* URL route for the blog section of your site.
|
||||||
* *DO NOT* include a trailing slash.
|
* *DO NOT* include a trailing slash.
|
||||||
|
@ -209,13 +215,4 @@ module.exports = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--
|
As an example, we host a second blog [here](/second-blog).
|
||||||
|
|
||||||
Adding a blog using the blog plugin.
|
|
||||||
|
|
||||||
References
|
|
||||||
---
|
|
||||||
- [source code](/packages/docusaurus-plugin-content-blog/src/index.js)
|
|
||||||
- [v1 doc](https://docusaurus.io/docs/en/next/adding-blog)
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
slug: /resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Articles
|
|
||||||
|
|
||||||
- [Live code editing in Docusaurus](https://dev.to/mrmuhammadali/live-code-editing-in-docusaurus-28k)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
|
|
||||||
- [posthog-docusaurus](https://github.com/PostHog/posthog-docusaurus) - Integrate [PostHog](https://posthog.com/) product analytics with Docusaurus v2
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,80 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
slug: /team
|
|
||||||
---
|
|
||||||
|
|
||||||
import TeamProfileCard from "@site/src/components/TeamProfileCard"
|
|
||||||
|
|
||||||
export function TeamProfileCardCol(props) { return <TeamProfileCard {...props} className={'col col--6 margin-bottom--lg'}/> }
|
|
||||||
|
|
||||||
## Active Team
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Alexey Pyltsyn"
|
|
||||||
githubUrl="https://github.com/lex111"
|
|
||||||
>
|
|
||||||
Obsessed open-source enthusiast 👋 Eternal amateur at everything 🤷♂️ Maintainer of Russian docs on PHP, React, Kubernetes and much more 🧐
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Fanny Vieira"
|
|
||||||
githubUrl="https://github.com/fanny"
|
|
||||||
twitterUrl="https://twitter.com/fannyvieiira"
|
|
||||||
>
|
|
||||||
Fanny got started with web development in high school, building a project for the school kitchen. In her free time she loves contributing to Open Source, occasionally writing on <a href="https://dev.to/fannyvieira" target="_blank">her blog</a> about her experiences, cooking, and creating <a href="https://open.spotify.com/user/anotherfanny" target="_blank">Spotify playlists</a>.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Joel Marcey"
|
|
||||||
githubUrl="https://github.com/JoelMarcey"
|
|
||||||
twitterUrl="https://twitter.com/joelmarcey"
|
|
||||||
>
|
|
||||||
Docusaurus founder and now ever grateful Docusaurus cheerleader to those who actually write code for it.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Sébastien Lorber"
|
|
||||||
githubUrl="https://github.com/slorber"
|
|
||||||
twitterUrl="https://twitter.com/sebastienlorber"
|
|
||||||
>
|
|
||||||
React lover since 2014. Freelance, helping Facebook ship Docusaurus v2.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Yangshun Tay"
|
|
||||||
githubUrl="https://github.com/yangshun"
|
|
||||||
twitterUrl="https://twitter.com/yangshunz"
|
|
||||||
>
|
|
||||||
Full Front End Stack developer who likes working on the Jamstack. Working on Docusaurus made him Facebook's unofficial part-time Open Source webmaster, which is an awesome role to be in.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<TeamProfileCardCol name="Endilie Yacop Sucipto" githubUrl="https://github.com/endiliey" twitterUrl="https://twitter.com/endiliey">
|
|
||||||
Maintainer @docusaurus · 🔥🔥🔥
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Wei Gao"
|
|
||||||
githubUrl="https://github.com/wgao19"
|
|
||||||
twitterUrl="https://twitter.com/wgao19"
|
|
||||||
>
|
|
||||||
🏻🌾 Work in progress React developer, maintains Docusaurus, writes docs and spams this world with many websites.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- [Elvis Wolcott](https://github.com/elviswolcott)
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- [Fienny Angelina](https://github.com/fiennyangeln)
|
|
||||||
- [Frank Li](https://github.com/deltice)
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- [Ramón Lamana](https://github.com/rlamana)
|
|
||||||
- [Ricky Vetter](https://github.com/rickyvetter)
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -31,6 +31,33 @@ module.exports = {
|
||||||
},
|
},
|
||||||
themes: ['@docusaurus/theme-live-codeblock'],
|
themes: ['@docusaurus/theme-live-codeblock'],
|
||||||
plugins: [
|
plugins: [
|
||||||
|
[
|
||||||
|
'@docusaurus/plugin-content-docs',
|
||||||
|
{
|
||||||
|
id: 'community',
|
||||||
|
path: 'community',
|
||||||
|
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website/',
|
||||||
|
routeBasePath: 'community',
|
||||||
|
sidebarPath: require.resolve('./sidebarsCommunity.js'),
|
||||||
|
showLastUpdateAuthor: true,
|
||||||
|
showLastUpdateTime: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'@docusaurus/plugin-content-blog',
|
||||||
|
{
|
||||||
|
id: 'second-blog',
|
||||||
|
path: 'dogfooding/second-blog',
|
||||||
|
routeBasePath: 'second-blog',
|
||||||
|
editUrl:
|
||||||
|
'https://github.com/facebook/docusaurus/edit/master/website/dogfooding',
|
||||||
|
postsPerPage: 3,
|
||||||
|
feedOptions: {
|
||||||
|
type: 'all',
|
||||||
|
copyright: `Copyright © ${new Date().getFullYear()} Facebook, Inc.`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'@docusaurus/plugin-client-redirects',
|
'@docusaurus/plugin-client-redirects',
|
||||||
{
|
{
|
||||||
|
@ -42,6 +69,20 @@ module.exports = {
|
||||||
return [`${path}/introduction`];
|
return [`${path}/introduction`];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
redirects: [
|
||||||
|
{
|
||||||
|
from: ['/docs/support', '/docs/next/support'],
|
||||||
|
to: '/community/support',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: ['/docs/team', '/docs/next/team'],
|
||||||
|
to: '/community/team',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: ['/docs/resources', '/docs/next/resources'],
|
||||||
|
to: '/community/resources',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -116,6 +157,7 @@ module.exports = {
|
||||||
'@docusaurus/preset-classic',
|
'@docusaurus/preset-classic',
|
||||||
{
|
{
|
||||||
docs: {
|
docs: {
|
||||||
|
// routeBasePath: '/',
|
||||||
homePageId: 'introduction',
|
homePageId: 'introduction',
|
||||||
path: 'docs',
|
path: 'docs',
|
||||||
sidebarPath: require.resolve('./sidebars.js'),
|
sidebarPath: require.resolve('./sidebars.js'),
|
||||||
|
@ -127,6 +169,7 @@ module.exports = {
|
||||||
disableVersioning: !!process.env.DISABLE_VERSIONING,
|
disableVersioning: !!process.env.DISABLE_VERSIONING,
|
||||||
},
|
},
|
||||||
blog: {
|
blog: {
|
||||||
|
// routeBasePath: '/',
|
||||||
path: '../website-1.x/blog',
|
path: '../website-1.x/blog',
|
||||||
editUrl:
|
editUrl:
|
||||||
'https://github.com/facebook/docusaurus/edit/master/website-1.x/',
|
'https://github.com/facebook/docusaurus/edit/master/website-1.x/',
|
||||||
|
@ -188,10 +231,10 @@ module.exports = {
|
||||||
{to: 'blog', label: 'Blog', position: 'left'},
|
{to: 'blog', label: 'Blog', position: 'left'},
|
||||||
{to: 'showcase', label: 'Showcase', position: 'left'},
|
{to: 'showcase', label: 'Showcase', position: 'left'},
|
||||||
{
|
{
|
||||||
to: 'docs/next/support',
|
to: '/community/support',
|
||||||
label: 'Community',
|
label: 'Community',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
activeBaseRegex: `docs/next/(support|team|resources)`,
|
activeBaseRegex: `/community/`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
to: '/versions',
|
to: '/versions',
|
||||||
|
@ -243,7 +286,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Help',
|
label: 'Help',
|
||||||
to: 'docs/next/support',
|
to: '/community/support',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
title: Using twice the blog plugin
|
||||||
|
author: Sebastien Lorber
|
||||||
|
authorURL: https://sebastienlorber.com
|
||||||
|
authorImageURL: https://github.com/slorber.png
|
||||||
|
authorFBID: 611217057
|
||||||
|
authorTwitter: sebastienlorber
|
||||||
|
tags: [blog, docusaurus]
|
||||||
|
---
|
||||||
|
|
||||||
|
Did you know you can use multiple instances of the same plugin?
|
||||||
|
|
||||||
|
<!--truncate-->
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
Using twice the blog plugin permits you to create more than one blog on the same Docusaurus website!
|
||||||
|
|
||||||
|
:::
|
|
@ -51,19 +51,4 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
community: [
|
|
||||||
'community/support',
|
|
||||||
'community/team',
|
|
||||||
'community/resources',
|
|
||||||
{
|
|
||||||
type: 'link',
|
|
||||||
href: '/showcase',
|
|
||||||
label: 'Showcase',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'link',
|
|
||||||
href: '/feedback',
|
|
||||||
label: 'Feedback',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
24
website/sidebarsCommunity.js
Normal file
24
website/sidebarsCommunity.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
community: [
|
||||||
|
'support',
|
||||||
|
'team',
|
||||||
|
'resources',
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
href: '/showcase',
|
||||||
|
label: 'Showcase',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
href: '/feedback',
|
||||||
|
label: 'Feedback',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,68 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
---
|
|
||||||
|
|
||||||
## Meet the Docusaurus Team
|
|
||||||
|
|
||||||
### Alexey Pyltsyn
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
[@lex111 on GitHub](https://github.com/lex111)
|
|
||||||
|
|
||||||
### Fanny Vieira
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
[@fanny on GitHub](https://github.com/fanny) · [@fannyvieiira on Twitter](https://twitter.com/fannyvieiira)
|
|
||||||
|
|
||||||
### Joel Marcey
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
[@joelmarcey on GitHub](https://github.com/joelmarcey) · [@joelmarcey on Twitter](https://twitter.com/joelmarcey)
|
|
||||||
|
|
||||||
### Yangshun Tay
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
[@yangshun on GitHub](https://github.com/yangshun) · [@yangshunz on Twitter](https://twitter.com/yangshunz)
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
### Endilie Yacop Sucipto
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
[@endiliey on GitHub](https://github.com/endiliey) · [@endiliey on Twitter](https://twitter.com/endiliey)
|
|
||||||
|
|
||||||
### Wei Gao
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||

|
|
||||||
[@wgao19 on GitHub](https://github.com/wgao19) · [@wgao19 on Twitter](https://twitter.com/wgao19)
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- Elvis Wolcott
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- Fienny Angelina
|
|
||||||
- Frank Li
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- Ramón Lamana
|
|
||||||
- Ricky Vetter
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,174 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
---
|
|
||||||
|
|
||||||
## Active Team
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/lex111.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Alexey Pyltsyn</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Obsessed open-source enthusiast 👋 Eternal amateur at everything 🤷♂️ Maintainer of Russian docs on PHP, React, Kubernetes and much more 🧐
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/lex111">GitHub</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/fanny.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Fanny Vieira</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Fanny got started with web development in high school, building a project for the school kitchen. In her free time she loves contributing to Open Source, occasionally writing on <a href="https://dev.to/fannyvieira" target="_blank">her blog</a> about her experiences, cooking, and creating <a href="https://open.spotify.com/user/anotherfanny" target="_blank">Spotify playlists</a>.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/fanny">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/fannyvieiira">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/JoelMarcey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Joel Marcey</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Docusaurus founder and now ever grateful Docusaurus cheerleader to those who actually write code for it.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/JoelMarcey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/joelmarcey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/yangshun.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Yangshun Tay</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Full Front End Stack developer who likes working on the Jamstack. Working on Docusaurus made him Facebook's unofficial part-time Open Source webmaster, which is an awesome role to be in.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/yangshun">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/yangshunz">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/endiliey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Endilie Yacop Sucipto</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Maintainer @docusaurus · 🔥🔥🔥
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/endiliey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/endiliey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/wgao19.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Wei Gao</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
👩🏻🌾 Work in progress React developer, maintains Docusaurus, writes docs and spams this world with many websites.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/wgao19">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/wgao19">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- [Elvis Wolcott](https://github.com/elviswolcott)
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- [Fienny Angelina](https://github.com/fiennyangeln)
|
|
||||||
- [Frank Li](https://github.com/deltice)
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- [Ramón Lamana](https://github.com/rlamana)
|
|
||||||
- [Ricky Vetter](https://github.com/rickyvetter)
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -1,45 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Articles
|
|
||||||
|
|
||||||
- [Live code editing in Docusaurus](https://dev.to/mrmuhammadali/live-code-editing-in-docusaurus-28k)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,174 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
---
|
|
||||||
|
|
||||||
## Active Team
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/lex111.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Alexey Pyltsyn</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Obsessed open-source enthusiast 👋 Eternal amateur at everything 🤷♂️ Maintainer of Russian docs on PHP, React, Kubernetes and much more 🧐
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/lex111">GitHub</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/fanny.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Fanny Vieira</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Fanny got started with web development in high school, building a project for the school kitchen. In her free time she loves contributing to Open Source, occasionally writing on <a href="https://dev.to/fannyvieira" target="_blank">her blog</a> about her experiences, cooking, and creating <a href="https://open.spotify.com/user/anotherfanny" target="_blank">Spotify playlists</a>.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/fanny">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/fannyvieiira">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/JoelMarcey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Joel Marcey</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Docusaurus founder and now ever grateful Docusaurus cheerleader to those who actually write code for it.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/JoelMarcey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/joelmarcey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/yangshun.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Yangshun Tay</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Full Front End Stack developer who likes working on the Jamstack. Working on Docusaurus made him Facebook's unofficial part-time Open Source webmaster, which is an awesome role to be in.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/yangshun">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/yangshunz">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/endiliey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Endilie Yacop Sucipto</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Maintainer @docusaurus · 🔥🔥🔥
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/endiliey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/endiliey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/wgao19.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Wei Gao</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
👩🏻🌾 Work in progress React developer, maintains Docusaurus, writes docs and spams this world with many websites.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/wgao19">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/wgao19">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- [Elvis Wolcott](https://github.com/elviswolcott)
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- [Fienny Angelina](https://github.com/fiennyangeln)
|
|
||||||
- [Frank Li](https://github.com/deltice)
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- [Ramón Lamana](https://github.com/rlamana)
|
|
||||||
- [Ricky Vetter](https://github.com/rickyvetter)
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -1,45 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Articles
|
|
||||||
|
|
||||||
- [Live code editing in Docusaurus](https://dev.to/mrmuhammadali/live-code-editing-in-docusaurus-28k)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,174 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
---
|
|
||||||
|
|
||||||
## Active Team
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/lex111.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Alexey Pyltsyn</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Obsessed open-source enthusiast 👋 Eternal amateur at everything 🤷♂️ Maintainer of Russian docs on PHP, React, Kubernetes and much more 🧐
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/lex111">GitHub</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/fanny.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Fanny Vieira</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Fanny got started with web development in high school, building a project for the school kitchen. In her free time she loves contributing to Open Source, occasionally writing on <a href="https://dev.to/fannyvieira" target="_blank">her blog</a> about her experiences, cooking, and creating <a href="https://open.spotify.com/user/anotherfanny" target="_blank">Spotify playlists</a>.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/fanny">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/fannyvieiira">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/JoelMarcey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Joel Marcey</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Docusaurus founder and now ever grateful Docusaurus cheerleader to those who actually write code for it.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/JoelMarcey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/joelmarcey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/yangshun.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Yangshun Tay</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Full Front End Stack developer who likes working on the Jamstack. Working on Docusaurus made him Facebook's unofficial part-time Open Source webmaster, which is an awesome role to be in.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/yangshun">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/yangshunz">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/endiliey.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Endilie Yacop Sucipto</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
Maintainer @docusaurus · 🔥🔥🔥
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/endiliey">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/endiliey">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col col--6 margin-bottom--lg">
|
|
||||||
<div className="card card--full-height">
|
|
||||||
<div className="card__header">
|
|
||||||
<div className="avatar avatar--vertical">
|
|
||||||
<img
|
|
||||||
className="avatar__photo avatar__photo--xl"
|
|
||||||
src="https://github.com/wgao19.png"
|
|
||||||
/>
|
|
||||||
<div className="avatar__intro">
|
|
||||||
<h3 className="avatar__name">Wei Gao</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="card__body">
|
|
||||||
👩🏻🌾 Work in progress React developer, maintains Docusaurus, writes docs and spams this world with many websites.
|
|
||||||
</div>
|
|
||||||
<div className="card__footer">
|
|
||||||
<div className="button-group button-group--block">
|
|
||||||
<a className="button button--secondary" href="https://github.com/wgao19">GitHub</a>
|
|
||||||
<a className="button button--secondary" href="https://twitter.com/wgao19">Twitter</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- [Elvis Wolcott](https://github.com/elviswolcott)
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- [Fienny Angelina](https://github.com/fiennyangeln)
|
|
||||||
- [Frank Li](https://github.com/deltice)
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- [Ramón Lamana](https://github.com/rlamana)
|
|
||||||
- [Ricky Vetter](https://github.com/rickyvetter)
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
slug: /support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
id: resources
|
|
||||||
title: Awesome Resources
|
|
||||||
slug: /resources
|
|
||||||
---
|
|
||||||
|
|
||||||
A curated list of interesting Docusaurus community projects.
|
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
|
|
||||||
|
|
||||||
## Articles
|
|
||||||
|
|
||||||
- [Live code editing in Docusaurus](https://dev.to/mrmuhammadali/live-code-editing-in-docusaurus-28k)
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
See the <a href={require('@docusaurus/useBaseUrl').default('showcase')}>showcase</a>.
|
|
||||||
|
|
||||||
## Official plugins
|
|
||||||
|
|
||||||
- [@docusaurus/plugin-content-blog](using-plugins.md#docusaurusplugin-content-blog)
|
|
||||||
- [@docusaurus/plugin-content-docs](using-plugins.md#docusaurusplugin-content-docs)
|
|
||||||
- [@docusaurus/plugin-content-pages](using-plugins.md#docusaurusplugin-content-pages)
|
|
||||||
- [@docusaurus/plugin-google-analytics](using-plugins.md#docusaurusplugin-google-analytics)
|
|
||||||
- [@docusaurus/plugin-google-gtag](using-plugins.md#docusaurusplugin-google-gtag)
|
|
||||||
- [@docusaurus/plugin-sitemap](using-plugins.md#docusaurusplugin-sitemap)
|
|
||||||
- [@docusaurus/plugin-ideal-image](using-plugins.md#docusaurusplugin-ideal-image)
|
|
||||||
|
|
||||||
## Community plugins
|
|
||||||
|
|
||||||
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
|
|
||||||
- [docusaurus-lunr-search](https://github.com/lelouch77/docusurus-lunr-search) - Offline Search for Docusaurus v2
|
|
||||||
- [docusaurus-search-local](https://github.com/cmfcmf/docusaurus-search-local) - Offline/local search for Docusaurus v2
|
|
||||||
- [docusaurus-pdf](https://github.com/KohheePeace/docusaurus-pdf) - Generate documentation into PDF format
|
|
||||||
- [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) - Sass/SCSS stylesheets support
|
|
||||||
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
|
|
||||||
- [posthog-docusaurus](https://github.com/PostHog/posthog-docusaurus) - Integrate [PostHog](https://posthog.com/) product analytics with Docusaurus v2
|
|
||||||
|
|
||||||
## Enterprise usage
|
|
||||||
|
|
||||||
- Facebook
|
|
||||||
- Google
|
|
||||||
- Stripe
|
|
||||||
- Algolia
|
|
||||||
- Callstack
|
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
id: support
|
|
||||||
title: Support
|
|
||||||
slug: /support
|
|
||||||
---
|
|
||||||
|
|
||||||
Docusaurus has a community of thousands of developers.
|
|
||||||
|
|
||||||
On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
|
|
||||||
|
|
||||||
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
|
|
||||||
|
|
||||||
## Stack Overflow
|
|
||||||
|
|
||||||
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
|
|
||||||
|
|
||||||
## Discussion forums
|
|
||||||
|
|
||||||
There are many online forums which are a great place for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
|
|
||||||
|
|
||||||
- [Docusaurus online chat](https://discord.gg/docusaurus)
|
|
||||||
- [#docusaurus-2-dogfooding](https://discord.gg/7wjJ9yH) for user help
|
|
||||||
- [#docusaurus-2-dev](https://discord.gg/6g6ASPA) for contributing help
|
|
||||||
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
|
|
||||||
|
|
||||||
## Feature requests
|
|
||||||
|
|
||||||
For new feature requests, you can create a post on our [Canny board](/feedback), which is a handy tool for roadmapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
|
|
||||||
|
|
||||||
## News
|
|
||||||
|
|
||||||
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
|
|
|
@ -1,80 +0,0 @@
|
||||||
---
|
|
||||||
id: team
|
|
||||||
title: Team
|
|
||||||
slug: /team
|
|
||||||
---
|
|
||||||
|
|
||||||
import TeamProfileCard from "@site/src/components/TeamProfileCard"
|
|
||||||
|
|
||||||
export function TeamProfileCardCol(props) { return <TeamProfileCard {...props} className={'col col--6 margin-bottom--lg'}/> }
|
|
||||||
|
|
||||||
## Active Team
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Alexey Pyltsyn"
|
|
||||||
githubUrl="https://github.com/lex111"
|
|
||||||
>
|
|
||||||
Obsessed open-source enthusiast 👋 Eternal amateur at everything 🤷♂️ Maintainer of Russian docs on PHP, React, Kubernetes and much more 🧐
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Fanny Vieira"
|
|
||||||
githubUrl="https://github.com/fanny"
|
|
||||||
twitterUrl="https://twitter.com/fannyvieiira"
|
|
||||||
>
|
|
||||||
Fanny got started with web development in high school, building a project for the school kitchen. In her free time she loves contributing to Open Source, occasionally writing on <a href="https://dev.to/fannyvieira" target="_blank">her blog</a> about her experiences, cooking, and creating <a href="https://open.spotify.com/user/anotherfanny" target="_blank">Spotify playlists</a>.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Joel Marcey"
|
|
||||||
githubUrl="https://github.com/JoelMarcey"
|
|
||||||
twitterUrl="https://twitter.com/joelmarcey"
|
|
||||||
>
|
|
||||||
Docusaurus founder and now ever grateful Docusaurus cheerleader to those who actually write code for it.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Sébastien Lorber"
|
|
||||||
githubUrl="https://github.com/slorber"
|
|
||||||
twitterUrl="https://twitter.com/sebastienlorber"
|
|
||||||
>
|
|
||||||
React lover since 2014. Freelance, helping Facebook ship Docusaurus v2.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Yangshun Tay"
|
|
||||||
githubUrl="https://github.com/yangshun"
|
|
||||||
twitterUrl="https://twitter.com/yangshunz"
|
|
||||||
>
|
|
||||||
Full Front End Stack developer who likes working on the Jamstack. Working on Docusaurus made him Facebook's unofficial part-time Open Source webmaster, which is an awesome role to be in.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Honorary Alumni
|
|
||||||
|
|
||||||
<div className="row">
|
|
||||||
<TeamProfileCardCol name="Endilie Yacop Sucipto" githubUrl="https://github.com/endiliey" twitterUrl="https://twitter.com/endiliey">
|
|
||||||
Maintainer @docusaurus · 🔥🔥🔥
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
<TeamProfileCardCol
|
|
||||||
name="Wei Gao"
|
|
||||||
githubUrl="https://github.com/wgao19"
|
|
||||||
twitterUrl="https://twitter.com/wgao19"
|
|
||||||
>
|
|
||||||
🏻🌾 Work in progress React developer, maintains Docusaurus, writes docs and spams this world with many websites.
|
|
||||||
</TeamProfileCardCol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
|
|
||||||
|
|
||||||
- [Amy Lam](https://github.com/amyrlam)
|
|
||||||
- [Cheng Lou](https://github.com/chenglou)
|
|
||||||
- [Christine Abernathy](https://github.com/caabernathy)
|
|
||||||
- [Christopher Chedeau](https://github.com/vjeux)
|
|
||||||
- [Elvis Wolcott](https://github.com/elviswolcott)
|
|
||||||
- [Eric Nakagawa](https://github.com/ericnakagawa)
|
|
||||||
- [Fienny Angelina](https://github.com/fiennyangeln)
|
|
||||||
- [Frank Li](https://github.com/deltice)
|
|
||||||
- [Héctor Ramos](https://github.com/hramos)
|
|
||||||
- [Ramón Lamana](https://github.com/rlamana)
|
|
||||||
- [Ricky Vetter](https://github.com/rickyvetter)
|
|
||||||
- [Sam Zhou](https://github.com/SamChou19815)
|
|
|
@ -128,29 +128,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.54/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.54/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.54/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.54/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,29 +128,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.55/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.55/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.55/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.55/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,29 +128,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.56/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.56/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.56/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.56/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,29 +134,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.58/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.58/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.58/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.58/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,29 +138,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.60/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.60/community/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.60/community/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.60/community/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,29 +138,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"version-2.0.0-alpha.61/community": [
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.61/community/support"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.61/community/team"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doc",
|
|
||||||
"id": "version-2.0.0-alpha.61/community/resources"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/showcase",
|
|
||||||
"label": "Showcase"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"href": "/feedback",
|
|
||||||
"label": "Feedback"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue