mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-07 13:22:26 +02:00
fix(core): prevent 404 when accessing /page.html (#7184)
This commit is contained in:
parent
4e4aa6add7
commit
c4e92c89e8
5 changed files with 78 additions and 18 deletions
|
@ -12,6 +12,7 @@ process.env.TZ = 'UTC';
|
||||||
const ignorePatterns = [
|
const ignorePatterns = [
|
||||||
'/node_modules/',
|
'/node_modules/',
|
||||||
'__fixtures__',
|
'__fixtures__',
|
||||||
|
'__mocks__',
|
||||||
'/testUtils.ts',
|
'/testUtils.ts',
|
||||||
'/packages/docusaurus/lib',
|
'/packages/docusaurus/lib',
|
||||||
'/packages/docusaurus-logger/lib',
|
'/packages/docusaurus-logger/lib',
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* 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 [
|
||||||
|
{
|
||||||
|
path: '/page.html',
|
||||||
|
exact: true,
|
||||||
|
component: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/docs',
|
||||||
|
exact: false,
|
||||||
|
component: '',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/docs/installation',
|
||||||
|
exact: true,
|
||||||
|
component: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
component: '',
|
||||||
|
},
|
||||||
|
];
|
|
@ -43,6 +43,33 @@ describe('normalizeLocation', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes html extension', () => {
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/docs/installation.html',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/docs/installation',
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
normalizeLocation({
|
||||||
|
pathname: '/docs/introduction/foo.html',
|
||||||
|
search: '',
|
||||||
|
hash: '#bar',
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
pathname: '/docs/introduction/foo',
|
||||||
|
search: '',
|
||||||
|
hash: '#bar',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not strip extension if the route location has one', () => {
|
||||||
|
expect(normalizeLocation({pathname: '/page.html'})).toEqual({
|
||||||
|
pathname: '/page.html',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('leaves pathnames untouched', () => {
|
it('leaves pathnames untouched', () => {
|
||||||
const replaceMock = jest.spyOn(String.prototype, 'replace');
|
const replaceMock = jest.spyOn(String.prototype, 'replace');
|
||||||
|
|
||||||
|
@ -72,18 +99,6 @@ describe('normalizeLocation', () => {
|
||||||
});
|
});
|
||||||
expect(replaceMock).toBeCalledTimes(1);
|
expect(replaceMock).toBeCalledTimes(1);
|
||||||
|
|
||||||
expect(
|
|
||||||
normalizeLocation({
|
|
||||||
pathname: '/docs/introduction/foo.html',
|
|
||||||
search: '',
|
|
||||||
hash: '#bar',
|
|
||||||
}),
|
|
||||||
).toEqual({
|
|
||||||
pathname: '/docs/introduction/foo.html',
|
|
||||||
search: '',
|
|
||||||
hash: '#bar',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
normalizeLocation({
|
normalizeLocation({
|
||||||
pathname: '/',
|
pathname: '/',
|
||||||
|
|
|
@ -5,23 +5,33 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {matchRoutes} from 'react-router-config';
|
||||||
|
import routes from '@generated/routes';
|
||||||
import type {Location} from 'history';
|
import type {Location} from 'history';
|
||||||
|
|
||||||
// Memoize previously normalized pathnames.
|
// Memoize previously normalized pathnames.
|
||||||
const pathnames: {[rawPathname: string]: string} = {};
|
const pathnames = new Map<string, string>();
|
||||||
|
|
||||||
export default function normalizeLocation<T extends Location>(location: T): T {
|
export default function normalizeLocation<T extends Location>(location: T): T {
|
||||||
if (pathnames[location.pathname]) {
|
if (pathnames.has(location.pathname)) {
|
||||||
return {
|
return {
|
||||||
...location,
|
...location,
|
||||||
pathname: pathnames[location.pathname],
|
pathname: pathnames.get(location.pathname),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathname =
|
// If the location was registered with an `.html` extension, we don't strip it
|
||||||
location.pathname.trim().replace(/\/index\.html$/, '') || '/';
|
// away, or it will render to a 404 page.
|
||||||
|
const matchedRoutes = matchRoutes(routes, location.pathname);
|
||||||
|
if (matchedRoutes.some(({route}) => route.exact === true)) {
|
||||||
|
pathnames.set(location.pathname, location.pathname);
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
pathnames[location.pathname] = pathname;
|
const pathname =
|
||||||
|
location.pathname.trim().replace(/(?:\/index)?\.html$/, '') || '/';
|
||||||
|
|
||||||
|
pathnames.set(location.pathname, pathname);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...location,
|
...location,
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
|
---
|
||||||
|
slug: dummy.html
|
||||||
|
---
|
||||||
|
|
||||||
# Just a dummy page
|
# Just a dummy page
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue