diff --git a/packages/docusaurus-utils-validation/src/validationUtils.ts b/packages/docusaurus-utils-validation/src/validationUtils.ts index 7b20ce7244..3c15dbb125 100644 --- a/packages/docusaurus-utils-validation/src/validationUtils.ts +++ b/packages/docusaurus-utils-validation/src/validationUtils.ts @@ -35,7 +35,7 @@ export const logValidationBugReportHint = (): void => { ); }; -function printWarning(warning?: Joi.ValidationError) { +export function printWarning(warning?: Joi.ValidationError) { if (warning) { const warningMessages = warning.details .map(({message}) => message) diff --git a/packages/docusaurus/src/server/__tests__/configValidation.test.ts b/packages/docusaurus/src/server/__tests__/configValidation.test.ts index bc4a633e65..acd4e24650 100644 --- a/packages/docusaurus/src/server/__tests__/configValidation.test.ts +++ b/packages/docusaurus/src/server/__tests__/configValidation.test.ts @@ -5,7 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import {DEFAULT_CONFIG, validateConfig} from '../configValidation'; +import { + ConfigSchema, + DEFAULT_CONFIG, + validateConfig, +} from '../configValidation'; import {DocusaurusConfig} from '@docusaurus/types'; const baseConfig = { @@ -197,3 +201,26 @@ describe('normalizeConfig', () => { ).toThrowErrorMatchingSnapshot(); }); }); + +describe('config warnings', () => { + function getWarning(config: unknown) { + return ConfigSchema.validate(config).warning; + } + + test('baseConfig has no warning', () => { + const warning = getWarning(baseConfig); + expect(warning).toBeUndefined(); + }); + + test('site url has warning when using subpath', () => { + const warning = getWarning({ + ...baseConfig, + url: 'https://mysite.com/someSubpath', + }); + expect(warning).toBeDefined(); + expect(warning?.details.length).toEqual(1); + expect(warning?.details[0].message).toMatchInlineSnapshot( + `"Docusaurus config validation warning. Field \\"url\\": the url is not supposed to contain a sub-path like '/someSubpath', please use the baseUrl field for sub-paths"`, + ); + }); +}); diff --git a/packages/docusaurus/src/server/configValidation.ts b/packages/docusaurus/src/server/configValidation.ts index 66f1e842cf..673c130f87 100644 --- a/packages/docusaurus/src/server/configValidation.ts +++ b/packages/docusaurus/src/server/configValidation.ts @@ -12,6 +12,7 @@ import { logValidationBugReportHint, isValidationDisabledEscapeHatch, URISchema, + printWarning, } from '@docusaurus/utils-validation'; const DEFAULT_I18N_LOCALE = 'en'; @@ -107,8 +108,20 @@ const I18N_CONFIG_SCHEMA = Joi.object({ .optional() .default(DEFAULT_I18N_CONFIG); +const SiteUrlSchema = URISchema.required().custom(function (value, helpers) { + try { + const {pathname} = new URL(value); + if (pathname !== '/') { + helpers.warn('docusaurus.configValidationWarning', { + warningMessage: `the url is not supposed to contain a sub-path like '${pathname}', please use the baseUrl field for sub-paths`, + }); + } + } catch (e) {} + return value; +}, 'siteUrlCustomValidation'); + // TODO move to @docusaurus/utils-validation -const ConfigSchema = Joi.object({ +export const ConfigSchema = Joi.object({ baseUrl: Joi.string() .required() .regex(new RegExp('/$', 'm')) @@ -116,7 +129,7 @@ const ConfigSchema = Joi.object({ baseUrlIssueBanner: Joi.boolean().default(DEFAULT_CONFIG.baseUrlIssueBanner), favicon: Joi.string().required(), title: Joi.string().required(), - url: URISchema.required(), + url: SiteUrlSchema, trailingSlash: Joi.boolean(), // No default value! undefined = retrocompatible legacy behavior! i18n: I18N_CONFIG_SCHEMA, onBrokenLinks: Joi.string() @@ -163,15 +176,21 @@ const ConfigSchema = Joi.object({ .try(Joi.string().equal('babel'), Joi.function()) .optional(), }).optional(), +}).messages({ + 'docusaurus.configValidationWarning': + 'Docusaurus config validation warning. Field {#label}: {#warningMessage}', }); // TODO move to @docusaurus/utils-validation export function validateConfig( config: Partial, ): DocusaurusConfig { - const {error, value} = ConfigSchema.validate(config, { + const {error, warning, value} = ConfigSchema.validate(config, { abortEarly: false, }); + + printWarning(warning); + if (error) { logValidationBugReportHint(); if (isValidationDisabledEscapeHatch) {