Can someone explain Webpack's CommonsChunkPlugin
I get the general gist that the CommonsChunkPlugin
looks at all the entry points, checks to see if there are common packages/dependencies between them and separates them into their own bundle.
So, let's assume I have the following configuration:
...
enrty : {
entry1 : 'entry1.js', //which has 'jquery' as a dependency
entry2 : 'entry2.js', //which has 'jquery as a dependency
vendors : [
'jquery',
'some_jquery_plugin' //which has 'jquery' as a dependency
]
},
output: {
path: PATHS.build,
filename: '[name].bundle.js'
}
...
If I bundle without using CommonsChunkPlugin
I will end up with 3 new bundle files:
-
entry1.bundle.js
which contains the complete code fromentry1.js
andjquery
and contains its own runtime -
entry2.bundle.js
which contains the complete code fromentry2.js
andjquery
and contains its own runtime -
vendors.bundle.js
which contains the complete code fromjquery
andsome_jquery_plugin
and contains its own runtime
This is obviously bad because I will potentially load jquery
3 times in the page, so we don't want that.
If I bundle using CommonsChunkPlugin
Depending on what arguments I pass to CommonsChunkPlugin
any of the following will happen:
-
CASE 1 : If I pass
{ name : 'commons' }
I will end up with the following bundle files:-
entry1.bundle.js
which contains the complete code fromentry1.js
, a requirement forjquery
and does not contain the runtime -
entry2.bundle.js
which contains the complete code fromentry2.js
, a requirement forjquery
and does not contain the runtime -
vendors.bundle.js
which contains the complete code fromsome_jquery_plugin
, a requirement forjquery
and does not contain the runtime -
commons.bundle.js
which contains the complete code fromjquery
and contains the runtime
This way we end up with some smaller bundles overall and the runtime is contained in the
commons
bundle. Pretty ok but not ideal. -
-
CASE 2 : If I pass
{ name : 'vendors' }
I will end up with the following bundle files:-
entry1.bundle.js
which contains the complete code fromentry1.js
, a requirement forjquery
and does not contain the runtime -
entry2.bundle.js
which contains the complete code fromentry2.js
, a requirement forjquery
and does not contain the runtime -
vendors.bundle.js
which contains the complete code fromjquery
andsome_jquery_plugin
and contains the runtime.
This way, again, we end up with some smaller bundles overall but the runtime is now contained in the
vendors
bundle. It's a little worse than the previous case, since the runtime is now in thevendors
bundle. -
-
CASE 3 : If I pass
{ names : ['vendors', 'manifest'] }
I will end up with the following bundle files:-
entry1.bundle.js
which contains the complete code fromentry1.js
, a requirement forjquery
and does not contain the runtime -
entry2.bundle.js
which contains the complete code fromentry2.js
, a requirement forjquery
and does not contain the runtime -
vendors.bundle.js
which contains the complete code fromjquery
andsome_jquery_plugin
and does not contain the runtime -
manifest.bundle.js
which contains requirements for every other bundle and contains the runtime
This way we end up with some smaller bundles overall and the runtime is contained in the
manifest
bundle. This is the ideal case. -
What I do not understand/I am not sure I understand
In CASE 2 why did we end up with the
vendors
bundle containing both the common code (jquery
) and whatever remained from thevendors
entry (some_jquery_plugin
)? From my understanding, what theCommonsChunkPlugin
did here was that it gathered the common code (jquery
), and since we forced it to output it to thevendors
bundle, it kind of "merged" the common code into thevendors
bundle (which now only contained the code fromsome_jquery_plugin
). Please confirm or explain.In CASE 3 I do not understand what happened when we passed
{ names : ['vendors', 'manifest'] }
to the plugin. Why/how was thevendors
bundle kept intact, containing bothjquery
andsome_jquery_plugin
, whenjquery
is clearly a common dependency, and why was the generatedmanifest.bundle.js
file created the way it was created (requiring all other bundles and containing the runtime) ?
Solution 1:
This is how the CommonsChunkPlugin
works.
A common chunk "receives" the modules shared by several entry chunks. A good example of a complex configuration can be found in the Webpack repository.
The CommonsChunkPlugin
is run during the optimization phase of Webpack, which means that it operates in memory, just before the chunks are sealed and written to the disk.
When several common chunks are defined, they are processed in order. In your case 3, it is like running the plugin twice. But please note that the CommonsChunkPlugin
can have a more complex configuration (minSize, minChunks, etc) that impacts the way modules are moved.
CASE 1:
- There are 3
entry
chunks (entry1
,entry2
andvendors
). - The configuration sets the
commons
chunk as a common chunk. - The plugin processes the
commons
common chunk (since the chunk does not exist, it is created):- It collects the modules that are used more than once in the other chunks:
entry1
,entry2
andvendors
usejquery
so the module is removed from these chunks and is added to thecommons
chunk. - The
commons
chunk is flagged as anentry
chunk while theentry1
,entry2
andvendors
chunks are unflagged asentry
.
- It collects the modules that are used more than once in the other chunks:
- Finally, since the
commons
chunk is anentry
chunk it contains the runtime and thejquery
module.
CASE 2:
- There are 3
entry
chunks (entry1
,entry2
andvendors
). - The configuration sets the
vendors
chunk as a common chunk. - The plugin processes the
vendors
common chunk:- It collects the modules that are used more than once in the other chunks:
entry1
andentry2
usejquery
so the module is removed from these chunks (note that it is not added to thevendors
chunk because thevendors
chunk already contains it). - The
vendors
chunk is flagged as anentry
chunk while theentry1
andentry2
chunks are unflagged asentry
.
- It collects the modules that are used more than once in the other chunks:
- Finally, since the
vendors
chunk is anentry
chunk, it contains the runtime and thejquery
/jquery_plugin
modules.
CASE 3:
- There are 3
entry
chunks (entry1
,entry2
andvendors
). - The configuration sets the
vendors
chunk and themanifest
chunk as common chunks. - The plugin creates the
manifest
chunk as it does not exist. - The plugin processes the
vendors
common chunk:- It collects the modules that are used more than once in the other chunks:
entry1
andentry2
usejquery
so the module is removed from these chunks (note that it is not added to thevendors
chunk because thevendors
chunk already contains it). - The
vendors
chunk is flagged as anentry
chunk while theentry1
andentry2
chunks are unflagged asentry
.
- It collects the modules that are used more than once in the other chunks:
- The plugin processes the
manifest
common chunk (since the chunk does not exist, it is created):- It collects the modules that are used more than once in the other chunks: as there are no modules used more than once, no module is moved.
- The
manifest
chunk is flagged asentry
chunk while theentry1
,entry2
andvendors
are unflagged asentry
.
- Finally, since the
manifest
chunk is anentry
chunk it contains the runtime.
Hope it helps.