feat: new Rsdoctor official plugin (#10588)

This commit is contained in:
Sébastien Lorber 2024-10-17 17:20:06 +02:00 committed by GitHub
parent f6a6ca899f
commit 24716787d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 331 additions and 54 deletions

View file

@ -0,0 +1,3 @@
.tsbuildinfo*
tsconfig*
__tests__

View file

@ -0,0 +1,7 @@
# `@docusaurus/plugin-rsdoctor`
[Rsdoctor](https://rsdoctor.dev/) plugin for Docusaurus.
## Usage
See [plugin-rsdoctor documentation](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-rsdoctor).

View file

@ -0,0 +1,35 @@
{
"name": "@docusaurus/plugin-rsdoctor",
"version": "3.5.2",
"description": "Rsdoctor plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
"build": "tsc --build",
"watch": "tsc --build --watch"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/facebook/docusaurus.git",
"directory": "packages/docusaurus-plugin-rsdoctor"
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "3.5.2",
"@docusaurus/types": "3.5.2",
"@docusaurus/utils-validation": "3.5.2",
"@rsdoctor/webpack-plugin": "^0.4.6",
"@rsdoctor/rspack-plugin": "^0.4.6",
"tslib": "^2.6.0"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"engines": {
"node": ">=18.0"
}
}

View file

@ -0,0 +1,102 @@
/**
* 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 {normalizePluginOptions} from '@docusaurus/utils-validation';
import {
validateOptions,
type PluginOptions,
type Options,
DEFAULT_OPTIONS,
} from '../options';
import type {Validate} from '@docusaurus/types';
function validate(options?: Options) {
return validateOptions({
validate: normalizePluginOptions as Validate<
Options | undefined,
PluginOptions
>,
options,
});
}
function result(options?: Options) {
return {
id: 'default',
...DEFAULT_OPTIONS,
...options,
};
}
describe('validateOptions', () => {
it('accepts undefined', () => {
expect(validate(undefined)).toEqual(result(DEFAULT_OPTIONS));
});
it('accepts empty object', () => {
expect(validate({})).toEqual(result(DEFAULT_OPTIONS));
});
it('accepts defaults', () => {
expect(validate(DEFAULT_OPTIONS)).toEqual(result(DEFAULT_OPTIONS));
});
it('rejects null', () => {
expect(
// @ts-expect-error: TS should error
() => validate(null),
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
});
it('rejects number', () => {
expect(
// @ts-expect-error: TS should error
() => validate(42),
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
});
describe('rsdoctorOptions', () => {
it('accepts undefined', () => {
expect(validate({rsdoctorOptions: undefined})).toEqual(
result(DEFAULT_OPTIONS),
);
});
it('accepts empty', () => {
expect(validate({rsdoctorOptions: {}})).toEqual(result(DEFAULT_OPTIONS));
});
it('accepts any record', () => {
expect(
validate({rsdoctorOptions: {any: 'value', evenNumbers: 42}}),
).toEqual(
result({
...DEFAULT_OPTIONS,
rsdoctorOptions: {
any: 'value',
evenNumbers: 42,
},
}),
);
});
it('accepts default', () => {
expect(
validate({rsdoctorOptions: DEFAULT_OPTIONS.rsdoctorOptions}),
).toEqual(result(DEFAULT_OPTIONS));
});
it('rejects number values', () => {
expect(() =>
// @ts-expect-error: invalid type
validate({rsdoctorOptions: 42}),
).toThrowErrorMatchingInlineSnapshot(
`""rsdoctorOptions" must be of type object"`,
);
});
});
});

View file

@ -0,0 +1,55 @@
/**
* 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 {RsdoctorRspackMultiplePlugin} from '@rsdoctor/rspack-plugin';
import {RsdoctorWebpackMultiplePlugin} from '@rsdoctor/webpack-plugin';
import type {CurrentBundler, LoadContext, Plugin} from '@docusaurus/types';
import type {PluginOptions, Options} from './options';
function createRsdoctorBundlerPlugin({
isServer,
currentBundler,
options,
}: {
isServer: boolean;
currentBundler: CurrentBundler;
options: PluginOptions;
}) {
const RsdoctorPlugin =
currentBundler.name === 'rspack'
? RsdoctorRspackMultiplePlugin
: RsdoctorWebpackMultiplePlugin;
return new RsdoctorPlugin({
name: isServer ? 'server' : 'client',
...options.rsdoctorOptions,
});
}
export default (async function pluginRsdoctor(
context: LoadContext,
options: PluginOptions,
): Promise<Plugin | null> {
return {
name: 'docusaurus-plugin-rsdoctor',
configureWebpack: (__config, isServer) => {
return {
plugins: [
createRsdoctorBundlerPlugin({
isServer,
currentBundler: context.currentBundler,
options,
}),
],
};
},
};
});
export {validateOptions} from './options';
export type {PluginOptions, Options};

View file

@ -0,0 +1,34 @@
/**
* 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 {Joi} from '@docusaurus/utils-validation';
import type {OptionValidationContext} from '@docusaurus/types';
export type PluginOptions = {
rsdoctorOptions: Record<string, unknown>;
};
export type Options = {
rsdoctorOptions?: Record<string, unknown>;
};
export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
rsdoctorOptions: {},
};
const pluginOptionsSchema = Joi.object<PluginOptions>({
rsdoctorOptions: Joi.object()
.pattern(Joi.string(), Joi.any())
.optional()
.default(DEFAULT_OPTIONS.rsdoctorOptions),
}).default(DEFAULT_OPTIONS);
export function validateOptions({
validate,
options,
}: OptionValidationContext<Options | undefined, PluginOptions>): PluginOptions {
return validate(pluginOptionsSchema, options);
}

View file

@ -0,0 +1,8 @@
/**
* 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.
*/
/// <reference types="@docusaurus/module-type-aliases" />

View file

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"noEmit": false
},
"include": ["src"],
"exclude": ["**/__tests__/**"]
}

View file

@ -0,0 +1,57 @@
---
sidebar_position: 7
slug: /api/plugins/@docusaurus/plugin-rsdoctor
---
# 📦 plugin-rsdoctor
import APITable from '@site/src/components/APITable';
A [Rsdoctor](https://rsdoctor.dev/) plugin can help you troubleshoot the bundling phase of your Docusaurus site, supporting both Webpack and Rspack.
:::tip
Use it to figure out which plugin or loader is slowing down the bundler, and focus your efforts on optimizing the bottleneck.
:::
## Installation {#installation}
```bash npm2yarn
npm install --save @docusaurus/plugin-rsdoctor
```
## Configuration {#configuration}
Accepted fields:
```mdx-code-block
<APITable>
```
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `rsdoctorOptions` | `object` | `{}` | The [Rsdoctor bundler plugin options](https://rsdoctor.dev/config/options/options), forwarded as is |
```mdx-code-block
</APITable>
```
### Example configuration {#ex-config}
You can configure this plugin through plugin options.
```js title="docusaurus.config.js"
export default {
plugins: [
[
'rsdoctor',
{
rsdoctorOptions: {
mode: 'lite',
},
},
],
],
};
```

View file

@ -9,7 +9,6 @@ import npm2yarn from '@docusaurus/remark-plugin-npm2yarn';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import configTabs from './src/remark/configTabs';
import RsdoctorPlugin from './src/plugins/rsdoctor/RsdoctorPlugin';
import versions from './versions.json';
import VersionsArchived from './versionsArchived.json';
@ -129,6 +128,8 @@ const isI18nStaging = process.env.I18N_STAGING === 'true';
const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
const isRsdoctor = process.env.RSDOCTOR === 'true';
/*
const TwitterSvg =
'<svg style="fill: #1DA1F2; vertical-align: middle; margin-left: 3px;" width="16" height="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>';
@ -259,7 +260,25 @@ export default async function createConfigAsync() {
],
themes: ['live-codeblock', ...dogfoodingThemeInstances],
plugins: [
RsdoctorPlugin,
isRsdoctor && [
'rsdoctor',
{
rsdoctorOptions: {
disableTOSUpload: true,
supports: {
// https://rsdoctor.dev/config/options/options#generatetilegraph
generateTileGraph: true,
},
linter: {
// See https://rsdoctor.dev/guide/usage/rule-config
rules: {
'ecma-version-check': 'off',
'duplicate-package': 'off',
},
},
},
},
],
[
'./src/plugins/changelog/index.js',
{

View file

@ -43,6 +43,7 @@
"@docusaurus/plugin-client-redirects": "3.5.2",
"@docusaurus/plugin-ideal-image": "3.5.2",
"@docusaurus/plugin-pwa": "3.5.2",
"@docusaurus/plugin-rsdoctor": "3.5.2",
"@docusaurus/preset-classic": "3.5.2",
"@docusaurus/remark-plugin-npm2yarn": "3.5.2",
"@docusaurus/theme-classic": "3.5.2",
@ -84,8 +85,6 @@
"devDependencies": {
"@docusaurus/eslint-plugin": "3.5.2",
"@docusaurus/tsconfig": "3.5.2",
"@rsdoctor/webpack-plugin": "^0.4.6",
"@rsdoctor/rspack-plugin": "^0.4.6",
"@types/color": "^3.0.4",
"@types/jest": "^29.5.3",
"cross-env": "^7.0.3",

View file

@ -1,50 +0,0 @@
/**
* 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 type {PluginConfig} from '@docusaurus/types';
function createRsdoctorBundlerPlugin({isServer}: {isServer: boolean}) {
// TODO Shitty workaround to bypass lib typechecking
// package does not work will with skipLibCheck false
// // eslint-disable-next-line
// const {RsdoctorWebpackMultiplePlugin} = require('@rsdoctor/webpack-plugin');
// eslint-disable-next-line
const {RsdoctorRspackMultiplePlugin} = require('@rsdoctor/rspack-plugin');
// return new RsdoctorWebpackMultiplePlugin({
return new RsdoctorRspackMultiplePlugin({
name: isServer ? 'server' : 'client',
disableTOSUpload: true,
supports: {
// https://rsdoctor.dev/config/options/options#generatetilegraph
generateTileGraph: true,
},
linter: {
rules: {
'ecma-version-check': 'off',
},
},
});
}
export default (async function RsdoctorPlugin() {
if (!process.env.RSDOCTOR) {
return null;
}
const pluginClient = await createRsdoctorBundlerPlugin({isServer: false});
const pluginServer = await createRsdoctorBundlerPlugin({isServer: true});
console.log('Rsdoctor plugin enabled');
return {
name: 'rsdoctor-plugin',
configureWebpack: (__config, isServer) => {
const plugin = isServer ? pluginServer : pluginClient;
return {
plugins: [plugin],
};
},
};
} satisfies PluginConfig);