mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-28 09:47:48 +02:00
fix(v2): sitemap plugin should handle siteConfig.trailingSlash automatically (#4950)
* create new @docusaurus/utils-common and move applyTrailingSlash there * sitemap plugin should handle siteConfig.trailingSlash automatically * typo
This commit is contained in:
parent
4e5f0febb9
commit
aeb8e9da51
18 changed files with 127 additions and 35 deletions
2
.husky/.gitignore
vendored
2
.husky/.gitignore
vendored
|
@ -1 +1 @@
|
|||
_
|
||||
_
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"@docusaurus/core": "2.0.0-beta.0",
|
||||
"@docusaurus/types": "2.0.0-beta.0",
|
||||
"@docusaurus/utils": "2.0.0-beta.0",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.0",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"sitemap": "^7.0.0",
|
||||
|
|
|
@ -30,8 +30,13 @@ describe('normalizeSitemapPluginOptions', () => {
|
|||
priority: 0.9,
|
||||
trailingSlash: false,
|
||||
};
|
||||
const {value} = await PluginOptionSchema.validate(userOptions);
|
||||
const {value, warning} = await PluginOptionSchema.validate(userOptions);
|
||||
expect(value).toEqual(userOptions);
|
||||
|
||||
expect(warning?.details?.length).toEqual(1);
|
||||
expect(warning?.details[0].message).toMatchInlineSnapshot(
|
||||
`"Option \\"trailingSlash\\" of the sitemap plugin is deprecated: Please use the new Docusaurus global trailingSlash config instead, and the sitemaps plugin will use it."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('should reject out-of-range priority inputs', () => {
|
||||
|
|
|
@ -9,6 +9,7 @@ import {SitemapStream, streamToPromise} from 'sitemap';
|
|||
import {PluginOptions} from './types';
|
||||
import {DocusaurusConfig} from '@docusaurus/types';
|
||||
import {addTrailingSlash} from '@docusaurus/utils';
|
||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||
|
||||
export default async function createSitemap(
|
||||
siteConfig: DocusaurusConfig,
|
||||
|
@ -25,11 +26,21 @@ export default async function createSitemap(
|
|||
hostname,
|
||||
});
|
||||
|
||||
function applySitemapTrailingSlash(routePath: string): string {
|
||||
// kept for retrocompatibility
|
||||
// TODO remove deprecated trailingSlash option before 2022
|
||||
if (options.trailingSlash) {
|
||||
return addTrailingSlash(routePath);
|
||||
} else {
|
||||
return applyTrailingSlash(routePath, trailingSlash);
|
||||
}
|
||||
}
|
||||
|
||||
routesPaths
|
||||
.filter((route) => !route.endsWith('404.html'))
|
||||
.map((routePath) =>
|
||||
sitemapStream.write({
|
||||
url: trailingSlash ? addTrailingSlash(routePath) : routePath,
|
||||
url: applySitemapTrailingSlash(routePath),
|
||||
changefreq,
|
||||
priority,
|
||||
}),
|
||||
|
|
|
@ -25,5 +25,11 @@ export const PluginOptionSchema = Joi.object({
|
|||
.valid(...Object.values(EnumChangefreq))
|
||||
.default(DEFAULT_OPTIONS.changefreq),
|
||||
priority: Joi.number().min(0).max(1).default(DEFAULT_OPTIONS.priority),
|
||||
trailingSlash: Joi.bool().default(false),
|
||||
trailingSlash: Joi.bool().default(false).warning('deprecate.error', {
|
||||
msg:
|
||||
'Please use the new Docusaurus global trailingSlash config instead, and the sitemaps plugin will use it.',
|
||||
}),
|
||||
}).messages({
|
||||
'deprecate.error':
|
||||
'Option {#label} of the sitemap plugin is deprecated: {#msg}',
|
||||
});
|
||||
|
|
3
packages/docusaurus-utils-common/README.md
Normal file
3
packages/docusaurus-utils-common/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# `@docusaurus/utils`
|
||||
|
||||
Common (Node/Browser) utility functions for Docusaurus packages.
|
27
packages/docusaurus-utils-common/package.json
Normal file
27
packages/docusaurus-utils-common/package.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@docusaurus/utils-common",
|
||||
"version": "2.0.0-beta.0",
|
||||
"description": "Common (Node/Browser) utility functions for Docusaurus packages.",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facebook/docusaurus.git",
|
||||
"directory": "packages/docusaurus-utils-common"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@docusaurus/types": "2.0.0-beta.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
}
|
||||
}
|
|
@ -86,4 +86,25 @@ describe('applyTrailingSlash', () => {
|
|||
'/abc/?search#anchor',
|
||||
);
|
||||
});
|
||||
|
||||
test('should apply to fully qualified urls', () => {
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', true),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', false),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', undefined),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', true),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', false),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', undefined),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
});
|
||||
});
|
|
@ -14,12 +14,14 @@ export default function applyTrailingSlash(
|
|||
return path;
|
||||
}
|
||||
|
||||
// TODO deduplicate: also present in @docusaurus/utils
|
||||
function addTrailingSlash(str: string): string {
|
||||
return str.endsWith('/') ? str : `${str}/`;
|
||||
}
|
||||
function removeTrailingSlash(str: string): string {
|
||||
return str.endsWith('/') ? str.slice(0, -1) : str;
|
||||
}
|
||||
|
||||
// undefined = legacy retrocompatible behavior
|
||||
if (typeof trailingSlash === 'undefined') {
|
||||
return path;
|
8
packages/docusaurus-utils-common/src/index.ts
Normal file
8
packages/docusaurus-utils-common/src/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
export {default as applyTrailingSlash} from './applyTrailingSlash';
|
10
packages/docusaurus-utils-common/tsconfig.json
Normal file
10
packages/docusaurus-utils-common/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||
"rootDir": "src",
|
||||
"outDir": "lib",
|
||||
"noEmitHelpers": false
|
||||
}
|
||||
}
|
|
@ -35,6 +35,15 @@ export const logValidationBugReportHint = (): void => {
|
|||
);
|
||||
};
|
||||
|
||||
function printWarning(warning?: Joi.ValidationError) {
|
||||
if (warning) {
|
||||
const warningMessages = warning.details
|
||||
.map(({message}) => message)
|
||||
.join('\n');
|
||||
console.log(chalk.yellow(warningMessages));
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizePluginOptions<T extends {id?: string}>(
|
||||
schema: Joi.ObjectSchema<T>,
|
||||
options: Partial<T>,
|
||||
|
@ -44,9 +53,12 @@ export function normalizePluginOptions<T extends {id?: string}>(
|
|||
const finalSchema = schema.append({
|
||||
id: PluginIdSchema,
|
||||
});
|
||||
const {error, value} = finalSchema.validate(options, {
|
||||
const {error, warning, value} = finalSchema.validate(options, {
|
||||
convert: false,
|
||||
});
|
||||
|
||||
printWarning(warning);
|
||||
|
||||
if (error) {
|
||||
logValidationBugReportHint();
|
||||
if (isValidationDisabledEscapeHatch) {
|
||||
|
@ -56,6 +68,7 @@ export function normalizePluginOptions<T extends {id?: string}>(
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -68,10 +81,12 @@ export function normalizeThemeConfig<T>(
|
|||
// otherwise one theme would fail validating the data of another theme
|
||||
const finalSchema = schema.unknown();
|
||||
|
||||
const {error, value} = finalSchema.validate(themeConfig, {
|
||||
const {error, warning, value} = finalSchema.validate(themeConfig, {
|
||||
convert: false,
|
||||
});
|
||||
|
||||
printWarning(warning);
|
||||
|
||||
if (error) {
|
||||
logValidationBugReportHint();
|
||||
if (isValidationDisabledEscapeHatch) {
|
||||
|
@ -112,6 +127,8 @@ export function validateFrontMatter<T>(
|
|||
abortEarly: false,
|
||||
});
|
||||
|
||||
printWarning(warning);
|
||||
|
||||
if (error) {
|
||||
const frontMatterString = JSON.stringify(frontMatter, null, 2);
|
||||
const errorDetails = error.details;
|
||||
|
@ -132,12 +149,5 @@ export function validateFrontMatter<T>(
|
|||
throw error;
|
||||
}
|
||||
|
||||
if (warning) {
|
||||
const warningMessages = warning.details
|
||||
.map(({message}) => message)
|
||||
.join('\n');
|
||||
console.log(chalk.yellow(warningMessages));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# `@docusaurus/utils`
|
||||
|
||||
Node validation utility functions for Docusaurus packages.
|
||||
Node utility functions for Docusaurus packages.
|
||||
|
|
|
@ -313,13 +313,15 @@ export function resolvePathname(to: string, from?: string): string {
|
|||
export function addLeadingSlash(str: string): string {
|
||||
return str.startsWith('/') ? str : `/${str}`;
|
||||
}
|
||||
export function addTrailingSlash(str: string): string {
|
||||
return str.endsWith('/') ? str : `${str}/`;
|
||||
}
|
||||
|
||||
export function addTrailingPathSeparator(str: string): string {
|
||||
return str.endsWith(path.sep) ? str : `${str}${path.sep}`;
|
||||
}
|
||||
|
||||
// TODO deduplicate: also present in @docusaurus/utils-common
|
||||
export function addTrailingSlash(str: string): string {
|
||||
return str.endsWith('/') ? str : `${str}/`;
|
||||
}
|
||||
export function removeTrailingSlash(str: string): string {
|
||||
return removeSuffix(str, '/');
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"@docusaurus/react-loadable": "5.5.0",
|
||||
"@docusaurus/types": "2.0.0-beta.0",
|
||||
"@docusaurus/utils": "2.0.0-beta.0",
|
||||
"@docusaurus/utils-common": "2.0.0-beta.0",
|
||||
"@docusaurus/utils-validation": "2.0.0-beta.0",
|
||||
"@slorber/static-site-generator-webpack-plugin": "^4.0.0",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
|
|
|
@ -13,7 +13,7 @@ import isInternalUrl from './isInternalUrl';
|
|||
import ExecutionEnvironment from './ExecutionEnvironment';
|
||||
import {useLinksCollector} from '../LinksCollector';
|
||||
import {useBaseUrlUtils} from './useBaseUrl';
|
||||
import applyTrailingSlash from './applyTrailingSlash';
|
||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||
|
||||
import type {LinkProps} from '@docusaurus/Link';
|
||||
import type docusaurus from '../docusaurus';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import {RouteConfig} from '@docusaurus/types';
|
||||
import {addTrailingSlash, removeTrailingSlash} from '@docusaurus/utils';
|
||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||
|
||||
export default function applyRouteTrailingSlash(
|
||||
route: RouteConfig,
|
||||
|
@ -17,23 +17,9 @@ export default function applyRouteTrailingSlash(
|
|||
return route;
|
||||
}
|
||||
|
||||
function getNewRoutePath() {
|
||||
// undefined = legacy retrocompatible behavior
|
||||
if (typeof trailingSlash === 'undefined') {
|
||||
return route.path;
|
||||
}
|
||||
// The trailing slash should be handled before the ?search#hash !
|
||||
// For routing #anchor is normally not possible, but querystring remains possible
|
||||
const [pathname] = route.path.split(/[#?]/);
|
||||
const newPathname = trailingSlash
|
||||
? addTrailingSlash(pathname)
|
||||
: removeTrailingSlash(pathname);
|
||||
return route.path.replace(pathname, newPathname);
|
||||
}
|
||||
|
||||
return {
|
||||
...route,
|
||||
path: getNewRoutePath(),
|
||||
path: applyTrailingSlash(route.path, trailingSlash),
|
||||
...(route.routes && {
|
||||
routes: route.routes.map((subroute) =>
|
||||
applyRouteTrailingSlash(subroute, trailingSlash),
|
||||
|
|
|
@ -10,7 +10,6 @@ Object {
|
|||
"@docusaurus/Link": "../../client/exports/Link.tsx",
|
||||
"@docusaurus/Noop": "../../client/exports/Noop.ts",
|
||||
"@docusaurus/Translate": "../../client/exports/Translate.tsx",
|
||||
"@docusaurus/applyTrailingSlash": "../../client/exports/applyTrailingSlash.tsx",
|
||||
"@docusaurus/constants": "../../client/exports/constants.ts",
|
||||
"@docusaurus/context": "../../client/exports/context.ts",
|
||||
"@docusaurus/isInternalUrl": "../../client/exports/isInternalUrl.ts",
|
||||
|
|
Loading…
Add table
Reference in a new issue