Issue 1:
Need

As a developer
I want to reduce duplication in my configs
So that they're more maintainable.

Deliverables

Given I have config A
And I have config B
And config A defines variable 'FOO' to be 'A'
And config B defines variable 'FOO' to be 'B'
And config B extends config A
When I load config B through webpack
Then 'FOO' will be injected with the value 'B'

// config A
module.exports = {
plugins: [
new DefinePlugin({FOO: 'A'})
]
};

// config B
var config = require('./a.config.js');
config.plugins.push(
new DefinePlugin({FOO: 'B'})
);
module.exports = config;

The more practical use cases is having a production.config.js and a staging.config.js with the latter extending the former. I have a LOG_ERRORS variable defined in production.config.js to be false and I want to overwrite it in staging.config.js to be true.

The workaround I'm using now is to make sure the DefinePlugin instance is the last element in the plugins list in production.config.js and pop() it and replace it with another instance in staging.config.js. Not very future proof.

What I'd like is for newer instances of DefinePlugin in the plugins list to overwrite any definitions set by previous instances.

exports.plugins = [
new DefinePlugin({FOO: 'A'}),
new DefinePlugin({FOO: 'B'}),
new DefinePlugin({FOO: 'C'})
];

// I expect `FOO` to be `C`.

Notes

I looked at lib/definePluggin.js and I saw that for every definition a compiler.parser callback is registered. I'm assuming that when the first callback is called and modifies the code, the rest of the callbacks won't be called as the code doesn't match them anymore.

I tried working out a solution where the callbacks request the latest definition of a key, but it required the assumption that the type of key (value, typeof etc) wouldn't change between definitions (because different callbacks handle different types).

I'm more than happy to help with a PR if someone can point me in the right direction.

Issue 2:
Do you want to request a feature or report a bug?

Bug / Change in behaviour compared to Webpack 3

What is the current behavior?

When telling Webpack which chunk the runtime should be in, it doesn't appear to change the order of excecution - see below example.

If the current behavior is a bug, please provide the steps to reproduce.

vendor.js

import $ from 'jquery';
console.log('vendor run.');
$.fn.sayHi = function() {
alert('Hi');
};

main.js

import $ from 'jquery';
console.log('main run.');
$.fn.sayHi();

index.htm

<html>
<body>
<script src="dist/vendor.js"></script>
<script src="dist/main.js"></script>
</body>
</html>

Webpack 3 config

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

module.exports = {

mode: 'production',

entry: {
main: './main.js',
vendor: './vendor.js'
},

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

optimization: {
minimize: false,
runtimeChunk: {
name: 'vendor'
},
splitChunks: {
cacheGroups: {
default: false,
commons: {
test: /node_modules/,
name: "vendor",
chunks: "initial",
minSize: 1
}
}
}
}

};

Webpack 4 Result

As you can see, main run fires before vendor, even though the runtime has been put inside vendor and it's loaded first.

Webpack 3 Result

As you can see vendor run fires first, which means plugin is successfully registered and the alert dialog pops up.

~~

Original issue below - fixed by providing custom splitChunks. Above is now the current issue.

~~

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

Webpack 4 will add jQuery to both vendor.js and main.js when you use ProvidePlugin - this has a side effect that if you have a vendor plugin that is registering itself as a jQuery plugin in vendor.js thru $.fn it is only available for use in vendor.js and won't work in main.js

If the current behavior is a bug, please provide the steps to reproduce.

vendor.js

$.fn.sayHi = function() {
alert('Hi');
};

main.js

import $ from 'jquery';

$.fn.sayHi();

Webpack 3 config

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

module.exports = {

entry: {
main: './main.js',
vendor: './vendor.js'
},

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

plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
})
]

};

The webpack 4 config is exactly the same, except minus the CommonChunkPlugin

This is the output:

Webpack 3 with ProvidePlugin

Webpack 4 with ProvidePlugin

As you can see, Webpack 4 has added jQuery to both entries, though Webpack 3 hasn't.

What is the expected behavior?

To only include one version of jQuery.

If this is a feature request, what is motivation or use case for changing the behavior?

This is likely down to the new "rules" surrounding when to chunk and it also not playing nicely with the ProvidePlugin. This is something that will likely catch a lot of people out, if they use the default chunking algorithm in Webpack 4 along with ProvidePlugin. Maybe there is a way to default to the old behaviour as Webpack 3, but it's not immediately obvious to me how to do this.

Example Repository

https://github.com/garygreen/webpack4-chunks-prob

~~