webpack / webpack-cli

Webpack's Command Line Interface
https://webpack.js.org/api/cli
MIT License
2.56k stars 603 forks source link

Scoping: A typical webpack-addon-[name] package #42

Closed evenstensberg closed 7 years ago

evenstensberg commented 7 years ago

1. Discuss how we want to generate needed rules in a webpack-addon package

2. Discuss what to expected returned from an addons package for our transformer to run

3. Discuss on if we should allow .babelrc and such, to also be generated

4. Come up with an example of an webpack-addon

TheLarkInn commented 7 years ago

I'm going to ping @developit and @addyosmani so they can help mold the user (addon author) and consumer (addon user) api and functionality.

Below I'll list what I think feels like a great "user" surface api, and describe maybe a workflow.

Hypothetical "Addon Author Dream Workflow"

@developit is the maintainer of Preact and using webpack makes it trivial for his users to transition from react. But he also has a few boilerplates for initial setups (beyond a react=>preact) migrate that he recommends to people and would love to make the process easier and better adoption through a webpack addon.

Hi imagines a user could simply do: npm install webpack && webpack --init webpack-addon-preact and the user would be prompted with any information they would like to know. (Maybe he could even extend the webpack-addon-react as well: another story).

Addon Project Creation

Creates a new project locally and runs: npm install webpack-addon, $(npm bin)/webpack-addon --init. This would create a best practice recommendation setup for a webpack addon. Including package.json configuration, the correct tags, and prompts @developit for the right information about his addon (name, email, etc similar to npm init). In addition he also has keywords, metadata and special fields that will let webpack users and our org track and list all webpack-addon packages on npm that have been published with this specific metadata.

Addon defaults, node api, and addon customization

The webpack-addon repo comes with a "base" set of inquirer questions, and config out of the box. The webpack-addon lib has convenience api's for:

Now all that @Developit has to do is specify the packages he'd like the user to have by default, prompt the user for additional "preact-friendly" libs based on questions, and maybe custom webpack config that he can map the AST transform to a inquirer question.

He could even pull in a set of webpack-addon.mixins for "best-practice" styling, performance, "PWA" :hot:, etc. configs that could be composed together as well.

Addon deployment

From there webpack-addon-preact can be published simply by running webpack-addon publish [minor|major|patch]. This will publish to npm given that his user is already logged in and he has permissions.

TheLarkInn commented 7 years ago

This is just one idea, and maybe we can take pieces, start with a few items and go from there.

eliperelman commented 7 years ago

For the project and file generation, this should be easily doable from a Yeoman generator. This does raise some questions:

  1. Is a webpack config going to be generated at init-time? Does this mean that the precedence of addons is set in stone at init?
  2. Does this config just contain a merge of all the addon packages?
  3. If the user wants to override the config, does this mean they miss out on future updates to addons?
  4. Does the user need to re-run the tool in order to get updates from certain addons?
  5. Addon Dependencies: are they dependencies of the project (peerDependencies), or dependencies of the addon?

Speaking from the perspective of the Neutrino CLI which does the tool part (no project generation), an addon maps to a Neutrino preset. Here is how we addressed these questions:

  1. There is no initial configuration at project initialization, rather just a collection of one or more presets passed to Webpack which is a merge of all preset configuration. Precedence is set by the order specified either on the command line (--presets) or package.json (config.presets).
  2. Yes, all presets are merged together into a single configuration.
  3. Overriding configuration is orthogonal to updating packages; they can be done separately.
  4. Neutrino does not handle dependency updates, this is left to them by their project tool (npm or Yarn). Getting an updated preset will still keep local overrides.
  5. Dependencies of a preset stay with the preset. For example, neutrino-preset-react depends on eslint-plugin-react, which the project doesn't need to worry about maintaining. The project would still need to manage their own deps for React and ReactDOM, etc.

If you'd like to know more about how Neutrino tackled some of these issues, feel free to ask. I hope the work we've done so far can shed some light and help you with the webpack-cli tool. :smiley:

Links, for reference:

https://github.com/mozilla-neutrino/neutrino-dev https://neutrino.js.org/

evenstensberg commented 7 years ago

@TheLarkInn This is pretty rad. From engineer perspective we could do with webpack-addons ( the overhead for creating an addon) :

  1. Link a walkthrough of package creation through ./bin
  2. Have the functionality/utility for package creation in the same package

This would allow the user to both get a walkthrough of the addon creation as well as the actual functions/utils to use.

Including package.json configuration, the correct tags, and prompts @developit for the right information about his addon (name, email, etc similar to npm init). In addition he also has keywords, metadata and special fields that will let webpack users and our org track and list all webpack-addon packages on npm that have been published with this specific metadata.

This would be a bit outside the CLI scope, but the idea to send the metadata for us to track is great for organizational purposes, I'm +1 to that.

With the extend feature, I was thinking abit about using webpack-addons-mypackage for what it's worth. If you do something like

module.exports = {
....
childDep: ['webpack-addons-preact', 'webpack-addons-hot']
}

we could extend the base config in that way.

By default I think that the module layering, because of this is pretty convenient. If you specify overRideRules: true or for an rule in a addon:

module.exports = {
...
overRideRules: ['entry']
childDep: ['webpack-addons-preact', 'webpack-addons-hot']
}

you care about that rule for that package, and similar for other packages. By default, the overhead package should have the most importance, so if overRideRules gets called in a childDep, you ignore it.

My concern is getting to edge use cases like react-transform in a webpack config. When we have to deal with custom logic in a webpack config. I imagine we can let the user create a module in their addon, such as webpack-addons-transform

module.exports = {
...
module: require('./template.js')
}

with template literals and then we use that module as an injection instead of us generating it, except we only care about the logic outside the config.

template.js

Don't care about the code so much, just the idea of people expressing their code in various ways
module.exports = (c) => {
return(
`
  const path = require('path');
  const webpack = require('webpack');
  const CleanPlugin = require('clean-webpack-plugin');
  const ExtractTextPlugin = require('extract-text-webpack-plugin');
  const projectRootPath = path.resolve(__dirname, '../');
  const assetsPath = path.resolve(projectRootPath, './${c}');
  // https://github.com/halt-hammerzeit/webpack-isomorphic-tools
  const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
  const webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require('./webpack-isomorphic-tools'));
`
)
}

webpack-addons-something

Inject template at line 40 with the template given. (Readline is unstable, could need to use ASTs here too if it works. c in this case is getting answered in a inq prompt
module.exports = {
config: {
 injection: [40, c]
}
}

@eliperelman @TheLarkInn I think I touched some of your concerns too, feel free to reply if I forgot something. Keep in mind, we're adding -add later, so we could just add loaders etc on the fly for a config, so -init majorly is targeted to get a beginner-to-go approach using inquirer.

For the examples, I think you'll need some prerequisites.

Right now, we're doing just two things in webpack-addons-package:

module.exports = {
 Inquirer: Input(....),
 config: {
    entry,
    output
  }
}

The question type in inquirer must match the name of the config object in order for us to validate it. I imagine we can support various of variables later, but we need to define how webpack-addons works in specific before adding more functionality.

My main concern is to support edge cases while the tool is simple. Generally I'd like webpack-addons-mypackage to be so easily created as if my sister at 5 could make one. Yeoman, in my eyes makes it hard to just go in, write some really basic stuff and then feel like a superhero.

This means that we should focus on the user, inquirer, meta-programming and generalistic needs, but supporting advanced stuff like code injection as shown before.

Also, @TheLarkInn we should publish the webpack-addons somewhere now, so we have somewhere people can discuss it? webpack or webpack-contrib ?

eliperelman commented 7 years ago

@ev1stensberg my comment about Yeoman was more about using it internally, as it has a nice mapping of Inquirer prompts to file generation flow. You can use it programmatically without requiring the user to install yeoman, yo, or anything else. Pure webpack-cli.

For overrides, I think the default should be that local configuration always overrides addon configuration. By passing a parameter that says which fields addons override from local, how do you resolve the case of multiple addons overriding the same field? Last-in-wins?

evenstensberg commented 7 years ago

@eliperelman I'll have a look at it, was discussed when starting to work on this tool.

First in wins for childDep packages and first one in for initing with multiple addons. ...-init webpack-addons-1 webpack-addons-2 means number 1 gets first prio if it has override rules, could add a flag to specify that number 2 should be first prio in userland too, like --init webpack-addons-1 webpack-addons-2 --override=2 or something.

Have you accepted the invite for the cli slack?

eliperelman commented 7 years ago

@ev1stensberg yep! I'm in there.

addyosmani commented 7 years ago

Fwiw, https://github.com/yeoman/generator can help quite a lot with building out scaffolding support for community templates and has some nice helpers on top of inquirer as @eliperelman notes.

We use this type of setup internally at Google for a few projects and externally in projects like the polymer-cli, where you get to enable the add-on workflows described above without end-users needing to think about yo, yeoman etc. It's pretty transparent.

Over in Polymer, we implemented polymer init <template name> where anyone in the community can publish such templates to npm list and easily pull them in.

It sounds like Eli has you covered on Yeoman internals, but if any of us on the Yeoman side (including @sboudrias, @sindresorhus, @silvenon) can help, feel free to holler 👋

evenstensberg commented 7 years ago

@addyosmani Could you get someone from Polymer involved in this thread? These features are relative to our CLI. Would be great to suck out information from one of them guys, so we can build ours as great as possible!

evenstensberg commented 7 years ago

Update: childDependencies is up to the authors, using this.ComposeWith. Injections may be a trick for some use cases, but in the end, we gotta resolve through AST's in init, so we might as well try to use it there as well.

evenstensberg commented 7 years ago

Resolved for now in #105, closing.