Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migrate to commander #1481

Merged
merged 44 commits into from
Apr 25, 2020
Merged

Conversation

knagaitsev
Copy link
Contributor

@knagaitsev knagaitsev commented Apr 18, 2020

What kind of change does this PR introduce?

refactor

Did you add tests for your changes?

Yes, updating tests

If relevant, did you update the documentation?

No

Summary

Picking up from #1347

Looking to get this done so we can move forward with webpack-cli serve.

Does this PR introduce a breaking change?

Breaking changes to adapt to the norms of commander:

  • An argument that expects a string will throw an error if one is not provided (e.g. webpack-cli --output will throw an error because output expects a string value following it)
  • In the case of our --mode and --no-mode arguments, the --no-mode argument actually functions in commander to set the --mode argument to false. Therefore, we can check if --no-mode has been set by checking if opts.mode === false. The quirk here is that if both are used, the one that comes last takes precedence. So if a user does --mode production --no-mode, then mode will be false, but if the user does --no-mode --mode production, mode will be production.

Other information

@knagaitsev
Copy link
Contributor Author

/cc @evilebottnawi

@alexander-akait
Copy link
Member

So if a user does --mode production --no-mode, then mode will be false, but if the user does --no-mode --mode production, mode will be production.

Maybe we should throw an error? I think we should not support multiple same arguments for mode (and for some other arguments)

@@ -27,8 +27,8 @@
"@webpack-cli/info": "^1.0.1-alpha.4",
"ansi-escapes": "^4.3.1",
"chalk": "^3.0.0",
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.0",
Copy link
Member

Choose a reason for hiding this comment

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

I think we don't need that package too

Copy link
Contributor Author

@knagaitsev knagaitsev Apr 21, 2020

Choose a reason for hiding this comment

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

@evilebottnawi Good you pointed that out, we actually still rely on it for webpack-cli help. It still functions correctly, since we didn't change the cli-flags object format at all. I think it is fine actually to continue using it as it formats nicely and we can keep our current CLI flags object format is it is so that it continues to work with command-line-usage.

The alternative is to start using the built in commander help, we would just need to do some work making the output look nicer. Here is the difference:

Current webpack-cli help output using command-line-usage:

webpack-cli-usage-help

commander help:

webpack-cli-commander-help

Copy link
Member

Choose a reason for hiding this comment

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

@Loonride Do we have API from commander for customize help output?

Copy link
Member

@jamesgeorge007 jamesgeorge007 Apr 21, 2020

Choose a reason for hiding this comment

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

Do we have API from commander for customize help output?

Yes indeed, https://github.com/tj/commander.js#custom-help

const devServerArgs = cli.commandLineArgs(devServer, { argv: args, partial: true });
const webpackArgs = cli.commandLineArgs(core, { argv: devServerArgs._unknown || [], stopAtFirstUnknown: false });
const finalArgs = argsToCamelCase(devServerArgs._all || {});
const filteredArgs = process.argv.filter((arg) => arg != 'serve');
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can implement API method on webpack-cli side, like getFlagsForCommand('serve') and it is remove unnecessary argv?

Copy link
Member

Choose a reason for hiding this comment

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

Will be great to avoid working with argv on command side and process on command side. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

actually this is not needed, it seems the filtered args are already passed into the serve command and I just wasn't aware of it

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.

Good job, I think we should improve some places

@rishabh3112
Copy link
Member

Maybe we should throw an error? I think we should not support multiple same arguments for mode (and for some other arguments)

Instead of error we should display warning. We should complete user's interaction where ever we can.

@alexander-akait
Copy link
Member

@rishabh3112 hm, other CLI programs always throw an error on invalid arguments, but I am ok with warning

@rishabh3112
Copy link
Member

@evilebottnawi My point of view on this (sharing to validate my thinking as I might be wrong):
In this case we don't have invalid arguments, instead we we have dilemma which of the two same flags takes precedence. This can be resolved with a logical decision.
But yes, Many CLIs (including legacy ones) throw error in this case. But I think throwing error in this case is bad for DX, when we can logically imply what user wants to do and warn user with decision we took and what assumptions we took to make this decision.

@knagaitsev
Copy link
Contributor Author

knagaitsev commented Apr 20, 2020

My personal opinion (feel free to disagree) is that we shouldn't have the --no-mode argument. It was introduced recently as described here: #1240

  • The same thing can already be done with --mode none
  • --no-argument generally implies to me that the argument is a boolean and you are switching it off
  • It adds ambiguities like if the user is doing --mode production --no-mode which need to be dealt with
  • commander doesn't support parse by telling us that --no-mode was provided so we would have to do our own parsing to see if the user has provided --mode and --no-mode (it simply sets --mode to false). Search for --no-cheese in here to see the behavior: https://github.com/tj/commander.js/

Edit: anyway for now I think I should just add the warning, and we can consider doing this for a later PR

@knagaitsev
Copy link
Contributor Author

knagaitsev commented Apr 21, 2020

Notes about commander:

  • it seems if you want to negate a boolean flag with --no- it has to actually be added as an option along with the original boolean flag
  • there is no negating of a boolean via --flag=false, though you can set string flags with --flag=value.

TODO:

  • figure out how to handle negated flags for booleans
  • fix resolveNegatedArgs in bootstrap
  • add warning if user includes both --mode and --no-mode
  • add getFlagsForCommand('serve') and related tests (no longer needed)
  • add tests to show --flag=value works
  • add tests for negated boolean flags and warnings related to them
  • add tests for arg-parser

What will be done in future PRs:

@alexander-akait
Copy link
Member

@Loonride

#1481 (comment)

Agree, let's remove --no-mode support 👍 We can do it after migration.

#1481 (comment)

Good job!

@knagaitsev
Copy link
Contributor Author

/cc @Loonride Couple questions

@evilebottnawi all done

Copy link
Member

@rishabh3112 rishabh3112 left a comment

Choose a reason for hiding this comment

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

Left a suggestion for a typo.

});
}

// Use customised help output is avaliable
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Use customised help output is avaliable
// Use customised help output if avaliable

});
}

// Use customised help output is avaliable
Copy link
Member

@snitin315 snitin315 Apr 24, 2020

Choose a reason for hiding this comment

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

Suggested change
// Use customised help output is avaliable
// Use customised help output if available

@@ -48,7 +48,8 @@ describe('stats flag', () => {
it('should warn when an unknown flag stats value is passed', () => {
const { stderr, stdout } = run(__dirname, ['--stats', 'foo']);
expect(stderr).toBeTruthy();
expect(stderr).toContain('No value recognised for "stats" option');
console.log(stderr);
Copy link
Member

Choose a reason for hiding this comment

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

Unnecessary log.

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.

/cc @webpack/cli-team let's merge it 🎉

@webpack-bot
Copy link

@jamesgeorge007 Thanks for your update.

I labeled the Pull Request so reviewers will review it again.

@evilebottnawi Please review the new changes.

@alexander-akait
Copy link
Member

/cc @jamesgeorge007

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants