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

Develop - Plugin API - Tapable: The Building Blocks #36

Closed
TheLarkInn opened this issue Jul 10, 2016 · 8 comments
Closed

Develop - Plugin API - Tapable: The Building Blocks #36

TheLarkInn opened this issue Jul 10, 2016 · 8 comments

Comments

@TheLarkInn
Copy link
Member

WIP

@pksjce
Copy link

pksjce commented Jul 12, 2016

Tapable is small module that allows you to add and apply plugins to a javascript module. It can be inherited or mixed in to other modules.

Provides two kind of functions

  • plugin(name,handler) - This function registers a plugin under a hash of name.
  • apply*(...) - The consumer can apply all the plugins under a particular hash using these functions.

The different apply functions cover the following use cases -

  • Plugins can run serially
  • Plugins can run in parallel
  • Plugins can run one after the other but taking input from the previous plugin (waterfall)
  • Plugins can run asynchronously

For eg - Webpack has something called a Compiler, which compiles all the webpack config and converts it into a compilation instance. When the compilation instance runs, it creates the required bundles.

Now Compiler needs to register and execute plugins on itself. It may do this in the following manner using Tapable

var Tapable = require("tapable");
function Compiler() {
    Tapable.call(this);
}
Compiler.prototype = Object.create(Tapable.prototype);

Now to write a plugin on the compiler,

compiler.plugin('emit', pluginFunction);

The compiler executes the plugin at the appropriate point in its lifecycle by

this.apply*("emit",options) // will fetch all plugins under 'emit' name and run them.

@TheLarkInn
Copy link
Member Author

TheLarkInn commented Jul 13, 2016

Awesome start @pksjce !!!! Id love To see What other consumers do webpack provide. Maybe even mentioning that this is a fundamental piece of webpacks functionality. Love what you have so far.

@pksjce
Copy link

pksjce commented Jul 13, 2016

Thanks for the feedback! How about something like.

Tapable is fundamental to the working of webpack. This is because all the moving components of webpack like Compilation, Compile, Parser use this to push all its side effects to plugins. Webpack is structured such that its internal modules read the configuration, and define a lifecycle. The lifecycle or state machine expects different behaviour from the plugin, some require aysnc runs, parallel runs or waterfall (like middleware) kind of runs. [this will need a diagram. I have something in mind, will update when done] One can register plugins at every checkpoint in the lifecycle. When the module component(ie like Compiler) changes its state, it invokes the registered plugins with appropriate state parameters through Tapable integration.

The whole of webpack runs as a set of state machines along with all logic pushed to internal Plugins. This framework allows webpack to be very flexible. One can achieve almost any transformation on the build files at any of the numerous lifecycle points by registering a plugin at the right lifecycle event.

@e-cloud
Copy link

e-cloud commented Sep 22, 2016

One thing is missing -- the apply method of the Tapable class.

And the explanation is a little misleading:

Provides two kind of functions

  • plugin(name,handler) - This function registers a plugin under a hash of name.
  • apply*(...) - The consumer can apply all the plugins under a particular hash using these functions.

@pksjce , i borrow some concepts from yours. Here is another version of my understanding:

Tapable is a variant of EventEmitter conceptually.

It doesn't have full implementation as the EventEmitter in node.js. It just focuses on event emission manipulation.

Basically, it has four groups of member functions:

  • plugin(name:string, handler:function) - This function registers a plugin under a hash of name.
    This acts as the same as on() of EventEmitter, for registering a handler/listener to do something when the signal/event happens.
  • apply(...pluginInstances: (AnyPlugin|function)[]) - AnyPlugin should be subclass of AbstractPlugin, or a class (or object, rare case) has apply method, or just a function with some registration code inside(also rare case, never seen, but works theoretically) .
    This method is just to apply plugins' definition, so that the real event listeners can be registered into registry. Mostly the apply method of a AnyPlugin is the main place to place extension logic.
  • applyPlugins*(name:string, ...) - The consumer can apply all the plugins under a particular hash using these functions.
    These group of method act like emit() of EventEmitter, to control the event emission meticulously with various strategy for various use cases.
  • mixin(pt: Object) - a simple method to extend Tapable's prototype. Only for highly customization. Rarely used.

The different applyPlugins* methods cover the following use cases:

  • Plugins can run serially
  • Plugins can run in parallel
  • Plugins can run one after the other but taking input from the previous plugin (waterfall)
  • Plugins can run asynchronously
  • Quit runing th plugins on bail: that is once one plugin returns non-undefined, jump out of the run flow and return the return of that plugin. This sounds like once() of EventEmitter but is totally different.

@bebraw
Copy link
Contributor

bebraw commented Sep 22, 2016

Could someone aggregate the ideas of this thread into a PR? Good to review there.

@TheLarkInn
Copy link
Member Author

Wow it had been awhile since I had reviewed this content I'll start adding this to my pr this week.

@TheLarkInn
Copy link
Member Author

TheLarkInn commented Nov 18, 2016

Alright created a new set of documents #361 This should allow us once merged to tackle individual tapable instances etc.

dear-lizhihua added a commit to docschina/webpack.js.org that referenced this issue Jan 8, 2017
@skipjack
Copy link
Collaborator

It seems this is complete with the /content/api/plugins pages which include a tapable page. If there's anything left it probably tackled with more targeted issues/prs. One thing we do need to do is make this section more visible (i.e. the only way to get to it now is from the /api/index.md link but that can be addressed in #438, #1153 and #980.

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

No branches or pull requests

5 participants