mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-04 11:52:39 +02:00
refactor(core): collocate CLI commands and their option types (#7292)
* refactor(core): collocate CLI commands and their option types * fixes
This commit is contained in:
parent
5bed55aeda
commit
c7a5af7c4d
13 changed files with 92 additions and 100 deletions
31
packages/docusaurus-types/src/index.d.ts
vendored
31
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -410,37 +410,6 @@ export type DocusaurusContext = {
|
|||
// isBrowser: boolean; // Not here on purpose!
|
||||
};
|
||||
|
||||
export type HostPortCLIOptions = {
|
||||
host?: string;
|
||||
port?: string;
|
||||
};
|
||||
|
||||
export type ConfigOptions = {
|
||||
config: string;
|
||||
};
|
||||
|
||||
export type StartCLIOptions = HostPortCLIOptions &
|
||||
ConfigOptions & {
|
||||
hotOnly: boolean;
|
||||
open: boolean;
|
||||
poll: boolean | number;
|
||||
locale?: string;
|
||||
};
|
||||
|
||||
export type ServeCLIOptions = HostPortCLIOptions &
|
||||
ConfigOptions & {
|
||||
dir: string;
|
||||
build: boolean;
|
||||
};
|
||||
|
||||
export type BuildCLIOptions = ConfigOptions & {
|
||||
bundleAnalyzer: boolean;
|
||||
outDir: string;
|
||||
minify: boolean;
|
||||
skipBuild: boolean;
|
||||
locale?: string;
|
||||
};
|
||||
|
||||
export type LoadContext = {
|
||||
siteDir: string;
|
||||
generatedFilesDir: string;
|
||||
|
|
|
@ -13,10 +13,10 @@ import ReactLoadableSSRAddon from 'react-loadable-ssr-addon-v5-slorber';
|
|||
import type {Configuration} from 'webpack';
|
||||
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
|
||||
import merge from 'webpack-merge';
|
||||
import {load, loadContext} from '../server';
|
||||
import {load, loadContext, type LoadContextOptions} from '../server';
|
||||
import {handleBrokenLinks} from '../server/brokenLinks';
|
||||
|
||||
import type {BuildCLIOptions, Props} from '@docusaurus/types';
|
||||
import type {Props} from '@docusaurus/types';
|
||||
import createClientConfig from '../webpack/client';
|
||||
import createServerConfig from '../webpack/server';
|
||||
import {
|
||||
|
@ -29,6 +29,14 @@ import {loadI18n} from '../server/i18n';
|
|||
import {mapAsyncSequential} from '@docusaurus/utils';
|
||||
import type {HelmetServerState} from 'react-helmet-async';
|
||||
|
||||
export type BuildCLIOptions = Pick<
|
||||
LoadContextOptions,
|
||||
'config' | 'locale' | 'outDir'
|
||||
> & {
|
||||
bundleAnalyzer?: boolean;
|
||||
minify?: boolean;
|
||||
};
|
||||
|
||||
export async function build(
|
||||
siteDir: string,
|
||||
cliOptions: Partial<BuildCLIOptions>,
|
||||
|
@ -64,8 +72,8 @@ export async function build(
|
|||
}
|
||||
const context = await loadContext({
|
||||
siteDir,
|
||||
customOutDir: cliOptions.outDir,
|
||||
customConfigFilePath: cliOptions.config,
|
||||
outDir: cliOptions.outDir,
|
||||
config: cliOptions.config,
|
||||
locale: cliOptions.locale,
|
||||
localizePath: cliOptions.locale ? false : undefined,
|
||||
});
|
||||
|
@ -113,8 +121,8 @@ async function buildLocale({
|
|||
|
||||
const props: Props = await load({
|
||||
siteDir,
|
||||
customOutDir: cliOptions.outDir,
|
||||
customConfigFilePath: cliOptions.config,
|
||||
outDir: cliOptions.outDir,
|
||||
config: cliOptions.config,
|
||||
locale,
|
||||
localizePath: cliOptions.locale ? false : undefined,
|
||||
});
|
||||
|
|
|
@ -1,24 +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 {choosePort} from '../server/choosePort';
|
||||
import type {HostPortCLIOptions} from '@docusaurus/types';
|
||||
import {DEFAULT_PORT} from '@docusaurus/utils';
|
||||
|
||||
export function getCLIOptionHost(
|
||||
hostOption: HostPortCLIOptions['host'],
|
||||
): string {
|
||||
return hostOption ?? 'localhost';
|
||||
}
|
||||
|
||||
export async function getCLIOptionPort(
|
||||
portOption: HostPortCLIOptions['port'],
|
||||
host: string,
|
||||
): Promise<number | null> {
|
||||
const basePort = portOption ? parseInt(portOption, 10) : DEFAULT_PORT;
|
||||
return choosePort(host, basePort);
|
||||
}
|
|
@ -9,12 +9,18 @@ import fs from 'fs-extra';
|
|||
import shell from 'shelljs';
|
||||
import logger from '@docusaurus/logger';
|
||||
import {hasSSHProtocol, buildSshUrl, buildHttpsUrl} from '@docusaurus/utils';
|
||||
import {loadContext} from '../server';
|
||||
import {loadContext, type LoadContextOptions} from '../server';
|
||||
import {build} from './build';
|
||||
import type {BuildCLIOptions} from '@docusaurus/types';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
export type DeployCLIOptions = Pick<
|
||||
LoadContextOptions,
|
||||
'config' | 'locale' | 'outDir'
|
||||
> & {
|
||||
skipBuild?: boolean;
|
||||
};
|
||||
|
||||
// GIT_PASS env variable should not appear in logs
|
||||
function obfuscateGitPass(str: string) {
|
||||
const gitPass = process.env.GIT_PASS;
|
||||
|
@ -36,12 +42,12 @@ function shellExecLog(cmd: string) {
|
|||
|
||||
export async function deploy(
|
||||
siteDir: string,
|
||||
cliOptions: Partial<BuildCLIOptions>,
|
||||
cliOptions: Partial<DeployCLIOptions>,
|
||||
): Promise<void> {
|
||||
const {outDir, siteConfig, siteConfigPath} = await loadContext({
|
||||
siteDir,
|
||||
customConfigFilePath: cliOptions.config,
|
||||
customOutDir: cliOptions.outDir,
|
||||
config: cliOptions.config,
|
||||
outDir: cliOptions.outDir,
|
||||
});
|
||||
|
||||
if (typeof siteConfig.trailingSlash === 'undefined') {
|
||||
|
|
|
@ -9,11 +9,17 @@ import http from 'http';
|
|||
import serveHandler from 'serve-handler';
|
||||
import logger from '@docusaurus/logger';
|
||||
import path from 'path';
|
||||
import type {LoadContextOptions} from '../server';
|
||||
import {loadSiteConfig} from '../server/config';
|
||||
import {build} from './build';
|
||||
import {getCLIOptionHost, getCLIOptionPort} from './commandUtils';
|
||||
import {getHostPort, type HostPortOptions} from '../server/getHostPort';
|
||||
import {DEFAULT_BUILD_DIR_NAME} from '@docusaurus/utils';
|
||||
import type {ServeCLIOptions} from '@docusaurus/types';
|
||||
|
||||
export type ServeCLIOptions = HostPortOptions &
|
||||
Pick<LoadContextOptions, 'config'> & {
|
||||
dir?: string;
|
||||
build?: boolean;
|
||||
};
|
||||
|
||||
export async function serve(
|
||||
siteDir: string,
|
||||
|
@ -33,8 +39,7 @@ export async function serve(
|
|||
);
|
||||
}
|
||||
|
||||
const host: string = getCLIOptionHost(cliOptions.host);
|
||||
const port: number | null = await getCLIOptionPort(cliOptions.port, host);
|
||||
const {host, port} = await getHostPort(cliOptions);
|
||||
|
||||
if (port === null) {
|
||||
process.exit();
|
||||
|
|
|
@ -17,17 +17,23 @@ import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
|
|||
import webpack from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import merge from 'webpack-merge';
|
||||
import {load} from '../server';
|
||||
import type {StartCLIOptions} from '@docusaurus/types';
|
||||
import {load, type LoadContextOptions} from '../server';
|
||||
import createClientConfig from '../webpack/client';
|
||||
import {
|
||||
applyConfigureWebpack,
|
||||
applyConfigurePostCss,
|
||||
getHttpsConfig,
|
||||
} from '../webpack/utils';
|
||||
import {getCLIOptionHost, getCLIOptionPort} from './commandUtils';
|
||||
import {getHostPort, type HostPortOptions} from '../server/getHostPort';
|
||||
import {getTranslationsLocaleDirPath} from '../server/translations/translations';
|
||||
|
||||
export type StartCLIOptions = HostPortOptions &
|
||||
Pick<LoadContextOptions, 'locale' | 'config'> & {
|
||||
hotOnly?: boolean;
|
||||
open?: boolean;
|
||||
poll?: boolean | number;
|
||||
};
|
||||
|
||||
export async function start(
|
||||
siteDir: string,
|
||||
cliOptions: Partial<StartCLIOptions>,
|
||||
|
@ -39,7 +45,7 @@ export async function start(
|
|||
function loadSite() {
|
||||
return load({
|
||||
siteDir,
|
||||
customConfigFilePath: cliOptions.config,
|
||||
config: cliOptions.config,
|
||||
locale: cliOptions.locale,
|
||||
localizePath: undefined, // Should this be configurable?
|
||||
});
|
||||
|
@ -50,8 +56,7 @@ export async function start(
|
|||
|
||||
const protocol: string = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
|
||||
const host: string = getCLIOptionHost(cliOptions.host);
|
||||
const port: number | null = await getCLIOptionPort(cliOptions.port, host);
|
||||
const {host, port} = await getHostPort(cliOptions);
|
||||
|
||||
if (port === null) {
|
||||
process.exit();
|
||||
|
|
|
@ -11,14 +11,14 @@ import path from 'path';
|
|||
import _ from 'lodash';
|
||||
import {Globby, posixPath, THEME_PATH} from '@docusaurus/utils';
|
||||
import type {SwizzleAction, SwizzleComponentConfig} from '@docusaurus/types';
|
||||
import type {SwizzleOptions} from './common';
|
||||
import type {SwizzleCLIOptions} from './common';
|
||||
import {askSwizzleAction} from './prompts';
|
||||
|
||||
export const SwizzleActions: SwizzleAction[] = ['wrap', 'eject'];
|
||||
|
||||
export async function getAction(
|
||||
componentConfig: SwizzleComponentConfig,
|
||||
options: Pick<SwizzleOptions, 'wrap' | 'eject'>,
|
||||
options: Pick<SwizzleCLIOptions, 'wrap' | 'eject'>,
|
||||
): Promise<SwizzleAction> {
|
||||
if (options.wrap) {
|
||||
return 'wrap';
|
||||
|
|
|
@ -61,7 +61,7 @@ export type SwizzlePlugin = {
|
|||
|
||||
export type SwizzleContext = {plugins: SwizzlePlugin[]};
|
||||
|
||||
export type SwizzleOptions = {
|
||||
export type SwizzleCLIOptions = {
|
||||
typescript: boolean;
|
||||
danger: boolean;
|
||||
list: boolean;
|
||||
|
@ -70,8 +70,8 @@ export type SwizzleOptions = {
|
|||
};
|
||||
|
||||
export function normalizeOptions(
|
||||
options: Partial<SwizzleOptions>,
|
||||
): SwizzleOptions {
|
||||
options: Partial<SwizzleCLIOptions>,
|
||||
): SwizzleCLIOptions {
|
||||
return {
|
||||
typescript: options.typescript ?? false,
|
||||
danger: options.danger ?? false,
|
||||
|
|
|
@ -10,7 +10,7 @@ import {getThemeName, getThemePath, getThemeNames} from './themes';
|
|||
import {getThemeComponents, getComponentName} from './components';
|
||||
import {helpTables, themeComponentsTable} from './tables';
|
||||
import type {SwizzleAction, SwizzleComponentConfig} from '@docusaurus/types';
|
||||
import type {SwizzleOptions, SwizzlePlugin} from './common';
|
||||
import type {SwizzleCLIOptions, SwizzlePlugin} from './common';
|
||||
import {normalizeOptions} from './common';
|
||||
import type {ActionResult} from './actions';
|
||||
import {eject, getAction, wrap} from './actions';
|
||||
|
@ -25,7 +25,7 @@ async function listAllThemeComponents({
|
|||
}: {
|
||||
themeNames: string[];
|
||||
plugins: SwizzlePlugin[];
|
||||
typescript: SwizzleOptions['typescript'];
|
||||
typescript: SwizzleCLIOptions['typescript'];
|
||||
}) {
|
||||
const themeComponentsTables = (
|
||||
await Promise.all(
|
||||
|
@ -90,7 +90,7 @@ export async function swizzle(
|
|||
siteDir: string,
|
||||
themeNameParam: string | undefined,
|
||||
componentNameParam: string | undefined,
|
||||
optionsParam: Partial<SwizzleOptions>,
|
||||
optionsParam: Partial<SwizzleCLIOptions>,
|
||||
): Promise<void> {
|
||||
const options = normalizeOptions(optionsParam);
|
||||
const {list, danger, typescript} = options;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {ConfigOptions, InitializedPlugin} from '@docusaurus/types';
|
||||
import type {InitializedPlugin} from '@docusaurus/types';
|
||||
import path from 'path';
|
||||
import {loadContext} from '../server';
|
||||
import {loadContext, type LoadContextOptions} from '../server';
|
||||
import {initPlugins} from '../server/plugins/init';
|
||||
|
||||
import {
|
||||
|
@ -23,6 +23,12 @@ import {
|
|||
} from '../server/translations/translationsExtractor';
|
||||
import {getCustomBabelConfigFilePath, getBabelOptions} from '../webpack/utils';
|
||||
|
||||
export type WriteTranslationsCLIOptions = Pick<
|
||||
LoadContextOptions,
|
||||
'config' | 'locale'
|
||||
> &
|
||||
WriteTranslationsOptions;
|
||||
|
||||
/**
|
||||
* This is a hack, so that @docusaurus/theme-common translations are extracted!
|
||||
* A theme doesn't have a way to express that one of its dependency (like
|
||||
|
@ -74,13 +80,11 @@ async function writePluginTranslationFiles({
|
|||
|
||||
export async function writeTranslations(
|
||||
siteDir: string,
|
||||
options: Partial<
|
||||
WriteTranslationsOptions & ConfigOptions & {locale?: string}
|
||||
>,
|
||||
options: Partial<WriteTranslationsCLIOptions>,
|
||||
): Promise<void> {
|
||||
const context = await loadContext({
|
||||
siteDir,
|
||||
customConfigFilePath: options.config,
|
||||
config: options.config,
|
||||
locale: options.locale,
|
||||
});
|
||||
const plugins = await initPlugins(context);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import {execSync, type ExecSyncOptionsWithStringEncoding} from 'child_process';
|
||||
import detect from 'detect-port';
|
||||
import logger from '@docusaurus/logger';
|
||||
import {DEFAULT_PORT} from '@docusaurus/utils';
|
||||
import prompts from 'prompts';
|
||||
|
||||
const execOptions: ExecSyncOptionsWithStringEncoding = {
|
||||
|
@ -48,7 +49,7 @@ function getProcessForPort(port: number): string | null {
|
|||
* port is already being used. This feature was heavily inspired by
|
||||
* create-react-app and uses many of the same utility functions to implement it.
|
||||
*/
|
||||
export async function choosePort(
|
||||
async function choosePort(
|
||||
host: string,
|
||||
defaultPort: number,
|
||||
): Promise<number | null> {
|
||||
|
@ -85,3 +86,18 @@ Would you like to run the app on another port instead?`),
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export type HostPortOptions = {
|
||||
host?: string;
|
||||
port?: string;
|
||||
};
|
||||
|
||||
export async function getHostPort(options: HostPortOptions): Promise<{
|
||||
host: string;
|
||||
port: number | null;
|
||||
}> {
|
||||
const host = options.host ?? 'localhost';
|
||||
const basePort = options.port ? parseInt(options.port, 10) : DEFAULT_PORT;
|
||||
const port = await choosePort(host, basePort);
|
||||
return {host, port};
|
||||
}
|
|
@ -31,10 +31,10 @@ import type {DocusaurusConfig, LoadContext, Props} from '@docusaurus/types';
|
|||
export type LoadContextOptions = {
|
||||
/** Usually the CWD; can be overridden with command argument. */
|
||||
siteDir: string;
|
||||
/** Can be customized with `--out-dir` option */
|
||||
customOutDir?: string;
|
||||
/** Can be customized with `--config` option */
|
||||
customConfigFilePath?: string;
|
||||
/** Custom output directory. Can be customized with `--out-dir` option */
|
||||
outDir?: string;
|
||||
/** Custom config path. Can be customized with `--config` option */
|
||||
config?: string;
|
||||
/** Default is `i18n.defaultLocale` */
|
||||
locale?: string;
|
||||
/**
|
||||
|
@ -55,7 +55,12 @@ export type LoadContextOptions = {
|
|||
export async function loadContext(
|
||||
options: LoadContextOptions,
|
||||
): Promise<LoadContext> {
|
||||
const {siteDir, customOutDir, locale, customConfigFilePath} = options;
|
||||
const {
|
||||
siteDir,
|
||||
outDir: baseOutDir = DEFAULT_BUILD_DIR_NAME,
|
||||
locale,
|
||||
config: customConfigFilePath,
|
||||
} = options;
|
||||
const generatedFilesDir = path.resolve(siteDir, GENERATED_FILES_DIR_NAME);
|
||||
|
||||
const {siteConfig: initialSiteConfig, siteConfigPath} = await loadSiteConfig({
|
||||
|
@ -72,7 +77,7 @@ export async function loadContext(
|
|||
pathType: 'url',
|
||||
});
|
||||
const outDir = localizePath({
|
||||
path: path.resolve(siteDir, customOutDir ?? DEFAULT_BUILD_DIR_NAME),
|
||||
path: path.resolve(siteDir, baseOutDir),
|
||||
i18n,
|
||||
options,
|
||||
pathType: 'fs',
|
||||
|
|
|
@ -37,9 +37,7 @@ describe('initPlugins', () => {
|
|||
|
||||
it('throws user-friendly error message for plugins with bad values', async () => {
|
||||
await expect(() =>
|
||||
loadSite({
|
||||
customConfigFilePath: 'badPlugins.docusaurus.config.js',
|
||||
}),
|
||||
loadSite({config: 'badPlugins.docusaurus.config.js'}),
|
||||
).rejects.toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue