mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-15 10:07:33 +02:00
fix(v2): redirect plugin: use siteConfig.trailingSlash (#4988)
This commit is contained in:
parent
80b6d9728e
commit
b54ec72389
15 changed files with 443 additions and 73 deletions
|
@ -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",
|
||||
"chalk": "^4.1.1",
|
||||
"eta": "^1.11.0",
|
||||
|
|
|
@ -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 [
|
||||
"<!DOCTYPE html>
|
||||
<html>
|
||||
|
|
|
@ -25,12 +25,17 @@ function createTestPluginContext(
|
|||
describe('collectRedirects', () => {
|
||||
test('should collect no redirect for undefined config', () => {
|
||||
expect(
|
||||
collectRedirects(createTestPluginContext(undefined, ['/', '/path'])),
|
||||
collectRedirects(
|
||||
createTestPluginContext(undefined, ['/', '/path']),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
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', () => {
|
||||
|
@ -42,6 +47,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/', '/somePath', '/otherPath.html'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
|
@ -64,6 +70,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/', '/somePath', '/otherPath.html'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
|
@ -91,6 +98,79 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/', '/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([
|
||||
{
|
||||
|
@ -130,6 +210,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/', '/someExistingPath', '/anotherExistingPath'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
@ -148,6 +229,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/', '/testpath', '/otherPath.html'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
|
@ -197,6 +279,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
@ -215,6 +298,7 @@ describe('collectRedirects', () => {
|
|||
},
|
||||
['/'],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
|
@ -236,6 +320,7 @@ describe('collectRedirects', () => {
|
|||
'/toShouldWork',
|
||||
],
|
||||
),
|
||||
undefined,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ describe('createToUrl', () => {
|
|||
});
|
||||
|
||||
describe('toRedirectFilesMetadata', () => {
|
||||
test('should create appropriate metadatas', async () => {
|
||||
test('should create appropriate metadatas trailingSlash=undefined', async () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
baseUrl: 'https://docusaurus.io',
|
||||
|
@ -55,10 +55,11 @@ describe('toRedirectFilesMetadata', () => {
|
|||
{from: '/xyz', to: '/'},
|
||||
],
|
||||
pluginContext,
|
||||
undefined,
|
||||
);
|
||||
|
||||
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, '/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 () => {
|
||||
const pluginContext = {
|
||||
outDir: '/tmp/someFixedOutDir',
|
||||
|
@ -76,6 +131,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
const redirectFiles = toRedirectFilesMetadata(
|
||||
[{from: '/abc.html', to: '/abc'}],
|
||||
pluginContext,
|
||||
undefined,
|
||||
);
|
||||
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
|
||||
'fileContent baseUrl=/',
|
||||
|
@ -90,6 +146,7 @@ describe('toRedirectFilesMetadata', () => {
|
|||
const redirectFiles = toRedirectFilesMetadata(
|
||||
[{from: '/abc.html', to: '/abc'}],
|
||||
pluginContext,
|
||||
undefined,
|
||||
);
|
||||
expect(redirectFiles.map((f) => f.fileContent)).toMatchSnapshot(
|
||||
'fileContent baseUrl=empty',
|
||||
|
|
|
@ -17,17 +17,36 @@ import {
|
|||
createToExtensionsRedirects,
|
||||
} from './extensionRedirects';
|
||||
import {validateRedirect} from './redirectValidation';
|
||||
import {applyTrailingSlash} from '@docusaurus/utils-common';
|
||||
|
||||
import chalk from 'chalk';
|
||||
|
||||
export default function collectRedirects(
|
||||
pluginContext: PluginContext,
|
||||
trailingSlash: boolean | undefined,
|
||||
): RedirectMetadata[] {
|
||||
const redirects = doCollectRedirects(pluginContext);
|
||||
let redirects = doCollectRedirects(pluginContext);
|
||||
redirects = applyRedirectsTrailingSlash(redirects, trailingSlash);
|
||||
validateCollectedRedirects(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(
|
||||
redirects: RedirectMetadata[],
|
||||
pluginContext: PluginContext,
|
||||
|
|
|
@ -15,13 +15,28 @@ import writeRedirectFiles, {
|
|||
RedirectFileMetadata,
|
||||
} from './writeRedirectFiles';
|
||||
import {removePrefix, addLeadingSlash} from '@docusaurus/utils';
|
||||
import chalk from 'chalk';
|
||||
|
||||
export default function pluginClientRedirectsPages(
|
||||
_context: LoadContext,
|
||||
context: LoadContext,
|
||||
opts: UserPluginOptions,
|
||||
): Plugin<unknown> {
|
||||
const {trailingSlash} = context.siteConfig;
|
||||
|
||||
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 {
|
||||
name: 'docusaurus-plugin-client-redirects',
|
||||
async postBuild(props: Props) {
|
||||
|
@ -34,11 +49,15 @@ export default function pluginClientRedirectsPages(
|
|||
options,
|
||||
};
|
||||
|
||||
const redirects: RedirectMetadata[] = collectRedirects(pluginContext);
|
||||
const redirects: RedirectMetadata[] = collectRedirects(
|
||||
pluginContext,
|
||||
trailingSlash,
|
||||
);
|
||||
|
||||
const redirectFiles: RedirectFileMetadata[] = toRedirectFilesMetadata(
|
||||
redirects,
|
||||
pluginContext,
|
||||
trailingSlash,
|
||||
);
|
||||
|
||||
// Write files only at the end: make code more easy to test without IO
|
||||
|
|
|
@ -27,6 +27,7 @@ export function createToUrl(baseUrl: string, to: string): string {
|
|||
export function toRedirectFilesMetadata(
|
||||
redirects: RedirectMetadata[],
|
||||
pluginContext: WriteFilesPluginContext,
|
||||
trailingSlash: boolean | undefined,
|
||||
): RedirectFileMetadata[] {
|
||||
// Perf: avoid rendering the template twice with the exact same "props"
|
||||
// We might create multiple redirect pages for the same destination url
|
||||
|
@ -36,10 +37,8 @@ export function toRedirectFilesMetadata(
|
|||
});
|
||||
|
||||
const createFileMetadata = (redirect: RedirectMetadata) => {
|
||||
const fileAbsolutePath = path.join(
|
||||
pluginContext.outDir,
|
||||
getFilePathForRoutePath(redirect.from),
|
||||
);
|
||||
const filePath = getFilePathForRoutePath(redirect.from, trailingSlash);
|
||||
const fileAbsolutePath = path.join(pluginContext.outDir, filePath);
|
||||
const toUrl = createToUrl(pluginContext.baseUrl, redirect.to);
|
||||
const fileContent = createPageContentMemoized(toUrl);
|
||||
return {
|
||||
|
|
|
@ -14,10 +14,20 @@ describe('applyTrailingSlash', () => {
|
|||
expect(applyTrailingSlash('', undefined)).toEqual('');
|
||||
});
|
||||
|
||||
test('should apply to /', () => {
|
||||
test('should not apply to /', () => {
|
||||
expect(applyTrailingSlash('/', true)).toEqual('/');
|
||||
expect(applyTrailingSlash('/', false)).toEqual('');
|
||||
expect(applyTrailingSlash('/', false)).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 ', () => {
|
||||
|
|
|
@ -9,8 +9,8 @@ export default function applyTrailingSlash(
|
|||
path: string,
|
||||
trailingSlash: boolean | undefined,
|
||||
): string {
|
||||
// Never apply trailing slash to an anchor link
|
||||
if (path.startsWith('#')) {
|
||||
// Never apply trailing slash to an anchor link
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,12 @@ export default function applyTrailingSlash(
|
|||
|
||||
// The trailing slash should be handled before the ?search#hash !
|
||||
const [pathname] = path.split(/[#?]/);
|
||||
const newPathname = trailingSlash
|
||||
|
||||
// Never transform '/' to ''
|
||||
const newPathname =
|
||||
pathname === '/'
|
||||
? '/'
|
||||
: trailingSlash
|
||||
? addTrailingSlash(pathname)
|
||||
: removeTrailingSlash(pathname);
|
||||
return path.replace(pathname, newPathname);
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
|
@ -21,7 +21,6 @@ import {
|
|||
removeTrailingSlash,
|
||||
removeSuffix,
|
||||
removePrefix,
|
||||
getFilePathForRoutePath,
|
||||
addLeadingSlash,
|
||||
getElementsAround,
|
||||
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', () => {
|
||||
test('can return elements around', () => {
|
||||
expect(getElementsAround(['a', 'b', 'c', 'd'], 0)).toEqual({
|
||||
|
|
43
packages/docusaurus-utils/src/getFilePathForRoutePath.ts
Normal file
43
packages/docusaurus-utils/src/getFilePathForRoutePath.ts
Normal 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`;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import {docuHash} from './docuHash';
|
|||
|
||||
export const posixPath = posixPathImport;
|
||||
|
||||
export * from './getFilePathForRoutePath';
|
||||
export * from './codeTranslationsUtils';
|
||||
export * from './markdownParser';
|
||||
export * from './markdownLinks';
|
||||
|
@ -325,12 +326,6 @@ export function removePrefix(str: string, prefix: string): string {
|
|||
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>(
|
||||
array: T[],
|
||||
aroundIndex: number,
|
||||
|
|
|
@ -12,11 +12,6 @@ export default function applyRouteTrailingSlash(
|
|||
route: RouteConfig,
|
||||
trailingSlash: boolean | undefined,
|
||||
) {
|
||||
// Never transform "/" to "" => cause router issues ("" catch everything)
|
||||
if (route.path === '/') {
|
||||
return route;
|
||||
}
|
||||
|
||||
return {
|
||||
...route,
|
||||
path: applyTrailingSlash(route.path, trailingSlash),
|
||||
|
|
|
@ -132,11 +132,7 @@ const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
|
|||
],
|
||||
[
|
||||
'@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'],
|
||||
createRedirects: function (path) {
|
||||
// redirect to /docs from /docs/introduction,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue