Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,14 @@
"watchpack"
],
"dictionaries": ["npm", "software-terms"],
"useGitignore": true,
"ignorePaths": [
"OPTIONS.md",
"SERVE-OPTIONS-v*.md",
"**/CHANGELOG.md",
"**/package.json",
"**/dist/**",
"**/__snapshots__/**",
"**/*.tsbuildinfo",
"**/*.png.tpl",
"**/package-lock.json",
"packages/*/lib/**",
"node_modules",
"coverage",
"*.log"
"**/package.json",
"**/package-lock.json"
]
}
11 changes: 1 addition & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 7 additions & 11 deletions packages/configtest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@ const WEBPACK_PACKAGE = process.env.WEBPACK_PACKAGE || "webpack";

class ConfigTestCommand {
async apply(cli: IWebpackCLI): Promise<void> {
await cli.makeCommand(
{
name: "configtest [config-path]",
alias: "t",
description: "Validate a webpack configuration.",
pkg: "@webpack-cli/configtest",
dependencies: [WEBPACK_PACKAGE],
},
[],
async (configPath: string | undefined): Promise<void> => {
await cli.makeCommand({
name: "configtest [config-path]",
alias: ["t"],
description: "Validate a webpack configuration.",
dependencies: [WEBPACK_PACKAGE],
async action(configPath: string | undefined): Promise<void> {
cli.webpack = await cli.loadWebpack();

const config = await cli.loadConfig(configPath ? { config: [configPath] } : {});
Expand Down Expand Up @@ -56,7 +52,7 @@ class ConfigTestCommand {

cli.logger.success("There are no validation errors in the given webpack configuration.");
},
);
});
}
}

Expand Down
18 changes: 7 additions & 11 deletions packages/info/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@ import { type IWebpackCLI } from "webpack-cli";

class InfoCommand {
async apply(cli: IWebpackCLI): Promise<void> {
await cli.makeCommand(
{
name: "info",
alias: "i",
description: "Outputs information about your system.",
usage: "[options]",
pkg: "@webpack-cli/info",
},
cli.getInfoOptions(),
async (options: { output: string; additionalPackage: string[] }) => {
await cli.makeCommand({
name: "info",
alias: ["i", "version", "v"],
description: "Outputs information about your system.",
options: cli.getInfoOptions().flatMap(cli.makeOption.bind(cli)),
async action(options: { output: string; additionalPackage: string[] }) {
const info = await cli.getInfoOutput(options);

cli.logger.raw(info);
},
);
});
}
}

Expand Down
70 changes: 20 additions & 50 deletions packages/serve/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,34 @@
import { type Compiler, type cli } from "webpack";
import { type IWebpackCLI, type StringsKeys, type WebpackDevServerOptions } from "webpack-cli";
import {
type IWebpackCLI,
type StringsKeys,
WebpackCLICommandOption,
type WebpackDevServerOptions,
} from "webpack-cli";

const WEBPACK_PACKAGE = process.env.WEBPACK_PACKAGE || "webpack";
const WEBPACK_DEV_SERVER_PACKAGE = process.env.WEBPACK_DEV_SERVER_PACKAGE || "webpack-dev-server";

type Problem = NonNullable<ReturnType<(typeof cli)["processArguments"]>>[0];

class ServeCommand {
async apply(cli: IWebpackCLI): Promise<void> {
const loadDevServerOptions = () => {
const devServer = require(WEBPACK_DEV_SERVER_PACKAGE);
async apply(cli: IWebpackCLI, options: WebpackCLICommandOption[]): Promise<void> {
const devServer = require(WEBPACK_DEV_SERVER_PACKAGE);

const devServerFlags = Object.entries(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const options: Record<string, any> = cli.webpack.cli.getArguments(devServer.schema);
// New options format
// { flag1: {}, flag2: {} }
return Object.keys(options).map((key) => {
options[key].name = key;

return options[key];
});
};

await cli.makeCommand(
{
name: "serve [entries...]",
alias: ["server", "s"],
description: "Run the webpack dev server and watch for source file changes while serving.",
usage: "[entries...] [options]",
pkg: "@webpack-cli/serve",
dependencies: [WEBPACK_PACKAGE, WEBPACK_DEV_SERVER_PACKAGE],
},
async () => {
let devServerFlags = [];

cli.webpack = await cli.loadWebpack();

try {
devServerFlags = loadDevServerOptions();
} catch (error) {
cli.logger.error(
`You need to install 'webpack-dev-server' for running 'webpack serve'.\n${error}`,
);
process.exit(2);
}

const builtInOptions = cli.getBuiltInOptions();

return [...builtInOptions, ...devServerFlags];
},
cli.webpack.cli.getArguments(devServer.schema) as Record<string, any>,
).map(([name, option]) => ({ name, ...option, group: "core", hidden: true }));

await cli.makeCommand({
name: "serve [entries...]",
alias: ["server", "s"],
description: "Run the webpack dev server and watch for source file changes while serving.",
options: [...options, ...devServerFlags.flatMap(cli.makeOption.bind(cli))],
dependencies: [WEBPACK_PACKAGE, WEBPACK_DEV_SERVER_PACKAGE],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async (entries: string[], options: any) => {
async action(entries: string[], options: any) {
const builtInOptions = cli.getBuiltInOptions();
let devServerFlags = [];

try {
devServerFlags = loadDevServerOptions();
} catch {
// Nothing, to prevent future updates
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const webpackCLIOptions: Record<string, any> = {};
Expand Down Expand Up @@ -243,7 +213,7 @@ class ServeCommand {
process.exit(2);
}
},
);
});
}
}

Expand Down
1 change: 0 additions & 1 deletion packages/webpack-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"commander": "^12.1.0",
"cross-spawn": "^7.0.6",
"envinfo": "^7.14.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^3.1.1",
"rechoir": "^0.8.0",
Expand Down
38 changes: 13 additions & 25 deletions packages/webpack-cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,8 @@ interface IWebpackCLI {
tryRequireThenImport<T = unknown>(module: ModuleName, handleError: boolean): Promise<T>;
getInfoOptions(): WebpackCLIBuiltInOption[];
getInfoOutput(options: { output: string; additionalPackage: string[] }): Promise<string>;
makeCommand(
commandOptions: WebpackCLIOptions,
options: WebpackCLICommandOptions,
action: CommandAction,
): Promise<WebpackCLICommand | undefined>;
makeOption(command: WebpackCLICommand, option: WebpackCLIBuiltInOption): void;
makeCommand(commandOptions: WebpackCLIOptions): Promise<WebpackCLICommand | undefined>;
makeOption(option: WebpackCLIBuiltInFlag): WebpackCLICommandOption[];
run(
args: Parameters<WebpackCLICommand["parseOptions"]>[0],
parseOptions?: ParseOptions,
Expand All @@ -80,6 +76,11 @@ interface IWebpackCLI {
runWebpack(options: WebpackRunOptions, isWatchCommand: boolean): Promise<void>;
}

declare interface WebpackCallback {
(err: null | Error, result?: Stats): void;
(err: null | Error, result?: MultiStats): void;
}

Comment on lines +79 to +83
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebpackCallback is declared twice in this file (once at lines 29-32 and again here at 79-82) with identical signatures. The duplicate declaration is redundant and can be confusing for maintainers; please remove one of them and keep a single definition that is exported as needed.

Suggested change
declare interface WebpackCallback {
(err: null | Error, result?: Stats): void;
(err: null | Error, result?: MultiStats): void;
}

Copilot uses AI. Check for mistakes.
interface WebpackCLIColors extends Colors {
isColorSupported: boolean;
}
Expand Down Expand Up @@ -118,18 +119,13 @@ type WebpackCLIMainOption = Pick<

interface WebpackCLIOptions extends CommandOptions {
name: string;
alias: string | string[];
description?: string;
usage?: string;
alias: string[];
description: string;
dependencies?: string[];
pkg?: string;
argsDescription?: Record<string, string>;
options?: Option[];
action: CommandAction;
}

type WebpackCLICommandOptions =
| WebpackCLIBuiltInOption[]
| (() => Promise<WebpackCLIBuiltInOption[]>);

interface WebpackCLIBuiltInFlag {
name: string;
alias?: string;
Expand All @@ -145,18 +141,13 @@ interface WebpackCLIBuiltInFlag {
describe?: string;
negatedDescription?: string;
defaultValue?: string;
helpLevel: "minimum" | "verbose";
hidden: boolean;
}

interface WebpackCLIBuiltInOption extends WebpackCLIBuiltInFlag {
hidden?: boolean;
group?: "core";
}

type WebpackCLIExternalCommandInfo = Pick<WebpackCLIOptions, "name" | "alias" | "description"> & {
pkg: string;
};

/**
* Webpack dev server
*/
Expand Down Expand Up @@ -254,7 +245,7 @@ type PotentialPromise<T> = T | Promise<T>;
type ModuleName = string;
type Path = string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type LogHandler = (value: any) => void;
type LogHandler = (value: any, raw?: boolean) => void;
type StringFormatter = (value: string) => string;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -313,7 +304,6 @@ export {
type CommandAction,
type CommanderOption,
type DynamicImport,
type EnumValue,
type FileSystemCacheOptions,
type IWebpackCLI,
type ImportLoaderError,
Expand All @@ -335,9 +325,7 @@ export {
type WebpackCLIColors,
type WebpackCLICommand,
type WebpackCLICommandOption,
type WebpackCLICommandOptions,
type WebpackCLIConfig,
type WebpackCLIExternalCommandInfo,
type WebpackCLILogger,
type WebpackCLIMainOption,
type WebpackCLIOptions,
Expand Down
Loading
Loading