Instantly share code, notes, and snippets.

Embed
What would you like to do?

RIP CommonsChunkPlugin

webpack 4 removes the CommonsChunkPlugin in favor of two new options (optimization.splitChunks and optimization.runtimeChunk). Here is how it works.

Defaults

By default it now does some optimizations that should work great for most users.

Note: The defaults only affect on-demand chunks, because changing initial chunks would affect the script tags in the HTML. If you can handle this (i. e. when generating the script tags from the entrypoints in stats) you can enable these default optimizations for initial chunks too with optimization.splitChunks.chunks: "all".

webpack automatically splits chunks based on these conditions:

  • New chunk can be shared OR modules are from the node_modules folder
  • New chunk would be bigger than 30kb (before min+gz)
  • Maximum number of parallel request when loading chunks on demand would be lower or equal to 5
  • Maximum number of parallel request at initial page load would be lower or equal to 3

When trying to fullfill the last two conditions, bigger chunks are preferred.

Let's take a look at some examples.

Example 1

// entry.js
import("./a");
// a.js
import "react";
// ...

Result: A separate chunk would be created containing react. At the import call this chunk is loaded in parallel to the original chunk containing ./a.

Why:

  • Condition 1: The chunk contains modules from node_modules
  • Condition 2: react is bigger than 30kb
  • Condition 3: Number of parallel requests at the import call is 2
  • Condition 4: Doesn't affect request at initial page load

Why does this make sense?

react probably doesn't change very often compared to your application code. By moving it into a separate chunk this chunk can be cached separately from your app code (assuming you are using Long Term Caching: chunkhash, records, Cache-Control).

Example 2

// entry.js
import("./a");
import("./b");
// a.js
import "./helpers"; // helpers is 40kb in size
// ...
// b.js
import "./helpers";
import "./more-helpers"; // more-helpers is also 40kb in size
// ...

Result: A separate chunk would be created containing ./helpers and all dependencies of it. At the import calls this chunk is loaded in parallel to the original chunks.

Why:

  • Condition 1: The chunk is shared between both import calls
  • Condition 2: helpers is bigger than 30kb
  • Condition 3: Number of parallel requests at the import calls is 2
  • Condition 4: Doesn't affect request at initial page load

Why does this make sense?

Putting the helpers code into each chunk may means it need to downloaded twice by the user. By using a separate chunk it's only downloaded once. Actually it's a tradeoff, because now we pay the cost of an additional request. That's why there is a minimum size of 30kb.


With optimizations.splitChunks.chunks: "all" the same would happend for initial chunks. Chunks can even be shared between entrypoints and on-demand loading.

Configuration

For these people that like to have more control over this functionality, there are a lot of options to fit it to your needs.

Disclaimer: Don't try to optimize manually without measuring. The defaults are choosen to fit best practices of web performance.

Cache Groups

The optimization assigns modules to cache groups.

The defaults assigns all modules from node_modules to a cache group called vendors and all modules duplicated in at least 2 chunks to a change group default.

A module can be assigned to multiple cache groups. The optimization then prefers the cache group with the higher priority (priority option) or that one that forms bigger chunks.

Conditions

Modules from the same chunks and cache group will form a new chunk when all conditions are fullfilled.

There are 4 options to configure the conditions:

  • minSize (default: 30000) Minimum size for a chunk.
  • minChunks (default: 1) Minimum number of chunks that share a module before splitting
  • maxInitialRequests (default 3) Maximum number of parallel requests at an entrypoint
  • maxAsyncRequests (default 5) Maximum number of parallel requests at on-demand loading

Naming

To control the chunk name of the split chunk the name option can be used.

Note: When assigning equal names to different split chunks they are merged together. This can be used i. e. to put all vendor modules into a single chunk shared by all other entrypoints/splitpoints, but I don't recommend doing so. This can lead to more code downloaded than needed.

The magic value true automatically chooses a name based on chunks and cache group key. Elsewise a string or function can be passed.

When the name matches an entrypoint name, the entrypoint is removed.

Select chunks

With the chunks option the selected chunks can be configured. There are 3 values possible "initial", "async" and "all". When configured the optimization only selects initial chunks, on-demand chunks or all chunks.

The option reuseExistingChunk allows to reuse existing chunks instead of creating a new one when modules match exactly.

This can be controlled per cache group.

Select modules

The test option controls which modules are selected by this cache group. Omitting it selects all modules. It can be a RegExp, string or function.

It can match the absolute module resource path or chunk names. When a chunk name is matched, all modules in this chunk are selected.

Configurate cache groups

This is the default configuration:

splitChunks: {
	chunks: "async",
	minSize: 30000,
	minChunks: 1,
	maxAsyncRequests: 5,
	maxInitialRequests: 3,
	name: true,
	cacheGroups: {
		default: {
			minChunks: 2,
			priority: -20
			reuseExistingChunk: true,
		},
		vendors: {
			test: /[\\/]node_modules[\\/]/,
			priority: -10
		}
	}
}

By default cache groups inherit options from splitChunks.*, but test, priority and reuseExistingChunk can only be configured on cache group level.

cacheGroups is an object where keys are cache group keys and values are options:

Otherwise all options from the options listed above are possible: chunks, minSize, minChunks, maxAsyncRequests, maxInitialRequests, name.

To disable the default groups pass false: optimization.splitChunks.cacheGroups.default: false

The priority of the default groups are negative so any custom cache group takes higher priority (default 0).

Here are some examples and their effect:

splitChunks: {
	cacheGroups: {
		commons: {
			name: "commons",
			chunks: "initial",
			minChunks: 2
		}
	}
}

Create a commons chunk, which includes all code shared between entrypoints.

Note: This downloads more code than neccessary.

splitChunks: {
	cacheGroups: {
		commons: {
			test: /[\\/]node_modules[\\/]
			name: "vendors",
			chunks: "all"
		}
	}
}

Create a vendors chunk, which includes all code from node_modules in the whole application.

Note: This downloads more code than neccessary.

optimization.runtimeChunk

optimization.runtimeChunk: true adds an additonal chunk to each entrypoint containing only the runtime.

@valorkin

This comment has been minimized.

Show comment
Hide comment
@valorkin

valorkin Jan 20, 2018

This is awesome!

valorkin commented Jan 20, 2018

This is awesome!

@hassanbazzi

This comment has been minimized.

Show comment
Hide comment
@hassanbazzi

hassanbazzi Jan 20, 2018

Super cool! When it comes to web performance best practices though, it seems that these are more aimed at users with HTTP/1 connections.

hassanbazzi commented Jan 20, 2018

Super cool! When it comes to web performance best practices though, it seems that these are more aimed at users with HTTP/1 connections.

@NE-SmallTown

This comment has been minimized.

Show comment
Hide comment
@NE-SmallTown

NE-SmallTown Jan 21, 2018

Great work!

By the way, what does 'initial' mean? Is it 'index.js' ?

NE-SmallTown commented Jan 21, 2018

Great work!

By the way, what does 'initial' mean? Is it 'index.js' ?

@limichange

This comment has been minimized.

Show comment
Hide comment
@limichange

limichange commented Jan 21, 2018

lol

@gismanli

This comment has been minimized.

Show comment
Hide comment
@gismanli

gismanli commented Jan 21, 2018

awesome!

@simonjoom

This comment has been minimized.

Show comment
Hide comment
@simonjoom

simonjoom Jan 22, 2018

cool but i have got a question:

Before i used an array to pass all common code shared between multiple chunks to an other one here named 'sharedcode' created with CommonsChunkPlugin

config.plugins.push(new webpack.optimize.CommonsChunkPlugin({
name: 'sharedcode',
chunks: ["card", "loginForm", "registerForm", "container", "flag", "chat", "snackbar", 'login', "about", "map", "article", "instructor", "clothes", "hotels", "contact", "promo", "video", "pay", "conditions", "error"],
}));

how i can control that with the new implementation ?

simonjoom commented Jan 22, 2018

cool but i have got a question:

Before i used an array to pass all common code shared between multiple chunks to an other one here named 'sharedcode' created with CommonsChunkPlugin

config.plugins.push(new webpack.optimize.CommonsChunkPlugin({
name: 'sharedcode',
chunks: ["card", "loginForm", "registerForm", "container", "flag", "chat", "snackbar", 'login', "about", "map", "article", "instructor", "clothes", "hotels", "contact", "promo", "video", "pay", "conditions", "error"],
}));

how i can control that with the new implementation ?

@ooflorent

This comment has been minimized.

Show comment
Hide comment
@ooflorent

ooflorent Jan 25, 2018

@simonjoom
how i can control that with the new implementation ?

Webpack will do it for you! However, you can still do it using cacheGroups and test.

ooflorent commented Jan 25, 2018

@simonjoom
how i can control that with the new implementation ?

Webpack will do it for you! However, you can still do it using cacheGroups and test.

@jimthedev

This comment has been minimized.

Show comment
Hide comment
@jimthedev

jimthedev Jan 25, 2018

Any idea if this works with the uglify plugin?

jimthedev commented Jan 25, 2018

Any idea if this works with the uglify plugin?

@dwiyatci

This comment has been minimized.

Show comment
Hide comment
@dwiyatci

dwiyatci Jan 28, 2018

🤔 How do these conditions hold true for both Example 1 and Example 2?

Condition 3: Number of parallel requests at the import calls is 2
Condition 4: Doesn't affect request at initial page load

...and what does this line mean?

When trying to fullfill the last two conditions, bigger chunks are preferred.

dwiyatci commented Jan 28, 2018

🤔 How do these conditions hold true for both Example 1 and Example 2?

Condition 3: Number of parallel requests at the import calls is 2
Condition 4: Doesn't affect request at initial page load

...and what does this line mean?

When trying to fullfill the last two conditions, bigger chunks are preferred.

@yesvods

This comment has been minimized.

Show comment
Hide comment
@yesvods

yesvods Jan 29, 2018

Awesome job guys, prefect strategy!

yesvods commented Jan 29, 2018

Awesome job guys, prefect strategy!

@zD98

This comment has been minimized.

Show comment
Hide comment
@zD98

zD98 Feb 5, 2018

Great work

zD98 commented Feb 5, 2018

Great work

@retyui

This comment has been minimized.

Show comment
Hide comment
@retyui

retyui Feb 19, 2018

Fix example :
image

retyui commented Feb 19, 2018

Fix example :
image

@timneutkens

This comment has been minimized.

Show comment
Hide comment
@timneutkens

timneutkens Feb 19, 2018

@sokra the vendors config is missing /, in test.

Correct config:

splitChunks: {
	cacheGroups: {
		commons: {
			test: /[\\/]node_modules[\\/]/,
			name: "vendors",
			chunks: "all"
		}
	}
}

timneutkens commented Feb 19, 2018

@sokra the vendors config is missing /, in test.

Correct config:

splitChunks: {
	cacheGroups: {
		commons: {
			test: /[\\/]node_modules[\\/]/,
			name: "vendors",
			chunks: "all"
		}
	}
}
@gricard

This comment has been minimized.

Show comment
Hide comment
@gricard

gricard Feb 20, 2018

I've spent some time trying to get this working, but am having problems. How do I get webpack 4 to output my main bundle and a separate bundle for node_modules code named vendor.min.js? This is what I did before:

new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    filename: 'vendor.min.js',
    minChunks: module => /node_modules/.test(module.resource)
}),

I've tried variations of this, but it keeps naming the vendor code as 0.bundle.min.js instead of the name I want it to be:

    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "vendor",
                    chunks: "all"
                }
            }
        }
    },

In my dev build it ends up being named 'vendor.bundle-dev.min.js'. Is there any way I can have control over the naming of the bundles in both production and development mode?

Edit: did some more digging and figured it out: https://gist.github.com/gricard/e8057f7de1029f9036a990af95c62ba8

gricard commented Feb 20, 2018

I've spent some time trying to get this working, but am having problems. How do I get webpack 4 to output my main bundle and a separate bundle for node_modules code named vendor.min.js? This is what I did before:

new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    filename: 'vendor.min.js',
    minChunks: module => /node_modules/.test(module.resource)
}),

I've tried variations of this, but it keeps naming the vendor code as 0.bundle.min.js instead of the name I want it to be:

    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "vendor",
                    chunks: "all"
                }
            }
        }
    },

In my dev build it ends up being named 'vendor.bundle-dev.min.js'. Is there any way I can have control over the naming of the bundles in both production and development mode?

Edit: did some more digging and figured it out: https://gist.github.com/gricard/e8057f7de1029f9036a990af95c62ba8

@ldrick

This comment has been minimized.

Show comment
Hide comment
@ldrick

ldrick Feb 23, 2018

Hi, I have a config, which has two entry points, but they share the same "runtime", which is moved to a "manifest.js".
Basicly this is what worked in webpack 3:

{
    entry: {
        main: "./main.ts",
        vendor: ["babel-polyfill", "./vendor.ts"],
    },
    plugins: [
        // Move node_modules to vendor bundle.
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",
            minChunks: (module) => {
                // This prevents stylesheet resources with the .css or .scss extension
                // from being moved from their original chunk to the vendor chunk.
                if (module.resource && /^.*\.(css|scss)$/.test(module.resource)) {
                    return false;
                }
                return module.context && module.context.indexOf("node_modules") !== -1;
            },
        }),
        // Now extract just the runtime code to the manifest file, to not screw up chaching.
        new webpack.optimize.CommonsChunkPlugin({
            name: "manifest",
            minChunks: Infinity,
        }),
    ],
}

This created 3 files (besides several dynamic imports): "main.js", "vendor.js" and "manifest.js".
If I try to achive same thing now, I'd do this:

{
    entry: {
        main: "./main.ts",
        vendor: ["babel-polyfill", "./vendor.ts"],
    },
    optimization: {
        runtimeChunk: true,
        splitChunks: {
            chunks: "initial",
            cacheGroups: {
                default: false,
                vendors: false,
            },
        },
    },
}

But it leaves me with "runtime-main.js", "runtime-vendor.js", "vendor.js" and "main.js".
Is it possible to somehow have only one runtime again?

ldrick commented Feb 23, 2018

Hi, I have a config, which has two entry points, but they share the same "runtime", which is moved to a "manifest.js".
Basicly this is what worked in webpack 3:

{
    entry: {
        main: "./main.ts",
        vendor: ["babel-polyfill", "./vendor.ts"],
    },
    plugins: [
        // Move node_modules to vendor bundle.
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",
            minChunks: (module) => {
                // This prevents stylesheet resources with the .css or .scss extension
                // from being moved from their original chunk to the vendor chunk.
                if (module.resource && /^.*\.(css|scss)$/.test(module.resource)) {
                    return false;
                }
                return module.context && module.context.indexOf("node_modules") !== -1;
            },
        }),
        // Now extract just the runtime code to the manifest file, to not screw up chaching.
        new webpack.optimize.CommonsChunkPlugin({
            name: "manifest",
            minChunks: Infinity,
        }),
    ],
}

This created 3 files (besides several dynamic imports): "main.js", "vendor.js" and "manifest.js".
If I try to achive same thing now, I'd do this:

{
    entry: {
        main: "./main.ts",
        vendor: ["babel-polyfill", "./vendor.ts"],
    },
    optimization: {
        runtimeChunk: true,
        splitChunks: {
            chunks: "initial",
            cacheGroups: {
                default: false,
                vendors: false,
            },
        },
    },
}

But it leaves me with "runtime-main.js", "runtime-vendor.js", "vendor.js" and "main.js".
Is it possible to somehow have only one runtime again?

@thecrypticace

This comment has been minimized.

Show comment
Hide comment
@thecrypticace

thecrypticace Feb 25, 2018

Does this work for you?

{
    optimization: {
        runtimeChunk: {
                name: "js/manifest"
        },
    },
}

thecrypticace commented Feb 25, 2018

Does this work for you?

{
    optimization: {
        runtimeChunk: {
                name: "js/manifest"
        },
    },
}
@dfederm

This comment has been minimized.

Show comment
Hide comment
@dfederm

dfederm Feb 26, 2018

If you don't mind the runtime chunk being called "runtime", you can simply do:

{
    optimization: {
        runtimeChunk: "single",
    },
}

dfederm commented Feb 26, 2018

If you don't mind the runtime chunk being called "runtime", you can simply do:

{
    optimization: {
        runtimeChunk: "single",
    },
}
@AMilassin

This comment has been minimized.

Show comment
Hide comment
@AMilassin

AMilassin Feb 26, 2018

    optimization: {
        runtimeChunk: false,
    ...
    },

Just set runtimeChunk to false to not generate separate runtime- entries.

AMilassin commented Feb 26, 2018

    optimization: {
        runtimeChunk: false,
    ...
    },

Just set runtimeChunk to false to not generate separate runtime- entries.

@jimblue

This comment has been minimized.

Show comment
Hide comment
@jimblue

jimblue Feb 26, 2018

Can't make it work since update to webpack 4.

Here is my webpack 3 Commons Chunk config:

  // Move modules used in multiple assets to a separate commons.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'commons',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: 2
  })

  // Move node_modules vendors to a separate vendors.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendors',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: module => {
      // This prevents stylesheet resources with the .css .sass .scss extension from being moved from their original chunk to the vendor chunk
      if (module.resource && /^.*\.(css|sass|scss)$/.test(module.resource)) {
        return false
      }
      return module.context && module.context.indexOf('node_modules') !== -1
    }
  })

  // Move modules used in multiple assets to a separate commons.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: Infinity
  })

I would really appreciate some help as the documentation is not finished.

Cheers

jimblue commented Feb 26, 2018

Can't make it work since update to webpack 4.

Here is my webpack 3 Commons Chunk config:

  // Move modules used in multiple assets to a separate commons.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'commons',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: 2
  })

  // Move node_modules vendors to a separate vendors.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendors',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: module => {
      // This prevents stylesheet resources with the .css .sass .scss extension from being moved from their original chunk to the vendor chunk
      if (module.resource && /^.*\.(css|sass|scss)$/.test(module.resource)) {
        return false
      }
      return module.context && module.context.indexOf('node_modules') !== -1
    }
  })

  // Move modules used in multiple assets to a separate commons.js file in order to support long-term caching. This will avoid hash recreation for other files when only application files are changed
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    filename: config.dev ? 'js/[name].js' : 'js/[name].[hash].js',
    minChunks: Infinity
  })

I would really appreciate some help as the documentation is not finished.

Cheers

@aflext

This comment has been minimized.

Show comment
Hide comment
@aflext

aflext Feb 28, 2018

six six six

aflext commented Feb 28, 2018

six six six

@polco

This comment has been minimized.

Show comment
Hide comment
@polco

polco Feb 28, 2018

Hello!
In a current project, I have a mobile and a desktop version which are 2 different entry points. I am making 2 different HTML pages for each version. I also have 2 vendors and 2 runtime chunks because both version are not using the same node modules. With that configuration, I can develop and test both the desktop and the mobile version at the same time. My server was serving the correct HTML page based on the user agent.
How can i achieve that with the new API ? Because now i don't think i can say 'First create a vendor A chunk that takes all the node modules requires by entry point A and give me a runtime for entry point A + vendor A. now i want the same for B'

I guess in development, i could just have the same vendor / runtime for both entries ? and make 2 different config for production.

polco commented Feb 28, 2018

Hello!
In a current project, I have a mobile and a desktop version which are 2 different entry points. I am making 2 different HTML pages for each version. I also have 2 vendors and 2 runtime chunks because both version are not using the same node modules. With that configuration, I can develop and test both the desktop and the mobile version at the same time. My server was serving the correct HTML page based on the user agent.
How can i achieve that with the new API ? Because now i don't think i can say 'First create a vendor A chunk that takes all the node modules requires by entry point A and give me a runtime for entry point A + vendor A. now i want the same for B'

I guess in development, i could just have the same vendor / runtime for both entries ? and make 2 different config for production.

@gpartida

This comment has been minimized.

Show comment
Hide comment
@gpartida

gpartida Feb 28, 2018

So how do we disable all automatic chunk creation if we always just want everything in one bundle file now?

gpartida commented Feb 28, 2018

So how do we disable all automatic chunk creation if we always just want everything in one bundle file now?

@pavelloz

This comment has been minimized.

Show comment
Hide comment
@pavelloz

pavelloz Mar 1, 2018

This is going to need A LOT of documentation, examples and pain. Kind of reminds me learning curve of webpack 1 back in the day... guess, rebuild, repeat, until something good happens.

pavelloz commented Mar 1, 2018

This is going to need A LOT of documentation, examples and pain. Kind of reminds me learning curve of webpack 1 back in the day... guess, rebuild, repeat, until something good happens.

@jconroy

This comment has been minimized.

Show comment
Hide comment
@jconroy

jconroy Mar 1, 2018

Thanks for the update! I'm also having a few difficulties updating my current config to use 4.x. https://gist.github.com/jconroy/b8f5e31ddfc040faf69a37fad3acb065 - it will be great to get the documentation cleaned up and finished.

jconroy commented Mar 1, 2018

Thanks for the update! I'm also having a few difficulties updating my current config to use 4.x. https://gist.github.com/jconroy/b8f5e31ddfc040faf69a37fad3acb065 - it will be great to get the documentation cleaned up and finished.

@buddyackerman

This comment has been minimized.

Show comment
Hide comment
@buddyackerman

buddyackerman Mar 2, 2018

I made the mistake of updating my project to use 4.0.1 (from v3.10.0) and now nothing builds because of this. I removed all references to CommonsChunk and after failing to get optimizations.splitChunks to work, removed that as well to let the default behavior run and I still get the following output. Lack of real documentation of this change is causing a real mess.

clean-webpack-plugin: C:\Projects\MyProjects\Accessories\Accessories.Web\snp\dist has been removed.
 10% building modules 3/3 modules 0 active(node:9072) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
 
(node:9072) DeprecationWarning: webpack: Using compiler.resolvers.normal is deprecated.

Use compiler.resolverFactory.plugin("resolver normal", resolver => {
  resolver.apply(/* ... */);
}); instead.

(node:9072) DeprecationWarning: Tapable.apply is deprecated. Call apply on the plugin direct 11% building modules 12/16 modules 4 active ...de_modules\@angular\core\esm5\core.jsC:\Projects\MyProjects\Accessories\Accessories.Web\snp\node_modules\webpack\lib\Chunk.js:449
                throw new Error("Chunk.blocks: Use ChunkGroup.getBlocks() instead");

My entry looks like this

"entry": {
  "main": [
      "./src\\main.ts"
  ],
  "polyfills": [
      "./src\\polyfills.ts"
  ],
  "styles": [
      "./src\\snp.css"
  ]
},

buddyackerman commented Mar 2, 2018

I made the mistake of updating my project to use 4.0.1 (from v3.10.0) and now nothing builds because of this. I removed all references to CommonsChunk and after failing to get optimizations.splitChunks to work, removed that as well to let the default behavior run and I still get the following output. Lack of real documentation of this change is causing a real mess.

clean-webpack-plugin: C:\Projects\MyProjects\Accessories\Accessories.Web\snp\dist has been removed.
 10% building modules 3/3 modules 0 active(node:9072) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
 
(node:9072) DeprecationWarning: webpack: Using compiler.resolvers.normal is deprecated.

Use compiler.resolverFactory.plugin("resolver normal", resolver => {
  resolver.apply(/* ... */);
}); instead.

(node:9072) DeprecationWarning: Tapable.apply is deprecated. Call apply on the plugin direct 11% building modules 12/16 modules 4 active ...de_modules\@angular\core\esm5\core.jsC:\Projects\MyProjects\Accessories\Accessories.Web\snp\node_modules\webpack\lib\Chunk.js:449
                throw new Error("Chunk.blocks: Use ChunkGroup.getBlocks() instead");

My entry looks like this

"entry": {
  "main": [
      "./src\\main.ts"
  ],
  "polyfills": [
      "./src\\polyfills.ts"
  ],
  "styles": [
      "./src\\snp.css"
  ]
},
@retorquere

This comment has been minimized.

Show comment
Hide comment
@retorquere

retorquere Mar 4, 2018

How do I get rid of the vendors chunk? I have this optimization block:

    "optimization": {
      "minimize": false,
      "concatenateModules": false,
      "noEmitOnErrors": true,
      "namedModules": true,
      "namedChunks": true,
      "runtimeChunk": false,
      "splitChunks": {
        "chunks": "all",
        "name": true,
        "cacheGroups": {
          "commons": {
            "name": "commons",
            "minChunks": 2
          }
        }
      }

and I'm trying to reproduce CommonsChunkPlugin({ minChunks: 2, name: 'common', filename: 'common.js' }), IOW everything shared, vendor or not, in a single commons.js.

retorquere commented Mar 4, 2018

How do I get rid of the vendors chunk? I have this optimization block:

    "optimization": {
      "minimize": false,
      "concatenateModules": false,
      "noEmitOnErrors": true,
      "namedModules": true,
      "namedChunks": true,
      "runtimeChunk": false,
      "splitChunks": {
        "chunks": "all",
        "name": true,
        "cacheGroups": {
          "commons": {
            "name": "commons",
            "minChunks": 2
          }
        }
      }

and I'm trying to reproduce CommonsChunkPlugin({ minChunks: 2, name: 'common', filename: 'common.js' }), IOW everything shared, vendor or not, in a single commons.js.

@jetmirshatri

This comment has been minimized.

Show comment
Hide comment
@jetmirshatri

jetmirshatri Mar 4, 2018

@retorquere, might change in the future once the docs are final but this works for me using the latest version of webpack 4.1.0.

optimization: {
    // ...
    splitChunks: {
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'all',
          minChunks: 2,
          enforce: true
        }
      }
    }
  }

This will produce a commons.js file.

jetmirshatri commented Mar 4, 2018

@retorquere, might change in the future once the docs are final but this works for me using the latest version of webpack 4.1.0.

optimization: {
    // ...
    splitChunks: {
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'all',
          minChunks: 2,
          enforce: true
        }
      }
    }
  }

This will produce a commons.js file.

@huanghanyue

This comment has been minimized.

Show comment
Hide comment
@huanghanyue

huanghanyue Mar 7, 2018

so awesome!

huanghanyue commented Mar 7, 2018

so awesome!

@StalkAlex

This comment has been minimized.

Show comment
Hide comment
@StalkAlex

StalkAlex Mar 7, 2018

@ldrick have you found a way to convert webpack 3 config to webpack 4 in part of manifest in CommonsChunkPlugin? I have broken hot-reload and I guess it has something with CommonsChunkPlugin.

StalkAlex commented Mar 7, 2018

@ldrick have you found a way to convert webpack 3 config to webpack 4 in part of manifest in CommonsChunkPlugin? I have broken hot-reload and I guess it has something with CommonsChunkPlugin.

@retorquere

This comment has been minimized.

Show comment
Hide comment
@retorquere

retorquere Mar 7, 2018

@jetmirshatri sorry for the late reaction, looks like gists don't send notifications.

That config took care of getting a single commons file, but now it looks like the runtime (like definitions of webpack_require) have moved from the common file (where they used to live in webpack 3) to the individual outputs based on the entries. This means that where multiple entry points which used to share state when loaded sequentially now don't (I think) because each will have its own private copy of installedModules. Is there a way to get the old behavior back?

retorquere commented Mar 7, 2018

@jetmirshatri sorry for the late reaction, looks like gists don't send notifications.

That config took care of getting a single commons file, but now it looks like the runtime (like definitions of webpack_require) have moved from the common file (where they used to live in webpack 3) to the individual outputs based on the entries. This means that where multiple entry points which used to share state when loaded sequentially now don't (I think) because each will have its own private copy of installedModules. Is there a way to get the old behavior back?

@l0gicgate

This comment has been minimized.

Show comment
Hide comment
@l0gicgate

l0gicgate Mar 7, 2018

My config is outputting 2 bundles for both JS and CSS. I want to output one vendors.js and one bundle.js and once bundle.css file. Somehow it is creating an empty vendors.css file. I tried using removeEmptyChunks (which is enabled by default) but it doesn't do anything. It'll still emit an empty chunk:

Here is the config

{
  splitChunks: {
    cacheGroups: {
      default: {
        chunks: 'initial',
        name: 'bundle',
        priority: -20,
        reuseExistingChunk: true,
      },
      vendor: {
        chunks: 'initial',
        name: 'vendor',
        priority: -10,
        test: /node_modules\/(.*)\.js/
      }
    }
  }
}

Is there a way through the configuration to omit generating that file altogether? I am using

l0gicgate commented Mar 7, 2018

My config is outputting 2 bundles for both JS and CSS. I want to output one vendors.js and one bundle.js and once bundle.css file. Somehow it is creating an empty vendors.css file. I tried using removeEmptyChunks (which is enabled by default) but it doesn't do anything. It'll still emit an empty chunk:

Here is the config

{
  splitChunks: {
    cacheGroups: {
      default: {
        chunks: 'initial',
        name: 'bundle',
        priority: -20,
        reuseExistingChunk: true,
      },
      vendor: {
        chunks: 'initial',
        name: 'vendor',
        priority: -10,
        test: /node_modules\/(.*)\.js/
      }
    }
  }
}

Is there a way through the configuration to omit generating that file altogether? I am using

@retorquere

This comment has been minimized.

Show comment
Hide comment
@retorquere

retorquere Mar 7, 2018

To answer my own question: this did it for me

    optimization: {
      splitChunks: {
        // name: true,
        cacheGroups: {
          common: {
            name: 'common',
            chunks: 'all',
            // minSize: 1,
            minChunks: 2,
            enforce: true,
          },
        },
      },
      runtimeChunk: {
        name: 'common'
      },
    },

This thread should really be prominently linked to from the webpack blog.

retorquere commented Mar 7, 2018

To answer my own question: this did it for me

    optimization: {
      splitChunks: {
        // name: true,
        cacheGroups: {
          common: {
            name: 'common',
            chunks: 'all',
            // minSize: 1,
            minChunks: 2,
            enforce: true,
          },
        },
      },
      runtimeChunk: {
        name: 'common'
      },
    },

This thread should really be prominently linked to from the webpack blog.

@ibreathebsb

This comment has been minimized.

Show comment
Hide comment
@ibreathebsb

ibreathebsb Mar 8, 2018

What is initial chunks?

ibreathebsb commented Mar 8, 2018

What is initial chunks?

@palnes

This comment has been minimized.

Show comment
Hide comment
@palnes

palnes Mar 8, 2018

@ibreathebsb initial chunks are the ones you link to in the HTML file. also known as entry chunks.

palnes commented Mar 8, 2018

@ibreathebsb initial chunks are the ones you link to in the HTML file. also known as entry chunks.

@vsambor

This comment has been minimized.

Show comment
Hide comment
@vsambor

vsambor Mar 9, 2018

I have a quite big vue js project and I am trying to migrate from webpack 2.7 to the last version 4.1.1.
I manage to have it working but the final bundle is bigger than before. And I don't understand why.

BEFORE

 app.bundle.js  2.72 MB       0  [emitted]  [big]  main

AFTER

app.bundle.js  4.48 MiB       0  [emitted]  [big]  main

This is my prod config:

const common = require('./webpack.common.js');
const merge = require('webpack-merge');
var webpack = require('webpack');

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = merge(common, {
  mode: 'production',
  devtool: '#source-map',
  plugins: [
    new OptimizeCssAssetsPlugin(),
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    }),
  ]
})

What am I missing? thank you!

vsambor commented Mar 9, 2018

I have a quite big vue js project and I am trying to migrate from webpack 2.7 to the last version 4.1.1.
I manage to have it working but the final bundle is bigger than before. And I don't understand why.

BEFORE

 app.bundle.js  2.72 MB       0  [emitted]  [big]  main

AFTER

app.bundle.js  4.48 MiB       0  [emitted]  [big]  main

This is my prod config:

const common = require('./webpack.common.js');
const merge = require('webpack-merge');
var webpack = require('webpack');

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = merge(common, {
  mode: 'production',
  devtool: '#source-map',
  plugins: [
    new OptimizeCssAssetsPlugin(),
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    }),
  ]
})

What am I missing? thank you!

@audiolion

This comment has been minimized.

Show comment
Hide comment
@audiolion

audiolion Mar 9, 2018

@vsambor the issue is you arent applying the uglifyjsplugin most likely.

$ npm i uglifyjs-webpack-plugin --save-dev

Then in your config file add

const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin');

module.exports = merge(common, {
   ...,
   optimization: {
     minimizer: [
       new UglifyJsWebpackPlugin({
         parallel: true, // uses all cores available on given machine
         sourceMap: <true/false>,
       }),
    ],
   }

audiolion commented Mar 9, 2018

@vsambor the issue is you arent applying the uglifyjsplugin most likely.

$ npm i uglifyjs-webpack-plugin --save-dev

Then in your config file add

const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin');

module.exports = merge(common, {
   ...,
   optimization: {
     minimizer: [
       new UglifyJsWebpackPlugin({
         parallel: true, // uses all cores available on given machine
         sourceMap: <true/false>,
       }),
    ],
   }
@jhsilva

This comment has been minimized.

Show comment
Hide comment
@jhsilva

jhsilva Mar 10, 2018

thanks ❤️

jhsilva commented Mar 10, 2018

thanks ❤️

@nirvinm

This comment has been minimized.

Show comment
Hide comment
@nirvinm

nirvinm Mar 13, 2018

In this case, how can I determine the order of <script> tags? In my case, there are 3 chunks are generated for first page.

page1.js
vendor-page1.js
vendor-page1-page2.js

How can I determine the orders of the script if Webpack dynamically generates the chunks?

nirvinm commented Mar 13, 2018

In this case, how can I determine the order of <script> tags? In my case, there are 3 chunks are generated for first page.

page1.js
vendor-page1.js
vendor-page1-page2.js

How can I determine the orders of the script if Webpack dynamically generates the chunks?

@creage

This comment has been minimized.

Show comment
Hide comment
@creage

creage Mar 14, 2018

Could someone please advice what config should I use in Webpack4 to get same results as Webpack3 gave with

new webpack.optimize.CommonsChunkPlugin({
    deepChildren: true,
    async: 'common',
    minChunks: 2
})

As my bundles had no overlaps on V3, and on V4 my overlapping is terrible 1186 files were bundled into 56 bundles. Of those, 34 bundles have overlaps. Tried different options, but can't get the same result.

creage commented Mar 14, 2018

Could someone please advice what config should I use in Webpack4 to get same results as Webpack3 gave with

new webpack.optimize.CommonsChunkPlugin({
    deepChildren: true,
    async: 'common',
    minChunks: 2
})

As my bundles had no overlaps on V3, and on V4 my overlapping is terrible 1186 files were bundled into 56 bundles. Of those, 34 bundles have overlaps. Tried different options, but can't get the same result.

@TheLarkInn

This comment has been minimized.

Show comment
Hide comment
@TheLarkInn

TheLarkInn Mar 15, 2018

@nirvinm compilation.stats will contain the chunkGraph information including which chunks have parents/children (which determines order)

TheLarkInn commented Mar 15, 2018

@nirvinm compilation.stats will contain the chunkGraph information including which chunks have parents/children (which determines order)

@christianhg

This comment has been minimized.

Show comment
Hide comment
@christianhg

christianhg Mar 16, 2018

Using webpack 3 and CommonsChunkPlugin I'm making sure none of my entries copy anything from one another. It might be a peculiar use case, but it's what I need right now for this project. I looks something like this:

module.exports = {
  entry: {
    core: './src/core/index.js',
    add: './src/plugins/add/index.js',
    bar: './src/plugins/bar/index.js',
    foo: './src/plugins/foo/index.js',
    subtract: './src/plugins/subtract/index.js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      // All chunk names have to be listed here. They are ordered a the way
      // that any chunk dependency needs to be listed after the chunk that
      // depends on it. Chunks with many dependencies are in the beginning of
      // the array and chunks with no dependencies are in the end.
      names: ['bar', 'foo', 'add', 'subtract', 'core']
    })
  ]
}

Is it possible to reach a similar output with webpack 4?

christianhg commented Mar 16, 2018

Using webpack 3 and CommonsChunkPlugin I'm making sure none of my entries copy anything from one another. It might be a peculiar use case, but it's what I need right now for this project. I looks something like this:

module.exports = {
  entry: {
    core: './src/core/index.js',
    add: './src/plugins/add/index.js',
    bar: './src/plugins/bar/index.js',
    foo: './src/plugins/foo/index.js',
    subtract: './src/plugins/subtract/index.js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      // All chunk names have to be listed here. They are ordered a the way
      // that any chunk dependency needs to be listed after the chunk that
      // depends on it. Chunks with many dependencies are in the beginning of
      // the array and chunks with no dependencies are in the end.
      names: ['bar', 'foo', 'add', 'subtract', 'core']
    })
  ]
}

Is it possible to reach a similar output with webpack 4?

@leuvi

This comment has been minimized.

Show comment
Hide comment
@leuvi

leuvi Mar 16, 2018

I have the same problem as you @l0gicgate

leuvi commented Mar 16, 2018

I have the same problem as you @l0gicgate

@dtothefp

This comment has been minimized.

Show comment
Hide comment
@dtothefp

dtothefp Mar 16, 2018

I'm upgrading from Webpack v2 to Webpack v4. I'm using mini-css-extract-plugin to replace extract-text-webpack-plugin. Previously I was using require.ensure to create multiple JS chunks but CSS modules imported into chunks were creating only a single CSS file. I'd like to maintain this functionality but I cannot seem to create a single CSS chunk. Tried the config below but it's not doing anything 🤷‍♂️

    optimization: {
      splitChunks: {
        cacheGroups: {
          commons: {
            name: 'commons',
            test: /\.css$/,
            chunks: 'all',
            minChunks: 2,
            enforce: true
          }
        }
      }
    },

dtothefp commented Mar 16, 2018

I'm upgrading from Webpack v2 to Webpack v4. I'm using mini-css-extract-plugin to replace extract-text-webpack-plugin. Previously I was using require.ensure to create multiple JS chunks but CSS modules imported into chunks were creating only a single CSS file. I'd like to maintain this functionality but I cannot seem to create a single CSS chunk. Tried the config below but it's not doing anything 🤷‍♂️

    optimization: {
      splitChunks: {
        cacheGroups: {
          commons: {
            name: 'commons',
            test: /\.css$/,
            chunks: 'all',
            minChunks: 2,
            enforce: true
          }
        }
      }
    },
@mnpenner

This comment has been minimized.

Show comment
Hide comment
@mnpenner

mnpenner Mar 16, 2018

@TheLarkInn Where is this chunkGraph you speak of?

I found assets.compilation.chunkGroups.0.chunks.0.files -- is that guaranteed to be in the proper order for inserting into HTML?

image

Specifically, something like this:

{
    apply: function(compiler) {
        compiler.plugin('done', function(stats, done) {
            let assets = {};
            
            for(let chunkGroup of stats.compilation.chunkGroups) {
                if(chunkGroup.name) {
                    let files = [];
                    for(let chunk of chunkGroup.chunks) {
                        files.push(...chunk.files);
                    }
                    assets[chunkGroup.name] = files;
                }
            }

            fs.writeFile('webpack.stats.json', JSON.stringify({
                assetsByChunkName: assets,
                publicPath: stats.compilation.outputOptions.publicPath
            }), done);
        });
    }
},

Will spit out this JSON:

{
    "assetsByChunkName": {
        "main": [
            "runtime~main.a23dfea309e23d13bfcb.js",
            "runtime~main.a23dfea309e23d13bfcb.js.map",
            "chunk.81da97be08338e4f2807.css",
            "chunk.81da97be08338e4f2807.js",
            "chunk.81da97be08338e4f2807.css.map",
            "chunk.81da97be08338e4f2807.js.map",
            "chunk.d68430785367f8475580.css",
            "chunk.d68430785367f8475580.js",
            "chunk.d68430785367f8475580.css.map",
            "chunk.d68430785367f8475580.js.map"
        ],
        "print": [
            "runtime~print.a22d41d203e00584dadd.js",
            "runtime~print.a22d41d203e00584dadd.js.map",
            "chunk.00ae08b2c535eb95bb2e.css",
            "chunk.00ae08b2c535eb95bb2e.js",
            "chunk.00ae08b2c535eb95bb2e.css.map",
            "chunk.00ae08b2c535eb95bb2e.js.map"
        ]
    },
    "publicPath": "/assets/"
}

Which should be easily parseable in your language of choice.

mnpenner commented Mar 16, 2018

@TheLarkInn Where is this chunkGraph you speak of?

I found assets.compilation.chunkGroups.0.chunks.0.files -- is that guaranteed to be in the proper order for inserting into HTML?

image

Specifically, something like this:

{
    apply: function(compiler) {
        compiler.plugin('done', function(stats, done) {
            let assets = {};
            
            for(let chunkGroup of stats.compilation.chunkGroups) {
                if(chunkGroup.name) {
                    let files = [];
                    for(let chunk of chunkGroup.chunks) {
                        files.push(...chunk.files);
                    }
                    assets[chunkGroup.name] = files;
                }
            }

            fs.writeFile('webpack.stats.json', JSON.stringify({
                assetsByChunkName: assets,
                publicPath: stats.compilation.outputOptions.publicPath
            }), done);
        });
    }
},

Will spit out this JSON:

{
    "assetsByChunkName": {
        "main": [
            "runtime~main.a23dfea309e23d13bfcb.js",
            "runtime~main.a23dfea309e23d13bfcb.js.map",
            "chunk.81da97be08338e4f2807.css",
            "chunk.81da97be08338e4f2807.js",
            "chunk.81da97be08338e4f2807.css.map",
            "chunk.81da97be08338e4f2807.js.map",
            "chunk.d68430785367f8475580.css",
            "chunk.d68430785367f8475580.js",
            "chunk.d68430785367f8475580.css.map",
            "chunk.d68430785367f8475580.js.map"
        ],
        "print": [
            "runtime~print.a22d41d203e00584dadd.js",
            "runtime~print.a22d41d203e00584dadd.js.map",
            "chunk.00ae08b2c535eb95bb2e.css",
            "chunk.00ae08b2c535eb95bb2e.js",
            "chunk.00ae08b2c535eb95bb2e.css.map",
            "chunk.00ae08b2c535eb95bb2e.js.map"
        ]
    },
    "publicPath": "/assets/"
}

Which should be easily parseable in your language of choice.

@jtomaszewski

This comment has been minimized.

Show comment
Hide comment
@jtomaszewski

jtomaszewski Mar 19, 2018

FYI: Documentation for SplitChunksPlugin which is currently in progress was very helpful to us during migration from webpack 3 to webpack 4.

Here's how we migrated our chunks configuration while keeping the same functionality as we had before:

// BEFORE (webpack 3)
  const config = { 
    entry: {
      app: ['./src/ng2/app.module'],
      main: ['./src/main-admin'],
    },
    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendors',
        minChunks: function(module) {
          return (
            module.resource &&
            (module.resource.startsWith(root('node_modules')) ||
              module.resource.startsWith(root('vendor')))
          );
        },
      }),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'commons',
        chunks: ['app', 'main'],
        minChunks: function(module) {
          return module.resource && module.resource.startsWith(root('src'));
        },
      }),
    ]
  };

// AFTER (webpack 4)
  const config = { 
    entry: {
      main: [
        './src/ng2/app.module',
        './src/main-admin',
      ],
    },
    optimization: {
      splitChunks: {
        chunks: 'all',
        minSize: 0,
        maxAsyncRequests: Infinity,
        maxInitialRequests: Infinity,
        name: true,
        cacheGroups: {
          default: {
            chunks: 'async',
            minSize: 30000,
            minChunks: 2,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            priority: -20,
            reuseExistingChunk: true,
          },
          vendors: {
            name: 'vendors',
            enforce: true,
            test: function(module) {
              return (
                module.resource &&
                (module.resource.startsWith(root('node_modules')) ||
                  module.resource.startsWith(root('vendor')))
              );
            },
            priority: -10,
            reuseExistingChunk: true,
          },
          commons: {
            name: 'commons',
            chunks: 'initial',
            minChunks: 2,
            test: function(module) {
              return module.resource && module.resource.startsWith(root('src'));
            },
            priority: -5,
            reuseExistingChunk: true,
          },
        },
      },
    }
  };

jtomaszewski commented Mar 19, 2018

FYI: Documentation for SplitChunksPlugin which is currently in progress was very helpful to us during migration from webpack 3 to webpack 4.

Here's how we migrated our chunks configuration while keeping the same functionality as we had before:

// BEFORE (webpack 3)
  const config = { 
    entry: {
      app: ['./src/ng2/app.module'],
      main: ['./src/main-admin'],
    },
    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendors',
        minChunks: function(module) {
          return (
            module.resource &&
            (module.resource.startsWith(root('node_modules')) ||
              module.resource.startsWith(root('vendor')))
          );
        },
      }),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'commons',
        chunks: ['app', 'main'],
        minChunks: function(module) {
          return module.resource && module.resource.startsWith(root('src'));
        },
      }),
    ]
  };

// AFTER (webpack 4)
  const config = { 
    entry: {
      main: [
        './src/ng2/app.module',
        './src/main-admin',
      ],
    },
    optimization: {
      splitChunks: {
        chunks: 'all',
        minSize: 0,
        maxAsyncRequests: Infinity,
        maxInitialRequests: Infinity,
        name: true,
        cacheGroups: {
          default: {
            chunks: 'async',
            minSize: 30000,
            minChunks: 2,
            maxAsyncRequests: 5,
            maxInitialRequests: 3,
            priority: -20,
            reuseExistingChunk: true,
          },
          vendors: {
            name: 'vendors',
            enforce: true,
            test: function(module) {
              return (
                module.resource &&
                (module.resource.startsWith(root('node_modules')) ||
                  module.resource.startsWith(root('vendor')))
              );
            },
            priority: -10,
            reuseExistingChunk: true,
          },
          commons: {
            name: 'commons',
            chunks: 'initial',
            minChunks: 2,
            test: function(module) {
              return module.resource && module.resource.startsWith(root('src'));
            },
            priority: -5,
            reuseExistingChunk: true,
          },
        },
      },
    }
  };
@alexcheuk

This comment has been minimized.

Show comment
Hide comment
@alexcheuk

alexcheuk Mar 22, 2018

Does anyone know if this is a bug or a Webpack 4 change?

for the option output.chunkFilename the docs says

This option determines the name of non-entry chunk files

In Webpack 4 this works properly as expect. Unless you split the runtimeChunk into a seperate file.

So using this config

let config = {
    output: {
        publicPath: config.production.publicPath,
        filename: '[name].js',
        chunkFilename: '[name].[chunkhash].js'
    },
    optimization: {
        runtimeChunk: false
    }
}

my entries files will follow the naming filename: '[name].js' and lazyloaded chunks will follow chunkFilename: '[name].[chunkhash].js'

but when I use this config (seperate the runtimeChunk):

let config = {
    output: {
        publicPath: config.production.publicPath,
        filename: '[name].js',
        chunkFilename: '[name].[chunkhash].js'
    },
    optimization: {
        runtimeChunk: { name: 'manifest' }
    }
}

all my files names becomes '[name].[chunkhash].js'

Is this an expected behaviour?

alexcheuk commented Mar 22, 2018

Does anyone know if this is a bug or a Webpack 4 change?

for the option output.chunkFilename the docs says

This option determines the name of non-entry chunk files

In Webpack 4 this works properly as expect. Unless you split the runtimeChunk into a seperate file.

So using this config

let config = {
    output: {
        publicPath: config.production.publicPath,
        filename: '[name].js',
        chunkFilename: '[name].[chunkhash].js'
    },
    optimization: {
        runtimeChunk: false
    }
}

my entries files will follow the naming filename: '[name].js' and lazyloaded chunks will follow chunkFilename: '[name].[chunkhash].js'

but when I use this config (seperate the runtimeChunk):

let config = {
    output: {
        publicPath: config.production.publicPath,
        filename: '[name].js',
        chunkFilename: '[name].[chunkhash].js'
    },
    optimization: {
        runtimeChunk: { name: 'manifest' }
    }
}

all my files names becomes '[name].[chunkhash].js'

Is this an expected behaviour?

@sherlock1982

This comment has been minimized.

Show comment
Hide comment
@sherlock1982

sherlock1982 Mar 22, 2018

Hi! All this is very interesting but fine tuning is a bit unclear.
What to do if:

  1. I have async chunk and don't want it to be splitted for vendors. Because webpack splits it into two: async~vendor (big) and async (small, approx. 130bytes). And that's overhead.

  2. I have entrypoint chunk and don't want it to be splitted. Because see 1.

  3. I have entrypoint chunk and do want it to be splitted because it's too big.

Well I understand that I can set chunks to all, initial, async but that changes whole application behavior.
Are there any reasons these shoudn't worry me and generating too small or too big chunks is ok?

sherlock1982 commented Mar 22, 2018

Hi! All this is very interesting but fine tuning is a bit unclear.
What to do if:

  1. I have async chunk and don't want it to be splitted for vendors. Because webpack splits it into two: async~vendor (big) and async (small, approx. 130bytes). And that's overhead.

  2. I have entrypoint chunk and don't want it to be splitted. Because see 1.

  3. I have entrypoint chunk and do want it to be splitted because it's too big.

Well I understand that I can set chunks to all, initial, async but that changes whole application behavior.
Are there any reasons these shoudn't worry me and generating too small or too big chunks is ok?

@malectro

This comment has been minimized.

Show comment
Hide comment
@malectro

malectro Mar 23, 2018

@jtomaszewski i think he means you want to call stats.toJson({entrypoints: true})?

malectro commented Mar 23, 2018

@jtomaszewski i think he means you want to call stats.toJson({entrypoints: true})?

@didschai

This comment has been minimized.

Show comment
Hide comment
@didschai

didschai Mar 29, 2018

@jtomaszewski Thanks for your example. I adapted parts of it and the files seem to look OK.
However, if I include the entrypoint bundle (which contains the webpackBootstrap runtime code) in my html page, it is not executed and no chunks are loaded.
This is the config which splits the webapp into 2 areas:

        minimize: false,
        splitChunks: {
            chunks: 'all',
            minSize: 0,
            maxAsyncRequests: Infinity,
            maxInitialRequests: Infinity,
            name: true,
            cacheGroups:
                {
                    default: {
                        chunks: 'async',
                        minSize: 30000,
                        minChunks: 2,
                        maxAsyncRequests: 5,
                        maxInitialRequests: 3,
                        priority: -20,
                        reuseExistingChunk: true,
                    },
                    main: {
                        name: "main",
                        test: function (module) {
                            return (
                              module.resource &&
                              (module.resource.includes('node_modules') ||
                                module.resource.includes('Root'))
                            );
                        },
                        reuseExistingChunk: true,
                        priority: -10,
                        enforce: true
                    },
                    admin: {
                        name: "admin",
                        test: function (module) {
                            return (
                              module.resource &&
                              (module.resource.includes('node_modules') ||
                                module.resource.includes('Admin'))
                            );
                        },
                        reuseExistingChunk: true,
                        priority: -9,
                        enforce: true
                    }
                }
        }
    }

the output file structure is:

./Root/...    // some other bundles
./Admin/shared/main.bundle.js
./Admin/dashboard/index.js    // this should be the main entry of admin area
./2.chunk.js
...
./admin.chunk.js
./main.chunk.js

is there anything I'm still missing?
Thanks!

didschai commented Mar 29, 2018

@jtomaszewski Thanks for your example. I adapted parts of it and the files seem to look OK.
However, if I include the entrypoint bundle (which contains the webpackBootstrap runtime code) in my html page, it is not executed and no chunks are loaded.
This is the config which splits the webapp into 2 areas:

        minimize: false,
        splitChunks: {
            chunks: 'all',
            minSize: 0,
            maxAsyncRequests: Infinity,
            maxInitialRequests: Infinity,
            name: true,
            cacheGroups:
                {
                    default: {
                        chunks: 'async',
                        minSize: 30000,
                        minChunks: 2,
                        maxAsyncRequests: 5,
                        maxInitialRequests: 3,
                        priority: -20,
                        reuseExistingChunk: true,
                    },
                    main: {
                        name: "main",
                        test: function (module) {
                            return (
                              module.resource &&
                              (module.resource.includes('node_modules') ||
                                module.resource.includes('Root'))
                            );
                        },
                        reuseExistingChunk: true,
                        priority: -10,
                        enforce: true
                    },
                    admin: {
                        name: "admin",
                        test: function (module) {
                            return (
                              module.resource &&
                              (module.resource.includes('node_modules') ||
                                module.resource.includes('Admin'))
                            );
                        },
                        reuseExistingChunk: true,
                        priority: -9,
                        enforce: true
                    }
                }
        }
    }

the output file structure is:

./Root/...    // some other bundles
./Admin/shared/main.bundle.js
./Admin/dashboard/index.js    // this should be the main entry of admin area
./2.chunk.js
...
./admin.chunk.js
./main.chunk.js

is there anything I'm still missing?
Thanks!

@BalticSoft

This comment has been minimized.

Show comment
Hide comment
@BalticSoft

BalticSoft Mar 30, 2018

Hi!. What means enforce: true ?

BalticSoft commented Mar 30, 2018

Hi!. What means enforce: true ?

@BalticSoft

This comment has been minimized.

Show comment
Hide comment
@BalticSoft

BalticSoft Mar 30, 2018

I have
new webpack.optimize.CommonsChunkPlugin({ name: "commons", filename: "commons_w.js", minChunks: 3, }),
But when i replaced for
optimization: { splitChunks: { cacheGroups: { common: { name: 'common_w', chunks: 'all', minChunks: 2, enforce: true, },}, } },. I have error "require is not defined".

index.html
`<script src="/assets/js/r/common_w"></script>
....

<script src="[other]"></script>

`
Thanks!

BalticSoft commented Mar 30, 2018

I have
new webpack.optimize.CommonsChunkPlugin({ name: "commons", filename: "commons_w.js", minChunks: 3, }),
But when i replaced for
optimization: { splitChunks: { cacheGroups: { common: { name: 'common_w', chunks: 'all', minChunks: 2, enforce: true, },}, } },. I have error "require is not defined".

index.html
`<script src="/assets/js/r/common_w"></script>
....

<script src="[other]"></script>

`
Thanks!

@budarin

This comment has been minimized.

Show comment
Hide comment
@budarin

budarin Apr 4, 2018

I can not optimize my bundles with a new version

here is my config:

export default {
    mode: 'production',
    target: 'web',
    cache: true,
    entry: {
        client: './src/client/index.js',
    },
    output: {
        path: path.resolve('./dist'),
        filename: '[name].[hash].js',
        chunkFilename: '[name].[chunkhash].chunk.js',
        publicPath: '/',
    },
    // devtool: 'inline-cheap-module-source-map',
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /node_modules/, // you may add "vendor.js" here if you want to
                    name: 'vendor',
                    chunks: 'all',
                    enforce: true,
                },
            },
        },
        runtimeChunk: {
            name: 'runtime',
        },
        minimizer: [new BabiliPlugin(), new OptimizeJsPlugin({ sourceMap: false })],
        occurrenceOrder: true,
    },
...

after building many bundles have common modules.
How to lift common modules to to a parent bundle?

Thanks

budarin commented Apr 4, 2018

I can not optimize my bundles with a new version

here is my config:

export default {
    mode: 'production',
    target: 'web',
    cache: true,
    entry: {
        client: './src/client/index.js',
    },
    output: {
        path: path.resolve('./dist'),
        filename: '[name].[hash].js',
        chunkFilename: '[name].[chunkhash].chunk.js',
        publicPath: '/',
    },
    // devtool: 'inline-cheap-module-source-map',
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /node_modules/, // you may add "vendor.js" here if you want to
                    name: 'vendor',
                    chunks: 'all',
                    enforce: true,
                },
            },
        },
        runtimeChunk: {
            name: 'runtime',
        },
        minimizer: [new BabiliPlugin(), new OptimizeJsPlugin({ sourceMap: false })],
        occurrenceOrder: true,
    },
...

after building many bundles have common modules.
How to lift common modules to to a parent bundle?

Thanks

@jamieYou

This comment has been minimized.

Show comment
Hide comment
@jamieYou

jamieYou Apr 5, 2018

How does webpack4 not generate a common file when processing multiple entries?

My webpack.config file.

entry: {
  client: '',
  admin: '',
},
optimization: {
  splitChunks: {
    chunks: 'all'
  },
},

However, in the case of multiple portals, the code shared by the third-party code and the two portals is split into several files.

    admin.bundle.js  
    admin~client.chunk.js 
    client.bundle.js    
    vendors~admin~client.chunk.js
    vendors~client.chunk.js
    // Occasionally there will be one more document
    // vendors~admin.chunk.js

My expectation is that the files after the two portals are packaged are not dependent on each other.
which is

    admin.bundle.js  
    vendors~admin.chunk.js 
    // ---------------------------
    client.bundle.js    
    vendors~client.chunk.js

jamieYou commented Apr 5, 2018

How does webpack4 not generate a common file when processing multiple entries?

My webpack.config file.

entry: {
  client: '',
  admin: '',
},
optimization: {
  splitChunks: {
    chunks: 'all'
  },
},

However, in the case of multiple portals, the code shared by the third-party code and the two portals is split into several files.

    admin.bundle.js  
    admin~client.chunk.js 
    client.bundle.js    
    vendors~admin~client.chunk.js
    vendors~client.chunk.js
    // Occasionally there will be one more document
    // vendors~admin.chunk.js

My expectation is that the files after the two portals are packaged are not dependent on each other.
which is

    admin.bundle.js  
    vendors~admin.chunk.js 
    // ---------------------------
    client.bundle.js    
    vendors~client.chunk.js
@MLuminary

This comment has been minimized.

Show comment
Hide comment
@MLuminary

MLuminary Apr 10, 2018

hi,I'm just a beginner and i have an unsolvable problem

this is my webpack.config.js

entry:{
    index: './src/js/index.js',
    cart: './src/js/cart.js',
    vendor: ['jquery','./src/js/common.js']
  },
optimization:{
    splitChunks: {
      cacheGroups: {
        commons: {
          name: "vendor",
          chunks: 'initial',
          priority: 10,
          minChunks: 3,
          enforce: true
        }
      }
    },
    runtimeChunk: true
  },

my css file cannot be introduced

when runtimeChunk is false,the css file can be introduced but 0.js and 1.js will appear

Do i have to configure css ? please tell me why , thankshi,I'm just a beginner and i have an unsolvable problem

this is my webpack.config.js

entry:{
    index: './src/js/index.js',
    cart: './src/js/cart.js',
    vendor: ['jquery','./src/js/common.js']
  },
optimization:{
    splitChunks: {
      cacheGroups: {
        commons: {
          name: "vendor",
          chunks: 'initial',
          priority: 10,
          minChunks: 3,
          enforce: true
        }
      }
    },
    runtimeChunk: true
  },

my css file cannot be introduced

when runtimeChunk is false,the css file can be introduced but 0.js and 1.js will appear

Do i have to configure css ? please tell me why , thanks

MLuminary commented Apr 10, 2018

hi,I'm just a beginner and i have an unsolvable problem

this is my webpack.config.js

entry:{
    index: './src/js/index.js',
    cart: './src/js/cart.js',
    vendor: ['jquery','./src/js/common.js']
  },
optimization:{
    splitChunks: {
      cacheGroups: {
        commons: {
          name: "vendor",
          chunks: 'initial',
          priority: 10,
          minChunks: 3,
          enforce: true
        }
      }
    },
    runtimeChunk: true
  },

my css file cannot be introduced

when runtimeChunk is false,the css file can be introduced but 0.js and 1.js will appear

Do i have to configure css ? please tell me why , thankshi,I'm just a beginner and i have an unsolvable problem

this is my webpack.config.js

entry:{
    index: './src/js/index.js',
    cart: './src/js/cart.js',
    vendor: ['jquery','./src/js/common.js']
  },
optimization:{
    splitChunks: {
      cacheGroups: {
        commons: {
          name: "vendor",
          chunks: 'initial',
          priority: 10,
          minChunks: 3,
          enforce: true
        }
      }
    },
    runtimeChunk: true
  },

my css file cannot be introduced

when runtimeChunk is false,the css file can be introduced but 0.js and 1.js will appear

Do i have to configure css ? please tell me why , thanks

@aspirisen

This comment has been minimized.

Show comment
Hide comment
@aspirisen

aspirisen Apr 16, 2018

What is the correct config for webpack 4 if in previous I had this. When i tried I always had all the common and vendor chunks together.
Thanks.

const path = require('path');
const webpack = require('webpack');

module.exports = {

    context: path.join(__dirname, 'src'),

    entry: {
        home: "./Home",
        order: "./Order",
        profile: "./Profile",
        shop: "./Shop",
        vendor: ["lodash", "jquery"]
    },

    output: {
        path: path.join(__dirname, "built"),
        filename: "[name].js"
    },

    resolve: {
        extensions: ['.js']
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ["common", 'vendor'],
            minChunks: 2,
        })
    ]

}

aspirisen commented Apr 16, 2018

What is the correct config for webpack 4 if in previous I had this. When i tried I always had all the common and vendor chunks together.
Thanks.

const path = require('path');
const webpack = require('webpack');

module.exports = {

    context: path.join(__dirname, 'src'),

    entry: {
        home: "./Home",
        order: "./Order",
        profile: "./Profile",
        shop: "./Shop",
        vendor: ["lodash", "jquery"]
    },

    output: {
        path: path.join(__dirname, "built"),
        filename: "[name].js"
    },

    resolve: {
        extensions: ['.js']
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ["common", 'vendor'],
            minChunks: 2,
        })
    ]

}
@lfkwtz

This comment has been minimized.

Show comment
Hide comment
@lfkwtz

lfkwtz Apr 16, 2018

@gricard what did you end up changing to no longer be stuck with 0.bundle.min.js?

lfkwtz commented Apr 16, 2018

@gricard what did you end up changing to no longer be stuck with 0.bundle.min.js?

@crazyfx1

This comment has been minimized.

Show comment
Hide comment
@crazyfx1

crazyfx1 Apr 20, 2018

@aspirisen Did you find a solution for this? I have exactly the same webpack 3 configuration with the array as name property and can't figure out the correct configuration for splitChunks.

crazyfx1 commented Apr 20, 2018

@aspirisen Did you find a solution for this? I have exactly the same webpack 3 configuration with the array as name property and can't figure out the correct configuration for splitChunks.

@rbinsztock

This comment has been minimized.

Show comment
Hide comment
@rbinsztock

rbinsztock Apr 25, 2018

splitChunks: {
	chunks: "async",
	minSize: 30000,
	minChunks: 1,
	maxAsyncRequests: 5,
	maxInitialRequests: 3,
	name: true,
	cacheGroups: {
		default: {
			minChunks: 2,
			priority: -20,
			reuseExistingChunk: true,
		},
		vendors: {
			test: /[\\/]node_modules[\\/]/,
			priority: -10
		}
	}
}

missing one ',' after priority: -20

rbinsztock commented Apr 25, 2018

splitChunks: {
	chunks: "async",
	minSize: 30000,
	minChunks: 1,
	maxAsyncRequests: 5,
	maxInitialRequests: 3,
	name: true,
	cacheGroups: {
		default: {
			minChunks: 2,
			priority: -20,
			reuseExistingChunk: true,
		},
		vendors: {
			test: /[\\/]node_modules[\\/]/,
			priority: -10
		}
	}
}

missing one ',' after priority: -20

@budarin

This comment has been minimized.

Show comment
Hide comment
@budarin

budarin May 4, 2018

Hi!

How move common modules into parent bundle like it was in webpack3?

    entry: {
        client: './src/client/index.js',
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                default: false,
                vendor: {
                    test: /[\\/]node_modules[\\/]/, // you may add "vendor.js" here if you want to
                    name: 'vendor',
                    chunks: 'all',
                    enforce: true,
                },
            },
        },
        runtimeChunk: {
            name: 'runtime',
        },
        occurrenceOrder: true,
    },

I have common code in many bundles, instead of lifting common code upper in bundles tree (not into the only one common chunk - its not right to have all common code to move into common chunk)

budarin commented May 4, 2018

Hi!

How move common modules into parent bundle like it was in webpack3?

    entry: {
        client: './src/client/index.js',
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                default: false,
                vendor: {
                    test: /[\\/]node_modules[\\/]/, // you may add "vendor.js" here if you want to
                    name: 'vendor',
                    chunks: 'all',
                    enforce: true,
                },
            },
        },
        runtimeChunk: {
            name: 'runtime',
        },
        occurrenceOrder: true,
    },

I have common code in many bundles, instead of lifting common code upper in bundles tree (not into the only one common chunk - its not right to have all common code to move into common chunk)

@IanVS

This comment has been minimized.

Show comment
Hide comment
@IanVS

IanVS May 9, 2018

I'm really struggling right now to duplicate the behavior that CommonsChunkPlugin gave for injecting code into all entries, by giving it a name which was the same as an entry point. It seems the behavior now for SplitChunksPlugin is to throw away the entry?! @simonjoom, I'm basically trying to do the same as you, were you able to figure it out?

IanVS commented May 9, 2018

I'm really struggling right now to duplicate the behavior that CommonsChunkPlugin gave for injecting code into all entries, by giving it a name which was the same as an entry point. It seems the behavior now for SplitChunksPlugin is to throw away the entry?! @simonjoom, I'm basically trying to do the same as you, were you able to figure it out?

@arthow4n

This comment has been minimized.

Show comment
Hide comment
@arthow4n

arthow4n May 15, 2018

Here's a side-by-side guide for folks trying to reproduce the "vendor bundle" chunking behavior in Webpack 4, this worked for me.
The key point is that you can pass function into chunks and test (undocumented in the doc of SplitChunksPlugin). After knowing this, all you need is insert a function with debugger statement into it, trial-and-error, look at the output of webpack-bundle-analyzer, and find out what works for you.
I couldn't figure this out without reading the webpack config schema. https://github.com/webpack/webpack/blob/master/schemas/WebpackOptions.json

@budarin might be interested in this?

Good Old Webpack 3

// vendor.js
import moment from 'moment';
moment.locale('zh-tw');
// application.js
console.log('application');
<!-- index.html -->
<script src="vendor.js"></script>
<script src="application.js"></script>
// webpack.config.js
module.exports = {
  entry: {
    vendor: 'src/vendor.js',
    application: 'src/application.js',
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      chunks: ['application'],
      minChunks: (module) => {
        const context = module.context;
        return context && context.indexOf('node_modules') >= 0;
      },
    }),
  ],
};

Upgrading to Webpack 4

The vendor bundle doesn't have to be modified.

// vendor.js
import moment from 'moment';
moment.locale('zh-tw');

You must import the vendor bundle explicitly in Webpack 4 even if you have placed both of the bundle script tags in order on the HTML.

// application.js
import './vendor';
console.log('application');

The HTML doesn't have to be modified.

<!-- index.html -->
<script src="vendor.js"></script>
<script src="application.js"></script>

Update your Webpack config:

// webpack.config.js
module.exports = {
  entry: {
    vendor: 'src/vendor.js',
    application: 'src/application.js',
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendor',
          reuseExistingChunk: true,
          chunks: chunk => ['vendor', 'application'].includes(chunk.name),
          test: module => /[\\/]node_modules[\\/]/.test(module.context),
          minChunks: 1,
          minSize: 0,
        },
      },
    },
  },
};

arthow4n commented May 15, 2018

Here's a side-by-side guide for folks trying to reproduce the "vendor bundle" chunking behavior in Webpack 4, this worked for me.
The key point is that you can pass function into chunks and test (undocumented in the doc of SplitChunksPlugin). After knowing this, all you need is insert a function with debugger statement into it, trial-and-error, look at the output of webpack-bundle-analyzer, and find out what works for you.
I couldn't figure this out without reading the webpack config schema. https://github.com/webpack/webpack/blob/master/schemas/WebpackOptions.json

@budarin might be interested in this?

Good Old Webpack 3

// vendor.js
import moment from 'moment';
moment.locale('zh-tw');
// application.js
console.log('application');
<!-- index.html -->
<script src="vendor.js"></script>
<script src="application.js"></script>
// webpack.config.js
module.exports = {
  entry: {
    vendor: 'src/vendor.js',
    application: 'src/application.js',
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      chunks: ['application'],
      minChunks: (module) => {
        const context = module.context;
        return context && context.indexOf('node_modules') >= 0;
      },
    }),
  ],
};

Upgrading to Webpack 4

The vendor bundle doesn't have to be modified.

// vendor.js
import moment from 'moment';
moment.locale('zh-tw');

You must import the vendor bundle explicitly in Webpack 4 even if you have placed both of the bundle script tags in order on the HTML.

// application.js
import './vendor';
console.log('application');

The HTML doesn't have to be modified.

<!-- index.html -->
<script src="vendor.js"></script>
<script src="application.js"></script>

Update your Webpack config:

// webpack.config.js
module.exports = {
  entry: {
    vendor: 'src/vendor.js',
    application: 'src/application.js',
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendor',
          reuseExistingChunk: true,
          chunks: chunk => ['vendor', 'application'].includes(chunk.name),
          test: module => /[\\/]node_modules[\\/]/.test(module.context),
          minChunks: 1,
          minSize: 0,
        },
      },
    },
  },
};
@petrdanecek

This comment has been minimized.

Show comment
Hide comment
@petrdanecek

petrdanecek Jul 7, 2018

Regards the vendor.js without the vendor.css (the node_module related CSS is not extracted to independent vendor.css, but the CSS is kept in the app.css instead of), this would be the solution:

  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/].*(?<!\.(sa|sc|c)ss)$/,
          name: 'vendor',
          chunks: 'all'
        }
      }
    }
  },

Test matches all files in node_modules expect the SCSS|SASS|CSS. Both app and vendor styles are extracted into app.css.

petrdanecek commented Jul 7, 2018

Regards the vendor.js without the vendor.css (the node_module related CSS is not extracted to independent vendor.css, but the CSS is kept in the app.css instead of), this would be the solution:

  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/].*(?<!\.(sa|sc|c)ss)$/,
          name: 'vendor',
          chunks: 'all'
        }
      }
    }
  },

Test matches all files in node_modules expect the SCSS|SASS|CSS. Both app and vendor styles are extracted into app.css.

@magicdawn

This comment has been minimized.

Show comment
Hide comment
@magicdawn

magicdawn commented Jul 24, 2018

typo
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment