Merge branch 'master' into next

This commit is contained in:
Tobias Koppers 2017-10-11 12:42:31 +02:00 committed by GitHub
commit 03b0ff2c9c
59 changed files with 1407 additions and 30 deletions

View File

@ -0,0 +1,856 @@
This example illustrates how common modules from deep ancestors of an entry point can be split into a seperate common chunk
* `pageA` and `pageB` are dynamically required
* `pageC` and `pageA` both require the `reusableComponent`
* `pageB` dynamically requires `PageC`
You can see that webpack outputs four files/chunks:
* `output.js` is the entry chunk and contains
* the module system
* chunk loading logic
* the entry point `example.js`
* module `reusableComponent`
* `0.output.js` is an additional chunk
* module `pageC`
* `1.output.js` is an additional chunk
* module `pageB`
* `2.output.js` is an additional chunk
* module `pageA`
# example.js
``` javascript
var main = function() {
console.log("Main class");
require.ensure([], () => {
const page = require("./pageA");
page();
});
require.ensure([], () => {
const page = require("./pageB");
page();
});
};
main();
```
# pageA.js
``` javascript
var reusableComponent = require("./reusableComponent");
module.exports = function() {
console.log("Page A");
reusableComponent();
};
```
# pageB.js
``` javascript
module.exports = function() {
console.log("Page B");
require.ensure([], ()=>{
const page = require("./pageC");
page();
});
};
```
# pageC.js
``` javascript
var reusableComponent = require("./reusableComponent");
module.exports = function() {
console.log("Page C");
reusableComponent();
};
```
# reusableComponent.js
``` javascript
module.exports = function() {
console.log("reusable Component");
};
```
# webpack.config.js
``` javascript
"use strict";
const webpack = require("../../");
const path = require("path");
module.exports = [
{
entry: {
main: ["./example.js"]
},
output: {
path: path.resolve(__dirname, "js"),
filename: "output.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "main",
minChunks: 2,
children: true,
deepChildren: true,
})
]
},
{
entry: {
main: ["./example.js"]
},
output: {
path: path.resolve(__dirname, "js"),
filename: "asyncoutput.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "main",
minChunks: 2,
async: true,
children: true,
deepChildren: true,
})
]
}
];
```
# js/output.js
<details><summary><code>/******/ (function(modules) { /* webpackBootstrap */ })</code></summary>
``` javascript
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ var parentJsonpFunction = window["webpackJsonp"];
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, resolves = [], result;
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
/******/ while(resolves.length) {
/******/ resolves.shift()();
/******/ }
/******/
/******/ };
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // objects to store loaded and loading chunks
/******/ var installedChunks = {
/******/ 3: 0
/******/ };
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
/******/ var installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData === 0) {
/******/ return new Promise(function(resolve) { resolve(); });
/******/ }
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ return installedChunkData[2];
/******/ }
/******/
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise(function(resolve, reject) {
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
/******/ });
/******/ installedChunkData[2] = promise;
/******/
/******/ // start chunk loading
/******/ var head = document.getElementsByTagName('head')[0];
/******/ var script = document.createElement('script');
/******/ script.type = 'text/javascript';
/******/ script.charset = 'utf-8';
/******/ script.async = true;
/******/ script.timeout = 120000;
/******/
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.src = __webpack_require__.p + "" + chunkId + ".output.js";
/******/ var timeout = setTimeout(onScriptComplete, 120000);
/******/ script.onerror = script.onload = onScriptComplete;
/******/ function onScriptComplete() {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var chunk = installedChunks[chunkId];
/******/ if(chunk !== 0) {
/******/ if(chunk) {
/******/ chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
/******/ }
/******/ installedChunks[chunkId] = undefined;
/******/ }
/******/ };
/******/ head.appendChild(script);
/******/
/******/ return promise;
/******/ };
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return 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/";
/******/
/******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
```
</details>
``` javascript
/******/ ([
/* 0 */
/*!**************************!*\
!*** multi ./example.js ***!
\**************************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(/*! ./example.js */1);
/***/ }),
/* 1 */
/*!********************!*\
!*** ./example.js ***!
\********************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var main = function() {
console.log("Main class");
__webpack_require__.e/* require.ensure */(2).then((() => {
const page = __webpack_require__(/*! ./pageA */ 3);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
__webpack_require__.e/* require.ensure */(1).then((() => {
const page = __webpack_require__(/*! ./pageB */ 4);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
};
main();
/***/ }),
/* 2 */
/*!******************************!*\
!*** ./reusableComponent.js ***!
\******************************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports) {
module.exports = function() {
console.log("reusable Component");
};
/***/ })
/******/ ]);
```
# js/0.output.js
``` javascript
webpackJsonp([0],{
/***/ 5:
/*!******************!*\
!*** ./pageC.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var reusableComponent = __webpack_require__(/*! ./reusableComponent */ 2);
module.exports = function() {
console.log("Page C");
reusableComponent();
};
/***/ })
});
```
# js/1.output.js
``` javascript
webpackJsonp([1],{
/***/ 4:
/*!******************!*\
!*** ./pageB.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
module.exports = function() {
console.log("Page B");
__webpack_require__.e/* require.ensure */(0).then((()=>{
const page = __webpack_require__(/*! ./pageC */ 5);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
};
/***/ })
});
```
# js/2.output.js
``` javascript
webpackJsonp([2],{
/***/ 3:
/*!******************!*\
!*** ./pageA.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var reusableComponent = __webpack_require__(/*! ./reusableComponent */ 2);
module.exports = function() {
console.log("Page A");
reusableComponent();
};
/***/ })
});
```
# js/asyncoutput.js
``` javascript
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ var parentJsonpFunction = window["webpackJsonp"];
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, resolves = [], result;
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
/******/ while(resolves.length) {
/******/ resolves.shift()();
/******/ }
/******/
/******/ };
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // objects to store loaded and loading chunks
/******/ var installedChunks = {
/******/ 4: 0
/******/ };
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
/******/ var installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData === 0) {
/******/ return new Promise(function(resolve) { resolve(); });
/******/ }
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ return installedChunkData[2];
/******/ }
/******/
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise(function(resolve, reject) {
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
/******/ });
/******/ installedChunkData[2] = promise;
/******/
/******/ // start chunk loading
/******/ var head = document.getElementsByTagName('head')[0];
/******/ var script = document.createElement('script');
/******/ script.type = 'text/javascript';
/******/ script.charset = 'utf-8';
/******/ script.async = true;
/******/ script.timeout = 120000;
/******/
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.src = __webpack_require__.p + "" + chunkId + ".asyncoutput.js";
/******/ var timeout = setTimeout(onScriptComplete, 120000);
/******/ script.onerror = script.onload = onScriptComplete;
/******/ function onScriptComplete() {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var chunk = installedChunks[chunkId];
/******/ if(chunk !== 0) {
/******/ if(chunk) {
/******/ chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
/******/ }
/******/ installedChunks[chunkId] = undefined;
/******/ }
/******/ };
/******/ head.appendChild(script);
/******/
/******/ return promise;
/******/ };
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return 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/";
/******/
/******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/*!**************************!*\
!*** multi ./example.js ***!
\**************************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(/*! ./example.js */1);
/***/ }),
/* 1 */
/*!********************!*\
!*** ./example.js ***!
\********************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var main = function() {
console.log("Main class");
Promise.all/* require.ensure */([__webpack_require__.e(0), __webpack_require__.e(2)]).then((() => {
const page = __webpack_require__(/*! ./pageA */ 2);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
__webpack_require__.e/* require.ensure */(1).then((() => {
const page = __webpack_require__(/*! ./pageB */ 3);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
};
main();
/***/ })
/******/ ]);
```
# js/0.asyncoutput.js
``` javascript
webpackJsonp([0],{
/***/ 4:
/*!******************************!*\
!*** ./reusableComponent.js ***!
\******************************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports) {
module.exports = function() {
console.log("reusable Component");
};
/***/ })
});
```
# js/1.asyncoutput.js
``` javascript
webpackJsonp([1],{
/***/ 3:
/*!******************!*\
!*** ./pageB.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
module.exports = function() {
console.log("Page B");
Promise.all/* require.ensure */([__webpack_require__.e(0), __webpack_require__.e(3)]).then((()=>{
const page = __webpack_require__(/*! ./pageC */ 5);
page();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
};
/***/ })
});
```
# js/2.asyncoutput.js
``` javascript
webpackJsonp([2],{
/***/ 2:
/*!******************!*\
!*** ./pageA.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var reusableComponent = __webpack_require__(/*! ./reusableComponent */ 4);
module.exports = function() {
console.log("Page A");
reusableComponent();
};
/***/ })
});
```
# js/3.asyncoutput.js
``` javascript
webpackJsonp([3],{
/***/ 5:
/*!******************!*\
!*** ./pageC.js ***!
\******************/
/*! no static exports found */
/*! all exports used */
/***/ (function(module, exports, __webpack_require__) {
var reusableComponent = __webpack_require__(/*! ./reusableComponent */ 4);
module.exports = function() {
console.log("Page C");
reusableComponent();
};
/***/ })
});
```
# Info
## Uncompressed
```
Hash: 777f989f517d7831d56f1d268f47bc8703ad9f73
Version: webpack 3.6.0
Child
Hash: 777f989f517d7831d56f
Asset Size Chunks Chunk Names
0.output.js 388 bytes 0 [emitted]
1.output.js 481 bytes 1 [emitted]
2.output.js 388 bytes 2 [emitted]
output.js 6.95 kB 3 [emitted] main
Entrypoint main = output.js
chunk {0} 0.output.js 142 bytes {3} [rendered]
> [4] ./pageB.js 3:1-6:3
[5] ./pageC.js 142 bytes {0} [built]
cjs require ./pageC [4] ./pageB.js 4:15-33
chunk {1} 1.output.js 140 bytes {3} [rendered]
> [1] ./example.js 7:1-10:3
[4] ./pageB.js 140 bytes {1} [built]
cjs require ./pageB [1] ./example.js 8:15-33
chunk {2} 2.output.js 142 bytes {3} [rendered]
> [1] ./example.js 3:1-6:3
[3] ./pageA.js 142 bytes {2} [built]
cjs require ./pageA [1] ./example.js 4:15-33
chunk {3} output.js (main) 333 bytes [entry] [rendered]
> main [0] multi ./example.js
[0] multi ./example.js 28 bytes {3} [built]
[1] ./example.js 233 bytes {3} [built]
single entry ./example.js [0] multi ./example.js main:100000
[2] ./reusableComponent.js 72 bytes {3} [built]
cjs require ./reusableComponent [3] ./pageA.js 1:24-54
cjs require ./reusableComponent [5] ./pageC.js 1:24-54
Child
Hash: 1d268f47bc8703ad9f73
Asset Size Chunks Chunk Names
0.asyncoutput.js 314 bytes 0 [emitted]
1.asyncoutput.js 522 bytes 1 [emitted]
2.asyncoutput.js 388 bytes 2 [emitted]
3.asyncoutput.js 388 bytes 3 [emitted]
asyncoutput.js 6.7 kB 4 [emitted] main
Entrypoint main = asyncoutput.js
chunk {0} 0.asyncoutput.js 72 bytes {4} [rendered]
> async commons [1] ./example.js 3:1-6:3
> async commons [3] ./pageB.js 3:1-6:3
[4] ./reusableComponent.js 72 bytes {0} [built]
cjs require ./reusableComponent [2] ./pageA.js 1:24-54
cjs require ./reusableComponent [5] ./pageC.js 1:24-54
chunk {1} 1.asyncoutput.js 140 bytes {4} [rendered]
> [1] ./example.js 7:1-10:3
[3] ./pageB.js 140 bytes {1} [built]
cjs require ./pageB [1] ./example.js 8:15-33
chunk {2} 2.asyncoutput.js 142 bytes {4} [rendered]
> [1] ./example.js 3:1-6:3
[2] ./pageA.js 142 bytes {2} [built]
cjs require ./pageA [1] ./example.js 4:15-33
chunk {3} 3.asyncoutput.js 142 bytes {1} [rendered]
> [3] ./pageB.js 3:1-6:3
[5] ./pageC.js 142 bytes {3} [built]
cjs require ./pageC [3] ./pageB.js 4:15-33
chunk {4} asyncoutput.js (main) 261 bytes [entry] [rendered]
> main [0] multi ./example.js
[0] multi ./example.js 28 bytes {4} [built]
[1] ./example.js 233 bytes {4} [built]
single entry ./example.js [0] multi ./example.js main:100000
```
## Minimized (uglify-js, no zip)
```
Hash: 777f989f517d7831d56f1d268f47bc8703ad9f73
Version: webpack 3.6.0
Child
Hash: 777f989f517d7831d56f
Asset Size Chunks Chunk Names
0.output.js 98 bytes 0 [emitted]
1.output.js 340 bytes 1 [emitted]
2.output.js 98 bytes 2 [emitted]
output.js 6.46 kB 3 [emitted] main
Entrypoint main = output.js
chunk {0} 0.output.js 142 bytes {3} [rendered]
> [4] ./pageB.js 3:1-6:3
[5] ./pageC.js 142 bytes {0} [built]
cjs require ./pageC [4] ./pageB.js 4:15-33
chunk {1} 1.output.js 140 bytes {3} [rendered]
> [1] ./example.js 7:1-10:3
[4] ./pageB.js 140 bytes {1} [built]
cjs require ./pageB [1] ./example.js 8:15-33
chunk {2} 2.output.js 142 bytes {3} [rendered]
> [1] ./example.js 3:1-6:3
[3] ./pageA.js 142 bytes {2} [built]
cjs require ./pageA [1] ./example.js 4:15-33
chunk {3} output.js (main) 333 bytes [entry] [rendered]
> main [0] multi ./example.js
[0] multi ./example.js 28 bytes {3} [built]
[1] ./example.js 233 bytes {3} [built]
single entry ./example.js [0] multi ./example.js main:100000
[2] ./reusableComponent.js 72 bytes {3} [built]
cjs require ./reusableComponent [3] ./pageA.js 1:24-54
cjs require ./reusableComponent [5] ./pageC.js 1:24-54
ERROR in 1.output.js from UglifyJs
Unexpected token: punc ()) [1.output.js:8,53]
ERROR in output.js from UglifyJs
Unexpected token: punc ()) [output.js:161,53]
Child
Hash: 1d268f47bc8703ad9f73
Asset Size Chunks Chunk Names
0.asyncoutput.js 93 bytes 0 [emitted]
1.asyncoutput.js 381 bytes 1 [emitted]
2.asyncoutput.js 98 bytes 2 [emitted]
3.asyncoutput.js 98 bytes 3 [emitted]
asyncoutput.js 6.37 kB 4 [emitted] main
Entrypoint main = asyncoutput.js
chunk {0} 0.asyncoutput.js 72 bytes {4} [rendered]
> async commons [1] ./example.js 3:1-6:3
> async commons [3] ./pageB.js 3:1-6:3
[4] ./reusableComponent.js 72 bytes {0} [built]
cjs require ./reusableComponent [2] ./pageA.js 1:24-54
cjs require ./reusableComponent [5] ./pageC.js 1:24-54
chunk {1} 1.asyncoutput.js 140 bytes {4} [rendered]
> [1] ./example.js 7:1-10:3
[3] ./pageB.js 140 bytes {1} [built]
cjs require ./pageB [1] ./example.js 8:15-33
chunk {2} 2.asyncoutput.js 142 bytes {4} [rendered]
> [1] ./example.js 3:1-6:3
[2] ./pageA.js 142 bytes {2} [built]
cjs require ./pageA [1] ./example.js 4:15-33
chunk {3} 3.asyncoutput.js 142 bytes {1} [rendered]
> [3] ./pageB.js 3:1-6:3
[5] ./pageC.js 142 bytes {3} [built]
cjs require ./pageC [3] ./pageB.js 4:15-33
chunk {4} asyncoutput.js (main) 261 bytes [entry] [rendered]
> main [0] multi ./example.js
[0] multi ./example.js 28 bytes {4} [built]
[1] ./example.js 233 bytes {4} [built]
single entry ./example.js [0] multi ./example.js main:100000
ERROR in 1.asyncoutput.js from UglifyJs
Unexpected token: punc ()) [1.asyncoutput.js:8,94]
ERROR in asyncoutput.js from UglifyJs
Unexpected token: punc ()) [asyncoutput.js:161,94]
```

View File

@ -0,0 +1,2 @@
global.NO_TARGET_ARGS = true;
require("../build-common");

View File

@ -0,0 +1,13 @@
var main = function() {
console.log("Main class");
require.ensure([], () => {
const page = require("./pageA");
page();
});
require.ensure([], () => {
const page = require("./pageB");
page();
});
};
main();

View File

@ -0,0 +1,6 @@
var reusableComponent = require("./reusableComponent");
module.exports = function() {
console.log("Page A");
reusableComponent();
};

View File

@ -0,0 +1,7 @@
module.exports = function() {
console.log("Page B");
require.ensure([], ()=>{
const page = require("./pageC");
page();
});
};

View File

@ -0,0 +1,6 @@
var reusableComponent = require("./reusableComponent");
module.exports = function() {
console.log("Page C");
reusableComponent();
};

View File

@ -0,0 +1,3 @@
module.exports = function() {
console.log("reusable Component");
};

View File

@ -0,0 +1,124 @@
This example illustrates how common modules from deep ancestors of an entry point can be split into a seperate common chunk
* `pageA` and `pageB` are dynamically required
* `pageC` and `pageA` both require the `reusableComponent`
* `pageB` dynamically requires `PageC`
You can see that webpack outputs four files/chunks:
* `output.js` is the entry chunk and contains
* the module system
* chunk loading logic
* the entry point `example.js`
* module `reusableComponent`
* `0.output.js` is an additional chunk
* module `pageC`
* `1.output.js` is an additional chunk
* module `pageB`
* `2.output.js` is an additional chunk
* module `pageA`
# example.js
``` javascript
{{example.js}}
```
# pageA.js
``` javascript
{{pageA.js}}
```
# pageB.js
``` javascript
{{pageB.js}}
```
# pageC.js
``` javascript
{{pageC.js}}
```
# reusableComponent.js
``` javascript
{{reusableComponent.js}}
```
# webpack.config.js
``` javascript
{{webpack.config.js}}
```
# js/output.js
``` javascript
{{js/output.js}}
```
# js/0.output.js
``` javascript
{{js/0.output.js}}
```
# js/1.output.js
``` javascript
{{js/1.output.js}}
```
# js/2.output.js
``` javascript
{{js/2.output.js}}
```
# js/asyncoutput.js
``` javascript
{{js/asyncoutput.js}}
```
# js/0.asyncoutput.js
``` javascript
{{js/0.asyncoutput.js}}
```
# js/1.asyncoutput.js
``` javascript
{{js/1.asyncoutput.js}}
```
# js/2.asyncoutput.js
``` javascript
{{js/2.asyncoutput.js}}
```
# js/3.asyncoutput.js
``` javascript
{{js/3.asyncoutput.js}}
```
# Info
## Uncompressed
```
{{stdout}}
```
## Minimized (uglify-js, no zip)
```
{{min:stdout}}
```

View File

@ -0,0 +1,41 @@
"use strict";
const webpack = require("../../");
const path = require("path");
module.exports = [
{
entry: {
main: ["./example.js"]
},
output: {
path: path.resolve(__dirname, "js"),
filename: "output.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "main",
minChunks: 2,
children: true,
deepChildren: true,
})
]
},
{
entry: {
main: ["./example.js"]
},
output: {
path: path.resolve(__dirname, "js"),
filename: "asyncoutput.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "main",
minChunks: 2,
async: true,
children: true,
deepChildren: true,
})
]
}
];

View File

@ -2,6 +2,7 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const fs = require("fs");
const path = require("path");

View File

@ -584,8 +584,8 @@ class Compilation extends Tapable {
chunk.entryModule = module;
self.assignIndex(module);
self.assignDepth(module);
self.processDependenciesBlockForChunk(module, chunk);
});
self.processDependenciesBlocksForChunks(self.chunks.slice());
self.sortModules(self.modules);
self.applyPlugins0("optimize");
@ -852,11 +852,16 @@ class Compilation extends Tapable {
}
}
processDependenciesBlockForChunk(module, chunk) {
let block = module;
const initialChunk = chunk;
processDependenciesBlocksForChunks(inputChunks) {
const chunkDependencies = new Map(); // Map<Chunk, Array<{Module, Chunk}>>
const queue = inputChunks.map(chunk => ({
block: chunk.entryModule,
module: chunk.entryModule,
chunk: chunk
}));
let block, module, chunk;
const iteratorBlock = b => {
let c;
if(!b.chunks) {
@ -901,12 +906,6 @@ class Compilation extends Tapable {
}
};
const queue = [{
block,
module,
chunk
}];
while(queue.length) {
const queueItem = queue.pop();
block = queueItem.block;
@ -926,13 +925,12 @@ class Compilation extends Tapable {
}
}
chunk = initialChunk;
let chunks = new Set();
const queue2 = [{
const queue2 = inputChunks.map(chunk => ({
chunk,
chunks
}];
chunks: new Set()
}));
let chunks;
const filterFn = dep => {
if(chunks.has(dep.chunk)) return false;
for(const chunk of chunks) {

View File

@ -42,7 +42,7 @@ class UmdMainTemplatePlugin {
apply(compilation) {
const mainTemplate = compilation.mainTemplate;
compilation.templatesPlugin("render-with-entry", (source, chunk, hash) => {
let externals = chunk.getModules().filter(m => m.external);
let externals = chunk.getModules().filter(m => m.external && (m.type === "umd" || m.type === "umd2"));
const optionalExternals = [];
let requiredExternals = [];
if(this.optionalAmdExternalAsGlobal) {

View File

@ -28,6 +28,10 @@ class AMDDefineDependencyParserPlugin {
this.options = options;
}
newDefineDependency(range, arrayRange, functionRange, objectRange, namedModule) {
return new AMDDefineDependency(range, arrayRange, functionRange, objectRange, namedModule);
}
apply(parser) {
const options = this.options;
parser.plugin("call define", (expr) => {
@ -156,7 +160,7 @@ class AMDDefineDependencyParserPlugin {
parser.walkExpression(fn || obj);
}
const dep = new AMDDefineDependency(
const dep = this.newDefineDependency(
expr.range,
array ? array.range : null,
fn ? fn.range : null,

View File

@ -4,6 +4,7 @@
*/
"use strict";
let nextIdent = 0;
class CommonsChunkPlugin {
constructor(options) {
if(arguments.length > 1) {
@ -31,6 +32,7 @@ The available options are:
this.minChunks = normalizedOptions.minChunks;
this.selectedChunks = normalizedOptions.selectedChunks;
this.children = normalizedOptions.children;
this.deepChildren = normalizedOptions.deepChildren;
this.async = normalizedOptions.async;
this.minSize = normalizedOptions.minSize;
this.ident = __filename + (nextIdent++);
@ -76,6 +78,7 @@ You can however specify the name of the async chunk by passing the desired strin
minChunks: options.minChunks,
selectedChunks: options.chunks,
children: options.children,
deepChildren: options.deepChildren,
async: options.async,
minSize: options.minSize
};
@ -104,7 +107,7 @@ You can however specify the name of the async chunk by passing the desired strin
/**
* These chunks are subject to get "common" modules extracted and moved to the common chunk
*/
const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children);
const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.deepChildren, this.children);
// bail if no chunk is affected
if(!affectedChunks) {
@ -211,7 +214,37 @@ You can however specify the name of the async chunk by passing the desired strin
Take a look at the "name"/"names" or async/children option.`);
}
getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, children) {
getAffectedUnnamedChunks(affectedChunks, targetChunk, asyncOption, deepChildrenOption) {
for(const chunk of targetChunk.chunksIterable) {
if(chunk.isInitial()) {
continue;
}
// If all the parents of a chunk are either
// a) the target chunk we started with
// b) themselves affected chunks
// we can assume that this chunk is an affected chunk too, as there is no way a chunk that
// isn't only depending on the target chunk is a parent of the chunk tested
if(asyncOption || chunk.parents.every((parentChunk) => parentChunk === targetChunk || affectedChunks.has(parentChunk))) {
// This check not only dedupes the affectedChunks but also guarantees we avoid endless loops
if(!affectedChunks.has(chunk) || affectedChunks.values().next().value === chunk) {
// We mutate the affected chunks before going deeper, so the deeper levels and other branches
// Have the information of this chunk being affected for their assertion if a chunk should
// not be affected
affectedChunks.add(chunk);
// We recurse down to all the children of the chunk, applying the same assumption.
// This guarantees that if a chunk should be an affected chunk,
// at the latest the last connection to the same chunk meets the
// condition to add it to the affected chunks.
if(deepChildrenOption === true) {
this.getAffectedUnnamedChunks(affectedChunks, chunk, asyncOption, deepChildrenOption);
}
}
}
}
}
getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, deepChildrenOption, children) {
const asyncOrNoSelectedChunk = children || asyncOption;
if(Array.isArray(selectedChunks)) {
@ -223,17 +256,9 @@ Take a look at the "name"/"names" or async/children option.`);
}
if(asyncOrNoSelectedChunk) {
return targetChunk.getChunks().filter((chunk) => {
// we only are interested in on-demand chunks
if(chunk.isInitial())
return false;
// we can only move modules from this chunk if the "commonChunk" is the only parent
if(!asyncOption)
return chunk.getNumberOfParents() === 1;
return true;
});
let affectedChunks = new Set();
this.getAffectedUnnamedChunks(affectedChunks, targetChunk, asyncOption, deepChildrenOption);
return Array.from(affectedChunks);
}
/**

View File

@ -0,0 +1,13 @@
it("should handle circular chunks correctly", function(done) {
import(/* webpackChunkName: "a" */"./module-a").then(function(result) {
return result.default();
}).then(function(result2) {
result2.default().should.be.eql("x");
done();
}).catch(function(e) {
done(e);
});
const couldBe = function() {
return import(/* webpackChunkName: "b" */"./module-b");
};
});

View File

@ -0,0 +1,3 @@
export default function() {
return import(/* webpackChunkName: "c" */"./module-c");
};

View File

@ -0,0 +1 @@
export default "a2";

View File

@ -0,0 +1,5 @@
import "./module-x";
export default function() {
return import(/* webpackChunkName: "c" */"./module-c");
};

View File

@ -0,0 +1 @@
export default "b2";

View File

@ -0,0 +1,9 @@
import x from "./module-x";
export default function() {
if(Math.random() < -1) {
import(/* webpackChunkName: "a" */"./module-a");
import(/* webpackChunkName: "b" */"./module-b");
}
return x;
}

View File

@ -0,0 +1 @@
export default "x";

View File

@ -0,0 +1,12 @@
it("should correctly include indirect children in common chunk", function(done) {
Promise.all([
import('./pageA'),
import('./pageB')
]).then((imports) => {
imports[0].default.should.be.eql("reuse");
imports[1].default.should.be.eql("reuse");
done();
}).catch(e => {
done(e);
})
});

View File

@ -0,0 +1,3 @@
var reusableComponent = require("./reusableComponent");
export default reusableComponent.default;

View File

@ -0,0 +1 @@
module.exports = import('./pageC')

View File

@ -0,0 +1,3 @@
var reusableComponent = require("./reusableComponent");
export default reusableComponent.default;

View File

@ -0,0 +1,3 @@
const reuse = "reuse";
export default reuse;

View File

@ -0,0 +1,8 @@
it("should handle indirect children with multiple parents correctly", function(done) {
import('./pageB').then(b => {
b.default.should.be.eql("reuse");
done()
}).catch(e => {
done();
})
})

View File

@ -0,0 +1,8 @@
module.exports = {
findBundle: function(i, options) {
return [
"./main.js",
"./misc.js",
];
}
};

View File

@ -0,0 +1,19 @@
var CommonsChunkPlugin = require("../../../../lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
main: "./index",
misc: "./second",
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin({
name: "main",
minChunks: 2,
children: true,
deepChildren: true,
})
]
};

View File

@ -0,0 +1,23 @@
require("should");
var fs = require("fs");
var path = require("path");
it("should correctly import a UMD external", function() {
var external = require("external0");
external.should.be.eql("module 0");
});
it("should contain `require()` statements for the UMD external", function() {
var source = fs.readFileSync(path.join(__dirname, "bundle0.js"), "utf-8");
source.should.containEql("require(\"external0\")");
});
it("should correctly import a non-UMD external", function() {
var external = require("external1");
external.should.be.eql("abc");
});
it("should not contain `require()` statements for the non-UMD external", function() {
var source = fs.readFileSync(path.join(__dirname, "bundle0.js"), "utf-8");
source.should.not.containEql("require(\"'abc'\")");
});

View File

@ -0,0 +1,5 @@
module.exports = {
modules: {
external0: "module 0"
}
};

View File

@ -0,0 +1,13 @@
module.exports = {
output: {
libraryTarget: "umd"
},
externals: {
external0: "external0",
external1: "var 'abc'"
},
node: {
__dirname: false,
__filename: false
}
};

View File

@ -0,0 +1,23 @@
require("should");
var fs = require("fs");
var path = require("path");
it("should correctly import a UMD2 external", function() {
var external = require("external0");
external.should.be.eql("module 0");
});
it("should contain `require()` statements for the UMD2 external", function() {
var source = fs.readFileSync(path.join(__dirname, "bundle0.js"), "utf-8");
source.should.containEql("require(\"external0\")");
});
it("should correctly import a non-UMD2 external", function() {
var external = require("external1");
external.should.be.eql("abc");
});
it("should not contain `require()` statements for the non-UMD2 external", function() {
var source = fs.readFileSync(path.join(__dirname, "bundle0.js"), "utf-8");
source.should.not.containEql("require(\"'abc'\")");
});

View File

@ -0,0 +1,5 @@
module.exports = {
modules: {
external0: "module 0"
}
};

View File

@ -0,0 +1,13 @@
module.exports = {
output: {
libraryTarget: "umd2"
},
externals: {
external0: "external0",
external1: "var 'abc'"
},
node: {
__dirname: false,
__filename: false
}
};

View File

@ -0,0 +1,8 @@
chunk {0} 0.bundle.js (b) 49 bytes {2} {3} [rendered]
[2] (webpack)/test/statsCases/circular-correctness/module-b.js 49 bytes {0} [built]
chunk {1} 1.bundle.js (a) 49 bytes {2} {3} [rendered]
[0] (webpack)/test/statsCases/circular-correctness/module-a.js 49 bytes {1} [built]
chunk {2} 2.bundle.js (c) 98 bytes {0} {1} [rendered]
[1] (webpack)/test/statsCases/circular-correctness/module-c.js 98 bytes {2} [built]
chunk {3} bundle.js (main) 98 bytes [entry] [rendered]
[3] (webpack)/test/statsCases/circular-correctness/index.js 98 bytes {3} [built]

View File

@ -0,0 +1,2 @@
import(/* webpackChunkName: "a" */"./module-a");
import(/* webpackChunkName: "b" */"./module-b");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "c" */"./module-c");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "c" */"./module-c");

View File

@ -0,0 +1,2 @@
import(/* webpackChunkName: "a" */"./module-a");
import(/* webpackChunkName: "b" */"./module-b");

View File

@ -0,0 +1,14 @@
module.exports = {
entry: "./index",
output: {
filename: "bundle.js"
},
stats: {
hash: false,
timings: false,
assets: false,
chunks: true,
chunkModules: true,
modules: false
}
};

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "a" */"./module-a");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "c" */"./module-c");

View File

@ -0,0 +1,15 @@
chunk {0} 0.js (c) 49 bytes {2} {3} [rendered]
[1] (webpack)/test/statsCases/graph-correctness-entries/module-c.js 49 bytes {0} [built]
import() ./module-c [3] (webpack)/test/statsCases/graph-correctness-entries/module-b.js 1:0-47
import() ./module-c [4] (webpack)/test/statsCases/graph-correctness-entries/e2.js 1:0-47
chunk {1} 1.js (a) 49 bytes {0} {4} [rendered]
[0] (webpack)/test/statsCases/graph-correctness-entries/module-a.js 49 bytes {1} [built]
import() ./module-a [1] (webpack)/test/statsCases/graph-correctness-entries/module-c.js 1:0-47
import() ./module-a [2] (webpack)/test/statsCases/graph-correctness-entries/e1.js 1:0-47
chunk {2} 2.js (b) 49 bytes {1} [rendered]
[3] (webpack)/test/statsCases/graph-correctness-entries/module-b.js 49 bytes {2} [built]
import() ./module-b [0] (webpack)/test/statsCases/graph-correctness-entries/module-a.js 1:0-47
chunk {3} e2.js (e2) 49 bytes [entry] [rendered]
[4] (webpack)/test/statsCases/graph-correctness-entries/e2.js 49 bytes {3} [built]
chunk {4} e1.js (e1) 49 bytes [entry] [rendered]
[2] (webpack)/test/statsCases/graph-correctness-entries/e1.js 49 bytes {4} [built]

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "b" */"./module-b");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "c" */"./module-c");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "a" */"./module-a");

View File

@ -0,0 +1,18 @@
module.exports = {
entry: {
e1: "./e1",
e2: "./e2"
},
output: {
filename: "[name].js"
},
stats: {
hash: false,
timings: false,
assets: false,
chunks: true,
chunkModules: true,
modules: false,
reasons: true
}
};

View File

@ -0,0 +1,2 @@
import "./module-x";
import(/* webpackChunkName: "a" */"./module-a");

View File

@ -0,0 +1,2 @@
import "./module-x";
import(/* webpackChunkName: "c" */"./module-c");

View File

@ -0,0 +1,26 @@
chunk {0} 0.js (y) 0 bytes {4} {5} [rendered]
[1] (webpack)/test/statsCases/graph-correctness-modules/module-y.js 0 bytes {0} [built]
import() ./module-y [0] (webpack)/test/statsCases/graph-correctness-modules/module-x.js 1:0-47
chunk {1} 1.js (c) 49 bytes {3} {4} [rendered]
[3] (webpack)/test/statsCases/graph-correctness-modules/module-c.js 49 bytes {1} [built]
import() ./module-c [5] (webpack)/test/statsCases/graph-correctness-modules/module-b.js 1:0-47
import() ./module-c [6] (webpack)/test/statsCases/graph-correctness-modules/e2.js 2:0-47
chunk {2} 2.js (a) 49 bytes {1} {5} [rendered]
[2] (webpack)/test/statsCases/graph-correctness-modules/module-a.js 49 bytes {2} [built]
import() ./module-a [3] (webpack)/test/statsCases/graph-correctness-modules/module-c.js 1:0-47
import() ./module-a [4] (webpack)/test/statsCases/graph-correctness-modules/e1.js 2:0-47
chunk {3} 3.js (b) 179 bytes {2} [rendered]
[5] (webpack)/test/statsCases/graph-correctness-modules/module-b.js 179 bytes {3} [built]
import() ./module-b [2] (webpack)/test/statsCases/graph-correctness-modules/module-a.js 1:0-47
chunk {4} e2.js (e2) 119 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/graph-correctness-modules/module-x.js 49 bytes {4} {5} [built]
harmony import ./module-x [4] (webpack)/test/statsCases/graph-correctness-modules/e1.js 1:0-20
import() ./module-x [5] (webpack)/test/statsCases/graph-correctness-modules/module-b.js 2:0-20
harmony import ./module-x [6] (webpack)/test/statsCases/graph-correctness-modules/e2.js 1:0-20
[6] (webpack)/test/statsCases/graph-correctness-modules/e2.js 70 bytes {4} [built]
chunk {5} e1.js (e1) 119 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/graph-correctness-modules/module-x.js 49 bytes {4} {5} [built]
harmony import ./module-x [4] (webpack)/test/statsCases/graph-correctness-modules/e1.js 1:0-20
import() ./module-x [5] (webpack)/test/statsCases/graph-correctness-modules/module-b.js 2:0-20
harmony import ./module-x [6] (webpack)/test/statsCases/graph-correctness-modules/e2.js 1:0-20
[4] (webpack)/test/statsCases/graph-correctness-modules/e1.js 70 bytes {5} [built]

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "b" */"./module-b");

View File

@ -0,0 +1,2 @@
import(/* webpackChunkName: "c" */"./module-c");
import("./module-x"); // This should not create a chunk, because module-x is in both entrypoints (in every path to this module-b)

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "a" */"./module-a");

View File

@ -0,0 +1 @@
import(/* webpackChunkName: "y" */"./module-y");

View File

@ -0,0 +1,18 @@
module.exports = {
entry: {
e1: "./e1",
e2: "./e2"
},
output: {
filename: "[name].js"
},
stats: {
hash: false,
timings: false,
assets: false,
chunks: true,
chunkModules: true,
modules: false,
reasons: true
}
};