{"action":"created","issue":{"url":"https://api.github.com/repos/webpack/webpack/issues/1212","labels_url":"https://api.github.com/repos/webpack/webpack/issues/1212/labels{/name}","comments_url":"https://api.github.com/repos/webpack/webpack/issues/1212/comments","events_url":"https://api.github.com/repos/webpack/webpack/issues/1212/events","html_url":"https://github.com/webpack/webpack/issues/1212","id":92022286,"number":1212,"title":"Plugin for code splitting","user":{"login":"tuchk4","id":5140611,"avatar_url":"https://avatars.githubusercontent.com/u/5140611?v=3","gravatar_id":"","url":"https://api.github.com/users/tuchk4","html_url":"https://github.com/tuchk4","followers_url":"https://api.github.com/users/tuchk4/followers","following_url":"https://api.github.com/users/tuchk4/following{/other_user}","gists_url":"https://api.github.com/users/tuchk4/gists{/gist_id}","starred_url":"https://api.github.com/users/tuchk4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tuchk4/subscriptions","organizations_url":"https://api.github.com/users/tuchk4/orgs","repos_url":"https://api.github.com/users/tuchk4/repos","events_url":"https://api.github.com/users/tuchk4/events{/privacy}","received_events_url":"https://api.github.com/users/tuchk4/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-06-30T08:16:16Z","updated_at":"2015-07-01T11:57:00Z","closed_at":"2015-07-01T11:57:00Z","body":"Hello \r\n\r\nI want to split code by path. For example:\r\n```js\r\nentry: {\r\n build: [\r\n   'babel/polyfill',\r\n   'js/controllers/user.js',\r\n   'js/controllers/profile.js',\r\n   'bootstrap.js'\r\n ]\r\n},\r\nsplit: {\r\n vendor: node_modules/\r\n app: js/.+\\.js,\r\n templates: js/.+\\.jade,\r\n bootstrap: bootstrap.js\r\n}\r\n```\r\n**js/controllers/user.js**:\r\n```js\r\nimport isArray from 'lodash/lang/isArray';\r\n\r\n...\r\n```\r\n\r\n**js/controllers/profile.js**:\r\n```js\r\nimport ProfileTemplate form './profile.jade'\r\n\r\n....\r\n```\r\n\r\nSo as built results - 5 files:\r\n\r\n- build.js (main entry point. chunk.entry = true) All modules that did not match any split regex - fall in this chunk)\r\n- vendor.js (chunk.entry = false)\r\n- templates.js (chunk.entry = false)\r\n- app.js (chunk.entry = false)\r\n- bootstrap.js (chunk.entry = false)\r\n\r\nHere is plugin (if need I could rewrite without ES6):\r\n```js\r\n// Based on Split by Name Webpack Plugin – https://github.com/soundcloud/split-by-name-webpack-plugin\r\n// +\r\n// https://github.com/BohdanTkachenko/webpack-split-by-path\r\n// This plugin is OK and I took it as a basis. But there are some problem with:\r\n// - regexps \r\n// - build time in watch mode\r\n// - does not not work correctly  if there are more than one entry point (I'm not saying 100 percent. maybe // I made a mistake somewhere)\r\n// I am going to understand all and make PR to this plugin\r\n//\r\n\r\nimport isArray from 'lodash/lang/isArray';\r\nimport values from 'lodash/object/values';\r\n\r\n\r\nexport default class SplitByPathPlugin {\r\n  constructor(options) {\r\n    this.buckets = [];\r\n    for (var bucket of options) {\r\n      var paths = null;\r\n      if (isArray(bucket.path)) {\r\n        paths = bucket.path;\r\n      } else {\r\n        paths = [bucket.path];\r\n      }\r\n\r\n      this.buckets.push({\r\n        name: bucket.name,\r\n        path: paths.map(path => new RegExp(path))\r\n      });\r\n    }\r\n  }\r\n\r\n  apply(compiler) {\r\n    var match = (chunk) => {\r\n      var match = null;\r\n      this.buckets.some(bucket => {\r\n        return bucket.path.some(path => {\r\n          if (path.test(chunk.userRequest)) {\r\n            match = bucket;\r\n            return true;\r\n          }\r\n        });\r\n      });\r\n\r\n      return match;\r\n    };\r\n\r\n    compiler.plugin('compilation', compilation => {\r\n      var splitedChunks = {};\r\n\r\n      compilation.plugin('optimize-chunks', function(chunks) {\r\n        var filtered = chunks.slice().filter(chunk => chunk.entry);\r\n\r\n        var waitForRemove = [];\r\n\r\n        for (var chunk of filtered) {\r\n          for (var mod of chunk.modules) {\r\n            var bucket = match(mod);\r\n\r\n            //console.log(chunk.modules.length, mod.userRequest);\r\n\r\n            if (bucket) {\r\n            //  console.log(bucket.name, mod.userRequest);\r\n              var newChunk = splitedChunks[bucket.name];\r\n              if (!newChunk) {\r\n                newChunk = this.addChunk(bucket.name, mod);\r\n                splitedChunks[bucket.name] = newChunk;\r\n              }\r\n\r\n              // add the module to the new chunk\r\n              newChunk.addModule(mod);\r\n              mod.addChunk(newChunk);\r\n\r\n              // remove it from the existing chunk\r\n              waitForRemove.push(mod);\r\n              //mod.removeChunk(chunk);\r\n              //chunk.removeModule(mod);\r\n            } else {\r\n              //console.log('original', mod.userRequest);\r\n            }\r\n          }\r\n\r\n          for (var removeMod of waitForRemove) {\r\n            chunk.removeModule(removeMod);\r\n            removeMod.removeChunk(chunk);\r\n          }\r\n\r\n\r\n          /**\r\n           *\r\n           * Entry chunk\r\n           * An entry chunk contains the runtime plus a bunch of modules.\r\n           * If the chunk contains the module 0 the runtime executes it.\r\n           * If not, it waits for chunks that contains the module 0 and executes it (every time when there is a chunk\r\n           * with a module 0).\r\n           *\r\n           * Normal chunk\r\n           * A normal chunk contains no runtime.\r\n           * It only contains a bunch of modules.\r\n           * The structure depends on the chunk loading algorithm.\r\n           * I. e. for jsonp the modules are wrapped in a jsonp callback function. The chunk also contains a list of\r\n           * chunk id that it fulfills.\r\n           *\r\n           * Initial chunk (non-entry)\r\n           * An initial chunk is a normal chunk.\r\n           * The only difference is that optimization treats it as more important because it counts toward the initial\r\n           * loading time (like entry chunks). That chunk type can occur in combination with the CommonsChunkPlugin.\r\n           */\r\n\r\n          var all = values(splitedChunks);\r\n          //all.push(chunk);\r\n\r\n          //var main = all.shift();\r\n          var main = chunk;\r\n\r\n          main.entry = true;\r\n          main.initial = true;\r\n          main.chunks = all;\r\n\r\n          for (var resultChunk of all) {\r\n            // get the first chunk as a parent\r\n            resultChunk.parents = [main];\r\n            resultChunk.entry = false;\r\n            resultChunk.initial = false;\r\n          }\r\n        }\r\n      }, this);\r\n    });\r\n  }\r\n}\r\n```\r\nContent of output scripts is OK. Each chunk includes correct scripts (according to code split regexps).\r\n\r\nBut there is when run in browser:\r\n\r\n`Uncaught TypeError: Cannot read property 'call' of undefined` (moduleId == 1 at this error)\r\n\r\n**build.js** - entry point and its content:\r\n```js\r\n/******/ (function(modules) { // webpackBootstrap\r\n/******/ \t// install a JSONP callback for chunk loading\r\n/******/ \tvar parentJsonpFunction = window[\"webpackJsonp\"];\r\n/******/ \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\r\n/******/ \t\t// add \"moreModules\" to the modules object,\r\n/******/ \t\t// then flag all \"chunkIds\" as loaded and fire callback\r\n/******/ \t\tvar moduleId, chunkId, i = 0, callbacks = [];\r\n/******/ \t\tfor(;i < chunkIds.length; i++) {\r\n/******/ \t\t\tchunkId = chunkIds[i];\r\n/******/ \t\t\tif(installedChunks[chunkId])\r\n/******/ \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\r\n/******/ \t\t\tinstalledChunks[chunkId] = 0;\r\n/******/ \t\t}\r\n/******/ \t\tfor(moduleId in moreModules) {\r\n/******/ \t\t\tmodules[moduleId] = moreModules[moduleId];\r\n/******/ \t\t}\r\n/******/ \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\r\n/******/ \t\twhile(callbacks.length)\r\n/******/ \t\t\tcallbacks.shift().call(null, __webpack_require__);\r\n/******/\r\n/******/ \t};\r\n/******/\r\n/******/ \t// The module cache\r\n/******/ \tvar installedModules = {};\r\n/******/\r\n/******/ \t// object to store loaded and loading chunks\r\n/******/ \t// \"0\" means \"already loaded\"\r\n/******/ \t// Array means \"loading\", array contains callbacks\r\n/******/ \tvar installedChunks = {\r\n/******/ \t\t0:0\r\n/******/ \t};\r\n/******/\r\n/******/ \t// The require function\r\n/******/ \tfunction __webpack_require__(moduleId) {\r\n/******/\r\n/******/ \t\t// Check if module is in cache\r\n/******/ \t\tif(installedModules[moduleId])\r\n/******/ \t\t\treturn installedModules[moduleId].exports;\r\n/******/\r\n/******/ \t\t// Create a new module (and put it into the cache)\r\n/******/ \t\tvar module = installedModules[moduleId] = {\r\n/******/ \t\t\texports: {},\r\n/******/ \t\t\tid: moduleId,\r\n/******/ \t\t\tloaded: false\r\n/******/ \t\t};\r\n/******/\r\n/******/ \t\t// Execute the module function\r\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\r\n/******/\r\n/******/ \t\t// Flag the module as loaded\r\n/******/ \t\tmodule.loaded = true;\r\n/******/\r\n/******/ \t\t// Return the exports of the module\r\n/******/ \t\treturn module.exports;\r\n/******/ \t}\r\n/******/\r\n/******/ \t// This file contains only the entry chunk.\r\n/******/ \t// The chunk loading function for additional chunks\r\n/******/ \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\r\n/******/ \t\t// \"0\" is the signal for \"already loaded\"\r\n/******/ \t\tif(installedChunks[chunkId] === 0)\r\n/******/ \t\t\treturn callback.call(null, __webpack_require__);\r\n/******/\r\n/******/ \t\t// an array means \"currently loading\".\r\n/******/ \t\tif(installedChunks[chunkId] !== undefined) {\r\n/******/ \t\t\tinstalledChunks[chunkId].push(callback);\r\n/******/ \t\t} else {\r\n/******/ \t\t\t// start chunk loading\r\n/******/ \t\t\tinstalledChunks[chunkId] = [callback];\r\n/******/ \t\t\tvar head = document.getElementsByTagName('head')[0];\r\n/******/ \t\t\tvar script = document.createElement('script');\r\n/******/ \t\t\tscript.type = 'text/javascript';\r\n/******/ \t\t\tscript.charset = 'utf-8';\r\n/******/ \t\t\tscript.async = true;\r\n/******/\r\n/******/ \t\t\tscript.src = __webpack_require__.p + \"\" + ({\"1\":\"js/vendor\",\"2\":\"js/app\",\"3\":\"js/templates\",\"4\":\"js/bootstrap\"}[chunkId]||chunkId) + \".js\";\r\n/******/ \t\t\thead.appendChild(script);\r\n/******/ \t\t}\r\n/******/ \t};\r\n/******/\r\n/******/ \t// expose the modules object (__webpack_modules__)\r\n/******/ \t__webpack_require__.m = modules;\r\n/******/\r\n/******/ \t// expose the module cache\r\n/******/ \t__webpack_require__.c = installedModules;\r\n/******/\r\n/******/ \t// __webpack_public_path__\r\n/******/ \t__webpack_require__.p = \"\";\r\n/******/\r\n/******/ \t// Load entry module and return exports\r\n/******/ \treturn __webpack_require__(0);\r\n/******/ })\r\n/************************************************************************/\r\n/******/ ({\r\n\r\n/***/ 0:\r\n/*!**********************!*\\\r\n  !*** multi js/build ***!\r\n  \\**********************/\r\n/***/ function(module, exports, __webpack_require__) {\r\n\t__webpack_require__(/*! babel/polyfill */1);\r\n\t__webpack_require__(/*! js/controllers/user.js */12);\r\n\t__webpack_require__(/*! js/controllers/profile.js */13);\r\n\t__webpack_require__(/*! bootstrap.js */14);\r\n/******/ });\r\n```\r\n\r\nCan not load `__webpack_require__(/*! babel/polyfill */1);` because  this module is located at **vendor.js** chunk and  included to html after **build.js**\r\n\r\nPlease help to make this work correctly. Seems problem at creating new chunks and movinf modules form one chunk to another. But I dont know where exactly the error\r\n\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/webpack/webpack/issues/comments/117630970","html_url":"https://github.com/webpack/webpack/issues/1212#issuecomment-117630970","issue_url":"https://api.github.com/repos/webpack/webpack/issues/1212","id":117630970,"user":{"login":"tuchk4","id":5140611,"avatar_url":"https://avatars.githubusercontent.com/u/5140611?v=3","gravatar_id":"","url":"https://api.github.com/users/tuchk4","html_url":"https://github.com/tuchk4","followers_url":"https://api.github.com/users/tuchk4/followers","following_url":"https://api.github.com/users/tuchk4/following{/other_user}","gists_url":"https://api.github.com/users/tuchk4/gists{/gist_id}","starred_url":"https://api.github.com/users/tuchk4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tuchk4/subscriptions","organizations_url":"https://api.github.com/users/tuchk4/orgs","repos_url":"https://api.github.com/users/tuchk4/repos","events_url":"https://api.github.com/users/tuchk4/events{/privacy}","received_events_url":"https://api.github.com/users/tuchk4/received_events","type":"User","site_admin":false},"created_at":"2015-07-01T11:57:00Z","updated_at":"2015-07-01T11:57:00Z","body":"OK\r\n\r\nI found solution\r\n\r\njust  use as entry bundle one of generated bundles and default bundle push to end. Like at this plugin https://github.com/BohdanTkachenko/webpack-split-by-path\r\n\r\nBut problem in this way - rebuild in watch mode take more time (~ 1.5s) because entry bundle contains all vendors (in my case).\r\n\r\nTo resolve this - I changed devtool from **sourcemaps** to **eval**."}}