From 106b9d8062bf6cf9b8af0f33746c2207f456be28 Mon Sep 17 00:00:00 2001 From: Ramon Lamana Date: Wed, 11 Mar 2020 01:37:40 +0100 Subject: [PATCH 1/4] fix(v2): normalize location path for route matching --- .../src/client/PendingNavigation.js | 17 ++++-- .../__tests__/normalizeLocation.test.js | 58 +++++++++++++++++++ .../src/client/normalizeLocation.js | 20 +++++++ 3 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 packages/docusaurus/src/client/__tests__/normalizeLocation.test.js create mode 100644 packages/docusaurus/src/client/normalizeLocation.js diff --git a/packages/docusaurus/src/client/PendingNavigation.js b/packages/docusaurus/src/client/PendingNavigation.js index 860557956e93..2c92388f35db 100644 --- a/packages/docusaurus/src/client/PendingNavigation.js +++ b/packages/docusaurus/src/client/PendingNavigation.js @@ -11,6 +11,7 @@ import nprogress from 'nprogress'; import clientLifecyclesDispatcher from './client-lifecycles-dispatcher'; import preload from './preload'; +import normalizeLocation from './normalizeLocation'; import 'nprogress/nprogress.css'; @@ -24,6 +25,7 @@ class PendingNavigation extends React.Component { this.previousLocation = null; this.progressBarTimeout = null; this.state = { + location: normalizeLocation(props.location), nextRouteHasLoaded: true, }; } @@ -37,19 +39,21 @@ class PendingNavigation extends React.Component { // If `routeDidChange` is true, means the router is trying to navigate to a new // route. We will preload the new route. if (routeDidChange) { + const nextLocation = normalizeLocation(nextProps.location); this.startProgressBar(delay); // Save the location first. - this.previousLocation = this.props.location; + this.previousLocation = this.state.location; this.setState({ + location: nextLocation, nextRouteHasLoaded: false, }); // Load data while the old screen remains. - preload(routes, nextProps.location.pathname) + preload(routes, nextLocation.pathname) .then(() => { clientLifecyclesDispatcher.onRouteUpdate({ previousLocation: this.previousLocation, - location: nextProps.location, + location: nextLocation, }); // Route has loaded, we can reset previousLocation. this.previousLocation = null; @@ -59,7 +63,7 @@ class PendingNavigation extends React.Component { }, this.stopProgressBar, ); - const {hash} = nextProps.location; + const {hash} = nextLocation; if (!hash) { window.scrollTo(0, 0); } else { @@ -94,7 +98,7 @@ class PendingNavigation extends React.Component { this.clearProgressBarTimeout(); this.progressBarTimeout = setTimeout(() => { clientLifecyclesDispatcher.onRouteUpdateDelayed({ - location: this.props.location, + location: this.state.location, }); nprogress.start(); }, delay); @@ -106,7 +110,8 @@ class PendingNavigation extends React.Component { } render() { - const {children, location} = this.props; + const {children} = this.props; + const {location} = this.state; return children} />; } } diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js new file mode 100644 index 000000000000..75cc131764b2 --- /dev/null +++ b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js @@ -0,0 +1,58 @@ +/** + * 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 normalizeLocation from '../normalizeLocation'; + +describe('normalizeLocation', () => { + test('rewrite locations with index.html', () => { + expect( + normalizeLocation({ + pathname: '/docs/introduction/index.html', + search: '#features', + hash: '', + }), + ).toEqual({ + pathname: '/docs/introduction', + search: '#features', + hash: '', + }); + + expect( + normalizeLocation({ + pathname: '/index.html', + search: '#features', + hash: '', + }), + ).toEqual({ + pathname: '/', + search: '#features', + hash: '', + }); + }); + + test('untouched pathnames', () => { + expect( + normalizeLocation({ + pathname: '/docs/introduction', + search: '#features', + hash: '', + }), + ).toEqual({ + pathname: '/docs/introduction', + search: '#features', + hash: '', + }); + + expect( + normalizeLocation({ + pathname: '/', + }), + ).toEqual({ + pathname: '/', + }); + }); +}); diff --git a/packages/docusaurus/src/client/normalizeLocation.js b/packages/docusaurus/src/client/normalizeLocation.js new file mode 100644 index 000000000000..7b26ac1ef2e2 --- /dev/null +++ b/packages/docusaurus/src/client/normalizeLocation.js @@ -0,0 +1,20 @@ +/** + * 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. + */ + +function normalizeLocation(location) { + let pathname = location.pathname || '/'; + pathname = pathname.trim().replace(/\/index\.html$/, ''); + if (pathname === '') { + pathname = '/'; + } + return { + ...location, + pathname, + }; +} + +export default normalizeLocation; From c117b108e1310b32fd99bfc09c52fbe1b699c0a9 Mon Sep 17 00:00:00 2001 From: Ramon Lamana Date: Mon, 23 Mar 2020 13:48:35 +0100 Subject: [PATCH 2/4] fix(v2): Memoize normalized pathnames --- .../src/client/PendingNavigation.js | 11 +++--- .../__tests__/normalizeLocation.test.js | 36 ++++++++++++------- .../src/client/normalizeLocation.js | 8 +++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus/src/client/PendingNavigation.js b/packages/docusaurus/src/client/PendingNavigation.js index 2c92388f35db..d231406f1fa0 100644 --- a/packages/docusaurus/src/client/PendingNavigation.js +++ b/packages/docusaurus/src/client/PendingNavigation.js @@ -25,7 +25,6 @@ class PendingNavigation extends React.Component { this.previousLocation = null; this.progressBarTimeout = null; this.state = { - location: normalizeLocation(props.location), nextRouteHasLoaded: true, }; } @@ -42,9 +41,8 @@ class PendingNavigation extends React.Component { const nextLocation = normalizeLocation(nextProps.location); this.startProgressBar(delay); // Save the location first. - this.previousLocation = this.state.location; + this.previousLocation = normalizeLocation(this.props.location); this.setState({ - location: nextLocation, nextRouteHasLoaded: false, }); @@ -110,9 +108,10 @@ class PendingNavigation extends React.Component { } render() { - const {children} = this.props; - const {location} = this.state; - return children} />; + const {children, location} = this.props; + return ( + children} /> + ); } } diff --git a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js index 75cc131764b2..415250a2cd28 100644 --- a/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js +++ b/packages/docusaurus/src/client/__tests__/normalizeLocation.test.js @@ -12,25 +12,25 @@ describe('normalizeLocation', () => { expect( normalizeLocation({ pathname: '/docs/introduction/index.html', - search: '#features', - hash: '', + search: '?search=foo', + hash: '#features', }), ).toEqual({ pathname: '/docs/introduction', - search: '#features', - hash: '', + search: '?search=foo', + hash: '#features', }); expect( normalizeLocation({ pathname: '/index.html', - search: '#features', - hash: '', + search: '', + hash: '#features', }), ).toEqual({ pathname: '/', - search: '#features', - hash: '', + search: '', + hash: '#features', }); }); @@ -38,13 +38,25 @@ describe('normalizeLocation', () => { expect( normalizeLocation({ pathname: '/docs/introduction', - search: '#features', - hash: '', + search: '', + hash: '#features', }), ).toEqual({ pathname: '/docs/introduction', - search: '#features', - hash: '', + search: '', + hash: '#features', + }); + + expect( + normalizeLocation({ + pathname: '/docs/introduction/foo.html', + search: '', + hash: '#bar', + }), + ).toEqual({ + pathname: '/docs/introduction/foo.html', + search: '', + hash: '#bar', }); expect( diff --git a/packages/docusaurus/src/client/normalizeLocation.js b/packages/docusaurus/src/client/normalizeLocation.js index 7b26ac1ef2e2..9143dd98feae 100644 --- a/packages/docusaurus/src/client/normalizeLocation.js +++ b/packages/docusaurus/src/client/normalizeLocation.js @@ -4,13 +4,21 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +const pathnames = {}; function normalizeLocation(location) { + if (pathnames[location.pathname]) { + return { + ...location, + pathname: pathnames[location.pathname], + }; + } let pathname = location.pathname || '/'; pathname = pathname.trim().replace(/\/index\.html$/, ''); if (pathname === '') { pathname = '/'; } + pathnames[location.pathname] = pathname; return { ...location, pathname, From 4667ab70578917dee6fd57bc4c5ca6635a5784f3 Mon Sep 17 00:00:00 2001 From: Ramon Lamana Date: Mon, 23 Mar 2020 18:19:20 +0100 Subject: [PATCH 3/4] fix(v2): fix wrong reference to this.state instead of normalized location --- packages/docusaurus/src/client/PendingNavigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus/src/client/PendingNavigation.js b/packages/docusaurus/src/client/PendingNavigation.js index d231406f1fa0..ae6a22d29ec4 100644 --- a/packages/docusaurus/src/client/PendingNavigation.js +++ b/packages/docusaurus/src/client/PendingNavigation.js @@ -96,7 +96,7 @@ class PendingNavigation extends React.Component { this.clearProgressBarTimeout(); this.progressBarTimeout = setTimeout(() => { clientLifecyclesDispatcher.onRouteUpdateDelayed({ - location: this.state.location, + location: normalizeLocation(this.props.location), }); nprogress.start(); }, delay); From 203adee455214f96f13230e39c6c49ac46a2b72d Mon Sep 17 00:00:00 2001 From: Yangshun Tay Date: Tue, 24 Mar 2020 01:33:41 +0800 Subject: [PATCH 4/4] Update normalizeLocation.js --- packages/docusaurus/src/client/normalizeLocation.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/docusaurus/src/client/normalizeLocation.js b/packages/docusaurus/src/client/normalizeLocation.js index 9143dd98feae..5e85db009e43 100644 --- a/packages/docusaurus/src/client/normalizeLocation.js +++ b/packages/docusaurus/src/client/normalizeLocation.js @@ -4,6 +4,8 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ + +// Memoize previously normalized pathnames. const pathnames = {}; function normalizeLocation(location) { @@ -13,12 +15,16 @@ function normalizeLocation(location) { pathname: pathnames[location.pathname], }; } + let pathname = location.pathname || '/'; pathname = pathname.trim().replace(/\/index\.html$/, ''); + if (pathname === '') { pathname = '/'; } + pathnames[location.pathname] = pathname; + return { ...location, pathname,