Code Monkey home page Code Monkey logo

happypack's Introduction

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> [email protected]

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.

happypack's People

Contributors

adventure-yunfei avatar akkuma avatar amilajack avatar amireh avatar astaroverov avatar benhughes avatar blowery avatar danielsunnerberg avatar filipesilva avatar grigory51 avatar johnnyreilly avatar kokororin avatar leecrossley avatar lijianzhang avatar marcokam avatar raymondsze avatar rpellerin avatar saifelse avatar sejoker avatar sresant avatar tarjei avatar therealparmesh avatar tom910 avatar trusktr avatar yangshun avatar yanni4night avatar yyx990803 avatar zinserjan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

happypack's Issues

Happy id with query property in loader fails

Using:

        {
          test:    /.js$/,
          exclude: /node_modules/,
          loader:  'babel',
          query:   babelrcJsonFileToObject,
          happy:   { id: 'babelJs' }
        }
...
       plugins: [
          new HappyPack({ id: 'babelJs' }),
       ]

Fails with:

Module build failed: AssertionError: HappyPack: plugin for the loader 'babelJs?{"presets":["es2015-webpack","react","stage-0"],"plugins":["transform-runtime","transform-decorators-legacy","jsx-control-statements",["typecheck",{"disable":{"production":true}}]],"env":{"test":{"presets":["es2015-webpack","react","stage-0"],"plugins":["transform-runtime","transform-decorators-legacy","jsx-control-statements",["typecheck",{"disable":{"production":true}}]]},"browser":{"presets":["es2015-webpack","react","stage-0"],"plugins":["transform-runtime","transform-decorators-legacy","jsx-control-statements",["typecheck",{"disable":{"production":true}}],["react-transform",{"transforms":[{"transform":"react-transform-hmr","imports":["react"],"locals":["module"]},{"transform":"react-transform-catch-errors","imports":["react","redbox-react"]}]}]]},"production":{"presets":["es2015-webpack","react","stage-0"],"plugins":["transform-runtime","transform-decorators-legacy","jsx-control-statements","transform-flow-strip-types","react-remove-prop-types"]}}}'

could not be found! Did you forget to add it to the plugin list?

Happypack doesn't seem to work with postcss plugin packs

I'm using happypack in a rather large webpack config. One of our build steps requires different postcss configs for different files, so we use postcss plugin packs:

function postcssConfig() {
  ...
  return {
    defaults: [customMedia({extensions: mediaQueries}), properties({variables: cssVariables}), cssnano(opts)],
    three: [cssnano(opts), prefix({prefix: '.v3'})],
  };
}

These are then typically selected via a query string:

postcss?pack=three

The issue I'm having is that it appears that postcss-loader never has its query property set. I checked this via file writes from post-css loader, and I never get any output for query:

in postcss-loader's index.js:

var loaderUtils = require('loader-utils');
var postcss     = require('postcss');
var fs = require('fs');

module.exports = function (source, map) {
    if ( this.cacheable ) this.cacheable();

    var file   = this.resourcePath;
    fs.appendFile('/home/aleks/debug.txt', this.query);
    var params = loaderUtils.parseQuery(this.query);

Considered this as a native plugin feature in Webpack

Is there a reason you haven't submitted this parallel file loading as a feature or plugin into webpack? @sokra @jhnns and I were talking about way to have faster webpack builds and this has the potential with a bit of cleanup. Have you considered submitting this plugin for a PR. We are also looking into a strategy that caches the dependency AST as loaders run and persisting them for chained loaders tied to it etc.

SourceMap support

TODO:

  • figure out what sourcemaps actually look like between loaders (seem to be objects, but the end result might be stringified)
  • serialize source-maps (we serialize them as JSON in case they're objects, otherwise we assume they're strings and write them down normally)
  • cache source-maps

HappyThread: expected loader to be pending on source file

Hi @amireh,
Thanks for this great tool.

I was wondering if you could help me please, I'm faced with an AssertionError: HappyThread: expected loader to be pending on source file but don't understand from this message what is going on or what I can do to resolve it. I'm probably missing something obvious.

As a guess, I thought this might be some kind of locking or race condition, so I tried setting threads to 1 – but that had no effect.

{
  AssertionError: HappyThread: expected loader to be pending on source file '/Users/jmason/Development/project/src/app/Routes/InPlay.js' (this is likely an internal error!)
  at ChildProcess.acceptMessageFromWorker(/Users/jmason/Development/project/node_modules/happypack/lib/HappyThread.js:37:11)
  at emitTwo(events.js:111:20)
  at ChildProcess.emit(events.js:191:7)
  at process.nextTick(internal/child_process.js:719:12)
  at _combinedTickCallback(internal/process/next_tick.js:67:7)
  at Immediate._tickCallback[as _onImmediate](internal/process/next_tick.js:98:9)
  at tryOnImmediate(timers.js:543:15)
  at processImmediate[as _immediateCallback](timers.js:523:5)
  name: 'AssertionError',
  actual: false,
  expected: true,
  operator: '==',
  message: 'HappyThread: expected loader to be pending on source file \'/Users/jmason/Development/project/src/app/Routes/InPlay.js\' (this is likely an internal error!)',
  generatedMessage: false
}

Appreciate your time, thank you.

Smarter cache detection?

Actually, cache stale detection is done using mtime field, which works pretty well.
I was considering whether it might have sense to use a clever mechanism, such as hashing the file content.

The main reason for that is, basically, CI environment re-download sources every time, so the cache would be stale by default (which is not really true)

AssertionError: HappyPack[1]: Loader must have a @path property or be a string.

var path = require('path');
var HappyPack = require('happypack')

module.exports = {
  entry: path.resolve(__dirname, 'a.js'),

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },

  plugins: [
    new HappyPack({
      cache: process.env.HAPPY_CACHE === '1',
      loaders: [
          {
            test: /\.js$/,
            loader: 'babel',
            exclude: [/node_modules/]
          },
          {
            test: /\.json$/,
            loader: 'json-loader'
          }
      ],
      threads: 2
    })
  ],

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'happypack/loader',
      }
    ]
  }
}

Add verbose option to docs

Would be cool to know of that option without looking the source, specially if you want to do a profile

Build includes wrong folder

I tried to follow your PR for the react-redux-universal-hot-example erikras/react-redux-universal-hot-example#1090 but am getting this error:

Module parse failed: /Users/ali/myproject/client/static/locale/de.json Unexpected token (2:10)
[0] You may need an appropriate loader to handle this file type.

You wrote the createSourceLoader function to only include files under the src/ folder. I checked the folder is correct but it still includes stuff from static/.
The build without Happypack works btw.

This is the whole configuration file:

require('babel-polyfill');

// Webpack config for development
var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
var assetsPath = path.resolve(__dirname, '../static/dist');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var host = (process.env.HOST || 'localhost');
var port = (+process.env.PORT + 1) || 3001;
var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: 4 });

// https://github.com/halt-hammerzeit/webpack-isomorphic-tools
var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
var webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require('./webpack-isomorphic-tools'));

var babelrc = fs.readFileSync('./.babelrc');
var babelrcObject = {};

try {
  babelrcObject = JSON.parse(babelrc);
} catch (err) {
  console.error('==>     ERROR: Error parsing your .babelrc.');
  console.error(err);
}


var babelrcObjectDevelopment = babelrcObject.env && babelrcObject.env.development || {};

// merge global and dev-only plugins
var combinedPlugins = babelrcObject.plugins || [];
combinedPlugins = combinedPlugins.concat(babelrcObjectDevelopment.plugins);

var babelLoaderQuery = Object.assign({}, babelrcObjectDevelopment, babelrcObject, {plugins: combinedPlugins});
delete babelLoaderQuery.env;

// Since we use .babelrc for client and server, and we don't want HMR enabled on the server, we have to add
// the babel plugin react-transform-hmr manually here.

// make sure react-transform is enabled
babelLoaderQuery.plugins = babelLoaderQuery.plugins || [];
var reactTransform = null;
for (var i = 0; i < babelLoaderQuery.plugins.length; ++i) {
  var plugin = babelLoaderQuery.plugins[i];
  if (Array.isArray(plugin) && plugin[0] === 'react-transform') {
    reactTransform = plugin;
  }
}

if (!reactTransform) {
  reactTransform = ['react-transform', {transforms: []}];
  babelLoaderQuery.plugins.push(reactTransform);
}

if (!reactTransform[1] || !reactTransform[1].transforms) {
  reactTransform[1] = Object.assign({}, reactTransform[1], {transforms: []});
}

// make sure react-transform-hmr is enabled
reactTransform[1].transforms.push({
  transform: 'react-transform-hmr',
  imports: ['react'],
  locals: ['module']
});

module.exports = {
  devtool: 'inline-source-map',
  context: path.resolve(__dirname, '..'),
  entry: {
    'main': [
      'webpack-hot-middleware/client?path=http://' + host + ':' + port + '/__webpack_hmr',
            'tether',
      'bootstrap-loader',
      'font-awesome-webpack!./src/theme/font-awesome.config.js',
      './src/client.js'
    ]
  },
  output: {
    path: assetsPath,
    filename: '[name]-[hash].js',
    chunkFilename: '[name]-[chunkhash].js',
    publicPath: 'http://' + host + ':' + port + '/dist/'
  },
  module: {
    loaders: [
            { test: /\.css$/, loaders: [ 'style', 'css', 'postcss' ] },
            { test: /\.scss$/, loaders: [ 'style', 'css', 'postcss', 'sass' ] },
            createSourceLoader({
                happy: { id: 'jsx' },
                test: /\.jsx?$/,
                loaders: ['babel?' + JSON.stringify(babelLoaderQuery), 'eslint-loader'],
            }),

            createSourceLoader({
                happy: { id: 'json' },
                test: /\.json$/,
                loader: 'json-loader',
            }),
      { test: /\.less$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
      { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
      { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
      { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
      { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
      { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
      { test: webpackIsomorphicToolsPlugin.regular_expression('images'), loader: 'url-loader?limit=10240' }
        ]
  },
  progress: true,
  resolve: {
    modulesDirectories: [
      'src',
      'node_modules'
    ],
    extensions: ['', '.json', '.js', '.jsx']
  },
  plugins: [
    // hot reload
    new webpack.HotModuleReplacementPlugin(),
        //new ExtractTextPlugin('[name]-[chunkhash].css', {allChunks: true}),
    new webpack.IgnorePlugin(/webpack-stats\.json$/),
        new webpack.ProvidePlugin({
      "window.Tether": "tether"
    }),
    new webpack.DefinePlugin({
      __CLIENT__: true,
      __SERVER__: false,
      __DEVELOPMENT__: true,
      __DEVTOOLS__: true  // <-------- DISABLE redux-devtools HERE
    }),
    webpackIsomorphicToolsPlugin.development(),

        createHappyPlugin('jsx'),
    createHappyPlugin('json'),
  ]
};

// restrict loader to files under /src
function createSourceLoader(spec) {
  var test =  Object.keys(spec).reduce(function(x, key) {
    x[key] = spec[key];

    return x;
  }, {
    include: [ path.resolve(__dirname, '../src') ]
  });
    return test
}

function createHappyPlugin(id) {
  return new HappyPack({
    id: id,
    threadPool: happyThreadPool,

    // disable happypack with HAPPY=0
    enabled: process.env.HAPPY !== '0',

    // disable happypack caching with HAPPY_CACHE=0
    cache: process.env.HAPPY_CACHE !== '0',

    // make happypack more verbose with HAPPY_VERBOSE=1
    verbose: process.env.HAPPY_VERBOSE === '1',
  });
}

webpack2 support

Gave it a spin:

Error: Signature changed: context parameter added
    at Tapable.resolve (/Users/beckend/Coding/test/node_modules/enhanced-resolve/lib/Resolver.js:30:9)
    at /Users/beckend/Coding/test/node_modules/happypack/lib/WebpackUtils.js:22:33
    at /Users/beckend/Coding/test/node_modules/async/lib/async.js:718:13
    at async.forEachOf.async.eachOf (/Users/beckend/Coding/test/node_modules/async/lib/async.js:233:13)
    at _parallel (/Users/beckend/Coding/test/node_modules/async/lib/async.js:717:9)
    at Object.async.parallel (/Users/beckend/Coding/test/node_modules/async/lib/async.js:731:9)
    at Object.exports.resolveLoaders (/Users/beckend/Coding/test/node_modules/happypack/lib/WebpackUtils.js:19:9)
    at resolveLoaders (/Users/beckend/Coding/test/node_modules/happypack/lib/HappyPlugin.js:181:20)
    at /Users/beckend/Coding/test/node_modules/async/lib/async.js:718:13
    at Immediate.iterate [as _onImmediate] (/Users/beckend/Coding/test/node_modules/async/lib/async.js:262:13)
    at tryOnImmediate (timers.js:534:15)
    at processImmediate [as _immediateCallback] (timers.js:514:5)

Re-enable tests on older node versions

Node pre v4 were disabled on travis since we're no longer using babel to transpile the tests but that's not a permanent solution. Need to re-add these versions (especially v0.12) to the matrix.

the ability to use existing loaders

it would be nice if we could have an internal transformer that actually pipes to existing webpack loaders and provides them with the proper context like webpack does.

Compatible with Webpack multi builds?

We're using Webpack in it's multi-build setup, where the config is an array of webpack configs:

module.exports = [
 { output, resolve },
 { output2, resolve2 },
]

When we configure both the configs to use Happypack, only one configuration starts and runs.

Any ideas on what's happening? Is this a tested/support configuration?

Babel queries for loaders

I cannot get happypack to work when I have:

{ 
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: [
          {
            loader: 'babel',
            query: {
              plugins: [
                'transform-runtime',
                'add-module-exports',
                'transform-decorators-legacy',
                'transform-react-display-name',
                'typecheck',
                'transform-react-jsx-self',
                'transform-react-jsx-source'
              ],
              presets: ['react', 'es2015-webpack', 'stage-0', 'react-hmre'],
              cacheDirectory: true
            }
          },
          'eslint-loader'
        ],
      },

Errors with:

/Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/WebpackUtils.js:9
  var loaderStrings = string.split('!');
                             ^

TypeError: string.split is not a function
    at disectLoaderString (/Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/WebpackUtils.js:9:30)
    at Array.map (native)
    at normalizeLoaders (/Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/HappyPlugin.js:171:10)
    at /Users/mmahalwy/Sites/sparrow/node_modules/happypack/node_modules/async/lib/async.js:713:13
    at Immediate.iterate (/Users/mmahalwy/Sites/sparrow/node_modules/happypack/node_modules/async/lib/async.js:262:13)
    at runCallback (timers.js:570:20)
    at tryOnImmediate (timers.js:550:5)
    at processImmediate [as _immediateCallback] (timers.js:529:5)

If I move it to the new HappyPack({ id: 'js', loaders: ...}) if throws error:

assert.js:89
  throw new assert.AssertionError({
  ^
AssertionError: HappyPack[js]: Loader must have a @path property or be a string.
    at /Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/OptionParser.js:31:7
    at Array.reduce (native)
    at parseAndValidateOptions (/Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/OptionParser.js:19:30)
    at new HappyPlugin (/Users/mmahalwy/Sites/sparrow/node_modules/happypack/lib/HappyPlugin.js:33:17)
    at Object.<anonymous> (/Users/mmahalwy/Sites/sparrow/webpack/dev.config.js:69:5)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)

AssertionError: HappyPlugin[js]; you have not specified any loaders and there is no matching loader entry with this id either.

HappyPack does not seem to work when trying to "infer" the loaders from preLoaders. Is this true? Can it be made to work? If not, I can easily specify it, just wondering.

  new HappyPack({ id: 'js' }),
       preLoaders: [

        /*
       * Source map loader support for *.js files
       * Extracts SourceMaps for source files that as added as sourceMappingURL comment.
       *
       * See: https://github.com/webpack/source-map-loader
       */
      {
        test: /\.js$/,
        loader: 'source-map-loader',
        exclude: [
          // these packages have problems with their sourcemaps
          helpers.root('node_modules/rxjs'),
          helpers.root('node_modules/@angular2-material'),
          helpers.root('node_modules/@angular')
        ],
        happy: { id: 'js' } // HappyPack middleware

      }
    ],
Happy[js]: Version: 2.1.1. Using cache? yes. Threads: 3

D:\Source\POC\ASP.Net.Core1.Angular2.Webpack.Starter\src\starterproject\node_modules\happypack\lib\HappyPlugin.js:165
      assert(loaders && loaders.length > 0,
      ^
AssertionError: HappyPlugin[js]; you have not specified any loaders and there is no matching loader entry with this id either.
    at normalizeLoaders (D:\Source\POC\ASP.Net.Core1.Angular2.Webpack.Starter\src\starterproject\node_modules\happypack\lib\HappyPlugin.js:165:7)
    at D:\Source\POC\ASP.Net.Core1.Angular2.Webpack.Starter\src\starterproject\node_modules\happypack\node_modules\async\lib\async.js:713:13
    at Immediate.iterate [as _onImmediate] (D:\Source\POC\ASP.Net.Core1.Angular2.Webpack.Starter\src\starterproject\node_modules\happypack\node_modules\async\lib\async.js:262:13)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

Apply HappyPack without loader specified

Is it possible to invoke the HappyPack plugin on the default webpack JS loader? Not sure what loaders webpack is using internally do resolve the dependency tree from the entry, or if there is a way to invoke the default behavior as a loader.

For example, a DLL bundle:

...
  entry: {
    'vendors': [getPath('vendors/entry.js')]
  },
  output: {
    filename: '[name].bundle.js',
    path: 'dist/vendors/',

    // The name of the global variable which the library's
    // require() function will be assigned to
    library: '[name]_lib',
  },
  plugins: [
    new webpack.DllPlugin({
      // The path to the manifest file which maps between
      // modules included in a bundle and the internal IDs
      // within that bundle
      path: 'dist/vendors/[name]-manifest.json',
      // The name of the global variable which the library's
      // require function has been assigned to. This must match the
      // output.library option above
      name: '[name]_lib'
    }),
    new HappyPack({ loaders: [ '??' ] })
  ]
...

React hot module replacement doesn’t when using Happypack

Hello there, Happypack breaks somehow Webpack HMR when updating React components like this:

[HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves.

Does anybody know how to make things working well when using both Happypack and Webpack’s HMR? Or what could go wrong?

TypeError: r.forEach is not a function

I get the following error:

Error

Here is my webpack config:

module: {
  loaders: [
    {
      test: /\.js$/,
      loaders: 'happypack/loader',
      include: [
        path.join(__dirname, 'src'),
        path.join(__dirname, 'demo', 'src')
      ]
    }, ...
  ]
},
plugins: {
  new HappyPack({
    loaders: [
      {
        path: path.join(__dirname, 'demo', 'src')
      }
    ]
  })
}

What am I doing wrong?

Also, I'm a bit confused with which paths should be in module.loaders.include vs plugins.happypack.loaders. Could you elaborate on the difference please?

babel-loader not picking up .babelrc

Nice project!

Was going to try it but got into troubles with babel loader. It seems that it isn't picking up .babelrc. Any ideas before I investigate?

I have extensive babel config so I cant use a query String

EventEmitter definition

Hello, and first of all, thank you for the project. I am really hoping this could speed up my compilation times.

For some strange reasons, I am stuck on node 0.10.41, and looks like the event emitter API is a bit different.

In particular, this line must be rewritten in this way

var callbacks = new EventEmitter.EventEmitter();

in order to make it work on that node js version.

Do you think would it be possible to handle both cases?

Module build failed: Error: Cannot read property 'filter' of undefined

I'm running this against Webpack 2.1.0-beta7 in watch mode and this is what happens on file change

TypeError: Cannot read property 'filter' of undefined
    at Object.HappyLoader (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/HappyLoader.js:14:37)
    at applySyncOrAsync (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:340:21)
    at apply (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:267:5)
    at /Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:130:7
    at applyPitchLoader (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:183:14)
    at applyPitchLoader (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:191:14)
    at applyPitchLoaders (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:221:4)
    at applyLoaders (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/applyLoaders.js:115:3)
    at HappyWorker.compile (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/HappyWorker.js:32:3)
    at process.accept (/Users/omni/Documents/git/vault-extension/node_modules/happypack/lib/HappyWorkerChannel.js:24:14)

Silencing happypack output

Is it possible to silence HappyPack's output? I don't see anything in the readme pertaining to this functionality. My motivation behind this is when I output the stats.json file for profiling. HappyPack prepends this with the following:

Happy[js]: Version: 2.1.1. Using cache? yes. Threads: 4 (shared pool)
Happy[js]: Loaded 226 entries from cache. (0 were stale)
Happy[js]: All set; signalling webpack to proceed.
{
  "errors": [],
  "warnings": [],
  "version": "1.13.1",
...

Although fairly easy to remove, if unmodified, this does lead to invalid json.

Error listen EADDRINUSE if run with --debug flag

I'm using webpack-dev-middleware and webpack-hot-middleware, so I can start webpack dev server directly from my main app.
However, if I run node with the --debug flag, it looks like it gets propagated to the child processes that Happy creates. As a result, with 3 threads I get 3 times EADDRINUSE error on the console.

Removing the flag makes Happy happy again 😄 (and my build times are 60% faster!!)
Is there a way to say to Happy to ignore the debug flag?

HappyPack does not notices the cache?

I am not sure why, but when using webpack-dev-server, happypack is writing .happypack directory but on the same time, it is not able to detect the cache and regenerates the entire build on subsequent runs.

Any suggestion?

Unable to cache between machines.

We're currently investigating using happypack to cache our ci builds between different commits. Our basic setup is to download a happypack cache (if one exists), clone, run webpack, upload happypack cache.

We've hit two issues with this. The first is that modified-time isn't preserved by git (we worked around this by changing the signature function to be a hash of the file content). The second issue that we're hitting is that the happypack cache uses absolute file paths, which aren't consistent between builds.

I would like to propose changing the structure of the cache to enable cached builds across machines and clones...

From:

{
  '/path/to/files.js': {
    mtime: '2016-05-25 25:12:12', // pretend this is a real time stamp
    compiledPath: '/path/.happypack/s--1411414904'
  },
},

To:

{
  // sha-256 based on file content.
  'fa9a499ca3f660206bec74fb7ed3603174c17c2f3846a9968a3caf8e995b791b': {
    compiledPath: '.happpack/s--1411414904' // config.tempDir + cache file name.
  }
}

I'd be happy to work on this, but I wanted to get your opinion first.

Error when starting with less-loader and ExtractTextPlugin

I'm using the settings that are written in @amireh #14 and get an error

TypeError: loaderContext.loadModule is not a function
at /node_modules/less-loader/index.js:117:18
at HappyFakeCompiler.HFCPt._handleResponse (/node_modules/happypack/lib/HappyFakeCompiler.js:58:3)

[email protected], [email protected], [email protected], [email protected]

If I use Webpack 2, I get a completely different problem

/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:30
throw new Error("Signature changed: context parameter added");
^

Error: Signature changed: context parameter added
at Tapable.resolve (/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:30:9)
at Object.HappyRPCHandler.execute (/node_modules/happypack/lib/HappyRPCHandler.js:25:37)
at ChildProcess.acceptMessageFromWorker (/node_modules/happypack/lib/HappyThread.js:49:27)
at emitTwo (events.js:111:20)
at ChildProcess.emit (events.js:191:7)
at process.nextTick (internal/child_process.js:719:12)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)

[email protected], [email protected], [email protected], [email protected]/[email protected]

SASS loader support

HappyPack is making us very happy, thanks for that!

How would I go about enabling happypack for this loader:

{ 
    test: /\.scss$/, 
    loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap&' 
},

Cheers!

shared thread pools

For projects with many loaders (like canvas-lms), having 8+ plugin instances is an overkill especially since some loaders handle as few as a 100 files. It would be nice if we could let the user supply their own HappyThreadPool to the plugins which they can share.

Using HappyPack with Awesome Typescript Loader

This seems to be closely related to #32 but I didn't want to hijack that post by talking about a different TypeScript loader.

If possible, I would like to use HappyPack in the following way:

module: {
    loaders: [
        { test: /\.tsx?$/, loader: 'happypack/loader' }
    ]
},
plugins: [
    new HappyPack({
        loaders: [ 'awesome-typescript-loader' ]
    })
]

This is currently leading to errors like:

ERROR in ./App/Initialise.ts
Module parse failed: C:\path\to\src\node_modules\happypack\loader.js!C:\path\to\src\App\Initialise.ts Line 1: Unexpected identifier
You may need an appropriate loader to handle this file type.
| [object Promise]

Is it possible to use these two loaders together at the moment?

infer loaders & use webpack loader resolver

instead of requiring absolute paths to loaders, we can reuse webpack loader resolver to find them for us. Then the integration could be as simple as:

// @file webpack.config.js
exports.module = {
  loaders: [{
    happy: { id: 'js' },
    test: /\.js$/,
    loaders: [ 'babel?presets[]=es2015', 'react-i18nliner/webpack-loader' ]
  }]
};

exports.plugins = [
  new HappyPack({
    id: 'js',
    inferLoaders: true
  })
]

The inferLoaders flag will be required because I'd like to keep the original notation supported.

Trying to use Happypack with multiple loaders

Hello. I'm trying to use Happypack with the following loaders:

new HappyPack({
      id: 'js',
      threads: 4,
      loaders: [
        'ng-annotate',
        'babel',
        'eslint'
      ]
    }),

And I'm calling happypack like so:

{
        test: /\.js$/,
        loaders: 'happypack/loader?id=js',
        exclude: /node_modules/
      },

Unfortunately I'm getting the following error TypeError: r.forEach is not a function:

 Happy[js]: Version: 2.1.0. Using cache? yes. Threads: 4                                                1579ms  Fri Apr 29 13:51:21 2016
Happy[js]: No cache was found, starting fresh.
Happy[js]: All set; signalling webpack to proceed.
/Users/vramanujam/Sites/mast_fe/node_modules/webpack/node_modules/webpack-core/lib/LoadersList.js:81
        r.forEach(function(r) {
          ^

TypeError: r.forEach is not a function

ModuleNotFoundError causes build to hang

If an import/require path is wrong, causing a ModuleNotFoundError error, the build hangs and never completes.

You can reproduce this in the single-loader example by changing a.js to:

require('./b1');

Adding HappyPack caused all webpack module IDs to change

Hey, loving the plugin and it seems to be working splendidly, but on my first run I found every file changed, and my webpack records file had every module ID shuffled around. Is there any reason HappyPack wouldn't respect an existing webpack records file?

If this is something I have to pay the piper on once, that's fine. I'm just worried that this ID shuffling will happen on future builds, and require me to cache bust my entire site even if I'm only altering one bundle.

Let me know if I can provide more information!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.