Skip to content

Commit 054aa7a

Browse files
authored
Merge pull request #379 from kalcifer/pluginsapi/intro
Plugins api docs
2 parents 4582874 + 1a4b047 commit 054aa7a

File tree

4 files changed

+175
-33
lines changed

4 files changed

+175
-33
lines changed

content/concepts/plugins.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ They also serve the purpose of doing **anything else** that a [loader](/concepts
1414

1515
A webpack **plugin** is a JavaScript object that has an `apply` property. This `apply` property is called by the webpack compiler, giving access to the **entire** compilation lifecycle.
1616

17-
1817
**ConsoleLogOnBuildWebpackPlugin.js**
1918

2019
```javascript

content/pluginsapi/compiler.md

Lines changed: 92 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,116 @@ title: Compiler
33
sort: 2
44
---
55

6-
## Compiler
6+
The `Compiler` module of webpack is the main engine that creates a compilation instance with all the options passed through webpack CLI or `webpack` api or webpack comfiguration file.
77

8-
## Watching
9-
10-
## MultiCompiler
11-
12-
## Event Hooks
8+
It is exported by `webpack` api under `webpack.Compiler`.
139

14-
`environment()`
10+
The compiler is used by webpack by instantiating it and then calling the `run` method. Below is a trivial example of how one might use the `Compiler`. In fact, this is very close to how webpack itself uses it.
1511

16-
`after-environment()`
12+
[__compiler-example__](https://github.com/pksjce/webpack-internal-examples/blob/master/compiler-example.js)
1713

18-
`before-run(compiler: Compiler, callback)`
14+
```javascript
15+
// Can be imported from webpack package
16+
import {Compiler} from 'webpack';
1917

20-
`run(callback)`
18+
// Create a new compiler instance
19+
const compiler = new Compiler();
2120

22-
`watch-run(watching: Watching, callback)`
21+
// Populate all required options
22+
compiler.options = {...};
2323

24-
`normal-module-factory(normalModuleFactory: NormalModuleFactory)`
24+
// Creating a plugin.
25+
class LogPlugin {
26+
apply (compiler) {
27+
compiler.plugin('should-emit', compilation => {
28+
console.log('should i emit?');
29+
return true;
30+
})
31+
}
32+
}
2533

26-
`context-module-factory(contextModuleFactory: ContextModuleFactory)`
34+
// Apply the compiler to the plugin
35+
new LogPlugin().apply(compiler);
2736

28-
`compilation(compilation: Compilation, params: Object)`
37+
/* Add other supporting plugins */
2938

30-
`this-compilation(compilation: Compilation, params: Object)`
39+
// Callback to be executed after run is complete
40+
const callback = (err, stats) => {
41+
console.log('Compiler has finished execution.');
42+
/* Do something to show the stats */
43+
};
3144

32-
`after-plugins(compiler: Compiler)`
45+
// call run on the compiler along with the callback
46+
compiler.run(callback);
47+
```
3348

34-
`after-resolvers(compiler: Compiler)`
49+
The `Compiler` is what we call a `Tapable` instance. By this, we mean that it mixes in `Tapable` class to imbibe functionality to register and call plugins on itself.
50+
Most user facing plugins are first registered on the `Compiler`.
51+
The working of a Compiler can be condensed into the following highlights
52+
- Usually there is one master instance of Compiler. Child compilers can be created for delegating specific tasks.
53+
- A lot of the complexity in creating a compiler goes into populating all the relevant options for it.
54+
- `webpack` has [`WebpackOptionsDefaulter`](https://github.com/webpack/webpack/blob/master/lib/WebpackOptionsDefaulter.js) and [`WebpackOptionsApply`](https://github.com/webpack/webpack/blob/master/lib/WebpackOptionsApply.js) specifically designed to provide the `Compiler` with all the intial data it requires.
55+
- The `Compiler` is just ultimately just a function which performs bare minimum functionality to keep a lifecycle running. It delegates all the loading/bundling/writing work to various plugins.
56+
- `new LogPlugin(args).apply(compiler)` registers the plugin to any particular hook event in the `Compiler`'s lifecycle.
57+
- The `Compiler` exposes a `run` method which kickstarts all compilation work for `webpack`. When that is done, it should call the passed in `callback` function. All the tail end work of logging stats and errors are done in this callback function.
3558

36-
`should-emit(compilation: Compilation)`
59+
## Watching
3760

38-
`emit(compilation: Compilation, callback)`
61+
However, the `Compiler` supports two flavors of execution. One on watch mode and one on a normal single run.
62+
While it essentially performs the same functionality while watching, there are some additions to the lifecycle events. This allows `webpack` to have Watch specific plugins.
3963

40-
`after-emit(compilation: Compilation, callback)`
64+
## MultiCompiler
4165

42-
`done(stats: Stats)`
66+
This module, MultiCompiler, allows webpack to run multiple configurations in separate compiler.
67+
If the `options` parameter in the webpack's NodeJS api is an array of options, webpack applies separate compilers and calls the `callback` method at the end of each compiler execution.
4368

44-
`additional-pass(callback)`
69+
```javascript
70+
var webpack = require('webpack');
4571

46-
`failed(err: Error)`
72+
var config1 = {
73+
entry: './index1.js',
74+
output: {filename: 'bundle1.js'}
75+
}
76+
var config2 = {
77+
entry: './index2.js',
78+
output: {filename:'bundle2.js'}
79+
}
4780

48-
`invalid(fileName: string, changeTime)`
81+
webpack([config1, config2], (err, stats) => {
82+
process.stdout.write(stats.toString() + "\n");
83+
})
84+
```
4985

50-
`entry-option(context, entry)`
86+
## Event Hooks
5187

52-
## Examples
88+
This a reference guide to all the event hooks exposed by the `Compiler`.
89+
90+
| Event name | Reason | Params | Type |
91+
|----------------------------|-------------------------------------|----------------------|------------|
92+
| __`entry-option`__ | - | - | bailResult |
93+
| __`after-plugins`__ | After setting up initial set of plugins | `compiler` | sync |
94+
| __`after-resolvers`__ | After setting up the resolvers | `compiler` | sync |
95+
| __`environment`__ | - | - | sync |
96+
| __`after-environment`__ | Environment setup complete | - | sync |
97+
| __`before-run`__ | `compiler.run()` starts | `compiler` | async |
98+
| __`run`__ | Before reading records | `compiler` | async |
99+
| __`watch-run`__ | Before starting compilation after watch | `compiler` | async |
100+
| __`normal-module-factory`__ | After creating a `NormalModuleFactory` | `normalModuleFactory`| sync |
101+
| __`context-module-factory`__ | After creating a `ContextModuleFactory` | `contextModuleFactory`| sync |
102+
| __`before-compile`__ | Compilation parameters created | `compilationParams`` | sync |
103+
| __`compile`__ | Before creating new compilation | `compilationParams` | sync |
104+
| __`this-compilation`__ | Before emitting `compilation` event | `compilation` | sync |
105+
| __`compilation`__ | Compilation creation completed | `compilation` | sync |
106+
| __`make`__ | | `compilation` | parallel |
107+
| __`after-compile`__ | | `compilation` | async |
108+
| __`should-emit`__ | Can return true/false at this point | `compilation` | bailResult |
109+
| __`need-additional-pass`__ | | - | bailResult |
110+
| __`emit`__ | Before writing emitted assets to output dir | `compilation` | async |
111+
| __`after-emit`__ | After writing emitted assets to output dir | `compilation` | async |
112+
| __`done`__ | Completion of compile | `stats` | sync |
113+
| __`fail`__ | Failure of compile | `error` | sync |
114+
| __`invalid`__ | After invalidating a watch compile | `fileName`, `changeTime` | sync |
115+
116+
## Examples
117+
118+
?> TODO: Adds examples of usage for some of the above events

content/pluginsapi/index.md

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,89 @@ title: Plugins API
33
sort: 1
44
---
55

6+
webpack provides flexible and powerful customization api in the form of plugins. Using plugins, we can plug functionality into webpack. Additionally, webpack provides lifecycle hooks into which plugins can be registered. At each of these lifecycle points, webpack will run all of the registered plugins and provide them with the current state of the webpack compilation.
7+
68
## Tapable & Tapable instances
7-
**Tapable Instances** are classes in the webpack source code which have been extended or mixed in from class `Tapable`.
9+
10+
The plugin architecture is mainly possible for webpack due to an internal library named `Tapable`.
11+
**Tapable Instances** are classes in the webpack source code which have been extended or mixed in from class `Tapable`.
12+
13+
For plugin authors, it is important to know which are the `Tapable` instances in the webpack source code. These instances provide a variety of event hooks into which custom plugins can be attached.
14+
Hence, throughout this section are a list of all of the webpack `Tapable` instances (and their event hooks), which plugin authors can utilize.
15+
816
For more information on `Tapable` visit the [tapable repository](https://github.com/webpack/tapable) or visit the [complete overview](./tapable)
917

10-
Throughout this section are a list of all of the webpack Tapable instances (and their event hooks), which plugin authors can utilize.
18+
## Creating a Plugin
19+
20+
A plugin for `webpack` consists of
21+
22+
- A named JavaScript function.
23+
- Defines `apply` method in it's prototype.
24+
- Specifies webpack's event hook to attach itself.
25+
- Manipulates webpack internal instance specific data.
26+
- Invokes webpack provided callback after functionality is complete.
27+
28+
```javascript
29+
// A named JavaScript function.
30+
function MyExampleWebpackPlugin() {
31+
32+
};
33+
34+
// Defines `apply` method in it's prototype.
35+
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
36+
// Specifies webpack's event hook to attach itself.
37+
compiler.plugin('webpacksEventHook', function(compilation /* Manipulates webpack internal instance specific data. */, callback) {
38+
console.log("This is an example plugin!!!");
39+
40+
// Invokes webpack provided callback after functionality is complete.
41+
callback();
42+
});
43+
};
44+
```
45+
46+
### Different Plugin Shapes
47+
48+
A plugin can be classified into types based on the event it is registered to. Every event hook decides how it is going to apply the plugins in its registry.
49+
50+
- __synchronous__ The Tapable instance applies plugins using
51+
52+
`applyPlugins(name: string, args: any...)`
53+
54+
`applyPluginsBailResult(name: string, args: any...)`
55+
56+
This means that each of the plugin callbacks will be invoked one after the other with the specific `args`.
57+
This is the simplest format for a plugin. Many useful events like `"compile"`, `"this-compilation"` expect plugins to have synchronous execution.
58+
59+
- __waterfall__ Plugins applied using
60+
61+
`applyPluginsWaterfall(name: string, init: any, args: any...)`
62+
63+
Here each of the plugins are called one after the other with the args from the return value of the previous plugin. The plugin must take into consider the order of its execution.
64+
It must accept arguments from the previous plugin that was executed. The value for the first plugin is `init`. This pattern is used in the Tapable instances which are related to the `webpack` templates like `ModuleTemplate`, `ChunkTemplate` etc.
65+
66+
- __asynchronous__ When all the plugins are applied asynchronously using
67+
68+
`applyPluginsAsync(name: string, args: any..., callback: (err?: Error) -> void)`
69+
70+
The plugin handler functions are called with all args and a callback function with the signature `(err?: Error) -> void`. The hander functions are called in order of registration.`callback` is called after all the handlers are called.
71+
This is also a commonly used pattern for events like `"emit"`, `"run"`.
72+
73+
- __async waterfall__ The plugins will be applied asynchronously in the waterfall manner.
74+
75+
`applyPluginsAsyncWaterfall(name: string, init: any, callback: (err: Error, result: any) -> void)`
76+
77+
The plugin handler functions are called with the current value and a callback function with the signature `(err: Error, nextValue: any) -> void.` When called `nextValue` is the current value for the next handler. The current value for the first handler is `init`. After all handlers are applied, callback is called with the last value. If any handler passes a value for `err`, the callback is called with this error and no more handlers are called.
78+
This plugin pattern is expected for events like `"before-resolve"` and `"after-resolve"`.
79+
80+
- __async series__ It is the same as asynchronous but if any of the plugins registered fails, then no more plugins are called.
81+
82+
`applyPluginsAsyncSeries(name: string, args: any..., callback: (err: Error, result: any) -> void)`
83+
84+
-__parallel__ -
85+
86+
`applyPluginsParallel(name: string, args: any..., callback: (err?: Error) -> void)`
87+
88+
`applyPluginsParallelBailResult(name: string, args: any..., callback: (err: Error, result: any) -> void)`
89+
1190

12-
## Creating a Plugins
1391

14-
### Different Plugin Shapes

content/pluginsapi/tapable.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ However, in addition to this, `Tapable` allows you to have access to the "emitte
1616
* `plugin(name:string, handler:function)` - This allows a custom plugin to register into a **Tapable instance**'s event.
1717
This acts as the same as `on()` of `EventEmitter`, for registering a handler/listener to do something when the signal/event happens.
1818

19-
* `apply(...pluginInstances: (AnyPlugin|function)[])` - `AnyPlugin` should be subclass of [AbstractPlugin](https://github.com/webpack/webpack/blob/master/lib/AbstractPlugin.js), or a class (or object, rare case) has an `apply` method, or just a function with some registration code inside.
19+
* `apply(pluginInstances: (AnyPlugin|function)[])` - `AnyPlugin` should be subclass of [AbstractPlugin](https://github.com/webpack/webpack/blob/master/lib/AbstractPlugin.js), or a class (or object, rare case) has an `apply` method, or just a function with some registration code inside.
2020
This method is just to **apply** plugins' definition, so that the real event listeners can be registered into the **Tapable instance**'s registry.
2121

22-
* `applyPlugins*(name:string, ...)` - The **Tapable instance** can apply all the plugins under a particular hash using these functions.
22+
* `applyPlugins*(name:string, )` - The **Tapable instance** can apply all the plugins under a particular hash using these functions.
2323
These group of method act like `emit()` of `EventEmitter`, to control the event emission meticulously with various strategy for various use cases.
2424

2525
* `mixin(pt: Object)` - a simple method to extend `Tapable`'s prototype as a mixin rather than inheritance.

0 commit comments

Comments
 (0)