Skip to content

Commit

Permalink
allow to display used exports
Browse files Browse the repository at this point in the history
support Tree Shaking with import *
fixes webpack#2713
  • Loading branch information
sokra committed Jun 28, 2016
1 parent 4eea969 commit 78307a9
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 55 deletions.
10 changes: 10 additions & 0 deletions bin/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ yargs.options({
group: DISPLAY_GROUP,
describe: "Display reasons about module inclusion in the output"
},
"display-used-exports": {
type: "boolean",
group: DISPLAY_GROUP,
describe: "Display information about used exports in modules (Tree Shaking)"
},
"display-error-details": {
type: "boolean",
group: DISPLAY_GROUP,
Expand All @@ -105,6 +110,7 @@ var argv = yargs.argv;

if(argv.verbose) {
argv["display-reasons"] = true;
argv["display-used-exports"] = true;
argv["display-error-details"] = true;
argv["display-modules"] = true;
argv["display-cached"] = true;
Expand Down Expand Up @@ -183,6 +189,10 @@ function processOptions(options) {
outputOptions.reasons = bool;
});

ifArg("display-used-exports", function(bool) {
outputOptions.usedExports = bool;
});

ifArg("display-error-details", function(bool) {
outputOptions.errorDetails = bool;
});
Expand Down
2 changes: 1 addition & 1 deletion examples/build-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ var fs = require("fs");
var extraArgs = "";

var targetArgs = global.NO_TARGET_ARGS ? "" : " ./example.js js/output.js";
var displayReasons = global.NO_REASONS ? "" : " --display-reasons";
var displayReasons = global.NO_REASONS ? "" : " --display-reasons --display-used-exports";
(function doIt(remainingTimes) {
cp.exec("node ../../bin/webpack.js" + displayReasons + " --display-chunks --display-modules --display-origins --output-public-path \"js/\" -p " + extraArgs + targetArgs, function (error, stdout, stderr) {
if(stderr && remainingTimes === 1)
Expand Down
118 changes: 68 additions & 50 deletions examples/harmony-unused/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ In addition to that, `library.js` simulates an entry point to a big library. `li

``` javascript
import { add } from './math';
import { reexportedMultiply } from "./library";
import * as library from "./library";

add(1, 2);
reexportedMultiply(1, 2);
library.reexportedMultiply(1, 2);
```

# math.js
Expand Down Expand Up @@ -88,6 +88,18 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
/******/ // identity function for calling harmory imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };

/******/ // define getter function for harmory exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ };

/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "js/";

Expand All @@ -102,26 +114,26 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
\*****************/
/***/ function(module, exports, __webpack_require__) {

"use strict";
/* harmony export */ exports["a"] = add;/* harmony export */ exports["b"] = multiply;/* unused harmony export list */function add() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
"use strict";
/* harmony export */ exports["a"] = add;/* harmony export */ exports["b"] = multiply;/* unused harmony export list */function add() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
}

function multiply() {
var product = 1, i = 0, args = arguments, l = args.length;
while (i < l) {
product *= args[i++];
}
return product;
function multiply() {
var product = 1, i = 0, args = arguments, l = args.length;
while (i < l) {
product *= args[i++];
}
return product;
}

function list() {
return Array.from(arguments);
}
function list() {
return Array.from(arguments);
}


/***/ },
Expand All @@ -131,14 +143,14 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
\********************/
/***/ function(module, exports, __webpack_require__) {

"use strict";
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__abc__ = __webpack_require__(/*! ./abc */ 2);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math__ = __webpack_require__(/*! ./math */ 0);
/* unused harmony reexport a */
/* unused harmony reexport b */
/* unused harmony reexport c */
/* unused harmony reexport reexportedAdd */
/* harmony reexport */ if(Object.prototype.hasOwnProperty.call(__WEBPACK_IMPORTED_MODULE_1__math__, "b")) Object.defineProperty(exports, "a", {configurable: false, enumerable: true, get: function() { return __WEBPACK_IMPORTED_MODULE_1__math__["b"]; }});
"use strict";
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__abc__ = __webpack_require__(/*! ./abc */ 2);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math__ = __webpack_require__(/*! ./math */ 0);
/* unused harmony reexport a */
/* unused harmony reexport b */
/* unused harmony reexport c */
/* unused harmony reexport reexportedAdd */
/* harmony reexport */ if(__webpack_require__.o(__WEBPACK_IMPORTED_MODULE_1__math__, "b")) __webpack_require__.d(exports, "a", function() { return __WEBPACK_IMPORTED_MODULE_1__math__["b"]; });



Expand All @@ -149,10 +161,10 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
\****************/
/***/ function(module, exports, __webpack_require__) {

"use strict";
/* unused harmony export a *//* unused harmony export b *//* unused harmony export c */function a() { console.log("a"); }
function b() { console.log("b"); }
function c() { console.log("c"); }
"use strict";
/* unused harmony export a *//* unused harmony export b *//* unused harmony export c */function a() { console.log("a"); }
function b() { console.log("b"); }
function c() { console.log("c"); }


/***/ },
Expand All @@ -162,14 +174,14 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
\********************/
/***/ function(module, exports, __webpack_require__) {

"use strict";
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__math__ = __webpack_require__(/*! ./math */ 0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__library__ = __webpack_require__(/*! ./library */ 1);
"use strict";
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__math__ = __webpack_require__(/*! ./math */ 0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__library__ = __webpack_require__(/*! ./library */ 1);



__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__math__["a" /* add */])(1, 2);
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__library__["a" /* reexportedMultiply */])(1, 2);
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__math__["a" /* add */])(1, 2);
__WEBPACK_IMPORTED_MODULE_1__library__["a" /* reexportedMultiply */](1, 2);


/***/ }
Expand All @@ -179,47 +191,53 @@ export { add as reexportedAdd, multiply as reexportedMultiply } from "./math";
# js/output.js

``` javascript
!function(t){function r(e){if(n[e])return n[e].exports;var u=n[e]={i:e,l:!1,exports:{}};return t[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}var n={};return r.m=t,r.c=n,r.i=function(t){return t},r.p="js/",r(r.s=3)}([function(t,r,n){"use strict";function e(){for(var t=0,r=0,n=arguments,e=n.length;e>r;)t+=n[r++];return t}function u(){for(var t=1,r=0,n=arguments,e=n.length;e>r;)t*=n[r++];return t}r.a=e,r.b=u},function(t,r,n){"use strict";var e=(n(2),n(0));Object.prototype.hasOwnProperty.call(e,"b")&&Object.defineProperty(r,"a",{configurable:!1,enumerable:!0,get:function(){return e.b}})},function(t,r,n){"use strict"},function(t,r,n){"use strict";var e=n(0),u=n(1);n.i(e.a)(1,2),n.i(u.a)(1,2)}]);
!function(t){function r(e){if(n[e])return n[e].exports;var u=n[e]={i:e,l:!1,exports:{}};return t[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}var n={};return r.m=t,r.c=n,r.i=function(t){return t},r.d=function(t,r,n){Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},r.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},r.p="js/",r(r.s=3)}([function(t,r,n){"use strict";function e(){for(var t=0,r=0,n=arguments,e=n.length;e>r;)t+=n[r++];return t}function u(){for(var t=1,r=0,n=arguments,e=n.length;e>r;)t*=n[r++];return t}r.a=e,r.b=u},function(t,r,n){"use strict";var e=(n(2),n(0));n.o(e,"b")&&n.d(r,"a",function(){return e.b})},function(t,r,n){"use strict"},function(t,r,n){"use strict";var e=n(0),u=n(1);n.i(e.a)(1,2),u.a(1,2)}]);
```
# Info
## Uncompressed
```
Hash: 37f6daade0e3e46fb0a8
Version: webpack 2.1.0-beta.11
Time: 75ms
Hash: a205275478a27b1aeb72
Version: webpack 2.1.0-beta.14
Time: 72ms
Asset Size Chunks Chunk Names
output.js 3.83 kB 0 [emitted] main
chunk {0} output.js (main) 728 bytes [rendered]
output.js 4.18 kB 0 [emitted] main
chunk {0} output.js (main) 726 bytes [rendered]
> main [3] ./example.js
[0] ./math.js 366 bytes {0} [built]
[only some exports used: add, multiply]
harmony import ./math [1] ./library.js 2:0-78
harmony import ./math [3] ./example.js 1:0-29
[1] ./library.js 112 bytes {0} [built]
harmony import ./library [3] ./example.js 2:0-47
[only some exports used: reexportedMultiply]
harmony import ./library [3] ./example.js 2:0-37
[2] ./abc.js 129 bytes {0} [built]
[no exports used]
harmony import ./abc [1] ./library.js 1:0-32
[3] ./example.js 121 bytes {0} [built]
[3] ./example.js 119 bytes {0} [built]
```
## Minimized (uglify-js, no zip)
```
Hash: 37f6daade0e3e46fb0a8
Version: webpack 2.1.0-beta.11
Time: 129ms
Hash: a205275478a27b1aeb72
Version: webpack 2.1.0-beta.14
Time: 131ms
Asset Size Chunks Chunk Names
output.js 705 bytes 0 [emitted] main
chunk {0} output.js (main) 728 bytes [rendered]
output.js 767 bytes 0 [emitted] main
chunk {0} output.js (main) 726 bytes [rendered]
> main [3] ./example.js
[0] ./math.js 366 bytes {0} [built]
[only some exports used: add, multiply]
harmony import ./math [1] ./library.js 2:0-78
harmony import ./math [3] ./example.js 1:0-29
[1] ./library.js 112 bytes {0} [built]
harmony import ./library [3] ./example.js 2:0-47
[only some exports used: reexportedMultiply]
harmony import ./library [3] ./example.js 2:0-37
[2] ./abc.js 129 bytes {0} [built]
[no exports used]
harmony import ./abc [1] ./library.js 1:0-32
[3] ./example.js 121 bytes {0} [built]
[3] ./example.js 119 bytes {0} [built]
```
4 changes: 2 additions & 2 deletions examples/harmony-unused/example.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { add } from './math';
import { reexportedMultiply } from "./library";
import * as library from "./library";

add(1, 2);
reexportedMultiply(1, 2);
library.reexportedMultiply(1, 2);
7 changes: 5 additions & 2 deletions lib/Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,11 @@ Parser.prototype.walkMemberExpression = function walkMemberExpression(expression
}
if(expr.type === "Identifier" && this.scope.definitions.indexOf(expr.name) === -1) {
exprName.unshift(this.scope.renames["$" + expr.name] || expr.name);
exprName = exprName.join(".");
var result = this.applyPluginsBailResult("expression " + exprName, expression);
var result = this.applyPluginsBailResult("expression " + exprName.join("."), expression);
if(result === true)
return;
exprName[exprName.length - 1] = "*";
result = this.applyPluginsBailResult("expression " + exprName.join("."), expression);
if(result === true)
return;
}
Expand Down
26 changes: 26 additions & 0 deletions lib/Stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Stats.prototype.toJson = function toJson(options, forToString) {
var showCachedModules = d(options.cached, true);
var showCachedAssets = d(options.cachedAssets, true);
var showReasons = d(options.reasons, !forToString);
var showUsedExports = d(options.usedExports, !forToString);
var showChildren = d(options.children, true);
var showSource = d(options.source, !forToString);
var showErrors = d(options.errors, true);
Expand Down Expand Up @@ -231,6 +232,9 @@ Stats.prototype.toJson = function toJson(options, forToString) {
return a.moduleId - b.moduleId;
});
}
if(showUsedExports) {
obj.usedExports = module.used ? module.usedExports : false;
}
if(showSource && module._source) {
obj.source = module._source.source();
}
Expand Down Expand Up @@ -593,6 +597,16 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
colors.bold(module.name);
processModuleAttributes(module);
newline();
if(module.usedExports !== undefined) {
if(module.usedExports !== true) {
colors.normal(" ");
if(module.usedExports === false)
colors.cyan("[no exports used]");
else
colors.cyan("[only some exports used: " + module.usedExports.join(", ") + "]");
newline();
}
}
if(module.reasons) {
module.reasons.forEach(function(reason) {
colors.normal(" ");
Expand Down Expand Up @@ -631,6 +645,16 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
colors.bold(module.name || module.identifier);
processModuleAttributes(module);
newline();
if(module.usedExports !== undefined) {
if(module.usedExports !== true) {
colors.normal(" ");
if(module.usedExports === false)
colors.cyan("[no exports used]");
else
colors.cyan("[only some exports used: " + module.usedExports.join(", ") + "]");
newline();
}
}
if(module.reasons) {
module.reasons.forEach(function(reason) {
colors.normal(" ");
Expand Down Expand Up @@ -706,6 +730,7 @@ Stats.presetToOptions = function(name) {
chunks: false,
modules: false,
reasons: false,
usedExports: false,
children: false,
source: false,
errors: false,
Expand All @@ -724,6 +749,7 @@ Stats.presetToOptions = function(name) {
//warnings: pn !== "errors-only",
errorDetails: pn !== "errors-only" && pn !== "minimal",
reasons: pn === "verbose",
usedExports: pn === "verbose",
colors: true
};
}
Expand Down
11 changes: 11 additions & 0 deletions lib/dependencies/HarmonyImportDependencyParserPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ module.exports = AbstractPlugin.create({
this.state.current.addDependency(dep);
return true;
},
"expression imported var.*": function(expr) {
var name = expr.object.name;
var settings = this.state.harmonySpecifier["$" + name];
if(settings[2] !== null)
return false;
var dep = new HarmonyImportSpecifierDependency(settings[0], settings[1], expr.property.name, name, expr.range);
dep.shorthand = this.scope.inShorthand;
dep.loc = expr.loc;
this.state.current.addDependency(dep);
return true;
},
"call imported var": function(expr) {
var args = expr.arguments;
var fullExpr = expr;
Expand Down
2 changes: 2 additions & 0 deletions test/Stats.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ describe("Stats", function() {
chunkModules: false,
errorDetails: true,
reasons: false,
usedExports: false,
colors: true
});
});
Expand All @@ -180,6 +181,7 @@ describe("Stats", function() {
chunks: false,
modules: false,
reasons: false,
usedExports: false,
children: false,
source: false,
errors: false,
Expand Down

0 comments on commit 78307a9

Please sign in to comment.