Skip to content

Conversation

@avivkeller
Copy link
Member

Summary

This is still quite a big PR, but I do believe it's an improvement. This PR changes the webpack-cli.ts file to use Commander's help and unknownCommand handlers over the previous custom-implementation.

What kind of change does this PR introduce?

This PR introduces a CLI change in the Commander program.

Did you add tests for your changes?

Nothing substantial changed that required additional tests, but all previous tests pass.

Note that tests that tested features that are no handled internally were removed, as those are tested by Commander, and don't need to be tested by us.

Also note that the commander unknown command output is slightly different from the previous implementation, so a few snapshots have been changed, but seeing as it's just one stderr line, I don't think it's a breaking change.

Does this PR introduce a breaking change?

As mentioned above, this PR does not include any breaking changes to CLI. The only difference is a slightly different output when an invalid command is passed (Commander gives recommendations in ()), but that's not breaking.

Copilot AI review requested due to automatic review settings January 31, 2026 18:42
@avivkeller avivkeller requested a review from a team as a code owner January 31, 2026 18:42
@avivkeller avivkeller force-pushed the chore/commander-simplifications branch from f92627e to ad96398 Compare January 31, 2026 18:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the webpack CLI to rely on Commander’s built-in help, error handling, and unknown-command behavior instead of custom implementations, while simplifying option wiring across built-in and external commands.

Changes:

  • Rewrote WebpackCLI.run and related plumbing to construct commands/options via Commander primitives, using showHelpAfterError, exitOverride, and unknownCommand rather than custom help/validation logic.
  • Simplified makeCommand / makeOption APIs and types, and updated built-in commands (build, watch, serve, info, configtest) plus their tests and snapshots to match Commander’s output and suggestion formats.
  • Removed the custom help rendering path and the fastest-levenshtein dependency, tightened spell-check configuration, and updated tests/snapshots for help and unknown-command/option behavior.

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/webpack-cli/src/webpack-cli.ts Core refactor: configures Commander output/exit behavior, rebuilds built-in commands and options using makeCommand/makeOption, and hooks global --help / --version / color flags into Commander instead of custom parsing.
packages/webpack-cli/src/types.ts Updates CLI types to match the new makeCommand/makeOption contract, introduces WebpackCallback typing for compiler callbacks, and adjusts logger and option metadata types.
packages/webpack-cli/src/bootstrap.ts Simplifies CLI bootstrap to call cli.run(args) and adds a small helper to auto-run when invoked from an npm_lifecycle_script named tsx.
packages/webpack-cli/package.json Removes the fastest-levenshtein dependency now that Commander drives unknown-option suggestions.
packages/serve/src/index.ts Changes ServeCommand.apply to accept pre-built options, derive dev-server flags via cli.webpack.cli.getArguments, and register serve using the new makeCommand / makeOption flow.
packages/info/src/index.ts Registers info via makeCommand, wiring its options through cli.makeOption, and extends aliases to include version/v so these commands reuse the info implementation.
packages/configtest/src/index.ts Registers configtest via the new makeCommand API, leaving the validation logic intact but delegating CLI wiring to the shared helpers.
test/help/help.test.js Prunes now-redundant help tests and adjusts the remaining tests to assert equivalence between --help and help command syntax plus the new invalid --help=<value> behavior.
test/help/__snapshots__/help.test.js.snap.devServer5.webpack5 Updates help snapshots to match Commander’s default help layout and wording for the root and command-specific help output.
test/build/unknown/__snapshots__/unknown.test.js.snap.webpack5 Refreshes snapshots for unknown flags/commands to reflect Commander’s suggestion format and colorized stderr output.
test/build/basic/basic.test.js Updates expectations for unknown-command messaging (e.g., Unknown command 'buil' and new suggestion phrasing) consistent with Commander’s output.
test/api/CLI.test.js Reworks CLI API tests to use the new makeCommand/makeOption signatures, exercising a wide variety of option shapes/types against the refactored wiring.
test/api/__snapshots__/CLI.test.js.snap.webpack5 Removes the snapshot for the now-deleted custom help output, since help is delegated to Commander.
package-lock.json Syncs lockfile with dependency changes (notably removing fastest-levenshtein and marking a dependency as peer: true).
.cspell.json Tightens spell-check configuration, enabling useGitignore and simplifying ignore paths to avoid checking snapshots and package manifests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +179 to +182
warn: (val, raw) => log("warn", this.colors.red(util.format(val)), raw),
info: (val, raw) => log("info", this.colors.red(util.format(val)), raw),
success: (val, raw) => log("log", this.colors.red(util.format(val)), raw),
log: (val, raw) => log("error", this.colors.red(util.format(val)), raw),
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.

The new getLogger implementation appears to regress the log levels and output streams: warn, info, and success all use this.colors.red(...), and log delegates to log("error", ...), which routes messages to stderr. Previously these methods used different colors and log went to standard output, and other parts of the code (e.g. CLIPlugin.setupHelpfulOutput) expect logger.log to behave as a general info logger, not an error logger. Please restore distinct colors for warn/info/success and have log write to stdout (e.g. via console.log or the log branch of the helper), to avoid misclassified and mis-colored output.

Suggested change
warn: (val, raw) => log("warn", this.colors.red(util.format(val)), raw),
info: (val, raw) => log("info", this.colors.red(util.format(val)), raw),
success: (val, raw) => log("log", this.colors.red(util.format(val)), raw),
log: (val, raw) => log("error", this.colors.red(util.format(val)), raw),
warn: (val, raw) => log("warn", this.colors.yellow(util.format(val)), raw),
info: (val, raw) => log("info", this.colors.cyan(util.format(val)), raw),
success: (val, raw) => log("log", this.colors.green(util.format(val)), raw),
log: (val, raw) => log("log", this.colors.cyan(util.format(val)), raw),

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Why it was changed if you write - Commander's help and unknownCommand handlers? How logger related to these changes?

Comment on lines +79 to +83
declare interface WebpackCallback {
(err: null | Error, result?: Stats): void;
(err: null | Error, result?: MultiStats): void;
}

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.
@codecov
Copy link

codecov bot commented Jan 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.65%. Comparing base (feae23e) to head (9c127f3).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #4642   +/-   ##
=======================================
  Coverage   95.65%   95.65%           
=======================================
  Files           2        2           
  Lines          23       23           
  Branches        4        4           
=======================================
  Hits           22       22           
  Misses          1        1           

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update feae23e...9c127f3. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@avivkeller avivkeller marked this pull request as draft January 31, 2026 18:53
Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

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

A lot of unrelated changed, at lease split PRs into small steps (commits), we have stable CLI over a lot of year and I sorry I can't review this code because a lot of different changes mixed in the one PR

@alexander-akait
Copy link
Member

At least please make logical commits and we can read what and where and why was changed

makeOption(command: WebpackCLICommand, option: WebpackCLIBuiltInOption) {
let mainOption: WebpackCLIMainOption;
let negativeOption;
makeOption(option: WebpackCLIBuiltInOption): WebpackCLICommandOption[] {
Copy link
Member

@alexander-akait alexander-akait Feb 1, 2026

Choose a reason for hiding this comment

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

Why makeOption was changed? Again - it is only Commander's help and unknownCommand handlers

...builtInFlags,
...Object.entries(this.webpack.cli.getArguments()).map<WebpackCLIBuiltInOption>(
let coreOptions: WebpackCLIBuiltInOption[] = [];
if (this.webpack) {
Copy link
Member

Choose a reason for hiding this comment

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

We always have webpack here

if (builtInExternalCommandInfo) {
({ pkg } = builtInExternalCommandInfo);
} else {
pkg = commandName;
Copy link
Member

Choose a reason for hiding this comment

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

Again - please split help changes and sumcommand refactor into two PRs (and maybe even more)

@avivkeller
Copy link
Member Author

A lot of these changes are interconnected, but perhaps if it aint broken, there's no need to fix it.

@avivkeller avivkeller closed this Feb 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants