fix(v2): redirect plugin: use siteConfig.trailingSlash (#4988)

This commit is contained in:
Sébastien Lorber 2021-06-16 19:04:28 +02:00 committed by GitHub
parent 80b6d9728e
commit b54ec72389
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 443 additions and 73 deletions

View file

@ -20,6 +20,7 @@
"@docusaurus/core": "2.0.0-beta.0", "@docusaurus/core": "2.0.0-beta.0",
"@docusaurus/types": "2.0.0-beta.0", "@docusaurus/types": "2.0.0-beta.0",
"@docusaurus/utils": "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", "@docusaurus/utils-validation": "2.0.0-beta.0",
"chalk": "^4.1.1", "chalk": "^4.1.1",
"eta": "^1.11.0", "eta": "^1.11.0",

View file

@ -32,7 +32,83 @@ Array [
] ]
`; `;
exports[`toRedirectFilesMetadata should create appropriate metadatas: fileContent 1`] = ` exports[`toRedirectFilesMetadata should create appropriate metadatas trailingSlash=false: fileContent 1`] = `
Array [
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/abc\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/abc\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/abc';
</script>
</html>",
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/def.html\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/def.html\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/def.html';
</script>
</html>",
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/';
</script>
</html>",
]
`;
exports[`toRedirectFilesMetadata should create appropriate metadatas trailingSlash=true: fileContent 1`] = `
Array [
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/abc\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/abc\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/abc';
</script>
</html>",
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/def.html\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/def.html\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/def.html';
</script>
</html>",
"<!DOCTYPE html>
<html>
<head>
<meta charset=\\"UTF-8\\">
<meta http-equiv=\\"refresh\\" content=\\"0; url=https://docusaurus.io/\\">
<link rel=\\"canonical\\" href=\\"https://docusaurus.io/\\" />
</head>
<script>
window.location.href = 'https://docusaurus.io/';
</script>
</html>",
]
`;
exports[`toRedirectFilesMetadata should create appropriate metadatas trailingSlash=undefined: fileContent 1`] = `
Array [ Array [
"<!DOCTYPE html> "<!DOCTYPE html>
<html> <html>

View file

@ -25,12 +25,17 @@ function createTestPluginContext(
describe('collectRedirects', () => { describe('collectRedirects', () => {
test('should collect no redirect for undefined config', () => { test('should collect no redirect for undefined config', () => {
expect( expect(
collectRedirects(createTestPluginContext(undefined, ['/', '/path'])), collectRedirects(
createTestPluginContext(undefined, ['/', '/path']),
undefined,
),
).toEqual([]); ).toEqual([]);
}); });
test('should collect no redirect for empty config', () => { test('should collect no redirect for empty config', () => {
expect(collectRedirects(createTestPluginContext({}))).toEqual([]); expect(collectRedirects(createTestPluginContext({}), undefined)).toEqual(
[],
);
}); });
test('should collect redirects to html/exe extension', () => { test('should collect redirects to html/exe extension', () => {
@ -42,6 +47,7 @@ describe('collectRedirects', () => {
}, },
['/', '/somePath', '/otherPath.html'], ['/', '/somePath', '/otherPath.html'],
), ),
undefined,
), ),
).toEqual([ ).toEqual([
{ {
@ -64,6 +70,7 @@ describe('collectRedirects', () => {
}, },
['/', '/somePath', '/otherPath.html'], ['/', '/somePath', '/otherPath.html'],
), ),
undefined,
), ),
).toEqual([ ).toEqual([
{ {
@ -91,6 +98,79 @@ describe('collectRedirects', () => {
}, },
['/', '/somePath'], ['/', '/somePath'],
), ),
undefined,
),
).toEqual([
{
from: '/someLegacyPath',
to: '/somePath',
},
{
from: '/someLegacyPathArray1',
to: '/',
},
{
from: '/someLegacyPathArray2',
to: '/',
},
]);
});
test('should collect redirects from plugin option redirects with trailingSlash=true', () => {
expect(
collectRedirects(
createTestPluginContext(
{
redirects: [
{
from: '/someLegacyPath',
to: '/somePath',
},
{
from: ['/someLegacyPathArray1', '/someLegacyPathArray2'],
to: '/',
},
],
},
['/', '/somePath/'],
),
true,
),
).toEqual([
{
from: '/someLegacyPath',
to: '/somePath/',
},
{
from: '/someLegacyPathArray1',
to: '/',
},
{
from: '/someLegacyPathArray2',
to: '/',
},
]);
});
test('should collect redirects from plugin option redirects with trailingSlash=false', () => {
expect(
collectRedirects(
createTestPluginContext(
{
redirects: [
{
from: '/someLegacyPath',
to: '/somePath/',
},
{
from: ['/someLegacyPathArray1', '/someLegacyPathArray2'],
to: '/',
},
],
},
['/', '/somePath'],
),
false,
), ),
).toEqual([ ).toEqual([
{ {
@ -130,6 +210,7 @@ describe('collectRedirects', () => {
}, },
['/', '/someExistingPath', '/anotherExistingPath'], ['/', '/someExistingPath', '/anotherExistingPath'],
), ),
undefined,
), ),
).toThrowErrorMatchingSnapshot(); ).toThrowErrorMatchingSnapshot();
}); });
@ -148,6 +229,7 @@ describe('collectRedirects', () => {
}, },
['/', '/testpath', '/otherPath.html'], ['/', '/testpath', '/otherPath.html'],
), ),
undefined,
), ),
).toEqual([ ).toEqual([
{ {
@ -197,6 +279,7 @@ describe('collectRedirects', () => {
}, },
['/'], ['/'],
), ),
undefined,
), ),
).toThrowErrorMatchingSnapshot(); ).toThrowErrorMatchingSnapshot();
}); });
@ -215,6 +298,7 @@ describe('collectRedirects', () => {
}, },
['/'], ['/'],
), ),
undefined,
), ),
).toThrowErrorMatchingSnapshot(); ).toThrowErrorMatchingSnapshot();
}); });
@ -236,6 +320,7 @@ describe('collectRedirects', () => {
'/toShouldWork', '/toShouldWork',
], ],
), ),
undefined,
), ),
).toEqual([ ).toEqual([
{ {

View file

@ -42,7 +42,7 @@ describe('createToUrl', () => {
}); });
describe('toRedirectFilesMetadata', () => { describe('toRedirectFilesMetadata', () => {
test('should create appropriate metadatas', async () => { test('should create appropriate metadatas trailingSlash=undefined', async () => {
const pluginContext = { const pluginContext = {
outDir: '/tmp/someFixedOutDir', outDir: '/tmp/someFixedOutDir',
baseUrl: 'https://docusaurus.io', baseUrl: 'https://docusaurus.io',
@ -55,10 +55,11 @@ describe('toRedirectFilesMetadata', () => {
{from: '/xyz', to: '/'}, {from: '/xyz', to: '/'},
], ],
pluginContext, pluginContext,
undefined,
); );
expect(redirectFiles.map((f) => f.fileAbsolutePath)).toEqual([ expect(redirectFiles.map((f) => f.fileAbsolutePath)).toEqual([
path.join(pluginContext.outDir, '/abc.html/index.html'), path.join(pluginContext.outDir, '/abc.html'),
path.join(pluginContext.outDir, '/def/index.html'), path.join(pluginContext.outDir, '/def/index.html'),
path.join(pluginContext.outDir, '/xyz/index.html'), path.join(pluginContext.outDir, '/xyz/index.html'),
]); ]);
@ -68,6 +69,60 @@ describe('toRedirectFilesMetadata', () => {
); );
}); });
test('should create appropriate metadatas trailingSlash=true', async () => {
const pluginContext = {
outDir: '/tmp/someFixedOutDir',
baseUrl: 'https://docusaurus.io',
};
const redirectFiles = toRedirectFilesMetadata(
[
{from: '/abc.html', to: '/abc'},
{from: '/def', to: '/def.html'},
{from: '/xyz', to: '/'},
],
pluginContext,
true,
);
expect(redirectFiles.map((f) => f.fileAbsolutePath)).toEqual([
path.join(pluginContext.outDir, '/abc.html'),
path.join(pluginContext.outDir, '/def/index.html'),
path.join(pluginContext.outDir, '/xyz/index.html'),
]);
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
'fileContent',
);
});
test('should create appropriate metadatas trailingSlash=false', async () => {
const pluginContext = {
outDir: '/tmp/someFixedOutDir',
baseUrl: 'https://docusaurus.io',
};
const redirectFiles = toRedirectFilesMetadata(
[
{from: '/abc.html', to: '/abc'},
{from: '/def', to: '/def.html'},
{from: '/xyz', to: '/'},
],
pluginContext,
false,
);
expect(redirectFiles.map((f) => f.fileAbsolutePath)).toEqual([
path.join(pluginContext.outDir, '/abc.html'),
path.join(pluginContext.outDir, '/def.html'),
path.join(pluginContext.outDir, '/xyz.html'),
]);
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
'fileContent',
);
});
test('should create appropriate metadatas for root baseUrl', async () => { test('should create appropriate metadatas for root baseUrl', async () => {
const pluginContext = { const pluginContext = {
outDir: '/tmp/someFixedOutDir', outDir: '/tmp/someFixedOutDir',
@ -76,6 +131,7 @@ describe('toRedirectFilesMetadata', () => {
const redirectFiles = toRedirectFilesMetadata( const redirectFiles = toRedirectFilesMetadata(
[{from: '/abc.html', to: '/abc'}], [{from: '/abc.html', to: '/abc'}],
pluginContext, pluginContext,
undefined,
); );
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot( expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
'fileContent baseUrl=/', 'fileContent baseUrl=/',
@ -90,6 +146,7 @@ describe('toRedirectFilesMetadata', () => {
const redirectFiles = toRedirectFilesMetadata( const redirectFiles = toRedirectFilesMetadata(
[{from: '/abc.html', to: '/abc'}], [{from: '/abc.html', to: '/abc'}],
pluginContext, pluginContext,
undefined,
); );
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot( expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
'fileContent baseUrl=empty', 'fileContent baseUrl=empty',

View file

@ -17,17 +17,36 @@ import {
createToExtensionsRedirects, createToExtensionsRedirects,
} from './extensionRedirects'; } from './extensionRedirects';
import {validateRedirect} from './redirectValidation'; import {validateRedirect} from './redirectValidation';
import {applyTrailingSlash} from '@docusaurus/utils-common';
import chalk from 'chalk'; import chalk from 'chalk';
export default function collectRedirects( export default function collectRedirects(
pluginContext: PluginContext, pluginContext: PluginContext,
trailingSlash: boolean | undefined,
): RedirectMetadata[] { ): RedirectMetadata[] {
const redirects = doCollectRedirects(pluginContext); let redirects = doCollectRedirects(pluginContext);
redirects = applyRedirectsTrailingSlash(redirects, trailingSlash);
validateCollectedRedirects(redirects, pluginContext); validateCollectedRedirects(redirects, pluginContext);
return filterUnwantedRedirects(redirects, pluginContext); return filterUnwantedRedirects(redirects, pluginContext);
} }
// If users wants to redirect to=/abc and they enable trailingSlash=true then
// => we don't want to reject the to=/abc (as only /abc/ is an existing/valid path now)
// => we want to redirect to=/abc/ without the user having to change all its redirect plugin options
// It should be easy to toggle siteConfig.trailingSlash option without having to change other configs
function applyRedirectsTrailingSlash(
redirects: RedirectMetadata[],
trailingSlash: boolean | undefined,
) {
return redirects.map((redirect) => {
return {
...redirect,
to: applyTrailingSlash(redirect.to, trailingSlash),
};
});
}
function validateCollectedRedirects( function validateCollectedRedirects(
redirects: RedirectMetadata[], redirects: RedirectMetadata[],
pluginContext: PluginContext, pluginContext: PluginContext,

View file

@ -15,13 +15,28 @@ import writeRedirectFiles, {
RedirectFileMetadata, RedirectFileMetadata,
} from './writeRedirectFiles'; } from './writeRedirectFiles';
import {removePrefix, addLeadingSlash} from '@docusaurus/utils'; import {removePrefix, addLeadingSlash} from '@docusaurus/utils';
import chalk from 'chalk';
export default function pluginClientRedirectsPages( export default function pluginClientRedirectsPages(
_context: LoadContext, context: LoadContext,
opts: UserPluginOptions, opts: UserPluginOptions,
): Plugin<unknown> { ): Plugin<unknown> {
const {trailingSlash} = context.siteConfig;
const options = normalizePluginOptions(opts); const options = normalizePluginOptions(opts);
// Special case, when using trailingSlash=false we output /xyz.html files instead of /xyz/index.html
// It makes no sense to use option fromExtensions=["html"]: the redirect files would be the same as the original files
if (options.fromExtensions.includes('html') && trailingSlash === false) {
console.warn(
chalk.yellow(`Using the Docusaurus redirect plugin with fromExtensions=['html'] and siteConfig.trailingSlash=false is prevented.
It would lead the redirect plugin to override all the page.html files created by Docusaurus.`),
);
options.fromExtensions = options.fromExtensions.filter(
(ext) => ext !== 'html',
);
}
return { return {
name: 'docusaurus-plugin-client-redirects', name: 'docusaurus-plugin-client-redirects',
async postBuild(props: Props) { async postBuild(props: Props) {
@ -34,11 +49,15 @@ export default function pluginClientRedirectsPages(
options, options,
}; };
const redirects: RedirectMetadata[] = collectRedirects(pluginContext); const redirects: RedirectMetadata[] = collectRedirects(
pluginContext,
trailingSlash,
);
const redirectFiles: RedirectFileMetadata[] = toRedirectFilesMetadata( const redirectFiles: RedirectFileMetadata[] = toRedirectFilesMetadata(
redirects, redirects,
pluginContext, pluginContext,
trailingSlash,
); );
// Write files only at the end: make code more easy to test without IO // Write files only at the end: make code more easy to test without IO

View file

@ -27,6 +27,7 @@ export function createToUrl(baseUrl: string, to: string): string {
export function toRedirectFilesMetadata( export function toRedirectFilesMetadata(
redirects: RedirectMetadata[], redirects: RedirectMetadata[],
pluginContext: WriteFilesPluginContext, pluginContext: WriteFilesPluginContext,
trailingSlash: boolean | undefined,
): RedirectFileMetadata[] { ): RedirectFileMetadata[] {
// Perf: avoid rendering the template twice with the exact same "props" // Perf: avoid rendering the template twice with the exact same "props"
// We might create multiple redirect pages for the same destination url // We might create multiple redirect pages for the same destination url
@ -36,10 +37,8 @@ export function toRedirectFilesMetadata(
}); });
const createFileMetadata = (redirect: RedirectMetadata) => { const createFileMetadata = (redirect: RedirectMetadata) => {
const fileAbsolutePath = path.join( const filePath = getFilePathForRoutePath(redirect.from, trailingSlash);
pluginContext.outDir, const fileAbsolutePath = path.join(pluginContext.outDir, filePath);
getFilePathForRoutePath(redirect.from),
);
const toUrl = createToUrl(pluginContext.baseUrl, redirect.to); const toUrl = createToUrl(pluginContext.baseUrl, redirect.to);
const fileContent = createPageContentMemoized(toUrl); const fileContent = createPageContentMemoized(toUrl);
return { return {

View file

@ -14,10 +14,20 @@ describe('applyTrailingSlash', () => {
expect(applyTrailingSlash('', undefined)).toEqual(''); expect(applyTrailingSlash('', undefined)).toEqual('');
}); });
test('should apply to /', () => { test('should not apply to /', () => {
expect(applyTrailingSlash('/', true)).toEqual('/'); expect(applyTrailingSlash('/', true)).toEqual('/');
expect(applyTrailingSlash('/', false)).toEqual(''); expect(applyTrailingSlash('/', false)).toEqual('/');
expect(applyTrailingSlash('/', undefined)).toEqual('/'); expect(applyTrailingSlash('/', undefined)).toEqual('/');
expect(applyTrailingSlash('/?query#anchor', true)).toEqual(
'/?query#anchor',
);
expect(applyTrailingSlash('/?query#anchor', false)).toEqual(
'/?query#anchor',
);
expect(applyTrailingSlash('/?query#anchor', undefined)).toEqual(
'/?query#anchor',
);
}); });
test('should not apply to #anchor links ', () => { test('should not apply to #anchor links ', () => {

View file

@ -9,8 +9,8 @@ export default function applyTrailingSlash(
path: string, path: string,
trailingSlash: boolean | undefined, trailingSlash: boolean | undefined,
): string { ): string {
// Never apply trailing slash to an anchor link
if (path.startsWith('#')) { if (path.startsWith('#')) {
// Never apply trailing slash to an anchor link
return path; return path;
} }
@ -29,7 +29,12 @@ export default function applyTrailingSlash(
// The trailing slash should be handled before the ?search#hash ! // The trailing slash should be handled before the ?search#hash !
const [pathname] = path.split(/[#?]/); const [pathname] = path.split(/[#?]/);
const newPathname = trailingSlash
// Never transform '/' to ''
const newPathname =
pathname === '/'
? '/'
: trailingSlash
? addTrailingSlash(pathname) ? addTrailingSlash(pathname)
: removeTrailingSlash(pathname); : removeTrailingSlash(pathname);
return path.replace(pathname, newPathname); return path.replace(pathname, newPathname);

View file

@ -0,0 +1,87 @@
/**
* 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 {getFilePathForRoutePath} from '../getFilePathForRoutePath';
import {posixPath} from '../posixPath';
describe('getFilePathForRoutePath trailingSlash=undefined', () => {
test('works for /', () => {
expect(posixPath(getFilePathForRoutePath('/', undefined))).toEqual(
'/index.html',
);
});
test('works for /somePath', () => {
expect(posixPath(getFilePathForRoutePath('/somePath', undefined))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/', () => {
expect(posixPath(getFilePathForRoutePath('/somePath/', undefined))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/xyz.html', () => {
expect(
posixPath(getFilePathForRoutePath('/somePath/xyz.html', undefined)),
).toEqual('/somePath/xyz.html');
});
});
describe('getFilePathForRoutePath trailingSlash=true', () => {
test('works for /', () => {
expect(posixPath(getFilePathForRoutePath('/', true))).toEqual(
'/index.html',
);
});
test('works for /somePath', () => {
expect(posixPath(getFilePathForRoutePath('/somePath', true))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/', () => {
expect(posixPath(getFilePathForRoutePath('/somePath/', true))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/xyz.html', () => {
expect(
posixPath(getFilePathForRoutePath('/somePath/xyz.html', true)),
).toEqual('/somePath/xyz.html');
});
});
describe('getFilePathForRoutePath trailingSlash=false', () => {
test('works for /', () => {
expect(posixPath(getFilePathForRoutePath('/', false))).toEqual(
'/index.html',
);
});
test('works for /somePath', () => {
expect(posixPath(getFilePathForRoutePath('/somePath', false))).toEqual(
'/somePath.html',
);
});
test('works for /somePath/', () => {
expect(posixPath(getFilePathForRoutePath('/somePath/', false))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/xyz.html', () => {
expect(
posixPath(getFilePathForRoutePath('/somePath/xyz.html', false)),
).toEqual('/somePath/xyz.html');
});
});

View file

@ -21,7 +21,6 @@ import {
removeTrailingSlash, removeTrailingSlash,
removeSuffix, removeSuffix,
removePrefix, removePrefix,
getFilePathForRoutePath,
addLeadingSlash, addLeadingSlash,
getElementsAround, getElementsAround,
mergeTranslations, mergeTranslations,
@ -401,22 +400,6 @@ describe('removePrefix', () => {
}); });
}); });
describe('getFilePathForRoutePath', () => {
test('works for /', () => {
expect(posixPath(getFilePathForRoutePath('/'))).toEqual('/index.html');
});
test('works for /somePath', () => {
expect(posixPath(getFilePathForRoutePath('/somePath'))).toEqual(
'/somePath/index.html',
);
});
test('works for /somePath/', () => {
expect(posixPath(getFilePathForRoutePath('/somePath/'))).toEqual(
'/somePath/index.html',
);
});
});
describe('getElementsAround', () => { describe('getElementsAround', () => {
test('can return elements around', () => { test('can return elements around', () => {
expect(getElementsAround(['a', 'b', 'c', 'd'], 0)).toEqual({ expect(getElementsAround(['a', 'b', 'c', 'd'], 0)).toEqual({

View file

@ -0,0 +1,43 @@
/**
* 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 path from 'path';
/*
export function getFilePathForRoutePath(routePath: string): string {
const fileName = path.basename(routePath);
const filePath = path.dirname(routePath);
return path.join(filePath, `${fileName}/index.html`);
}
*/
// Almost exact copy of the behavior we implemented in our Docusaurus fork of the webpack static gen plugin
// See https://github.com/slorber/static-site-generator-webpack-plugin/blob/master/index.js#L167
export function getFilePathForRoutePath(
routePath: string,
trailingSlash: boolean | undefined,
): string {
// const outputFileName = routePath.replace(/^(\/|\\)/, ''); // Remove leading slashes for webpack-dev-server
// Paths ending with .html are left untouched
if (/\.(html?)$/i.test(routePath)) {
return routePath;
}
// Legacy retro-compatible behavior
if (typeof trailingSlash === 'undefined') {
return path.join(routePath, 'index.html');
}
// New behavior: we can say if we prefer file/folder output
// Useful resource: https://github.com/slorber/trailing-slash-guide
if (routePath === '' || routePath.endsWith('/') || trailingSlash) {
return path.join(routePath, 'index.html');
} else {
return `${routePath}.html`;
}
}

View file

@ -27,6 +27,7 @@ import {docuHash} from './docuHash';
export const posixPath = posixPathImport; export const posixPath = posixPathImport;
export * from './getFilePathForRoutePath';
export * from './codeTranslationsUtils'; export * from './codeTranslationsUtils';
export * from './markdownParser'; export * from './markdownParser';
export * from './markdownLinks'; export * from './markdownLinks';
@ -325,12 +326,6 @@ export function removePrefix(str: string, prefix: string): string {
return str.startsWith(prefix) ? str.slice(prefix.length) : str; return str.startsWith(prefix) ? str.slice(prefix.length) : str;
} }
export function getFilePathForRoutePath(routePath: string): string {
const fileName = path.basename(routePath);
const filePath = path.dirname(routePath);
return path.join(filePath, `${fileName}/index.html`);
}
export function getElementsAround<T extends unknown>( export function getElementsAround<T extends unknown>(
array: T[], array: T[],
aroundIndex: number, aroundIndex: number,

View file

@ -12,11 +12,6 @@ export default function applyRouteTrailingSlash(
route: RouteConfig, route: RouteConfig,
trailingSlash: boolean | undefined, trailingSlash: boolean | undefined,
) { ) {
// Never transform "/" to "" => cause router issues ("" catch everything)
if (route.path === '/') {
return route;
}
return { return {
...route, ...route,
path: applyTrailingSlash(route.path, trailingSlash), path: applyTrailingSlash(route.path, trailingSlash),

View file

@ -132,11 +132,7 @@ const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
], ],
[ [
'@docusaurus/plugin-client-redirects', '@docusaurus/plugin-client-redirects',
isDeployPreview {
? // Plugin is disabled for deploy preview because we use trailing slashes on deploy previews
// This plugin is sensitive to trailing slashes, and we don't care much about making it work on deploy previews
{}
: {
fromExtensions: ['html'], fromExtensions: ['html'],
createRedirects: function (path) { createRedirects: function (path) {
// redirect to /docs from /docs/introduction, // redirect to /docs from /docs/introduction,