Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(client-redirects): make plugin respect onDuplicateRoutes config #7649

Merged
merged 1 commit into from Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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"}"
`);
});
});
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