Skip to content

Commit

Permalink
feat(client-redirects): make plugin respect onDuplicateRoutes config (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena committed Jun 22, 2022
1 parent 51d7899 commit 4b5a47b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 13 deletions.
Expand Up @@ -9,18 +9,21 @@ import {removeTrailingSlash} from '@docusaurus/utils';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import collectRedirects from '../collectRedirects';
import {validateOptions} from '../options';
import type {DocusaurusConfig} from '@docusaurus/types';
import type {Options} from '../options';
import type {PluginContext} from '../types';

function createTestPluginContext(
options?: Options,
relativeRoutesPaths: string[] = [],
siteConfig: Partial<DocusaurusConfig> = {},
): PluginContext {
return {
outDir: '/tmp',
baseUrl: 'https://docusaurus.io',
relativeRoutesPaths,
options: validateOptions({validate: normalizePluginOptions, options}),
siteConfig: {onDuplicateRoutes: 'warn', ...siteConfig} as DocusaurusConfig,
};
}

Expand Down Expand Up @@ -308,9 +311,10 @@ describe('collectRedirects', () => {
collectRedirects(
createTestPluginContext(
{
createRedirects: (routePath) => {
// @ts-expect-error: for test
createRedirects(routePath) {
if (routePath === '/') {
return [[`/fromPath`]] as unknown as string;
return [[`/fromPath`]];
}
return undefined;
},
Expand Down Expand Up @@ -356,4 +360,44 @@ describe('collectRedirects', () => {
},
]);
});

it('throws when creating duplicate redirect routes and onDuplicateRoutes=throw', () => {
expect(() =>
collectRedirects(
createTestPluginContext(
{
createRedirects() {
return '/random-path';
},
},
['/path-one', '/path-two'],
{onDuplicateRoutes: 'throw'},
),
undefined,
),
).toThrowErrorMatchingInlineSnapshot(`
"@docusaurus/plugin-client-redirects: multiple redirects are created with the same "from" pathname: "/random-path"
It is not possible to redirect the same pathname to multiple destinations:
- {"from":"/random-path","to":"/path-one"}
- {"from":"/random-path","to":"/path-two"}"
`);
expect(() =>
collectRedirects(
createTestPluginContext(
{
redirects: [
{from: '/path-three', to: '/path-one'},
{from: '/path-two', to: '/path-one'},
],
},
['/path-one', '/path-two'],
{onDuplicateRoutes: 'throw'},
),
undefined,
),
).toThrowErrorMatchingInlineSnapshot(`
"@docusaurus/plugin-client-redirects: some redirects would override existing paths, and will be ignored:
- {"from":"/path-two","to":"/path-one"}"
`);
});
});
22 changes: 12 additions & 10 deletions packages/docusaurus-plugin-client-redirects/src/collectRedirects.ts
Expand Up @@ -102,27 +102,29 @@ function filterUnwantedRedirects(
Object.entries(_.groupBy(redirects, (redirect) => redirect.from)).forEach(
([from, groupedFromRedirects]) => {
if (groupedFromRedirects.length > 1) {
logger.error`name=${'@docusaurus/plugin-client-redirects'}: multiple redirects are created with the same "from" pathname: path=${from}
It is not possible to redirect the same pathname to multiple destinations: ${groupedFromRedirects.map(
logger.report(
pluginContext.siteConfig.onDuplicateRoutes,
)`name=${'@docusaurus/plugin-client-redirects'}: multiple redirects are created with the same "from" pathname: path=${from}
It is not possible to redirect the same pathname to multiple destinations:${groupedFromRedirects.map(
(r) => JSON.stringify(r),
)}`;
}
},
);
const collectedRedirects = _.uniqBy(redirects, (redirect) => redirect.from);

// We don't want to override an already existing route with a redirect file!
const redirectsOverridingExistingPath = collectedRedirects.filter(
(redirect) => pluginContext.relativeRoutesPaths.includes(redirect.from),
);
const {false: newRedirects = [], true: redirectsOverridingExistingPath = []} =
_.groupBy(collectedRedirects, (redirect) =>
pluginContext.relativeRoutesPaths.includes(redirect.from),
);
if (redirectsOverridingExistingPath.length > 0) {
logger.error`name=${'@docusaurus/plugin-client-redirects'}: some redirects would override existing paths, and will be ignored: ${redirectsOverridingExistingPath.map(
logger.report(
pluginContext.siteConfig.onDuplicateRoutes,
)`name=${'@docusaurus/plugin-client-redirects'}: some redirects would override existing paths, and will be ignored:${redirectsOverridingExistingPath.map(
(r) => JSON.stringify(r),
)}`;
}
return collectedRedirects.filter(
(redirect) => !pluginContext.relativeRoutesPaths.includes(redirect.from),
);
return newRedirects;
}

function createRedirectsOptionRedirects(
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-client-redirects/src/index.ts
Expand Up @@ -31,6 +31,7 @@ export default function pluginClientRedirectsPages(
baseUrl: props.baseUrl,
outDir: props.outDir,
options,
siteConfig: props.siteConfig,
};

const redirects: RedirectItem[] = collectRedirects(
Expand Down
2 changes: 1 addition & 1 deletion packages/docusaurus-plugin-client-redirects/src/types.ts
Expand Up @@ -11,7 +11,7 @@ import type {PluginOptions} from './options';
/**
* The minimal infos the plugin needs to work
*/
export type PluginContext = Pick<Props, 'outDir' | 'baseUrl'> & {
export type PluginContext = Pick<Props, 'outDir' | 'baseUrl' | 'siteConfig'> & {
options: PluginOptions;
relativeRoutesPaths: string[];
};
Expand Down
6 changes: 6 additions & 0 deletions website/docs/api/plugins/plugin-client-redirects.md
Expand Up @@ -50,6 +50,12 @@ Accepted fields:
</APITable>
```

:::note

This plugin will also read the [`siteConfig.onDuplicateRoutes`](../docusaurus.config.js.md#onDuplicateRoutes) config to adjust its logging level when multiple files will be emitted to the same location.

:::

### Types {#types}

#### `RedirectRule` {#RedirectRule}
Expand Down

0 comments on commit 4b5a47b

Please sign in to comment.