From 2cc2bf93670e3f18349bdc684d347fc7d8cc4416 Mon Sep 17 00:00:00 2001 From: slorber Date: Mon, 12 Oct 2020 11:40:36 +0200 Subject: [PATCH] improve broken links error message: include help message for frequent broken links, usually found in layout --- .../__snapshots__/brokenLinks.test.ts.snap | 60 ++++++++++++++++--- .../src/server/__tests__/brokenLinks.test.ts | 33 ++++++++++ packages/docusaurus/src/server/brokenLinks.ts | 41 +++++++++++-- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/brokenLinks.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/brokenLinks.test.ts.snap index a195fad6d8f7..0972b81ac1ae 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/brokenLinks.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/brokenLinks.test.ts.snap @@ -1,18 +1,64 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`brokenLinks getBrokenLinksErrorMessage 1`] = ` -"Broken links found! -Please check the pages of your site in the list bellow, and make sure you don't reference any path that does not exist +"Docusaurus found broken links! + +Please check the pages of your site in the list bellow, and make sure you don't reference any path that does not exist. Note: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass. +Exhaustive list of all broken links found: + +- On source page path = /docs/mySourcePage: + -> linking to ./myBrokenLink (resolved as: /docs/myBrokenLink) + -> linking to ../otherBrokenLink (resolved as: /otherBrokenLink) + +- On source page path = /otherSourcePage: + -> linking to /badLink +" +`; + +exports[`brokenLinks getBrokenLinksErrorMessage with potential layout broken links 1`] = ` +"Docusaurus found broken links! + +Please check the pages of your site in the list bellow, and make sure you don't reference any path that does not exist. +Note: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass. + +It looks like some of the broken links we found appear in many pages of your site. +Maybe those broken links appear on all pages through your site layout? +We recommend that you check your theme configuration for such links (particularly, theme navbar and footer). +Frequent broken links are linking to: +- ./myBrokenLinkFrequent1 +- ./myBrokenLinkFrequent2 + + +Exhaustive list of all broken links found: + +- On source page path = /docs/page1: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) + +- On source page path = /docs/page2: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) + -> linking to ./myBrokenLinkInfrequent1 (resolved as: /docs/myBrokenLinkInfrequent1) + -> linking to ./myBrokenLinkInfrequent2 (resolved as: /docs/myBrokenLinkInfrequent2) +- On source page path = /docs/page3: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) -- Page path = /docs/mySourcePage: - -> link to ./myBrokenLink (resolved as: /docs/myBrokenLink) - -> link to ../otherBrokenLink (resolved as: /otherBrokenLink) +- On source page path = /docs/page4: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) + -> linking to ./myBrokenLinkInfrequent1 (resolved as: /docs/myBrokenLinkInfrequent1) + -> linking to ./myBrokenLinkInfrequent2 (resolved as: /docs/myBrokenLinkInfrequent2) +- On source page path = /docs/page5: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) -- Page path = /otherSourcePage: - -> link to /badLink +- On source page path = /docs/page6: + -> linking to ./myBrokenLinkFrequent1 (resolved as: /docs/myBrokenLinkFrequent1) + -> linking to ./myBrokenLinkFrequent2 (resolved as: /docs/myBrokenLinkFrequent2) " `; diff --git a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts index 5a6c7bcd310c..52da59184408 100644 --- a/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts +++ b/packages/docusaurus/src/server/__tests__/brokenLinks.test.ts @@ -25,6 +25,39 @@ describe('brokenLinks', () => { expect(message).toMatchSnapshot(); }); + test('getBrokenLinksErrorMessage with potential layout broken links', async () => { + const frequentLink = [ + { + link: './myBrokenLinkFrequent1', + resolvedLink: '/docs/myBrokenLinkFrequent1', + }, + { + link: './myBrokenLinkFrequent2', + resolvedLink: '/docs/myBrokenLinkFrequent2', + }, + ]; + const infrequentLink = [ + { + link: './myBrokenLinkInfrequent1', + resolvedLink: '/docs/myBrokenLinkInfrequent1', + }, + { + link: './myBrokenLinkInfrequent2', + resolvedLink: '/docs/myBrokenLinkInfrequent2', + }, + ]; + + const message = getBrokenLinksErrorMessage({ + '/docs/page1': [...frequentLink], + '/docs/page2': [...frequentLink, ...infrequentLink], + '/docs/page3': [...frequentLink], + '/docs/page4': [...frequentLink, ...infrequentLink], + '/docs/page5': [...frequentLink], + '/docs/page6': [...frequentLink], + }); + expect(message).toMatchSnapshot(); + }); + test('getAllBrokenLinks', async () => { const routes: RouteConfig[] = [ { diff --git a/packages/docusaurus/src/server/brokenLinks.ts b/packages/docusaurus/src/server/brokenLinks.ts index 0c1957d31add..89fee5b113e3 100644 --- a/packages/docusaurus/src/server/brokenLinks.ts +++ b/packages/docusaurus/src/server/brokenLinks.ts @@ -8,7 +8,7 @@ import {matchRoutes, RouteConfig as RRRouteConfig} from 'react-router-config'; import resolvePathname from 'resolve-pathname'; import fs from 'fs-extra'; -import {mapValues, pickBy} from 'lodash'; +import {mapValues, pickBy, flatten, countBy} from 'lodash'; import {RouteConfig, ReportingSeverity} from '@docusaurus/types'; import {removePrefix, removeSuffix} from '@docusaurus/utils'; import {getAllFinalRoutes, reportMessage} from './utils'; @@ -99,14 +99,45 @@ export function getBrokenLinksErrorMessage( pagePath: string, brokenLinks: BrokenLink[], ): string { - return `\n\n- Page path = ${pagePath}:\n -> link to ${brokenLinks + return `\n- On source page path = ${pagePath}:\n -> linking to ${brokenLinks .map(brokenLinkMessage) - .join('\n -> link to ')}`; + .join('\n -> linking to ')}`; + } + + // If there's a broken link appearing very often, it is probably a broken link on the layout! + // Add an additional message in such case to help user figure this out. + // see https://github.com/facebook/docusaurus/issues/3567#issuecomment-706973805 + function getLayoutBrokenLinksHelpMessage() { + const flatList = flatten( + Object.entries(allBrokenLinks).map(([pagePage, brokenLinks]) => + brokenLinks.map((brokenLink) => ({pagePage, brokenLink})), + ), + ); + + const countedBrokenLinks = countBy( + flatList, + (item) => item.brokenLink.link, + ); + + const FrequencyThreshold = 5; // Is this a good value? + const frequentLinks = Object.entries(countedBrokenLinks) + .filter(([, count]) => count >= FrequencyThreshold) + .map(([link]) => link); + + if (frequentLinks.length === 0) { + return ''; + } + + return `\n\nIt looks like some of the broken links we found appear in many pages of your site.\nMaybe those broken links appear on all pages through your site layout?\nWe recommend that you check your theme configuration for such links (particularly, theme navbar and footer).\nFrequent broken links are linking to: \n- ${frequentLinks.join( + `\n- `, + )}\n`; } return ( - `Broken links found!\nPlease check the pages of your site in the list bellow, and make sure you don't reference any path that does not exist\nNote: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass.\n\n` + - `${Object.entries(allBrokenLinks) + `Docusaurus found broken links!\n\nPlease check the pages of your site in the list bellow, and make sure you don't reference any path that does not exist.\nNote: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass.${getLayoutBrokenLinksHelpMessage()}` + + `\n\nExhaustive list of all broken links found:\n${Object.entries( + allBrokenLinks, + ) .map(([pagePath, brokenLinks]) => pageBrokenLinksMessage(pagePath, brokenLinks), )