[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\"env\", {\n      \"loose\": true,\n      \"modules\": false\n    }]\n  ],\n  \"plugins\": [\"transform-runtime\"]\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.idea\n"
  },
  {
    "path": "app/car.js",
    "content": "import { V8Engine } from './engine';\n\nclass SportsCar {\n  constructor(engine) {\n    this.engine = engine;\n  }\n\n  toString() {\n    return this.engine.toString() + ' Sports Car';\n  }\n}\n\nconsole.log(new SportsCar(new V8Engine()).toString());\n"
  },
  {
    "path": "app/engine.js",
    "content": "export class V6Engine {\n  toString() {\n    return 'V6';\n  }\n}\n\nexport class V8Engine {\n  toString() {\n    return 'V8';\n  }\n}\n\nexport function getVersion() {\n  return '1.0';\n}\n"
  },
  {
    "path": "dist/car.bundle.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__webpack_require__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 2);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nexports.default = function (instance, Constructor) {\n  if (!(instance instanceof Constructor)) {\n    throw new TypeError(\"Cannot call a class as a function\");\n  }\n};\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export V6Engine */\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return V8Engine; });\n/* unused harmony export getVersion */\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__ = __webpack_require__(0);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__);\n\nvar V6Engine = function () {\n  function V6Engine() {\n    __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, V6Engine);\n  }\n\n  V6Engine.prototype.toString = function toString() {\n    return 'V6';\n  };\n\n  return V6Engine;\n}();\n\nvar V8Engine = function () {\n  function V8Engine() {\n    __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, V8Engine);\n  }\n\n  V8Engine.prototype.toString = function toString() {\n    return 'V8';\n  };\n\n  return V8Engine;\n}();\n\nfunction getVersion() {\n  return '1.0';\n}\n\n/***/ }),\n/* 2 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__ = __webpack_require__(0);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__engine__ = __webpack_require__(1);\n\n\n\nvar SportsCar = function () {\n  function SportsCar(engine) {\n    __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, SportsCar);\n\n    this.engine = engine;\n  }\n\n  SportsCar.prototype.toString = function toString() {\n    return this.engine.toString() + ' Sports Car';\n  };\n\n  return SportsCar;\n}();\n\nconsole.log(new SportsCar(new __WEBPACK_IMPORTED_MODULE_1__engine__[\"a\" /* V8Engine */]()).toString());\n\n/***/ })\n/******/ ]);"
  },
  {
    "path": "dist/car.es2015.bundle.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__webpack_require__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 1);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export getVersion */\nclass V6Engine {\n  toString() {\n    return 'V6';\n  }\n}\n/* unused harmony export V6Engine */\n\n\nclass V8Engine {\n  toString() {\n    return 'V8';\n  }\n}\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = V8Engine;\n\n\nfunction getVersion() {\n  return '1.0';\n}\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__engine__ = __webpack_require__(0);\n\n\nclass SportsCar {\n  constructor(engine) {\n    this.engine = engine;\n  }\n\n  toString() {\n    return this.engine.toString() + ' Sports Car';\n  }\n}\n\nconsole.log(new SportsCar(new __WEBPACK_IMPORTED_MODULE_0__engine__[\"a\" /* V8Engine */]()).toString());\n\n\n/***/ })\n/******/ ]);"
  },
  {
    "path": "dist/car.es2015.prod.bundle.js",
    "content": "(function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.i=function(a){return a},b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=1)})([function(a,b){'use strict';b.a=class{toString(){return'V8'}}},function(a,b,c){'use strict';Object.defineProperty(b,'__esModule',{value:!0});var d=c(0);console.log(new class{constructor(a){this.engine=a}toString(){return this.engine.toString()+' Sports Car'}}(new d.a()).toString())}]);"
  },
  {
    "path": "dist/car.prod.bundle.js",
    "content": "!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,\"a\",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p=\"\",t(t.s=2)}([function(n,t,r){\"use strict\";t.__esModule=!0,t.default=function(n,t){if(!(n instanceof t))throw new TypeError(\"Cannot call a class as a function\")}},function(n,t,r){\"use strict\";r.d(t,\"a\",function(){return u});var e=r(0),o=r.n(e),u=(function(){function n(){o()(this,n)}n.prototype.toString=function(){return\"V6\"}}(),function(){function n(){o()(this,n)}return n.prototype.toString=function(){return\"V8\"},n}())},function(n,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var e=r(0),o=r.n(e),u=r(1),i=function(){function n(t){o()(this,n),this.engine=t}return n.prototype.toString=function(){return this.engine.toString()+\" Sports Car\"},n}();console.log(new i(new u.a).toString())}]);"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Tree-shaking example with Babel and Webpack</title>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"favicon.ico\"/>\n</head>\n<body>\n\n<script src=\"./dist/car.bundle.js\"></script>\n<!--<script src=\"./dist/car.prod.bundle.js\"></script>-->\n<!--<script src=\"./dist/car.es2015.bundle.js\"></script>-->\n<!--<script src=\"./dist/car.es2015.prod.bundle.js\"></script>-->\n</body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"babel-webpack-tree-shaking\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Tree-shaking example with Babel and Webpack\",\n  \"main\": \"dist/car.es2015.prod.bundle.js\",\n  \"scripts\": {\n    \"webpack\": \"webpack --config webpack.config.js\",\n    \"webpack-prod\": \"webpack --config webpack.prod.config.js\",\n    \"webpack-es2015\": \"webpack --config webpack.es2015.config.js\",\n    \"webpack-es2015-prod\": \"webpack --config webpack.es2015.prod.config.js\",\n    \"serve\": \"http-server -a 0.0.0.0 -p 9000\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/blacksonic/babel-webpack-tree-shaking.git\"\n  },\n  \"keywords\": [\n    \"tree-shaking\",\n    \"babel\",\n    \"webpack\"\n  ],\n  \"author\": {\n    \"name\": \"blacksonic\",\n    \"email\": \"soos.gabor86@gmail.com\"\n  },\n  \"license\": \"ISC\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"babel-core\": \"~6.25.0\",\n    \"babel-loader\": \"~7.0.0\",\n    \"babel-plugin-transform-runtime\": \"~6.23.0\",\n    \"babel-preset-env\": \"~1.5.2\",\n    \"babili\": \"~0.1.3\",\n    \"babili-webpack-plugin\": \"~0.1.1\",\n    \"http-server\": \"~0.10.0\",\n    \"webpack\": \"~2.6.1\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# Tree-shaking example with Babel and Webpack\n[![devDependency Status](https://david-dm.org/blacksonic/babel-webpack-tree-shaking/dev-status.svg)](https://david-dm.org/blacksonic/babel-webpack-tree-shaking?type=dev)\n\nThis repository shows how to configure Babel and Webpack to enable tree-shaking.\nIt will eliminate dead code if they have ES2015 module format.\n\nThe source code can be found in the ```app/``` folder,\nwhere the main file ```car.js``` doesn't use all the dependencies from ```engine.js```.\nThe built and transpiled files can be found in the ```/dist``` folder.\n\nWebpack only marks unused code at bundling and leaves the removing part to minifiers.\nThis is why all the code is included in development builds in contrary to Rollup.\n\nIf you want a more detailed explanation,\n[read this article](https://blog.craftlab.hu/how-to-do-proper-tree-shaking-in-webpack-2-e27852af8b21).\n\n### Webpack + Babel + UglifyJS\n\nCan only remove unused functions and variables.\n\nFor development build run ```npm run webpack``` (ES2015 -> ES5 bundle).\n\nFor production build run ```npm run webpack-prod``` (ES2015 -> ES5 bundle -> UglifyJS).\n\nWhen transpiling classes with Babel, it generates an IIFE with an assignment to the prototype.\nIt is considered as a side effect by UglifyJS and it skips removing of it.\n\nSee the issues below:\n\n- [Webpack issue](https://github.com/webpack/webpack/issues/2899) and a [more detailed one](https://github.com/webpack/webpack/issues/2867)\n- [UglifyJS issue](https://github.com/mishoo/UglifyJS2/issues/1261)\n\n### Webpack + Babili\n\nCan remove unused classes, functions and variables.\n\nFor development build run ```npm run webpack-es2015``` (ES2015 -> ES2015 bundle).\n\nFor production build run ```npm run webpack-es2015-prod``` (ES2015 -> ES2015 bundle -> Babili).\n\nIt uses the [Babili](https://github.com/babel/babili) ES6+ aware minifier and solves the issues what UglifyJS has.\n"
  },
  {
    "path": "webpack.config.js",
    "content": "'use strict';\n\nlet path = require('path');\n\nmodule.exports = {\n  entry: {\n    'car': './app/car.js'\n  },\n\n  output: {\n    path: path.resolve(process.cwd(), 'dist'),\n    filename: '[name].bundle.js'\n  },\n\n  module: {\n    rules: [\n      { test: /\\.js$/, loader: 'babel-loader' }\n    ]\n  },\n\n  resolve: {\n    modules: [\n      path.join(process.cwd(), 'app'),\n      'node_modules'\n    ],\n    extensions: ['.js', '.json']\n  },\n\n  devtool: false\n};\n"
  },
  {
    "path": "webpack.es2015.config.js",
    "content": "'use strict';\n\nlet path = require('path');\n\nmodule.exports = {\n  entry: {\n    'car.es2015': './app/car.js'\n  },\n\n  output: {\n    path: path.resolve(process.cwd(), 'dist'),\n    filename: '[name].bundle.js'\n  },\n\n  module: {\n    rules: []\n  },\n\n  plugins: [],\n\n  resolve: {\n    modules: [\n      path.join(process.cwd(), 'app'),\n      'node_modules'\n    ],\n    extensions: ['.js', '.json']\n  },\n\n  devtool: false\n};\n"
  },
  {
    "path": "webpack.es2015.prod.config.js",
    "content": "'use strict';\n\nlet BabiliPlugin = require(\"babili-webpack-plugin\");\nlet path = require('path');\n\nmodule.exports = {\n  entry: {\n    'car.es2015.prod': './app/car.js'\n  },\n\n  output: {\n    path: path.resolve(process.cwd(), 'dist'),\n    filename: '[name].bundle.js'\n  },\n\n  module: {\n    rules: []\n  },\n\n  plugins: [\n    new BabiliPlugin()\n  ],\n\n  resolve: {\n    modules: [\n      path.join(process.cwd(), 'app'),\n      'node_modules'\n    ],\n    extensions: ['.js', '.json']\n  },\n\n  devtool: false\n};\n"
  },
  {
    "path": "webpack.prod.config.js",
    "content": "'use strict';\n\nlet webpack = require('webpack');\nlet path = require('path');\n\nmodule.exports = {\n  entry: {\n    'car.prod': './app/car.js'\n  },\n\n  output: {\n    path: path.resolve(process.cwd(), 'dist'),\n    filename: '[name].bundle.js'\n  },\n\n  module: {\n    rules: [\n      { test: /\\.js$/, loader: 'babel-loader' }\n    ]\n  },\n\n  plugins: [\n    new webpack.LoaderOptionsPlugin({\n      minimize: true,\n      debug: false\n    }),\n    new webpack.optimize.UglifyJsPlugin({\n      compress: {\n        warnings: true\n      },\n      output: {\n        comments: false\n      },\n      sourceMap: false\n    })\n  ],\n\n  resolve: {\n    modules: [\n      path.join(process.cwd(), 'app'),\n      'node_modules'\n    ],\n    extensions: ['.js', '.json']\n  },\n\n  devtool: false\n};\n"
  }
]