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

Bug.

What is the current behavior?

By way of example, I have:

util.js: ES exports two methods: red and blue via two scenarios: one-file (all code within one file) and re-export (methods re-exported from external files)

app1.js: Imports and uses only red

app2.js: Imports and uses only blue

Expected: If I build webpack bundles for both apps, app1 will have red and blue will be eliminated. Conversely, app2 will have blue and red will be eliminated:

Actual: Depends on config

Array of Configs: If there is an array of configurations with a single entry point each for app1.js and app2.js the correct unused methods are dropped.

Multiple Entry Points: If there is a single configuration object with multiple entry points for both app1.js and app2.js, then neither blue nor red are eliminated in either bundle. I would consider this a bug. Perhaps there is some known thing for "multiple entry points get any esnext exports used by any other entry point", but that seems weird.

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

We made a repository with passing and failing mocha tests to show the situation: https://github.com/FormidableLabs/webpack-tree-shaking-multiple-entry-points.

Reproduction:

$ git clone https://github.com/FormidableLabs/webpack-tree-shaking-multiple-entry-points.git
$ cd webpack-tree-shaking-multiple-entry-points
$ yarn install
$ yarn run build
$ yarn run test

The test output is:

tree shaking in webpack4
array
one-file
✓ app1 should have red, not blue
✓ app2 should have blue, not red
re-export
✓ app1 should have red, not blue
✓ app2 should have blue, not red
multiple-entries
one-file
1) app1 should have red, not blue
2) app2 should have blue, not red
re-export
3) app1 should have red, not blue
4) app2 should have blue, not red

4 passing (22ms)
4 failing

The failing ones show that the ES methods that should be dropped aren't.

What is the expected behavior?

See above section on current behavior.

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

Nope, it's a bug.

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

$ node --version
v8.4.0

$ $ yarn list webpack
yarn list v1.3.2
└─ webpack@4.0.0-beta.1

$ uname -a
Darwin small.lan 16.7.0 Darwin Kernel Version 16.7.0: Thu Jan 11 22:59:40 PST 2018; root:xnu-3789.73.8~1/RELEASE_X86_64 x86_64

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

bug webpack 3.8.1

Tree shaking does not seem to work if an exported item is used in other chunks.

From the below example both page1.js and page2.js will have ALL the exports from utils.js even though page1 for only imported {a , b} from './utils' and page2 for only imported {c , d} from './utils';

I expected that each file will keep only the imports it needs and the reset will be minified away at production build.

However if for example I remove the {c} import from page2.js only then will c be mark as unused in both page1.js and page2.js complied files

e.g.

As seen both page1 and page 2 have the code for import a,b,c,d after compilation.

page1.js

import {
a,
b
} from "./utils";

console.log(a, b);

page2.js

import {
c,
d
} from "./utils";

console.log(c, d);

utils.js

export const a = 1;
export const b = 2;
export const c = 3;
export const d = 4;

After compilation

page1.js

(function(modules) { // webpackBootstrap
})
/************************************************************************/
([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
const a = 1;
/* harmony export (immutable) */ __webpack_exports__["a"] = a;

const b = 2;
/* harmony export (immutable) */ __webpack_exports__["b"] = b;

const c = 3;
/* harmony export (immutable) */ __webpack_exports__["c"] = c;

const d = 4;
/* harmony export (immutable) */ __webpack_exports__["d"] = d;

/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__utils__ = __webpack_require__(0);

console.log(__WEBPACK_IMPORTED_MODULE_0__utils__["a"], __WEBPACK_IMPORTED_MODULE_0__utils__["b"]);

/***/ })
]);

page2.js

(function(modules) { // webpackBootstrap
})
/************************************************************************/
([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
const a = 1;
/* harmony export (immutable) */ __webpack_exports__["a"] = a;

const b = 2;
/* harmony export (immutable) */ __webpack_exports__["b"] = b;

const c = 3;
/* harmony export (immutable) */ __webpack_exports__["c"] = c;

const d = 4;
/* harmony export (immutable) */ __webpack_exports__["d"] = d;

/***/ }),
/* 1 */,
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__utils__ = __webpack_require__(0);

console.log(__WEBPACK_IMPORTED_MODULE_0__utils__["c"], __WEBPACK_IMPORTED_MODULE_0__utils__["d"]);

/***/ })
]);

webpack config

module.exports = {
entry: {
page1: './page1.js',
page2: './page2.js'
},
output: {
filename: '[name].dist.js'
}
};