mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-21 20:17:50 +02:00
feat(core): allow plugins to self-disable by returning null (#10286)
This commit is contained in:
parent
8c2943421b
commit
80203b385d
13 changed files with 181 additions and 86 deletions
|
@ -21,7 +21,7 @@ const PluginName = 'docusaurus-plugin-client-redirects';
|
||||||
export default function pluginClientRedirectsPages(
|
export default function pluginClientRedirectsPages(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin<void> {
|
): Plugin<void> | null {
|
||||||
const {trailingSlash} = context.siteConfig;
|
const {trailingSlash} = context.siteConfig;
|
||||||
const router = context.siteConfig.future.experimental_router;
|
const router = context.siteConfig.future.experimental_router;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export default function pluginClientRedirectsPages(
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`${PluginName} does not support the Hash Router and will be disabled.`,
|
`${PluginName} does not support the Hash Router and will be disabled.`,
|
||||||
);
|
);
|
||||||
return {name: PluginName};
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -18,21 +18,21 @@ import type {PluginOptions, Options} from './options';
|
||||||
export default function pluginGoogleAnalytics(
|
export default function pluginGoogleAnalytics(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin {
|
): Plugin | null {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const {trackingID, anonymizeIP} = options;
|
const {trackingID, anonymizeIP} = options;
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-google-analytics',
|
name: 'docusaurus-plugin-google-analytics',
|
||||||
|
|
||||||
getClientModules() {
|
getClientModules() {
|
||||||
return isProd ? ['./analytics'] : [];
|
return ['./analytics'];
|
||||||
},
|
},
|
||||||
|
|
||||||
injectHtmlTags() {
|
injectHtmlTags() {
|
||||||
if (!isProd) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
headTags: [
|
headTags: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,8 +32,10 @@ function createConfigSnippets({
|
||||||
export default function pluginGoogleGtag(
|
export default function pluginGoogleGtag(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin {
|
): Plugin | null {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const firstTrackingId = options.trackingID[0];
|
const firstTrackingId = options.trackingID[0];
|
||||||
|
|
||||||
|
@ -45,13 +47,10 @@ export default function pluginGoogleGtag(
|
||||||
},
|
},
|
||||||
|
|
||||||
getClientModules() {
|
getClientModules() {
|
||||||
return isProd ? ['./gtag'] : [];
|
return ['./gtag'];
|
||||||
},
|
},
|
||||||
|
|
||||||
injectHtmlTags() {
|
injectHtmlTags() {
|
||||||
if (!isProd) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
// Gtag includes GA by default, so we also preconnect to
|
// Gtag includes GA by default, so we also preconnect to
|
||||||
// google-analytics.
|
// google-analytics.
|
||||||
|
|
|
@ -16,10 +16,12 @@ import type {PluginOptions, Options} from './options';
|
||||||
export default function pluginGoogleAnalytics(
|
export default function pluginGoogleAnalytics(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin {
|
): Plugin | null {
|
||||||
const {containerId} = options;
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {containerId} = options;
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-google-tag-manager',
|
name: 'docusaurus-plugin-google-tag-manager',
|
||||||
|
|
||||||
|
@ -28,9 +30,6 @@ export default function pluginGoogleAnalytics(
|
||||||
},
|
},
|
||||||
|
|
||||||
injectHtmlTags() {
|
injectHtmlTags() {
|
||||||
if (!isProd) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
preBodyTags: [
|
preBodyTags: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,8 +19,6 @@ import type {PluginOptions} from '@docusaurus/plugin-pwa';
|
||||||
|
|
||||||
const PluginName = 'docusaurus-plugin-pwa';
|
const PluginName = 'docusaurus-plugin-pwa';
|
||||||
|
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
|
||||||
|
|
||||||
function getSWBabelLoader() {
|
function getSWBabelLoader() {
|
||||||
return {
|
return {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
|
@ -45,12 +43,21 @@ function getSWBabelLoader() {
|
||||||
export default function pluginPWA(
|
export default function pluginPWA(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin<void> {
|
): Plugin<void> | null {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (context.siteConfig.future.experimental_router === 'hash') {
|
||||||
|
logger.warn(
|
||||||
|
`${PluginName} does not support the Hash Router and will be disabled.`,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
outDir,
|
outDir,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
i18n: {currentLocale},
|
i18n: {currentLocale},
|
||||||
siteConfig,
|
|
||||||
} = context;
|
} = context;
|
||||||
const {
|
const {
|
||||||
debug,
|
debug,
|
||||||
|
@ -61,13 +68,6 @@ export default function pluginPWA(
|
||||||
swRegister,
|
swRegister,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
if (siteConfig.future.experimental_router === 'hash') {
|
|
||||||
logger.warn(
|
|
||||||
`${PluginName} does not support the Hash Router and will be disabled.`,
|
|
||||||
);
|
|
||||||
return {name: PluginName};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: PluginName,
|
name: PluginName,
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export default function pluginPWA(
|
||||||
},
|
},
|
||||||
|
|
||||||
getClientModules() {
|
getClientModules() {
|
||||||
return isProd && swRegister ? [swRegister] : [];
|
return swRegister ? [swRegister] : [];
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultCodeTranslationMessages() {
|
getDefaultCodeTranslationMessages() {
|
||||||
|
@ -90,10 +90,6 @@ export default function pluginPWA(
|
||||||
},
|
},
|
||||||
|
|
||||||
configureWebpack(config) {
|
configureWebpack(config) {
|
||||||
if (!isProd) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.EnvironmentPlugin({
|
new webpack.EnvironmentPlugin({
|
||||||
|
@ -111,37 +107,31 @@ export default function pluginPWA(
|
||||||
|
|
||||||
injectHtmlTags() {
|
injectHtmlTags() {
|
||||||
const headTags: HtmlTags = [];
|
const headTags: HtmlTags = [];
|
||||||
if (isProd) {
|
pwaHead.forEach(({tagName, ...attributes}) => {
|
||||||
pwaHead.forEach(({tagName, ...attributes}) => {
|
(['href', 'content'] as const).forEach((attribute) => {
|
||||||
(['href', 'content'] as const).forEach((attribute) => {
|
const attributeValue = attributes[attribute];
|
||||||
const attributeValue = attributes[attribute];
|
|
||||||
|
|
||||||
if (!attributeValue) {
|
if (!attributeValue) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributePath =
|
const attributePath =
|
||||||
!!path.extname(attributeValue) && attributeValue;
|
!!path.extname(attributeValue) && attributeValue;
|
||||||
|
|
||||||
if (attributePath && !attributePath.startsWith(baseUrl)) {
|
if (attributePath && !attributePath.startsWith(baseUrl)) {
|
||||||
attributes[attribute] = normalizeUrl([baseUrl, attributeValue]);
|
attributes[attribute] = normalizeUrl([baseUrl, attributeValue]);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return headTags.push({
|
|
||||||
tagName,
|
|
||||||
attributes,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
return headTags.push({
|
||||||
|
tagName,
|
||||||
|
attributes,
|
||||||
|
});
|
||||||
|
});
|
||||||
return {headTags};
|
return {headTags};
|
||||||
},
|
},
|
||||||
|
|
||||||
async postBuild(props) {
|
async postBuild(props) {
|
||||||
if (!isProd) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const swSourceFileTest = /\.m?js$/;
|
const swSourceFileTest = /\.m?js$/;
|
||||||
|
|
||||||
const swWebpackConfig: Configuration = {
|
const swWebpackConfig: Configuration = {
|
||||||
|
|
|
@ -17,12 +17,12 @@ const PluginName = 'docusaurus-plugin-sitemap';
|
||||||
export default function pluginSitemap(
|
export default function pluginSitemap(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin<void> {
|
): Plugin<void> | null {
|
||||||
if (context.siteConfig.future.experimental_router === 'hash') {
|
if (context.siteConfig.future.experimental_router === 'hash') {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`${PluginName} does not support the Hash Router and will be disabled.`,
|
`${PluginName} does not support the Hash Router and will be disabled.`,
|
||||||
);
|
);
|
||||||
return {name: PluginName};
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -11,14 +11,15 @@ import type {PluginOptions, Options} from './options';
|
||||||
export default function pluginVercelAnalytics(
|
export default function pluginVercelAnalytics(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
options: PluginOptions,
|
options: PluginOptions,
|
||||||
): Plugin {
|
): Plugin | null {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin-vercel-analytics',
|
name: 'docusaurus-plugin-vercel-analytics',
|
||||||
|
|
||||||
getClientModules() {
|
getClientModules() {
|
||||||
return isProd ? ['./analytics'] : [];
|
return ['./analytics'];
|
||||||
},
|
},
|
||||||
|
|
||||||
contentLoaded({actions}) {
|
contentLoaded({actions}) {
|
||||||
|
|
5
packages/docusaurus-types/src/plugin.d.ts
vendored
5
packages/docusaurus-types/src/plugin.d.ts
vendored
|
@ -191,7 +191,10 @@ export type LoadedPlugin = InitializedPlugin & {
|
||||||
export type PluginModule<Content = unknown> = {
|
export type PluginModule<Content = unknown> = {
|
||||||
(context: LoadContext, options: unknown):
|
(context: LoadContext, options: unknown):
|
||||||
| Plugin<Content>
|
| Plugin<Content>
|
||||||
| Promise<Plugin<Content>>;
|
| Promise<Plugin<Content>>
|
||||||
|
| null
|
||||||
|
| Promise<null>;
|
||||||
|
|
||||||
validateOptions?: <T, U>(data: OptionValidationContext<T, U>) => U;
|
validateOptions?: <T, U>(data: OptionValidationContext<T, U>) => U;
|
||||||
validateThemeConfig?: <T>(data: ThemeConfigValidationContext<T>) => T;
|
validateThemeConfig?: <T>(data: ThemeConfigValidationContext<T>) => T;
|
||||||
|
|
||||||
|
|
|
@ -6,22 +6,41 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {loadContext} from '../../server/site';
|
import {loadContext} from '../../server/site';
|
||||||
import {initPlugins} from '../../server/plugins/init';
|
import {initPluginsConfigs} from '../../server/plugins/init';
|
||||||
import {loadPluginConfigs} from '../../server/plugins/configs';
|
import {loadPluginConfigs} from '../../server/plugins/configs';
|
||||||
import type {SwizzleCLIOptions, SwizzleContext} from './common';
|
import type {SwizzleCLIOptions, SwizzleContext, SwizzlePlugin} from './common';
|
||||||
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
|
|
||||||
|
async function getSwizzlePlugins(
|
||||||
|
context: LoadContext,
|
||||||
|
): Promise<SwizzlePlugin[]> {
|
||||||
|
const pluginConfigs = await loadPluginConfigs(context);
|
||||||
|
const pluginConfigInitResults = await initPluginsConfigs(
|
||||||
|
context,
|
||||||
|
pluginConfigs,
|
||||||
|
);
|
||||||
|
|
||||||
|
return pluginConfigInitResults.flatMap((initResult) => {
|
||||||
|
// Ignore self-disabling plugins returning null
|
||||||
|
if (initResult.plugin === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
// TODO this is a bit confusing, need refactor
|
||||||
|
{
|
||||||
|
plugin: initResult.config,
|
||||||
|
instance: initResult.plugin,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function initSwizzleContext(
|
export async function initSwizzleContext(
|
||||||
siteDir: string,
|
siteDir: string,
|
||||||
options: SwizzleCLIOptions,
|
options: SwizzleCLIOptions,
|
||||||
): Promise<SwizzleContext> {
|
): Promise<SwizzleContext> {
|
||||||
const context = await loadContext({siteDir, config: options.config});
|
const context = await loadContext({siteDir, config: options.config});
|
||||||
const plugins = await initPlugins(context);
|
|
||||||
const pluginConfigs = await loadPluginConfigs(context);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
plugins: plugins.map((plugin, pluginIndex) => ({
|
plugins: await getSwizzlePlugins(context),
|
||||||
plugin: pluginConfigs[pluginIndex]!,
|
|
||||||
instance: plugin,
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{it: 'should work'},
|
{it: 'should work'},
|
||||||
],
|
],
|
||||||
|
function (context, options) {
|
||||||
|
// it's ok for a plugin to self-disable
|
||||||
|
return null;
|
||||||
|
},
|
||||||
'./plugin3.js',
|
'./plugin3.js',
|
||||||
['./plugin4.js', {}],
|
['./plugin4.js', {}],
|
||||||
'./pluginEsm',
|
'./pluginEsm',
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* 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 = {
|
||||||
|
title: 'My Site',
|
||||||
|
tagline: 'The tagline of my site',
|
||||||
|
url: 'https://your-docusaurus-site.example.com',
|
||||||
|
baseUrl: '/',
|
||||||
|
favicon: 'img/favicon.ico',
|
||||||
|
plugins: [
|
||||||
|
function (context, options) {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -24,7 +24,7 @@ async function loadSite(
|
||||||
describe('initPlugins', () => {
|
describe('initPlugins', () => {
|
||||||
it('parses plugins correctly and loads them in correct order', async () => {
|
it('parses plugins correctly and loads them in correct order', async () => {
|
||||||
const {context, plugins} = await loadSite('site-with-plugin');
|
const {context, plugins} = await loadSite('site-with-plugin');
|
||||||
expect(context.siteConfig.plugins).toHaveLength(6);
|
expect(context.siteConfig.plugins).toHaveLength(7);
|
||||||
expect(plugins).toHaveLength(10);
|
expect(plugins).toHaveLength(10);
|
||||||
|
|
||||||
expect(plugins[0]!.name).toBe('preset-plugin1');
|
expect(plugins[0]!.name).toBe('preset-plugin1');
|
||||||
|
@ -85,4 +85,13 @@ describe('initPlugins', () => {
|
||||||
Note that even inline/anonymous plugin functions require a 'name' property."
|
Note that even inline/anonymous plugin functions require a 'name' property."
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws user-friendly error message for plugins returning undefined', async () => {
|
||||||
|
await expect(() => loadSite('site-with-undefined-plugin')).rejects
|
||||||
|
.toThrowErrorMatchingInlineSnapshot(`
|
||||||
|
"A Docusaurus plugin returned 'undefined', which is forbidden.
|
||||||
|
A plugin is expected to return an object having at least a 'name' property.
|
||||||
|
If you want a plugin to self-disable depending on context/options, you can explicitly return 'null' instead of 'undefined'"
|
||||||
|
`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,17 +49,32 @@ function getThemeValidationFunction(
|
||||||
return normalizedPluginConfig.plugin.validateThemeConfig;
|
return normalizedPluginConfig.plugin.validateThemeConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PluginConfigInitResult = {
|
||||||
|
config: NormalizedPluginConfig;
|
||||||
|
// Plugins might self-disable during initialization by returning null
|
||||||
|
plugin: InitializedPlugin | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This filters self-disabling plugins and returns only the initialized ones
|
||||||
|
function onlyInitializedPlugins(
|
||||||
|
initPluginsConfigsResults: PluginConfigInitResult[],
|
||||||
|
): InitializedPlugin[] {
|
||||||
|
return initPluginsConfigsResults
|
||||||
|
.map((results) => results.plugin)
|
||||||
|
.filter((p) => p !== null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the plugin constructors and returns their return values. It would load
|
* Runs the plugin constructors and returns their return values. It would load
|
||||||
* plugin configs from `plugins`, `themes`, and `presets`.
|
* plugin configs from `plugins`, `themes`, and `presets`.
|
||||||
*/
|
*/
|
||||||
export async function initPlugins(
|
export async function initPluginsConfigs(
|
||||||
context: LoadContext,
|
context: LoadContext,
|
||||||
): Promise<InitializedPlugin[]> {
|
pluginConfigs: NormalizedPluginConfig[],
|
||||||
|
): Promise<PluginConfigInitResult[]> {
|
||||||
// We need to resolve plugins from the perspective of the site config, as if
|
// We need to resolve plugins from the perspective of the site config, as if
|
||||||
// we are using `require.resolve` on those module names.
|
// we are using `require.resolve` on those module names.
|
||||||
const pluginRequire = createRequire(context.siteConfigPath);
|
const pluginRequire = createRequire(context.siteConfigPath);
|
||||||
const pluginConfigs = await loadPluginConfigs(context);
|
|
||||||
|
|
||||||
async function doLoadPluginVersion(
|
async function doLoadPluginVersion(
|
||||||
normalizedPluginConfig: NormalizedPluginConfig,
|
normalizedPluginConfig: NormalizedPluginConfig,
|
||||||
|
@ -108,13 +123,15 @@ export async function initPlugins(
|
||||||
|
|
||||||
async function initializePlugin(
|
async function initializePlugin(
|
||||||
normalizedPluginConfig: NormalizedPluginConfig,
|
normalizedPluginConfig: NormalizedPluginConfig,
|
||||||
): Promise<InitializedPlugin> {
|
): Promise<PluginConfigInitResult> {
|
||||||
const pluginVersion: PluginVersionInformation = await doLoadPluginVersion(
|
const pluginVersion: PluginVersionInformation = await doLoadPluginVersion(
|
||||||
normalizedPluginConfig,
|
normalizedPluginConfig,
|
||||||
);
|
);
|
||||||
const pluginOptions = doValidatePluginOptions(normalizedPluginConfig);
|
const pluginOptions = doValidatePluginOptions(normalizedPluginConfig);
|
||||||
|
|
||||||
// Side-effect: merge the normalized theme config in the original one
|
// Side-effect: merge the normalized theme config in the original one
|
||||||
|
// Note: it's important to do this before calling the plugin constructor
|
||||||
|
// Example: the theme classic plugin will read siteConfig.themeConfig
|
||||||
context.siteConfig.themeConfig = {
|
context.siteConfig.themeConfig = {
|
||||||
...context.siteConfig.themeConfig,
|
...context.siteConfig.themeConfig,
|
||||||
...doValidateThemeConfig(normalizedPluginConfig),
|
...doValidateThemeConfig(normalizedPluginConfig),
|
||||||
|
@ -125,26 +142,61 @@ export async function initPlugins(
|
||||||
pluginOptions,
|
pluginOptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!pluginInstance.name) {
|
// Returning null has been explicitly allowed
|
||||||
|
// It's a way for plugins to self-disable depending on context
|
||||||
|
// See https://github.com/facebook/docusaurus/pull/10286
|
||||||
|
if (pluginInstance === null) {
|
||||||
|
return {config: normalizedPluginConfig, plugin: null};
|
||||||
|
}
|
||||||
|
if (pluginInstance === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`A Docusaurus plugin returned 'undefined', which is forbidden.
|
||||||
|
A plugin is expected to return an object having at least a 'name' property.
|
||||||
|
If you want a plugin to self-disable depending on context/options, you can explicitly return 'null' instead of 'undefined'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pluginInstance?.name) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`A Docusaurus plugin is missing a 'name' property.
|
`A Docusaurus plugin is missing a 'name' property.
|
||||||
Note that even inline/anonymous plugin functions require a 'name' property.`,
|
Note that even inline/anonymous plugin functions require a 'name' property.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const plugin: InitializedPlugin = {
|
||||||
...pluginInstance,
|
...pluginInstance,
|
||||||
options: pluginOptions,
|
options: pluginOptions,
|
||||||
version: pluginVersion,
|
version: pluginVersion,
|
||||||
path: path.dirname(normalizedPluginConfig.entryPath),
|
path: path.dirname(normalizedPluginConfig.entryPath),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
config: normalizedPluginConfig,
|
||||||
|
plugin,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins: InitializedPlugin[] = await Promise.all(
|
const plugins: PluginConfigInitResult[] = (
|
||||||
pluginConfigs.map(initializePlugin),
|
await Promise.all(pluginConfigs.map(initializePlugin))
|
||||||
);
|
).filter((p) => p !== null);
|
||||||
|
|
||||||
ensureUniquePluginInstanceIds(plugins);
|
ensureUniquePluginInstanceIds(onlyInitializedPlugins(plugins));
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the plugin constructors and returns their return values
|
||||||
|
* for all the site context plugins that do not return null to self-disable.
|
||||||
|
*/
|
||||||
|
export async function initPlugins(
|
||||||
|
context: LoadContext,
|
||||||
|
): Promise<InitializedPlugin[]> {
|
||||||
|
const pluginConfigs = await loadPluginConfigs(context);
|
||||||
|
const initPluginsConfigsResults = await initPluginsConfigs(
|
||||||
|
context,
|
||||||
|
pluginConfigs,
|
||||||
|
);
|
||||||
|
|
||||||
|
return onlyInitializedPlugins(initPluginsConfigsResults);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue