mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 02:37:59 +02:00
fix: improve sidebar accessibility structure (#8429)
This commit is contained in:
parent
37d8844506
commit
d2884f66ff
9 changed files with 38 additions and 274 deletions
|
@ -24,16 +24,19 @@ function DocSidebarDesktop({path, sidebar, onCollapse, isHidden}: Props) {
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<nav
|
||||||
className={clsx(
|
className={clsx(
|
||||||
styles.sidebar,
|
styles.sidebar,
|
||||||
hideOnScroll && styles.sidebarWithHideableNavbar,
|
hideOnScroll && styles.sidebarWithHideableNavbar,
|
||||||
isHidden && styles.sidebarHidden,
|
isHidden && styles.sidebarHidden,
|
||||||
)}>
|
)}
|
||||||
{hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
|
aria-label="docs sidebar">
|
||||||
|
{hideOnScroll && (
|
||||||
|
<Logo tabIndex={-1} className={styles.sidebarLogo} aria-hidden="true" />
|
||||||
|
)}
|
||||||
<Content path={path} sidebar={sidebar} />
|
<Content path={path} sidebar={sidebar} />
|
||||||
{hideable && <CollapseButton onClick={onCollapse} />}
|
{hideable && <CollapseButton onClick={onCollapse} />}
|
||||||
</div>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
"core-js": "^3.31.1",
|
"core-js": "^3.31.1",
|
||||||
"del": "^6.1.1",
|
|
||||||
"detect-port": "^1.5.1",
|
"detect-port": "^1.5.1",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"eta": "^2.2.0",
|
"eta": "^2.2.0",
|
||||||
|
|
|
@ -26,6 +26,7 @@ import type {
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import type {SiteCollectedData} from '../../common';
|
import type {SiteCollectedData} from '../../common';
|
||||||
import {BuildCLIOptions} from './build';
|
import {BuildCLIOptions} from './build';
|
||||||
|
import clearPath from '../utils/clearPath';
|
||||||
|
|
||||||
export type BuildLocaleParams = {
|
export type BuildLocaleParams = {
|
||||||
siteDir: string;
|
siteDir: string;
|
||||||
|
@ -77,6 +78,11 @@ export async function buildLocale({
|
||||||
props,
|
props,
|
||||||
configureWebpackUtils,
|
configureWebpackUtils,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// We also clear website/build dir
|
||||||
|
// returns void, no useful result needed before compilation
|
||||||
|
// See also https://github.com/facebook/docusaurus/pull/11037
|
||||||
|
clearPath(outDir),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,14 @@ import {
|
||||||
DEFAULT_BUILD_DIR_NAME,
|
DEFAULT_BUILD_DIR_NAME,
|
||||||
GENERATED_FILES_DIR_NAME,
|
GENERATED_FILES_DIR_NAME,
|
||||||
} from '@docusaurus/utils';
|
} from '@docusaurus/utils';
|
||||||
|
import clearPath from './utils/clearPath';
|
||||||
|
|
||||||
async function removePath(entry: {path: string; description: string}) {
|
async function removePath(entry: {path: string; description: string}) {
|
||||||
if (!(await fs.pathExists(entry.path))) {
|
if (!(await fs.pathExists(entry.path))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await fs.remove(entry.path);
|
await clearPath(entry.path);
|
||||||
logger.success`Removed the ${entry.description} at path=${path.relative(
|
logger.success`Removed the ${entry.description} at path=${path.relative(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
entry.path,
|
entry.path,
|
||||||
|
|
22
packages/docusaurus/src/commands/utils/clearPath.ts
Normal file
22
packages/docusaurus/src/commands/utils/clearPath.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* 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 path from 'path';
|
||||||
|
import {rm} from 'fs/promises';
|
||||||
|
import {PerfLogger} from '@docusaurus/logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pathToClear
|
||||||
|
*/
|
||||||
|
export default async function clearPath(pathToClear: string): Promise<void> {
|
||||||
|
return PerfLogger.async(
|
||||||
|
`clearPath ${path.relative(process.cwd(), pathToClear)}`,
|
||||||
|
async () => {
|
||||||
|
await rm(pathToClear, {recursive: true, force: true});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
import {getProgressBarPlugin} from '@docusaurus/bundler';
|
import {getProgressBarPlugin} from '@docusaurus/bundler';
|
||||||
import {createBaseConfig} from './base';
|
import {createBaseConfig} from './base';
|
||||||
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
|
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
|
||||||
import CleanWebpackPlugin from './plugins/CleanWebpackPlugin';
|
|
||||||
import ForceTerminatePlugin from './plugins/ForceTerminatePlugin';
|
import ForceTerminatePlugin from './plugins/ForceTerminatePlugin';
|
||||||
import {createStaticDirectoriesCopyPlugin} from './plugins/StaticDirectoriesCopyPlugin';
|
import {createStaticDirectoriesCopyPlugin} from './plugins/StaticDirectoriesCopyPlugin';
|
||||||
import type {
|
import type {
|
||||||
|
@ -164,8 +163,6 @@ export async function createBuildClientConfig({
|
||||||
{
|
{
|
||||||
plugins: [
|
plugins: [
|
||||||
new ForceTerminatePlugin(),
|
new ForceTerminatePlugin(),
|
||||||
// Remove/clean build folders before building bundles.
|
|
||||||
new CleanWebpackPlugin({verbose: false}),
|
|
||||||
// Visualize size of webpack output files with an interactive zoomable
|
// Visualize size of webpack output files with an interactive zoomable
|
||||||
// tree map.
|
// tree map.
|
||||||
bundleAnalyzer && new BundleAnalyzerPlugin(),
|
bundleAnalyzer && new BundleAnalyzerPlugin(),
|
||||||
|
|
|
@ -1,263 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The MIT License (MIT)
|
|
||||||
* Copyright (c) 2015 John Agan
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Forked from https://github.com/johnagan/clean-webpack-plugin
|
|
||||||
// Modified to optimize performance for Docusaurus specific use case
|
|
||||||
// More context: https://github.com/facebook/docusaurus/pull/1839
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs-extra';
|
|
||||||
import {sync as delSync} from 'del';
|
|
||||||
import type {Compiler, Stats} from 'webpack';
|
|
||||||
|
|
||||||
export type Options = {
|
|
||||||
/**
|
|
||||||
* Write Logs to Console
|
|
||||||
* (Always enabled when dry is true)
|
|
||||||
*
|
|
||||||
* default: false
|
|
||||||
*/
|
|
||||||
verbose?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically remove all unused webpack assets on rebuild
|
|
||||||
*
|
|
||||||
* default: true
|
|
||||||
*/
|
|
||||||
cleanStaleWebpackAssets?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not allow removal of current webpack assets
|
|
||||||
*
|
|
||||||
* default: true
|
|
||||||
*/
|
|
||||||
protectWebpackAssets?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes files once prior to Webpack compilation
|
|
||||||
* Not included in rebuilds (watch mode)
|
|
||||||
*
|
|
||||||
* Use !negative patterns to exclude files
|
|
||||||
*
|
|
||||||
* default: ['**\/*']
|
|
||||||
*/
|
|
||||||
cleanOnceBeforeBuildPatterns?: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class CleanWebpackPlugin {
|
|
||||||
private readonly verbose: boolean;
|
|
||||||
private readonly cleanStaleWebpackAssets: boolean;
|
|
||||||
private readonly protectWebpackAssets: boolean;
|
|
||||||
private readonly cleanOnceBeforeBuildPatterns: string[];
|
|
||||||
private currentAssets: string[];
|
|
||||||
private initialClean: boolean;
|
|
||||||
private outputPath: string;
|
|
||||||
|
|
||||||
constructor(options: Options = {}) {
|
|
||||||
this.verbose = options.verbose === true || false;
|
|
||||||
|
|
||||||
this.cleanStaleWebpackAssets =
|
|
||||||
options.cleanStaleWebpackAssets === true ||
|
|
||||||
options.cleanStaleWebpackAssets === false
|
|
||||||
? options.cleanStaleWebpackAssets
|
|
||||||
: true;
|
|
||||||
|
|
||||||
this.protectWebpackAssets =
|
|
||||||
options.protectWebpackAssets === true ||
|
|
||||||
options.protectWebpackAssets === false
|
|
||||||
? options.protectWebpackAssets
|
|
||||||
: true;
|
|
||||||
|
|
||||||
this.cleanOnceBeforeBuildPatterns = Array.isArray(
|
|
||||||
options.cleanOnceBeforeBuildPatterns,
|
|
||||||
)
|
|
||||||
? options.cleanOnceBeforeBuildPatterns
|
|
||||||
: ['**/*'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store webpack build assets
|
|
||||||
*/
|
|
||||||
this.currentAssets = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only used with cleanOnceBeforeBuildPatterns
|
|
||||||
*/
|
|
||||||
this.initialClean = false;
|
|
||||||
|
|
||||||
this.outputPath = '';
|
|
||||||
|
|
||||||
this.apply = this.apply.bind(this);
|
|
||||||
this.handleInitial = this.handleInitial.bind(this);
|
|
||||||
this.handleDone = this.handleDone.bind(this);
|
|
||||||
this.removeFiles = this.removeFiles.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(compiler: Compiler): void {
|
|
||||||
if (!compiler.options.output.path) {
|
|
||||||
console.warn(
|
|
||||||
'clean-webpack-plugin: options.output.path not defined. Plugin disabled...',
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.outputPath = compiler.options.output.path;
|
|
||||||
|
|
||||||
const {hooks} = compiler;
|
|
||||||
|
|
||||||
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
|
|
||||||
hooks.compile.tap('clean-webpack-plugin', () => {
|
|
||||||
this.handleInitial();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hooks.done.tap('clean-webpack-plugin', (stats) => {
|
|
||||||
this.handleDone(stats);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initially remove files from output directory prior to build.
|
|
||||||
*
|
|
||||||
* Only happens once.
|
|
||||||
*
|
|
||||||
* Warning: It is recommended to initially clean your build directory outside
|
|
||||||
* of webpack to minimize unexpected behavior.
|
|
||||||
*/
|
|
||||||
handleInitial(): void {
|
|
||||||
if (this.initialClean) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
// eslint-disable-next-line no-restricted-properties
|
|
||||||
fs.pathExistsSync(this.outputPath) &&
|
|
||||||
// eslint-disable-next-line no-restricted-properties
|
|
||||||
fs.statSync(this.outputPath).isFile()
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`A file '${this.outputPath}' already exists. Docusaurus needs this directory to save the build output. Either remove/change the file or choose a different build directory via '--out-dir'.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initialClean = true;
|
|
||||||
|
|
||||||
this.removeFiles(this.cleanOnceBeforeBuildPatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDone(stats: Stats): void {
|
|
||||||
/**
|
|
||||||
* Do nothing if there is a webpack error
|
|
||||||
*/
|
|
||||||
if (stats.hasErrors()) {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.warn('clean-webpack-plugin: pausing due to webpack errors');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch Webpack's output asset files
|
|
||||||
*/
|
|
||||||
const statsAssets =
|
|
||||||
stats.toJson({
|
|
||||||
all: false,
|
|
||||||
assets: true,
|
|
||||||
}).assets ?? [];
|
|
||||||
const assets = statsAssets.map((asset: {name: string}) => asset.name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all files that were in the previous build but not the current
|
|
||||||
*
|
|
||||||
* (relies on del's cwd: outputPath option)
|
|
||||||
*/
|
|
||||||
const staleFiles = this.currentAssets.filter(
|
|
||||||
(previousAsset) => !assets.includes(previousAsset),
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save assets for next compilation
|
|
||||||
*/
|
|
||||||
this.currentAssets = assets.sort();
|
|
||||||
|
|
||||||
const removePatterns: string[] = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove unused webpack assets
|
|
||||||
*/
|
|
||||||
if (this.cleanStaleWebpackAssets && staleFiles.length !== 0) {
|
|
||||||
removePatterns.push(...staleFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removePatterns.length !== 0) {
|
|
||||||
this.removeFiles(removePatterns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFiles(patterns: string[]): void {
|
|
||||||
try {
|
|
||||||
const deleted = delSync(patterns, {
|
|
||||||
force: false,
|
|
||||||
// Change context to build directory
|
|
||||||
cwd: this.outputPath,
|
|
||||||
dryRun: false,
|
|
||||||
dot: true,
|
|
||||||
ignore: this.protectWebpackAssets ? this.currentAssets : [],
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log if verbose is enabled
|
|
||||||
*/
|
|
||||||
if (this.verbose) {
|
|
||||||
deleted.forEach((file) => {
|
|
||||||
const filename = path.relative(process.cwd(), file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use console.warn over .log
|
|
||||||
* https://github.com/webpack/webpack/issues/1904
|
|
||||||
* https://github.com/johnagan/clean-webpack-plugin/issues/11
|
|
||||||
*/
|
|
||||||
console.warn(`clean-webpack-plugin: removed ${filename}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
const needsForce = (err as Error).message.includes(
|
|
||||||
'Cannot delete files/folders outside the current working directory.',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (needsForce) {
|
|
||||||
const message =
|
|
||||||
'clean-webpack-plugin: Cannot delete files/folders outside the current working directory. Can be overridden with the "dangerouslyAllowCleanPatternsOutsideProject" option.';
|
|
||||||
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
# Project Words - DO NOT TOUCH - This is updated through CI
|
# Project Words - DO NOT TOUCH - This is updated through CI
|
||||||
abernathyca
|
abernathyca
|
||||||
Adriaan
|
Adriaan
|
||||||
Agan
|
|
||||||
alexbdebrie
|
alexbdebrie
|
||||||
Alexey
|
Alexey
|
||||||
algoliasearch
|
algoliasearch
|
||||||
|
|
|
@ -7339,7 +7339,7 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, de
|
||||||
has-property-descriptors "^1.0.0"
|
has-property-descriptors "^1.0.0"
|
||||||
object-keys "^1.1.1"
|
object-keys "^1.1.1"
|
||||||
|
|
||||||
del@^6.0.0, del@^6.1.1:
|
del@^6.0.0:
|
||||||
version "6.1.1"
|
version "6.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a"
|
resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a"
|
||||||
integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==
|
integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==
|
||||||
|
|
Loading…
Add table
Reference in a new issue