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

Better API or docs #1

Closed
ai opened this issue Jan 30, 2016 · 81 comments
Closed

Better API or docs #1

ai opened this issue Jan 30, 2016 · 81 comments

Comments

@ai
Copy link
Member

ai commented Jan 30, 2016

Let’s think how we make CLI better.

@corysimmons
Copy link
Contributor

@hawkrives seemed to have the best idea. @hawkrives care to put your proposed syntax in here?

@corysimmons
Copy link
Contributor

@ai If we rewrite this from scratch does this need to be a fork? Looks funny.

@hawkrives
Copy link

Oh, uh, I'll go look for my proposal. Was it in the old repo somewhere?

@hawkrives
Copy link

Found it.

TL;DR: postcss -p autoprefixer input.css > output.css and postcss -p [ autoprefixer -b "browsers" ] input.css > output.css, using subarg.

For other references, check out Browserify: browserify -t [ babelify --experimental ] -e input.js > output.js

Browserify gets all the arguments outside of the square brackets, and passes the ones inside to the invoked command.

The arguments are parsed into something like:

  • Browserify
    • -e input.js
    • -t
      • babelify
        • --experimental

Substack pulled the subarg parsing into its own package, at subarg.

An example for PostCSS would probably look something like postcss -p [ autoprefixer -b "browsers" ] input.css > output.css

Note that if you don't want to pass any args to the plugin, you dont need the brackets: postcss -p autoprefixer input.css > output.css

@hawkrives
Copy link

and/or other proposal:

postcss [-p plugin]] [some input files] [-o output-file] [--out-dir dir]

  • Any number of plugins, each with its own -p .
  • Each plugin can be either just a name, like autoprefixer, or it can pass options with subarg, like [autoprefixer --no-remove].
  • Any number of input files
    • If you give one input file, and no output, it'll write to stdout
    • If you give -o with one input file, it writes to that file
    • If you give multiple inputs, and no --out-dir, it'll overwrite the input files
    • If you give --out-dir with multiple input files, it'll write the corresponding files to the specified directory

I took --out-dir from Babel's cli.

@corysimmons
Copy link
Contributor

@hawkrives Thanks. How would multiple plugin options work?

For instance, what if I wanted to pass browsers: last 2 versions and remove: false with Autoprefixer?

@hawkrives
Copy link

Probably something like postcss -p [autoprefixer --browsers="last 2 versions" --no-remove] input.css, which would result in the autoprefixer plugin getting {browsers: 'last 2 versions', remove: false} as options.

(subarg and therefore minimist treat --no-arg and --arg=false the same, returning {arg: false} either way.)

@corysimmons
Copy link
Contributor

Gotcha. I think I like the plugin name on the outside of the brackets a bit better.

postcss -p [autoprefixer --browsers="last 2 versions" --no-remove] -p [cssnano --safe --sourcemap] -p postcss-cssnext input.css
postcss -p autoprefixer [--browsers="last 2 versions" --no-remove] -p cssnano [--safe --sourcemap] -p postcss-cssnext input.css

I'm also not sure I like the arrow.

postcss input.css > output.css
postcss input.css -o output.css

Thoughts?

Sidenote: I've been using Browserify all night to get more familiar with it's syntax. I can't help but to think there are a lot of brackets and curly braces involved.

"transform": [["babelify", { "presets": ["es2015"] }]] <- this is a real thing I hope postcss-cli can avoid.

@corysimmons
Copy link
Contributor

Anyone have any special feelings about https://github.com/sindresorhus/meow ? Looks pretty kewl to me. 💯

@TrySound
Copy link
Member

@corysimmons meow does not allow to use file config, only field from package.json. We have https://github.com/davidtheclark/cosmiconfig for such cases.

@corysimmons
Copy link
Contributor

We can use the two together right?

@TrySound
Copy link
Member

Hm.. yep, right.

@corysimmons
Copy link
Contributor

💯

@vincentorback
Copy link

Adding value of false to the output option should not write to any file: -o false.
This would be great if you just want to parse CSS for eg. linting.

@vitorgalvao
Copy link

I'm also not sure I like the arrow.

That’s standard unix redirection, so it makes sense for it to be there, you can’t really take it out.

Adding value of false to the output option should not write to any file: -o false.

Why complicate? Just behave like any other *nix tool.

I’m pretty sure what @hawkrives meant was for it to behave akin to curl. If you don’t specify an output, it’ll just output to STDOUT (i.e. show on the terminal). If you give it > file_name, it’ll write to file_name instead of being shown on the terminal. -o file_name would behave exactly the same as > file_name, but -o needs to be built into the tool, while > will just work by default, since it’s your shell doing the work, there.

@davidtheclark
Copy link

Yeah, we need to follow these CLI conventions that allow for piping, redirection, etc.

@hawkrives
Copy link

@corysimmons: @vitorgalvao has it right. I've been thinking that if you give it one input file, and no -o flag, it'll just print the processed file to stdout, where you can redirect it with your shell's redirection (usually >). This allows the famed unix composability, like postcss -p autoprefixer input.css | wc -c (counts the number of characters [or bytes] in the processed file.)

@corysimmons: About the braces: Babel (and babelify) has developed a lot of configurability with its latest release. And I was thinking that we could just use the subarg library to split up the options, which uses the first word inside the square brackets to denote the name of the … argument group, I guess we'd call it.

@corysimmons
Copy link
Contributor

Arrow is cool then. 👍

https://github.com/substack/subarg/blob/master/index.js seems pretty straightforward and hasn't been updated in years. We could make something similar and change the syntax from -p [foo options] to -p foo [options], then fork Meow and use it instead of just standard Minimist. Just a matter of what syntax everyone prefers.

Even if we use the -p [foo options] syntax and untouched subarg, we could fork Meow and add subarg instead of just minimist? It provides lots of sugar. (edit: I opened an issue with Meow to pass in custom minimist parsers or at least replace minimist with subarg)

In fact, I really don't care about the -p foo [options] syntax that much. It does look better imo, but people are already used to the Browserify syntax so that might be a bonus. I dunno, @ai whatcha think?

@corysimmons
Copy link
Contributor

@hawkrives Whatcha think?

@ai
Copy link
Member Author

ai commented Feb 2, 2016

BTW, we can move current API.md to some kind of JSDoc into JS sources.

@hawkrives
Copy link

wait, did I not reply last night? whoops.

@corysimmons:

  • I'm pretty sure it'll be simpler to parse the options with the plugin name inside of the square brackets.
  • I'm not married to using subarg, it's just that it exists already, if that makes sense?

@hawkrives
Copy link

and minimist is actually pretty powerful by itself: you can do automatic booleans and pass nested objects as args.

(live example: https://tonicdev.com/hawkrives/56b0cc8b65d8fc0c00633ef6)

-p 1 --no-power --nested.object.key --no-nested.object.value

{
  "_": [],
  "p": 1,
  "power": false,
  "nested": {
    "object": {
      "key": true,
      "value": false
    }
  }
}

@hawkrives
Copy link

But maybe we should figure out how we want it to look before we go bikeshedding on argument parsers 😜

@corysimmons
Copy link
Contributor

But maybe we should figure out how we want it to look before we go bikeshedding on argument parsers

💯

I still like cli -p plugin [--option1=foo --option2=bar] -w in.css > out.css. Just waiting on a couple other people to chime in.

@ben-eb
Copy link
Member

ben-eb commented Feb 2, 2016

I don't like the above, it's ambiguous. command line arguments should be in the form of a key value pair, or a boolean flag. A command line tool should not have to rely on the arguments order for option parsing as that syntax does.

Personally I use minimist which handles nested options well, as @hawkrives wrote. I don't see the point of reinventing the wheel for arguments parsing here, as a good range of solutions for this exist already.

@corysimmons
Copy link
Contributor

I'm all about minimist as it makes our job (and my desire to use Meow) that much easier. I'm just personally not a fan of that syntax. I dunno, can someone show me a minimist cmd that might include 2 or 3 postcss plugins with a few options assigned to each one? Like a real world command?

@corysimmons
Copy link
Contributor

@davidtheclark 99% of the time, people will be using configs instead of trying to config everything from the CLI. No one is saying we shouldn't heavily promote this approach. I'm just suggesting that we try to make the CLI as flexible as possible so we can support as many use cases as possible.

No CLI supports passing functions as args. People still make CLI's that accept args...

Sometimes, you just want to try something without setting up an entire config, and I find that really annoying to do with Webpack. I usually end up falling back to Browserify, actually, which lets you configure far more from the command line.

This a million times over. I don't want to configure something to play around with something... Anytime I make a semi-serious project (something I'm gonna be working on for more than 30 minutes) I configure it. Otherwise forcing people to configure something is a PITA.

@Siilwyn
Copy link

Siilwyn commented Feb 3, 2016

Finally had the time to read through this all. I think @davidtheclark brings the most sensible valid points to the table. Loading the configuration in the form of JavaScript enables for powerful options that can not be done in JSON on top of that this will work with all plugins.

We shouldn't reinvent the CLI but users should be able to configure the plugins by only using the CLI as far as that is possible in my opinion.

Also if we're passing multiple plugins with the same configuration flags wouldn't that cause issues? And thus mean we need to get the flags in a 'nested' form to prevent this problem?

@corysimmons
Copy link
Contributor

We shouldn't reinvent the CLI but users should be able to configure the plugins by only using the CLI as far as that is possible in my opinion.

I think everyone except @davidtheclark agrees with this so we should move forward and just make sure to thoroughly document that a config file is the preferred method.

Also if we're passing multiple plugins with the same configuration flags wouldn't that cause issues? And thus mean we need to get the flags in a 'nested' form to prevent this problem?

@hawkrives @ben-eb I think we're leaning towards minimist. Is this true for minimist?

@hawkrives
Copy link

Like, postcss -p autoprefixer --browsers '> 1%' -p cssnano ---browsers '> 1%'?

Stock minimist gives us this, because it groups same-named arguments into arrays.

{
  "_": ["input.css"],
  "p": [
    "autoprefixer",
    "cssnano"
  ],
  "browsers": [
    "> 1%",
    "> 1%"
  ],
  "o": "output.css"
}

This is kinda what subarg is designed for:

postcss -p [autoprefixer --browsers '> 1%'] -p [cssnano --browsers '> 1%'] input.css -o output.css

The brackets give let it know what key to associate the extra options with.

{
  "_": ["input.css"],
  "p": [
    {
      "_": ["autoprefixer"],
      "browsers": "> 1%"
    },
    {
      "_": ["cssnano"],
      "browsers": "> 1%"
    }
  ],
  "o": "output.css"
}

Does that answer your question, @corysimmons?

Edit: Live example again: https://tonicdev.com/hawkrives/56b26488414a7c0c0012b301

@corysimmons
Copy link
Contributor

Yeah thanks @hawkrives

I agree with @ben-eb that minimist looks best, but minimist just doesn't seem capable of passing plugin options in a robust way.

Maybe we should go back to not worrying about what tool we're gonna use and just focus on the API. Once we get that we can make a tool.

So can we all agree on this syntax?

postcss -p autoprefixer --browsers '> 1%' --no-remove -p cssnano --browsers '> 1%' in.css > out.css

If so, I think we can fix minimist to match

{
  "_": ["input.css"],
  "p": [
    "autoprefixer", <--- this
    "cssnano" <--- that
  ],
  "browsers": [
    "> 1%", <--- this
    "> 1%" <--- that
  ],
  "o": "output.css"
}

@hawkrives
Copy link

Minimist looks nicer, I'll agree, but I really like the unambiguousness of the Subarg syntax.

@corysimmons
Copy link
Contributor

lol, dammit, now I'm back to thinking postcss -p foo [--option1 'foo' --option2 'bar'] input.css > output.css is the best syntax... :(

(sorry I just really don't like the plugin name being inside the brackets for some reason...)

@corysimmons
Copy link
Contributor

We're back to #1 (comment)

@ai Read over this thread and pick one so we can move forward. 💃

@ai
Copy link
Member Author

ai commented Feb 12, 2016

@corysimmons ha-ha :) this question is too tricky. Right now I am thinking too that -p foo [--option1 'foo' --option2 'bar'] is the best. But it is soooo wierd.

@corysimmons
Copy link
Contributor

@sindresorhus thinks we should:

postcss --plugin="autoprefixer:{browsers: 'last 2', remove: 'false'}"

sindresorhus/meow#30 (comment)

Not sure how I feel about it. On one hand, json-like syntax is pretty easy to parse. On the other hand, where does it stop? Do 2 plugins look like: postcss --plugins="autoprefixer:{browsers: 'last 2', remove: 'false'}, lost:{flexbox 'flex', gutter: '60px'}"

Anyone like that?

@sindresorhus
Copy link

Do 2 plugins look like: postcss --plugins="autoprefixer:{browsers: 'last 2', remove: 'false'}, lost:{flexbox 'flex', gutter: '60px'}"

No:

postcss --plugin="autoprefixer:{browsers: 'last 2', remove: 'false'}" --plugin="something:{foo: 'bar'}"

Alternatively:

postcss --plugin-autoprefixer="browsers: 'last 2', remove: false" --plugin-something="foo: 'bar'"

Which I think I prefer.

@vitorgalvao
Copy link

I’m in agreement with @sindresorhus, for one simple important reason: clarity. I remember fighting with a tool (perhaps it was postcss-cli, even) some time ago while trying to figure out how to convert the examples in the a plugin pages to actual -- commands (don’t remember the actual issue, perhaps there were nested commands, or something).

I’m a heavy CLI user and build a lot of (mostly) bash and ruby scripts with flags. Even though -- flags make sense and are familiar, in this case we’re passing options to other tools and at some point it just becomes confusing.

Take this autoprefixer example. With @sindresorhus’ suggestion, it’d be trivial to convert. No need to transform their options into -- flags, just copy and paste the example as is in the correct place.

From the two examples, I think I prefer the first, but any of them seems like an improvement over the alternatives.

@corysimmons
Copy link
Contributor

postcss --plugin-autoprefixer="browsers: 'last 2', remove: false" --plugin-something="foo: 'bar'" I like that.

@ai Objections?

Also, is anyone considering stepping up to dev this?

@sindresorhus
Copy link

And as commented in sindresorhus/meow#30 (comment), you can use levn to parse the value.

@rafaelrinaldi
Copy link

Thinking about submitting a PR with improved instructions on the use of a configuration JSON (instead of CLI arguments). It was kinda tricky for me at first and some people at work also got confused by it.

@ai Thoughts?

@corysimmons
Copy link
Contributor

It'd be nice if we exposed config files to all 3 standard config types as well as CLI args: https://github.com/davidtheclark/cosmiconfig

@corysimmons
Copy link
Contributor

@ai Can you finalize this so someone can move forward?

@RyanZim
Copy link
Collaborator

RyanZim commented Sep 9, 2016

@ai ping?

@ai
Copy link
Member Author

ai commented Sep 9, 2016

@RyanZim I don’t use this project, so my thoughts will not be useful :)

@ai
Copy link
Member Author

ai commented Sep 9, 2016

But, right now I am thinking about having one common config for any PostCSS runner: https://github.com/michael-ciniawsky/postcss-load-plugins and https://github.com/michael-ciniawsky/postcss-load-config

I think CLI also should use that common config.

@watilde
Copy link
Member

watilde commented Sep 9, 2016

Personally, I agreed on this #1 (comment) and also I'd like to update all the cli option as well at the same time, like a breaking change.

@michael-ciniawsky
Copy link
Contributor

👋

--env|e

postcss --env|e  production
{
  "name": "css",
  "main": "postcss.config.js",
  "scripts": {
    "css:prod": "NODE_ENV=production postcss -o dest/index.css src/index.css",
    "css:dev": "NODE_ENV=development postcss -o dest/index.css src/index.css",
  },
}

--help|h

postcss --help|h  $plugin

npm home $plugin > npm repo $plugin > README.md (e.g github-man)

--bundle|b

postcss -p sugarss -u [postcss-import --option foo --option bar] ...
postcss --bundle|b $name

postcss-config-boilerplate

|–index.js (postcss.config.js)
|-package.json
|-README.md

package.json

{
  "name": "postcss-config-[name]",
  "main": "index.js",
  "postcss": {
    "parser": "sugarss",
    "plugins": {
      "postcss-import": { option: 'foo', option: 'bar' }
    }
  },
  "dependencies": {
     "postcss-import": "^8.1.2"
  }
}

index.js (postcss.config.js)

const options = require('package.json').postcss
const plugins = require('package.json').postcss.plugins

module.exports = (ctx) => {
  parser: ctx.parser || options.parser
  plugins: {
     'postcss-import': ctx.import || plugins['postcss-import']
     ...
  }
}

@thomasklein
Copy link

Hi guys! Any news on using cosmiconfig?

@RyanZim
Copy link
Collaborator

RyanZim commented Jan 5, 2017

@thomasklein Right now, we are working on postcss-cli v3. That is a complete rewrite that will use https://github.com/michael-ciniawsky/postcss-load-config, which uses cosmiconfig under the hood. See https://github.com/postcss/postcss-cli/projects/1 for more details and progress updates.

@RyanZim
Copy link
Collaborator

RyanZim commented Mar 20, 2017

v3.0.0 is out, so going to say that fixes this issue. https://github.com/postcss/postcss-cli/releases/tag/v3.0.0

Please open new issues for anything that you think could be improved. Thanks for all the brainstorming here!

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

No branches or pull requests