closure-webpack-plugin icon indicating copy to clipboard operation
closure-webpack-plugin copied to clipboard

Plugin relies on chunk loading order

Open DreierF opened this issue 5 years ago • 3 comments

The plugin still uses the "Webpack 3" way of loading asynchronous chunks in AGGRESSIVE_BUNDLE mode via the window.webpackJsonp function. This works as long as the main (or runtime chunk if using runtimeChunk: 'single') is loaded as the first script. This is however not the default in most configurations e.g. when using the default behavior of the HtmlWebpackPlugin.

As the order is non-deterministic or at least my change without touching the configuration you run into Uncaught ReferenceError: webpackJsonp is not defined when one if the async chunks is processed first.

The closure webpack plugin should instead use a mechanism similar to what Webpack 4+ does (Link) to load async chunks. Here window.webpackJsonp is initialized as (window.webpackJsonp = window.webpackJsonp || []).push(/* ... */);, which makes it independent from the script loading order as the runtime can pick up already loaded scripts from the array.

As a workaround I had to manually specify the loading order in HtmlWebpackPlugin like so:

new HtmlWebpackPlugin({
	chunksSortMode: function(a, b) {
		const partialOrderedChunks = [
			'runtime',
			'main'
		];
		return partialOrderedChunks.indexOf(b.names[0]) - partialOrderedChunks.indexOf(a.names[0]);
	}
}),

DreierF avatar Feb 11 '20 15:02 DreierF

Can you get a minimal demo of this behavior built? Ideally adding another demo of this to the project. Then I can take a look.

ChadKillingsworth avatar Feb 14 '20 12:02 ChadKillingsworth

I have constructed a minimal example here: https://github.com/DreierF/closure-webpack-plugin/commit/f0e92ab29658735500770e901575e9f10dfc54c0

It seems to happen as soon as an npm library is imported and the vendors chunk is created.

DreierF avatar Feb 14 '20 18:02 DreierF

I can fix the loading order, but that alone won't get the results you are after.

Closure-compiler has an optimization called cross chunk code motion. It's purpose is to push individual objects, functions and variables as far down the chunk graph as possible to defer loading. Since in this case all of the symbols in the vendor chunk (which is a direct parent of the entry point) are only referenced in the entry point, they all get moved right down into the entry point. You get left with a vendor chunk that is basically empty.

I probably need to go add a flag to closure-compiler to allow that optimization to be disabled. But until that time, I can't think of an easy way to prevent this from happening.

ChadKillingsworth avatar Feb 22 '20 13:02 ChadKillingsworth