UNPKG

11.6 kBMarkdownView Raw
1# HappyPack [![Build Status](https://travis-ci.org/amireh/happypack.svg?branch=master)](https://travis-ci.org/amireh/happypack) [![codecov.io](https://codecov.io/github/amireh/happypack/coverage.svg?branch=master)](https://codecov.io/github/amireh/happypack?branch=master)
2
3HappyPack makes initial webpack builds faster by transforming files [in
4parallel](#how-it-works).
5
6> **Maintenance mode notice**
7>
8> My interest in the project is fading away mainly because I'm not using
9> JavaScript as much as I was in the past. Additionally, Webpack's native
10> performance is improving and (I hope) it will soon make this plugin
11> unnecessary.
12>
13> See the FAQ entry about Webpack 4 and [thread-loader][thread-loader].
14>
15> Contributions are always welcome. Changes I make from this point will be
16> restricted to bug-fixing. If someone wants to take over, feel free to get
17> in touch.
18>
19> Thanks to everyone who used the library, contributed to it and helped in
20> refining it!!!
21
22## Usage
23
24```shell
25npm install --save-dev happypack
26```
27
28HappyPack provides both a plugin and a loader in order to do its job so you
29must use both to enable it.
30
31Normally, you define loader rules to tell webpack how to process certain files.
32With HappyPack, you switch things around so that you pass the loaders to
33HappyPack's plugin and instead tell webpack to use `happypack/loader`.
34
35Below is a sample configuration that shows those steps in action.
36
37```javascript
38// @file: webpack.config.js
39const HappyPack = require('happypack');
40
41exports.module = {
42 rules: [
43 {
44 test: /.js$/,
45 // 1) replace your original list of loaders with "happypack/loader":
46 // loaders: [ 'babel-loader?presets[]=es2015' ],
47 use: 'happypack/loader',
48 include: [ /* ... */ ],
49 exclude: [ /* ... */ ]
50 }
51 ]
52};
53
54exports.plugins = [
55 // 2) create the plugin:
56 new HappyPack({
57 // 3) re-add the loaders you replaced above in #1:
58 loaders: [ 'babel-loader?presets[]=es2015' ]
59 })
60];
61```
62
63That's it. Now sources that match `.js$` will be handed off to HappyPack which
64will transform them in parallel using the loaders you specified (`babel-loader`
65in this example.)
66
67## Configuration
68
69These are the parameters you can pass to the plugin when you instantiate it.
70`loaders` is the only required parameter.
71
72### `loaders: Array`
73
74Each entry consists of the name (or absolute path) of the loader that
75would transform the files and an optional query string to pass to it. This
76looks similar to what you'd pass to webpack's `loader` config.
77
78> **Heads up!**
79>
80> HappyPack doesn't work with *all* webpack loaders as some loader API are not
81> supported.
82>
83> See [this wiki page](https://github.com/amireh/happypack/wiki/Webpack-Loader-API-Support) for more details on current Loader API support.
84
85The following notations are officially supported and are all equivalent:
86
87```javascript
88{
89 loaders: [
90 // a string with embedded query for options
91 'babel-loader?presets[]=es2015',
92
93 {
94 loader: 'babel-loader'
95 },
96
97 // "query" string
98 {
99 loader: 'babel-loader',
100 query: '?presets[]=es2015'
101 },
102
103 // "query" object
104 {
105 loader: 'babel-loader',
106 query: {
107 presets: [ 'es2015' ]
108 }
109 },
110
111 // Webpack 2+ "options" object instead of "query"
112 {
113 loader: 'babel-loader',
114 options: {
115 presets: [ 'es2015' ]
116 }
117 }
118 ]
119}
120```
121
122### `id: String`
123
124A unique id for this happy plugin. This is used by the loader to know which
125plugin it's supposed to talk to.
126
127Normally, you would not need to specify this unless you have more than one
128HappyPack plugin defined, in which case you'll need distinct IDs to tell them
129apart. See [this section](#using-multiple-instances) for more information.
130
131Defaults to: `"1"`
132
133### `threads: Number`
134
135This number indicates how many Node VMs HappyPack will spawn for compiling
136the source files. After a lot of tinkering, I found 4 to yield the best
137results. There's certainly a diminishing return on this value and increasing
138beyond 8 actually slowed things down for me.
139
140Keep in mind that this is only relevant when performing **the initial build**
141as HappyPack will switch into a synchronous mode afterwards (i.e. in `watch`
142mode.)
143
144Defaults to: `3`
145
146### `threadPool: HappyThreadPool`
147
148A pre-defined thread-pool to use for retrieving worker threads. Normally, this
149is managed internally by each `HappyPlugin` instance, but you may override
150this behavior for better results.
151
152[The section on thread pools](#shared-thread-pools) explains how and when to
153use this.
154
155Defaults to: `null`
156
157### `verbose: Boolean`
158
159Enable this to log status messages from HappyPack to STDOUT like start-up
160banner, etc..
161
162Defaults to: `true`
163
164### `verboseWhenProfiling: Boolean`
165
166Enable this if you want HappyPack to still produce its output even when you're
167doing a `webpack --profile` run. Since this variable was introduced, HappyPack
168will be silent when doing a profile build in order not to corrupt any JSON
169output by webpack (i.e. when using `--json` as well.)
170
171Defaults to: `false`
172
173### `debug: Boolean`
174
175Enable this to log diagnostic messages from HappyPack to STDOUT. Useful for
176troubleshooting.
177
178Defaults to: `false`
179
180## How it works
181
182![A diagram showing the flow between HappyPack's components](doc/HappyPack_Workflow.png)
183
184HappyPack sits between webpack and your primary source files (like JS sources)
185where the bulk of loader transformations happen. Every time webpack resolves a
186module, HappyPack will take it and all its dependencies and distributes those
187files to multiple worker "threads".
188
189Those threads are actually simple node processes that invoke your transformer.
190When the compiled version is retrieved, HappyPack serves it to its loader and
191eventually your chunk.
192
193## Using multiple instances
194
195It's possible to define multiple HappyPack plugins for different types of
196sources/transformations. Just pass in a unique id for each plugin and make
197sure you pass it their loaders. For example:
198
199```javascript
200// @file webpack.config.js
201exports.plugins = [
202 new HappyPack({
203 id: 'jsx',
204 threads: 4,
205 loaders: [ 'babel-loader' ]
206 }),
207
208 new HappyPack({
209 id: 'styles',
210 threads: 2,
211 loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
212 })
213];
214
215exports.module.rules = [
216 {
217 test: /\.js$/,
218 use: 'happypack/loader?id=jsx'
219 },
220
221 {
222 test: /\.less$/,
223 use: 'happypack/loader?id=styles'
224 },
225]
226```
227
228Now `.js` files will be handled by the first Happy plugin which will use
229`babel-loader` to transform them, while `.less` files will be handled
230by the second one using the style loaders.
231
232## Shared thread pools
233
234Normally, each HappyPack plugin you create internally creates its own threads
235which are used to run the loaders. However, if you're using more than one
236HappyPack plugin it can be more optimal to create a thread pool yourself and
237then configure the plugins to share that pool, minimizing the idle time of
238threads within it.
239
240Here's an example of using a custom pool of 5 threads that will be shared
241between loaders for both JS and SCSS/LESS/whatever sources:
242
243```javascript
244// @file: webpack.config.js
245var HappyPack = require('happypack');
246var happyThreadPool = HappyPack.ThreadPool({ size: 5 });
247
248module.exports = {
249 // ...
250 plugins: [
251 new HappyPack({
252 id: 'js',
253 threadPool: happyThreadPool,
254 loaders: [ 'babel-loader' ]
255 }),
256
257 new HappyPack({
258 id: 'styles',
259 threadPool: happyThreadPool,
260 loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
261 })
262 ]
263};
264```
265
266## Benchmarks
267
268For the main repository I tested on, which had around 3067 modules, the build time went down from 39 seconds to a whopping ~10 seconds.
269
270Here's a rundown of the various states the build was performed in:
271
272Elapsed (ms) | Happy? | Using DLLs? |
273------------ | ------- | ----------- |
27439851 | NO | NO |
27537393 | NO | YES |
27614605 | YES | NO |
27713925 | YES | NO |
27811877 | YES | NO |
2799228 | YES | YES |
280
281The builds above were run under Linux on a machine with 12 cores.
282
283## Changes
284
285See [./CHANGELOG.md](./CHANGELOG.md).
286
287## FAQ
288
289### Does it work with Webpack 2 & 3?
290
291Yes. You should use version >= 4.0.1 (of HappyPack).
292
293### Is it necessary for Webpack 4?
294
295Short answer: _maybe_ not.
296
297Long answer: there's now a competing add-on in the form of a _loader_ for
298processing files in multiple threads, exactly what HappyPack does. The fact
299that it's a loader and not a plugin (or both, in case of H.P.) makes it much
300simpler to configure. Look at [thread-loader][thread-loader] and if it works
301for you - that's great, otherwise you can try HappyPack and see which fares
302better for you.
303
304YMMV.
305
306### Does it work with TypeScript?
307
308The short answer is: yes, it finally does! The longer answer is that you need
309to use [ts-loader](https://github.com/TypeStrong/ts-loader) in
310"transpiling-only" mode then use the special plugin [fork-ts-checker-notifier-webpack-plugin](https://github.com/johnnyreilly/fork-ts-checker-notifier-webpack-plugin) to perform static type checking.
311
312More information can be found in the [ts-loader "happypack mode" section](https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse) and you can refer to the [example](./examples/ts-loader) that shows this in action.
313
314Big thanks to @johnnyreilly, @aindlq, @piotr-oles, @abergs and many others for
315making this work.
316
317### Does it work with loader XYZ?
318
319We're keeping track of loader support in [this wiki page](https://github.com/amireh/happypack/wiki/Loader-Compatibility-List). Some loaders may require
320extra configuration to make them work.
321
322If the loader you're trying to use isn't listed there, you can refer to [this](https://github.com/amireh/happypack/wiki/Webpack-Loader-API-Support) wiki page
323to see which loader APIs are supported. If your loader uses any API that is NOT
324supported, chances are that it will not work with HappyPack.
325
326As a general rule, any loader that accepts "functions" in options will not work
327unless it also accepts reading those options from a file, like babel-loader
328does with `.babelrc` and postcss-loader too.
329
330### Does it work under Windows?
331
332Yes, as of version 4.0.0 it should. If you come across issues using the plugin
333on Windows, feel free to open a ticket.
334
335## Development
336
337See [HACKING.md](./HACKING.md).
338
339## License (MIT)
340
341Copyright (c) <2015-2017> <ahmad@amireh.net>
342
343Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
344
345The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
346
347THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
348
349[thread-loader]: https://github.com/webpack-contrib/thread-loader