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

Webpack 2 "watch" Extremely Slow #1922

Closed
dtothefp opened this issue Jan 23, 2016 · 19 comments
Closed

Webpack 2 "watch" Extremely Slow #1922

dtothefp opened this issue Jan 23, 2016 · 19 comments
Labels

Comments

@dtothefp
Copy link

I'm trying to upgrade to Webpack 2 and have had little problems except the "watch" task and watch done through webpack-dev-middleware are orders of magnitude slower (3 vs 35 seconds). Is there some sort of option I'm missing to speed this up?

note: I'm compiling a bunch of node_modules from es6 from our private NPM if you have a look at the exclude regex for Babel.

Webpack ^1.12.9:

webpack building...
[16:05:09] Webpack Bundled main bundle in 3714ms
webpack built 072b247072d6d3f314e3 in 3714ms
[16:05:26] Webpack Bundling main bundle
webpack building...
[16:05:26] Webpack Bundled main bundle in 554ms
webpack built 072b247072d6d3f314e3 in 554ms

webpack building...
[16:07:29] Webpack Bundled main bundle in 3487ms
webpack built c652ba9f489e2bab5a5e in 3487ms
[16:07:40] Webpack Bundling main bundle
webpack building...
[16:07:40] Webpack Bundled main bundle in 564ms
webpack built c652ba9f489e2bab5a5e in 564ms

Webpack 2.0.4-beta:

webpack building...
[15:34:03] Webpack Bundled main bundle in 35313ms
webpack built 7fbdcc793917d2b8c72a in 35313ms
[15:34:28] Webpack Bundling main bundle
webpack building...
[15:34:46] Webpack Bundled main bundle in 17344ms
webpack built 4425398f9ab1a3be7d51 in 17344ms

[15:39:19] Webpack Bundled main bundle in 28707ms
[15:39:31] Webpack Bundling main bundle
[15:39:46] Webpack Bundled main bundle in 14704ms

My config:

 if (runHot) {
  const Express = require('express');
  const app = new Express();
  const serverOptions = {
    contentBase: buildDir,
    quiet: true,
    noInfo: true,
    hot: true,
    inline: true,
    lazy: false,
    publicPath,
    headers: {'Access-Control-Allow-Origin': '*'},
    stats: {colors: true}
  };

  app.use(require('webpack-dev-middleware')(compiler, serverOptions));
  app.use(require('webpack-hot-middleware')(compiler));
} else {
  compiler.watch({
    aggregateTimeout: 300,
    poll: true
  }, logger);
}
{  
   "externals":{  
      "jquery":"jQuery"
   },
   "resolve":{  
      "extensions":[  
         "",
         ".js",
         ".json",
         ".jsx",
         ".html",
         ".css",
         ".scss",
         ".yaml",
         ".yml"
      ],
      "resolve":[  
         "node_modules",
         "src/js"
      ],
   },
   "node":{  
      "dns":"mock",
      "net":"mock",
      "fs":"empty",
      "__filename":true,
      "__dirname":true
   },
   "context":"/src",
   "cache":true,
   "debug":true,
   "entry":{  
      "main":[  
         "webpack-hot-middleware/client?path=http://localhost:8080/__webpack_hmr&reload=true&noInfo=true",
         "babel-polyfill",
         "./js/index.js"
      ]
   },
   "output":{  
      "path":"/dist",
      "publicPath":"http://localhost:8080/",
      "filename":"js/[name].js"
   },
   "module":{  
      "loaders":[  
         {  
            "test": /^.+\/node_modules\/(?!@hfa\/).+\.jsx?$/,
            "loader":"babel",
            "query":{  
               "presets":[  
                  "react",
                  "es2015-native-modules",
                  "stage-0"
               ],
               "plugins":[  
                  "transform-runtime",
                  "transform-decorators-legacy",
                  "typecheck",
                  [  
                     "react-transform",
                     {  
                        "transforms":[  
                           {  
                              "transform":"react-transform-hmr",
                              "imports":[  
                                 "react"
                              ],
                              "locals":[  
                                 "module"
                              ]
                           },
                           {  
                              "transform":"react-transform-catch-errors",
                              "imports":[  
                                 "react",
                                 "redbox-react"
                              ]
                           }
                        ]
                     }
                  ]
               ]
            }
         }
     ]
   },
   "devtool":"source-map"
}
@sokra
Copy link
Member

sokra commented Jan 25, 2016

I think the unsafe resolve cache was on by default in webpack 1 and is off by default in webpack 2 (need to enable it in the default).

Could you try setting resolve.unsafeCache = true?

btw. your settings resolve.resolve should be resolve.modules and "src/js" should be absolute.

@dtothefp
Copy link
Author

@sokra resolve.unsafeCache did speed it up about 20s give or take, but re-build times are still 7s to 10s which is significantly longer than Webpack 1.x. Also, in my above config I had a typo, I was in fact using resolve.modules not resolve.resolve. When I switch to resolve.modules = ['/some/abs/path'] it actually breaks, and only works if I do resolve.modules = ['some/path']. Anyway, pasting again my updated profiling and config in case it is interesting:

webpack building...
[09:51:24] Webpack Bundled main bundle in 14343ms
webpack built 95ffb13de548f1646630 in 14343ms
[09:51:29] Webpack Bundling main bundle
webpack building...
[09:51:36] Webpack Bundled main bundle in 7357ms
webpack built 95ffb13de548f1646630 in 7357ms
[09:51:38] Webpack Bundling main bundle
webpack building...
[09:51:48] Webpack Bundled main bundle in 10095ms
webpack built 8bc8ce86192757c9318b in 10095ms
[09:51:57] Webpack Bundling main bundle
webpack building...
[09:52:06] Webpack Bundled main bundle in 9448ms
webpack built d5946910abd498e4c71f in 9448ms
[09:52:09] Webpack Bundling main bundle
webpack building...
[09:52:16] Webpack Bundled main bundle in 7178ms
webpack built d5946910abd498e4c71f in 7178ms
[09:52:20] Webpack Bundling main bundle
webpack building...
[09:52:31] Webpack Bundled main bundle in 11090ms
webpack built 0823e57be07c95a99d11 in 11090ms
{ externals: {},
  eslint:
   { rules:
      { 
         //...lot's of rules
     },
     configFile: //..path to config file,
     formatter: [Function],
     emitError: false,
     emitWarning: false,
     failOnWarning: false,
     failOnError: false },
  resolve:
   { extensions:
      [ '',
        '.js',
        '.json',
        '.jsx',
        '.html',
        '.css',
        '.scss',
        '.yaml',
        '.yml' ],
     modules: [ 'node_modules', 'src/js' ],
     alias: {},
     unsafeCache: true },
  node: { dns: 'mock', net: 'mock', fs: 'empty' },
  context: //..path to /src,
  cache: true,
  debug: true,
  entry:
   { main:
      [ 'webpack-hot-middleware/client?path=http://localhost:8080/__webpack_hmr&reload=true&noInfo=true',
        'babel-polyfill',
        'js-cookie',
        'query-string',
        './js/index.jsx' ] },
  output:
   { path: //..path to dist,
     publicPath: 'http://localhost:8080/',
     filename: 'js/[name].js' },
  module:
   { preLoaders: [ [Object] ],
     loaders: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
     postLoaders: [ [Object], [Object], [Object] ] },
  plugins:
   [ OccurrenceOrderPlugin { preferEntry: undefined },
     NoErrorsPlugin {},
     DefinePlugin { definitions: [Object] },
     ExtractTextPlugin { filename: 'css/[name].css', options: [Object], id: 1 },
     DedupePlugin {},
     Plugin {
       options: [Object],
       log: [Object],
       regular_expressions: [Object],
       regularExpressions: [Object] },
     HotModuleReplacementPlugin { multiStep: undefined, fullBuildTimeout: 200 } ],
  postcss:
   [ { [Function]
       options: [Object],
       info: [Function],
       postcssPlugin: 'autoprefixer',
       postcssVersion: '5.0.14' } ],
  devtool: 'source-map' }

@sokra
Copy link
Member

sokra commented Jan 26, 2016

I had time to investigate yesterday. There is a bug which prevents the resolve cache from working. I fixed it locally, but nothing commited yet.

Also added some other performance tweaks...

I try to publish a new version soon, so you can benchmark it with your usecase.

@sokra
Copy link
Member

sokra commented Jan 26, 2016

Could you try again with the most recent version?

@ianks
Copy link
Contributor

ianks commented Jan 27, 2016

For some reason, when unsafeCache is enabled (in webpack-2.0.5-beta), I get errors like this:

ERROR in ./~/auth0-lock/lib/insert-css/index.js
Module not found: Error: Can't resolve 'fs' in '/home/ianks/Dropbox/Development/work/techstars/companies/adhawk/the-power/node_modules/auth0-lock/lib/insert-css'
 @ ./~/auth0-lock/lib/insert-css/index.js 5:9-22

This library is using brfs to transform the code, btw. Is the loader not getting run?

My incremental build times were cut in half, however, which is nice.

@dtothefp
Copy link
Author

@sokra this works great for me, thanks for the fix

webpack building...
[23:53:51] Webpack Bundled main bundle in 3855ms
webpack built 70292c503134ca49913e in 3855ms
[23:54:00] Webpack Bundling main bundle
webpack building...
[23:54:03] Webpack Bundled main bundle in 3518ms
webpack built 88e418465ccda7f0883c in 3518ms
[23:54:07] Webpack Bundling main bundle
webpack building...
[23:54:11] Webpack Bundled main bundle in 3716ms
webpack built 50b07e4cce892bee0b56 in 3716ms

Still can't get the absolute path working with resolve.modules, but not worried about that.

@ianks 2.0.5-beta works fine for me, must be something specific to your config

@maoueh
Copy link

maoueh commented Jan 28, 2016

@ianks Auth0 8.2.0 broke bundling with webpack. They did fix it in 8.2.1. See auth0/lock#301.

That may be completely unrelated but this seemed very likely to be the problem. If not, sorry for the noise :)

@ianks
Copy link
Contributor

ianks commented Jan 28, 2016

@maoueh 8.2.1 did not fix the issue for me. I ended up just using an external for Auth0. Much faster anyway :)

@sokra
Copy link
Member

sokra commented Jan 30, 2016

Still can't get the absolute path working with resolve.modules, but not worried about that.

Works for me...

If you have a small repro case I'll take a look.

@TheLarkInn
Copy link
Member

@sokra are we thinking resolve.unsafeCache: true needs to be enabled by default again for Webpack 2.0 for speed?

@TheLarkInn
Copy link
Member

@dtothefp @maoueh are you still having issues with slowness in later beta versions (beta.13+)? Also have you looked into DllPlugin for increasing build times?

@dtothefp
Copy link
Author

@TheLarkInn was working fine for me but I reverted from webpack 2 because of larger bundle sizes #1981

@SpaceK33z
Copy link
Member

Closing since confirmed to work again ^.

@giniedp
Copy link

giniedp commented Feb 10, 2017

same here. I want to migrate to Webpack 2. The build speed are

initial
Webpack 1: ~23s
Webpack 2: ~60s
incremental
Webpack 1: ~2s
Webpack 2: ~16s

Unfortunately its closed source, so i can not point to a repository. Has there been any progress or insight regarding build times lately? I also upgraded awesome-typescript-loader from 2.x to 3.0.3

I did try the Dll plugins, but as i remember, it did not help much. However, i have to give it another try tomorrow.

This is my config (Webpack 2)

"use strict";

let webpack = require("webpack");
let ProgressBarPlugin = require("progress-bar-webpack-plugin");
let config = require("./gulp.config.js");

let isProduction = config.isProduction;
let isTest = false;

module.exports = {

  /**
   * Developer tool to enhance debugging
   * See: https://webpack.js.org/configuration/devtool/
   */
   devtool: isProduction ? "hidden-source-map" : isTest ? "inline-source-map" : "cheap-module-source-map",

  /**
   * The entry point for the bundle.
   * See: https://webpack.js.org/configuration/entry-context/
   */
  entry: config.frontend.scripts,

  /**
   * Add additional plugins to the compiler.
   * See: https://webpack.js.org/configuration/plugins/
   */
  plugins: [].concat(isProduction ? [
    /**
     * Order the modules and chunks by occurrence.
     */
    // new webpack.optimize.OccurenceOrderPlugin(true),

  ] : []).concat(!isTest ? [

    // https://webpack.github.io/docs/code-splitting.html
    // https://webpack.js.org/plugins/commons-chunk-plugin/
    new webpack.optimize.CommonsChunkPlugin({
      name: Object.keys(config.frontend.scripts),
      minChunks: Infinity
    })

  ] : []).concat([

    new webpack.ProvidePlugin({
      jQuery: "jquery",
      $: "jquery",
      jquery: "jquery",
      _: "underscore",
      moment: "moment",
      Tether: "Tether"
    }),

    // https://webpack.js.org/plugins/define-plugin/
    new webpack.DefinePlugin({
      "IS_PRODUCTION": !!config.isProduction
    }),

    //https://github.com/clessg/progress-bar-webpack-plugin
    new ProgressBarPlugin()
  ]),

  /**
   * @See: https://webpack.js.org/configuration/module/
   */
  module: {
    rules: [{
      test: /\.ts$/,
      // https://github.com/s-panferov/awesome-typescript-loader
      loader: "awesome-typescript-loader",
      // query: {
      //   module: "commonjs",
      //   sourceMap: !isTest,
      //   inlineSourceMap: isTest,
      //   forkChecker: true
      // }
    }, {
      test: /\.ts$/,
      // https://github.com/brandonroberts/angular2-router-loader
      loader: "angular2-router-loader"
    }, {
      test: /\.ts$/,
      // https://github.com/TheLarkInn/angular2-template-loader
      loader: "angular2-template-loader"
    }, {
      test: /\.pug$/,
      loader: "pug-loader"
    }].concat(!isTest ? [] : [{
      test: /\.(js|ts)$/,
      enforce: "post",
      loader: "istanbul-instrumenter-loader",
      include: config.frontend.srcDir,
      exclude: [
        /\.(e2e|test)\.ts$/,
        /node_modules/
      ]
    }])
  },

  /**
   * Cache the generated webpack modules and chunks to improve build speed.
   * @See: https://webpack.js.org/configuration/other-options/#cache
   */
  cache: true,

  /**
   * Options affecting the output of the compilation.
   * @See: https://webpack.js.org/configuration/output/
   */
  output: {
    path: config.frontend.outDir,
    publicPath: "/",
    filename: "[name].js",
    sourceMapFilename: "[name].js.map",
    chunkFilename: "[id].chunk.js"
  },

  /**
   * These options change how modules are resolved
   * @See: https://webpack.js.org/configuration/resolve/
   */
  resolve: {
    extensions: [".webpack.js", ".web.js", ".ts", ".js"],
  },

  /**
   * Like resolve but for loaders.
   * @See: https://webpack.js.org/configuration/resolve/#resolveloader
   */
  resolveLoader: {
    modules: [
      // Unsere loader sind hier
      "tools/loaders",
      // Standardloader
      "web_loaders", "web_modules", "node_loaders", "node_modules"
    ],
  }
};

@giniedp
Copy link

giniedp commented Feb 10, 2017

Just to let you know. I just went back to the point before i started the webpack upgrade and upgraded only the awesome-typescript-loader. The build time increased from 23 to 40s.

@sokra
Copy link
Member

sokra commented Feb 10, 2017

"cheap-module-source-map" -> "eval-cheap-module-source-map" The eval versions are much faster on incremental build.


CommonsChunkPlugin config looks weird.

@giniedp
Copy link

giniedp commented Feb 12, 2017

i am getting the numbers down. Had to tweak the awesome typescript loader to get there. so, at-loader looks like this

  module: {
    rules: [{
      test: /\.ts$/,
      loader: "awesome-typescript-loader",
      query: {
        sourceMap: !IS_COVERAGE,
        inlineSourceMap: IS_COVERAGE,
        forkChecker: true,
        useTranspileModule: true,
        useCache: config.frontend.useCache,
        cacheDirectory: config.frontend.cacheDir
      }
    }, 
   // ...
  ]
}

The only webpack related tweak was to use the Dll plugins which saves me about 4-6 seconds.

cheap-module-source-map -> eval-cheap-module-source-map doesnt seem to help (yet). Mabye it will as the project grows.

Here are the numbers

no dll, no cache, initial: ~30s
no dll, no cache, incremental: ~4s

with dll, no cache, initial: ~24s
with dll, no cache, incremental: ~3.5s

with dll, with cache, initial: ~18s
with dll, with cache, incremental: ~3.5s

@Restuta
Copy link

Restuta commented Jun 1, 2017

Some findings that I think may be useful, we tried upgrading to Webpack 2.6, but our full build and incremental builds times increased dramatically.

Full Build 50s => 130s
Watch Build 8s => 22s

Then we reverted back and I realized that we are not using OccurrenceOrderPlugin in our Webpack 1 config, so I added that and it didn't change Full Build times, but Watch Build times grew from 8s to 20s.

Since OccurrenceOrderPlugin is now enabled by default in Webpack 2 I suspect this might be related. Is there a quick way to disable it so I can test if it's true?

Update

Went ahead and commented it out in node_modules/webpack/lib/WebpackOptionsApply and it didn't change anything for Full Build and Watch Build

@misantronic
Copy link

misantronic commented Jun 7, 2017

Just wanted to add, that I am experiencing similar issues after upgrading from 1.x -> 2.6.1. Initial build increased a bit which I don't mind. Incremental build time increased drastically by ~15s.

I might note that 71% sealing takes the longest time.

const excludeFilesRegEx = /node_modules|vendor|localizations|generated/;
const excludeFilesVendorRegEx = /node_modules|localizations|generated/;

module.exports = {
	context:  path.resolve(__dirname, 'scripts/main'),
	entry: {
		main: './main',
		develop: './develop',
		libs: [...]
	},
	output: {
		path: path.resolve(__dirname, 'dist/scripts'),
		publicPath: 'scripts/',
		filename: '[name].entry.js',
		chunkFilename: '[name].chunk.js'
	},
	externals: {...},
	resolve: {
		unsafeCache: true,

		modules: [
			'.',
			'node_modules',
			path.resolve(__dirname, 'scripts/main')
		],
		alias: {
			// Third party libraries
			...
		}
	},
	module: {
		rules: [
			{
				test: /\.js$/,
				exclude: [excludeFilesRegEx],
				use: [
					{
						loader: 'babel-loader',
						options: {
							presets: ['es2015'],
							cacheDirectory: true
						}
					},
					{
						loader: 'eslint-loader',
						options: {
							cache: true
						}
					}
				]
			},
			{
				test: /\.ejs$/,
				use: [
					{
						loader: 'ejs-loader',
						options: {
							escape: /<%[=]([\s\S]+?)%>/g,
							interpolate: /<%[=-]([\s\S]+?)%>/g,
							evaluate: /<%([\s\S]+?)%>/g
						}
					}
				]
			}
		],

		noParse: [
			/photoswipe\/dist\/photoswipe/,
			/photoswipe\/dist\/photoswipe-ui-default\.min/,
			/moment/,
			/momentjs/,
			/sinon/,
			/chai/
		]
	},
	plugins: [
		new webpack.optimize.CommonsChunkPlugin({
			names: ['libs', 'manifest']
		}),

		new webpack.DefinePlugin({ IS_DEV: true }),

		new webpack.ProvidePlugin({
			$: 'jquery',
			jQuery: 'jquery',
			'window.jQuery': 'jquery',
			'root.jQuery': 'jquery',
			_: 'underscore',
			Backbone: 'backbone',
			Marionette: 'marionette',
			i18n: 'i18n_manager'
		}),

		new HtmlWebpackPlugin({
			template: path.resolve(__dirname, 'template/index.ejs'),
			filename: '../index.html',
			excludeChunks: ['develop'],
			inject: true
		}),

		new HtmlWebpackPlugin({
			template: path.resolve(__dirname, 'template/develop.ejs'),
			filename: '../develop.html',
			excludeChunks: ['main'],
			inject: true
		})
	]
};

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

No branches or pull requests

10 participants