Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

happypack

amireh122.4kMIT5.0.1TypeScript support: definitely-typed

webpack speed booster, makes you happy!

webpack, plugin, fast, speed, performance, compilation, transformer, loader, happiness, happy

readme

HappyPack Build Status codecov.io

HappyPack makes initial webpack builds faster by transforming files in parallel.

Maintenance mode notice

My interest in the project is fading away mainly because I'm not using JavaScript as much as I was in the past. Additionally, Webpack's native performance is improving and (I hope) it will soon make this plugin unnecessary.

See the FAQ entry about Webpack 4 and thread-loader.

Contributions are always welcome. Changes I make from this point will be restricted to bug-fixing. If someone wants to take over, feel free to get in touch.

Thanks to everyone who used the library, contributed to it and helped in refining it!!!

Usage

npm install --save-dev happypack

HappyPack provides both a plugin and a loader in order to do its job so you must use both to enable it.

Normally, you define loader rules to tell webpack how to process certain files. With HappyPack, you switch things around so that you pass the loaders to HappyPack's plugin and instead tell webpack to use happypack/loader.

Below is a sample configuration that shows those steps in action.

// @file: webpack.config.js
const HappyPack = require('happypack');

exports.module = {
  rules: [
    {
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: 'happypack/loader',
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    }
  ]
};

exports.plugins = [
  // 2) create the plugin:
  new HappyPack({
    // 3) re-add the loaders you replaced above in #1:
    loaders: [ 'babel-loader?presets[]=es2015' ]
  })
];

That's it. Now sources that match .js$ will be handed off to HappyPack which will transform them in parallel using the loaders you specified (babel-loader in this example.)

Configuration

These are the parameters you can pass to the plugin when you instantiate it. loaders is the only required parameter.

loaders: Array

Each entry consists of the name (or absolute path) of the loader that would transform the files and an optional query string to pass to it. This looks similar to what you'd pass to webpack's loader config.

Heads up!

HappyPack doesn't work with all webpack loaders as some loader API are not supported.

See this wiki page for more details on current Loader API support.

The following notations are officially supported and are all equivalent:

{
  loaders: [
    // a string with embedded query for options
    'babel-loader?presets[]=es2015',

    {
      loader: 'babel-loader'
    },

    // "query" string
    {
      loader: 'babel-loader',
      query:  '?presets[]=es2015'
    },

    // "query" object
    {
      loader: 'babel-loader',
      query: {
        presets: [ 'es2015' ]
      }
    },

    // Webpack 2+ "options" object instead of "query"
    {
      loader: 'babel-loader',
      options: {
        presets: [ 'es2015' ]
      }
    }
  ]
}

id: String

A unique id for this happy plugin. This is used by the loader to know which plugin it's supposed to talk to.

Normally, you would not need to specify this unless you have more than one HappyPack plugin defined, in which case you'll need distinct IDs to tell them apart. See this section for more information.

Defaults to: "1"

threads: Number

This number indicates how many Node VMs HappyPack will spawn for compiling the source files. After a lot of tinkering, I found 4 to yield the best results. There's certainly a diminishing return on this value and increasing beyond 8 actually slowed things down for me.

Keep in mind that this is only relevant when performing the initial build as HappyPack will switch into a synchronous mode afterwards (i.e. in watch mode.)

Defaults to: 3

threadPool: HappyThreadPool

A pre-defined thread-pool to use for retrieving worker threads. Normally, this is managed internally by each HappyPlugin instance, but you may override this behavior for better results.

The section on thread pools explains how and when to use this.

Defaults to: null

verbose: Boolean

Enable this to log status messages from HappyPack to STDOUT like start-up banner, etc..

Defaults to: true

verboseWhenProfiling: Boolean

Enable this if you want HappyPack to still produce its output even when you're doing a webpack --profile run. Since this variable was introduced, HappyPack will be silent when doing a profile build in order not to corrupt any JSON output by webpack (i.e. when using --json as well.)

Defaults to: false

debug: Boolean

Enable this to log diagnostic messages from HappyPack to STDOUT. Useful for troubleshooting.

Defaults to: false

How it works

A diagram showing the flow between HappyPack's components

HappyPack sits between webpack and your primary source files (like JS sources) where the bulk of loader transformations happen. Every time webpack resolves a module, HappyPack will take it and all its dependencies and distributes those files to multiple worker "threads".

Those threads are actually simple node processes that invoke your transformer. When the compiled version is retrieved, HappyPack serves it to its loader and eventually your chunk.

Using multiple instances

It's possible to define multiple HappyPack plugins for different types of sources/transformations. Just pass in a unique id for each plugin and make sure you pass it their loaders. For example:

// @file webpack.config.js
exports.plugins = [
  new HappyPack({
    id: 'jsx',
    threads: 4,
    loaders: [ 'babel-loader' ]
  }),

  new HappyPack({
    id: 'styles',
    threads: 2,
    loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
  })
];

exports.module.rules = [
  {
    test: /\.js$/,
    use: 'happypack/loader?id=jsx'
  },

  {
    test: /\.less$/,
    use: 'happypack/loader?id=styles'
  },
]

Now .js files will be handled by the first Happy plugin which will use babel-loader to transform them, while .less files will be handled by the second one using the style loaders.

Shared thread pools

Normally, each HappyPack plugin you create internally creates its own threads which are used to run the loaders. However, if you're using more than one HappyPack plugin it can be more optimal to create a thread pool yourself and then configure the plugins to share that pool, minimizing the idle time of threads within it.

Here's an example of using a custom pool of 5 threads that will be shared between loaders for both JS and SCSS/LESS/whatever sources:

// @file: webpack.config.js
var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: 5 });

module.exports = {
  // ...
  plugins: [
    new HappyPack({
      id: 'js',
      threadPool: happyThreadPool,
      loaders: [ 'babel-loader' ]
    }),

    new HappyPack({
      id: 'styles',
      threadPool: happyThreadPool,
      loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
    })
  ]
};

Benchmarks

For the main repository I tested on, which had around 3067 modules, the build time went down from 39 seconds to a whopping ~10 seconds.

Here's a rundown of the various states the build was performed in:

Elapsed (ms) Happy? Using DLLs?
39851 NO NO
37393 NO YES
14605 YES NO
13925 YES NO
11877 YES NO
9228 YES YES

The builds above were run under Linux on a machine with 12 cores.

Changes

See ./CHANGELOG.md.

FAQ

Does it work with Webpack 2 & 3?

Yes. You should use version >= 4.0.1 (of HappyPack).

Is it necessary for Webpack 4?

Short answer: maybe not.

Long answer: there's now a competing add-on in the form of a loader for processing files in multiple threads, exactly what HappyPack does. The fact that it's a loader and not a plugin (or both, in case of H.P.) makes it much simpler to configure. Look at thread-loader and if it works for you - that's great, otherwise you can try HappyPack and see which fares better for you.

YMMV.

Does it work with TypeScript?

The short answer is: yes, it finally does! The longer answer is that you need to use ts-loader in "transpiling-only" mode then use the special plugin fork-ts-checker-notifier-webpack-plugin to perform static type checking.

More information can be found in the ts-loader "happypack mode" section and you can refer to the example that shows this in action.

Big thanks to @johnnyreilly, @aindlq, @piotr-oles, @abergs and many others for making this work.

Does it work with loader XYZ?

We're keeping track of loader support in this wiki page. Some loaders may require extra configuration to make them work.

If the loader you're trying to use isn't listed there, you can refer to this wiki page to see which loader APIs are supported. If your loader uses any API that is NOT supported, chances are that it will not work with HappyPack.

As a general rule, any loader that accepts "functions" in options will not work unless it also accepts reading those options from a file, like babel-loader does with .babelrc and postcss-loader too.

Does it work under Windows?

Yes, as of version 4.0.0 it should. If you come across issues using the plugin on Windows, feel free to open a ticket.

Development

See HACKING.md.

License (MIT)

Copyright (c) <2015-2017> ahmad@amireh.net

Permission 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:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE 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.

changelog

HappyPack Changelog

5.0.1

  • Fixed an issue causing HappyPack to fail when hard-source-webpack-plugin is enabled on Webpack 3. Refs GH-251, thanks to @FengXianGuo for the fix!

5.0.0

Breaking changes

  • Minimum supported version of node is now 6.11.5

Features

  • Added support for webpack 4
  • New option use
  • New option loaders

5.0.0-beta.4

  • The use option now works FRD. Who thought renaming variables would be so hard? Refs GH-225, thanks to @inoyakaigor

5.0.0-beta.3

  • The rules option that was introduced in 5.0.0-beta.1 was meant to be named use and has thus been renamed. Sorry about the confusion!

5.0.0-beta.2

  • Fixed deprecation notice introduced by webpack 4 re compiler.plugin. Thanks to @log2-hwan, refs GH-218.

5.0.0-beta.1

  • Added support for webpack4 resolving APIs, thanks to @marcokam. Refs GH-215
  • HappyPlugin now accepts rules along with loaders for the loader list so that it's consistent with webpack notation.

Breaking changes

  • Minimum supported version of node has been upped to v6.11.5 to match webpack's.

4.0.1

Maintenance release for stripping down the built package to include only the source files and to exclude transient/development-specific files. Refs GH-205, thanks to @filipesilva.

4.0.0

Breaking release with two primary changes:

First, this release contains a fix for a long-standing issue on Windows systems where the worker processes would hang indefinitely.

Second, the caching functionality has been removed[1]. Users relying on the caching functionality may want to consider using the dedicated cache-loader but please keep in mind that this is not officially supported or endorsed by HappyPack and is not guaranteed to work (as is the case with other loaders.)

[1] See this thread for more context about the caching change.

4.0.0-beta.5

  • Support for webpack{2,3} loader context API this.getDependencies
  • Support for webpack{2,3} loader context API this.getContextDependencies
  • Now interoperable with cache-loader

4.0.0-beta.4

  • Default to buffered messaging mode when using standalone thread pools on Windows.

4.0.0-beta.3

Fixed bug around the use of process.send() that was causing a hang on Windows with sufficiently large number of modules (and message length.)

The following parse (on Linux) shows the penalty in buffered vs non-buffered modes and implementations:

elapsed (ms) buffering mean (ms) penalty (ms)
22211 none
21816
22572
21179
21035 | 21762.6 0
21723 basic
22585
23372
22500
22693 | 22574.6 812
24865 async.queue
23010
22717
23530
23732 | 23570.8 1808
21363 basic + process.nextTick
22220
21901
21871
22306 | 21932.2 170
23349 basic (again)
22043
21904
23435
23508 | 22847.8 1085
22735 basic + process.nextTick (again)
21793
22412
21900
22656 | 22299.2 537

4.0.0-beta.2

  • Errors are now property serialized in emitWarning and emitError loader APIs. Refs GH-161
  • Deprecation upgrade: now using loaderUtils.getOptions instead of .parseQuery, refs GH-140

4.0.0-beta.1

  • Support for file-system caching has been dropped. Use cache- loader if you're after this functionality.
  • In the light of the caching change, the following options have lost their meaning and instead wish you a very happy life. Please note that as of this version configuring them will cause a warning to be logged to the console while in the future they will cause an exception to be thrown:
    • tempDir
    • cache
    • cachePath
    • cacheContext
    • cacheSignatureGenerator
  • The enabled option has been deprecated and will be removed in a future version. As disabling the plugin already requires the user to modify their config (e.g. to adjust the loader listings) this option had very little value.

3.1.0

  • Fixed an edge race condition re cache signatures. Thanks to @saifelse, refs GH-159
  • Now propagating loader errors correctly to webpack from background processes. Thanks to @zinserjan, refs GH-14
  • Now exposing "minimize" to loader contexts. Thanks to @adventure-yunfei, refs GH-139

3.0.3

  • Added more webpack2 compatibility fixes
  • Fixed an issue that was causing cached files to be ignored. Thanks to @lijianzhang, refs GH-115

3.0.2

  • Accept "this.plugins" as a function in the loader context since webpack2 now allows it to either be an object or a function. Thanks to @grigory51, refs GH-106

3.0.1

  • The temporary file path used for writing a loader's output is now suffixed with a random identifier to work around an edge case reported in GH-92. Big thanks to @frankLife for the effort.

3.0.0

This release, although it's a major one, was mostly concerned with internal changes and improvements to how the plugin worked. Most side-effects and global state has been eliminated, which should hopefully result in fewer surprises when attempting to use HappyPack in a multi-build webpack setting.

  • HappyPack will no longer output anything to the console if webpack is running in profiling mode (--profile) in order not to corrupt any JSON output. You can restore the previous behavior by setting the new option verboseWhenProfiling to true. Refs GH-76
  • [BREAKING] Inferring loaders for configuration is no longer supported! If you were supplying { happy: { id: 'something' } } to your webpack loader configuration so that HappyPack picks it up, you need to rewrite that part of the config as is shown in the README.
  • [POTENATIALLY BREAKING] HappyPlugin will no longer attempt to generate an incremental ID to use if none is passed. Instead, it will simply default to '1' for an id in case it was not overridden by the user. This behavior never actually provided any benefit since if you had multiple plugins referenced by multiple loaders, you still had to provide each loader with a distinct id (the loaders never incremented such a counter or relied on it.) This solves GH-88.
  • Thread pools can now be shared across multiple compilers/builds! The plugin and thread pools will correctly map each compiler to its configuration and instruct the workers to use the correct configuration when they do their work. Refs GH-82 and GH-72.

Internal refactors

  • HappyPlugin and HappyLoader no longer deal with the RPCHandler to register active compiler or loader instances. Instead, this book-keeping is done implicitly by the thread pools (which own the RPC handlers) when they are started, requested to compile, or stopped.
  • The internal API HappyPlugin.resetUID has been dropped
  • The internal API HappyPlugin.isVerbose is now hidden
  • The internal API HappyPlugin.isDebug is now hidden
  • The internal API HappyPlugin.prototype.compileInBackground is now hidden
  • The internal API HappyPlugin.prototype.compileInForeground is now hidden
  • The internal API HappyPlugin.prototype._performCompilationRequest is now hidden
  • The internal API HappyThreadPool.get has been dropped. Instead, the thread pool exposes a compile API similar to the Thread's.
  • The internal API HappyThreadPool.getRPCHandler has been dropped

2.2.1

  • Fixed an edge-case issue that was causing happypack to crash when a shared threadpool is used by a pre-loader and a loader (or post-loader) that are processing the same file. Refs GH-60
  • Made it possible to completely silence happypack's console output by setting verbose to false and introduced the debug option to control diagnostic message logging. Refs GH-64

2.2.0

  • Fixed a regression in scanning loader "string chains" (multiple loaders specified in the same string separated by !), refs GH-68
  • Added support for the loader API this.loadModule() which is used by less-loader, refs GH-66

2.1.3

  • Fixed an issue where certain loader configurations with queries weren't being properly recognized by HappyPack. Now, all known configuration variants should work. (GH-65 and GH-26)

2.1.2

  • Process argv will no longer be passed to the child processes spawned by HappyPack (refs GH-47)
  • Support for the target loader context variable has been added. Thanks to @Akkuma (refs GH-46)

2.1.1

  • Fixed an issue where happypack would crash when loading invalid/corrupt cache or source-map files. Big thanks to @benhughes for providing the patch in GH-42

2.1.0

  • Introduced SourceMap support

2.0.6

  • Introduced a new option cacheSignatureGenerator to handle use cases such as [GH-35]

2.0.5

  • Now using mkdirp for creating the temp directory to support nested ones

2.0.4

  • Fixed an issue where the cache was not being utilized on node v0.10 (since fs.statSync doesn't exist with that name there) - thanks to [@XVincentX]

2.0.2

  • Fixed an issue that was causing loaders running in foreground to not receive the compiler options

2.0.1

  • Package in NPM is now compact

2.0.0

  • Pitching loader support
  • More complete loader API support
  • More convenient configuration interface

1.1.4

  • Fixed an issue where the cache was being improperly invalidated due to cacheContext not being stored properly (refs GH-17, thanks to @blowery)

1.1.3

  • Fixed an issue where the initial cache was not being saved properly

1.1.2

  • Fixed an issue on old node versions (0.10) with the EventEmitter API (GH-10)
  • Fixed an issue that was breaking the compiler if an invalid threads option was passed (evaluating to NaN)

1.1.1

  • Unrecognized and invalid config parameters will now cause the process to abort
  • The active version is logged on launch

1.1.0

  • Now supporting basic webpack loaders
  • Dropped the transformer parameter as it's no longer needed
  • cache now defaults to true
  • Now using a forking model utilizing node.js's process.fork() for cleaner threading code

1.0.2

  • Loader will now accept IDs that aren't just numbers