Merge branch 'master' into patch-2

This commit is contained in:
Tobias Koppers 2018-03-26 16:06:59 +02:00 committed by GitHub
commit c3d1806329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
537 changed files with 21218 additions and 13583 deletions

View File

@ -8,15 +8,11 @@ trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
max_line_length = 233 max_line_length = 233
[*.json] [.prettierrc]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[*.yml] [*.{yml,yaml,json}]
indent_style = space
indent_size = 2
[*.yaml]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -1,15 +1,16 @@
module.exports = { module.exports = {
"root": true, root: true,
"plugins": ["node"], plugins: ["prettier", "node"],
"extends": ["eslint:recommended", "plugin:node/recommended"], extends: ["eslint:recommended", "plugin:node/recommended"],
"env": { env: {
"node": true, node: true,
"es6": true, es6: true
"mocha": true,
}, },
"parserOptions": { "ecmaVersion": 2017 }, parserOptions: {
"rules": { ecmaVersion: 2017
"quotes": ["error", "double"], },
rules: {
"prettier/prettier": "error",
"no-undef": "error", "no-undef": "error",
"no-extra-semi": "error", "no-extra-semi": "error",
"semi": "error", "semi": "error",
@ -21,51 +22,34 @@ module.exports = {
"brace-style": "error", "brace-style": "error",
"eol-last": "error", "eol-last": "error",
"no-extra-bind": "warn", "no-extra-bind": "warn",
"no-empty": "off",
"no-multiple-empty-lines": "error",
"no-multi-spaces": "error",
"no-process-exit": "warn", "no-process-exit": "warn",
"space-in-parens": "error",
"no-trailing-spaces": "error",
"no-use-before-define": "off", "no-use-before-define": "off",
"no-unused-vars": ["error", { "args": "none" }], "no-unused-vars": ["error", { args: "none" }],
"key-spacing": "error",
"space-infix-ops": "error",
"no-unsafe-negation": "error", "no-unsafe-negation": "error",
"no-loop-func": "warn", "no-loop-func": "warn",
"space-before-function-paren": ["error", "never"],
"space-before-blocks": "error",
"object-curly-spacing": ["error", "always"],
"indent": "off", "indent": "off",
"keyword-spacing": ["error", {
"after": false,
"overrides": {
"const": { "after": true },
"try": { "after": true },
"else": { "after": true },
"throw": { "after": true },
"case": { "after": true },
"return": { "after": true },
"finally": { "after": true },
"do": { "after": true },
"of": { "after": true }
}
}],
"no-console": "off", "no-console": "off",
"valid-jsdoc": "error", "valid-jsdoc": "error",
"node/no-unsupported-features": "error", "node/no-unsupported-features": "error",
"node/no-deprecated-api": "error", "node/no-deprecated-api": "error",
"node/no-missing-import": "error", "node/no-missing-import": "error",
"node/no-missing-require": [ "node/no-missing-require": ["error", { allowModules: ["webpack"] }],
"error",
{
"allowModules": [
"webpack"
]
}
],
"node/no-unpublished-bin": "error", "node/no-unpublished-bin": "error",
"node/no-unpublished-require": "error", "node/no-unpublished-require": "error",
"node/process-exit-as-throw": "error" "node/process-exit-as-throw": "error"
} },
overrides: [
{
files: ["lib/**/*.runtime.js", "buildin/*.js", "hot/*.js"],
env: {
es6: false
},
globals: {
Promise: false,
},
parserOptions: {
ecmaVersion: 5
}
}
]
}; };

View File

@ -1,25 +0,0 @@
{
"js": {
"allowed_file_extensions": ["js", "json", "jshintrc", "jsbeautifyrc"],
"brace_style": "collapse",
"break_chained_methods": false,
"e4x": true,
"eval_code": false,
"end_with_newline": true,
"indent_char": "\t",
"indent_level": 0,
"indent_size": 1,
"indent_with_tabs": true,
"jslint_happy": false,
"jslint_happy_align_switch_case": true,
"space_after_anon_function": false,
"keep_array_indentation": false,
"keep_function_indentation": false,
"max_preserve_newlines": 2,
"preserve_newlines": true,
"space_before_conditional": false,
"space_in_paren": false,
"unescape_strings": false,
"wrap_line_length": 0
}
}

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"tabWidth": 2,
"useTabs": true
}

View File

@ -31,20 +31,7 @@ If you have created your own loader/plugin please include it on the relevant doc
## Setup ## Setup
```bash [Setup your local webpack repository](_SETUP.md)
git clone https://github.com/webpack/webpack.git
cd webpack
npm install -g yarn
yarn
yarn link
yarn link webpack
```
To run the entire test suite use:
```bash
yarn test
```
## Submitting Changes ## Submitting Changes

View File

@ -1,6 +1,6 @@
<div align="center"> <div align="center">
<a href="https://github.com/webpack/webpack"> <a href="https://github.com/webpack/webpack">
<img width="200" heigth="200" src="https://webpack.js.org/assets/icon-square-big.svg"> <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
</a> </a>
<br> <br>
<br> <br>
@ -15,7 +15,7 @@
[![licenses][licenses]][licenses-url] [![licenses][licenses]][licenses-url]
<br> <br>
<a href="https://npmjs.com/package/webpack"> <a href="https://npmcharts.com/compare/webpack?minimal=true">
<img src="https://img.shields.io/npm/dm/webpack.svg"> <img src="https://img.shields.io/npm/dm/webpack.svg">
</a> </a>
<a href="https://opencollective.com/webpack#backer"> <a href="https://opencollective.com/webpack#backer">
@ -33,7 +33,7 @@
<h1>webpack</h1> <h1>webpack</h1>
<p> <p>
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset. webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
<p> </p>
</div> </div>
<h2 align="center">Install</h2> <h2 align="center">Install</h2>
@ -81,14 +81,12 @@ within webpack itself use this plugin interface. This makes webpack very
|Name|Status|Description| |Name|Status|Description|
|:--:|:----:|:----------| |:--:|:----:|:----------|
|[common-chunks-webpack-plugin][common]|![common-npm]|Generates chunks of common modules shared between entry points and splits them into separate bundles (e.g vendor.bundle.js && app.bundle.js)|
|[extract-text-webpack-plugin][extract]|![extract-npm]|Extracts Text (CSS) from your bundles into a separate file (app.bundle.css)| |[extract-text-webpack-plugin][extract]|![extract-npm]|Extracts Text (CSS) from your bundles into a separate file (app.bundle.css)|
|[compression-webpack-plugin][compression]|![compression-npm]|Prepares compressed versions of assets to serve them with Content-Encoding| |[compression-webpack-plugin][compression]|![compression-npm]|Prepares compressed versions of assets to serve them with Content-Encoding|
|[i18n-webpack-plugin][i18n]|![i18n-npm]|Adds i18n support to your bundles| |[i18n-webpack-plugin][i18n]|![i18n-npm]|Adds i18n support to your bundles|
|[html-webpack-plugin][html-plugin]|![html-plugin-npm]| Simplifies creation of HTML files (`index.html`) to serve your bundles| |[html-webpack-plugin][html-plugin]|![html-plugin-npm]| Simplifies creation of HTML files (`index.html`) to serve your bundles|
[common]: https://github.com/webpack/webpack/blob/master/lib/optimize/CommonsChunkPlugin.js
[common-npm]: https://img.shields.io/npm/v/webpack.svg [common-npm]: https://img.shields.io/npm/v/webpack.svg
[extract]: https://github.com/webpack/extract-text-webpack-plugin [extract]: https://github.com/webpack/extract-text-webpack-plugin
[extract-npm]: https://img.shields.io/npm/v/extract-text-webpack-plugin.svg [extract-npm]: https://img.shields.io/npm/v/extract-text-webpack-plugin.svg
@ -184,7 +182,7 @@ or are automatically applied via regex from your webpack configuration.
|Name|Status|Description| |Name|Status|Description|
|:--:|:----:|:----------| |:--:|:----:|:----------|
|<a href="https://github.com/webpack/style-loader">`<style>`|![style-npm]|Add exports of a module as style to DOM| |<a href="https://github.com/webpack/style-loader">`<style>`</a>|![style-npm]|Add exports of a module as style to DOM|
|<a href="https://github.com/webpack/css-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/css-3.svg"></a>|![css-npm]|Loads CSS file with resolved imports and returns CSS code| |<a href="https://github.com/webpack/css-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/css-3.svg"></a>|![css-npm]|Loads CSS file with resolved imports and returns CSS code|
|<a href="https://github.com/webpack/less-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/less-63.svg"></a>|![less-npm]|Loads and compiles a LESS file| |<a href="https://github.com/webpack/less-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/less-63.svg"></a>|![less-npm]|Loads and compiles a LESS file|
|<a href="https://github.com/jtangelder/sass-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/sass-1.svg"></a>|![sass-npm]|Loads and compiles a SASS/SCSS file| |<a href="https://github.com/jtangelder/sass-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/sass-1.svg"></a>|![sass-npm]|Loads and compiles a SASS/SCSS file|
@ -344,7 +342,7 @@ If you have discovered a 🐜 or have a feature suggestion, feel free to create
<a href="https://github.com/spacek33z">Kees Kluskens</a> <a href="https://github.com/spacek33z">Kees Kluskens</a>
<p>Development</p> <p>Development</p>
<br> <br>
<p>Sponsor<p> <p>Sponsor</p>
<a href="https://codeyellow.nl/"> <a href="https://codeyellow.nl/">
<img height="15px" src="https://cloud.githubusercontent.com/assets/1365881/20286583/ad62eb04-aac7-11e6-9c14-a0fef35b9b56.png"> <img height="15px" src="https://cloud.githubusercontent.com/assets/1365881/20286583/ad62eb04-aac7-11e6-9c14-a0fef35b9b56.png">
</a> </a>
@ -371,7 +369,7 @@ This is how we use the donations:
<h2 align="center">Premium Partners</h2> <h2 align="center">Premium Partners</h2>
<div align="center"> <div align="center">
<a href="https://www.ag-grid.com/?utm_source=webpack&utm_medium=banner&utm_campaign=sponsorship" target="_blank"><img align="center" src="https://raw.githubusercontent.com/webpack/media/2b399d58/horiz-banner-ad-ag-grid.png"> <a href="https://www.ag-grid.com/?utm_source=webpack&utm_medium=banner&utm_campaign=sponsorship" target="_blank"><img align="center" src="https://raw.githubusercontent.com/webpack/media/2b399d58/horiz-banner-ad-ag-grid.png">
</a> </a>
@ -382,11 +380,11 @@ This is how we use the donations:
Before we started using OpenCollective, donations were made anonymously. Now that we have made the switch, we would like to acknowledge these sponsors (and the ones who continue to donate using OpenCollective). If we've missed someone, please send us a PR, and we'll add you to this list. Before we started using OpenCollective, donations were made anonymously. Now that we have made the switch, we would like to acknowledge these sponsors (and the ones who continue to donate using OpenCollective). If we've missed someone, please send us a PR, and we'll add you to this list.
<div align="center"> <div align="center">
[Google Angular Team](https://angular.io/), [Architects.io](http://architects.io/), [Google Angular Team](https://angular.io/), [Architects.io](http://architects.io/),
<a href="https://moonmail.io" target="_blank" title="Email Marketing Software"><img <a href="https://moonmail.io" target="_blank" title="Email Marketing Software"><img
src="https://static.moonmail.io/moonmail-logo.svg" height="30" alt="MoonMail"></a> src="https://static.moonmail.io/moonmail-logo.svg" height="30" alt="MoonMail"></a>
<a href="https://monei.net" target="_blank" title="Best payment gateway rates"><img <a href="https://monei.net" target="_blank" title="Best payment gateway rates"><img
src="https://static.monei.net/monei-logo.svg" height="30" alt="MONEI"></a> src="https://static.monei.net/monei-logo.svg" height="30" alt="MONEI"></a>
</div> </div>

18
_SETUP.md Normal file
View File

@ -0,0 +1,18 @@
# Setup
Setup your local webpack repository
```bash
git clone https://github.com/webpack/webpack.git
cd webpack
npm install -g yarn
yarn install
yarn link
yarn link webpack
```
To run the entire test suite use:
```bash
yarn test
```

View File

@ -4,15 +4,17 @@ let webpackCliInstalled = false;
try { try {
require.resolve("webpack-cli"); require.resolve("webpack-cli");
webpackCliInstalled = true; webpackCliInstalled = true;
} catch(e) { } catch (e) {
webpackCliInstalled = false; webpackCliInstalled = false;
} }
if(webpackCliInstalled) { if (webpackCliInstalled) {
require("webpack-cli"); // eslint-disable-line node/no-missing-require, node/no-extraneous-require, node/no-unpublished-require require("webpack-cli"); // eslint-disable-line node/no-missing-require, node/no-extraneous-require, node/no-unpublished-require
} else { } else {
console.error("The CLI moved into a separate package: webpack-cli."); console.error("The CLI moved into a separate package: webpack-cli.");
console.error("Please install 'webpack-cli' in addition to webpack itself to use the CLI."); console.error(
"Please install 'webpack-cli' in addition to webpack itself to use the CLI."
);
console.error("-> When using npm: npm install webpack-cli -D"); console.error("-> When using npm: npm install webpack-cli -D");
console.error("-> When using yarn: yarn add webpack-cli -D"); console.error("-> When using yarn: yarn add webpack-cli -D");
process.exitCode = 1; process.exitCode = 1;

View File

@ -7,11 +7,10 @@ g = (function() {
try { try {
// This works if eval is allowed (see CSP) // This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this"); g = g || Function("return this")() || (1, eval)("this");
} catch(e) { } catch (e) {
// This works if the window reference is available // This works if the window reference is available
if(typeof window === "object") if (typeof window === "object") g = window;
g = window;
} }
// g can still be undefined, but nothing to do about it... // g can still be undefined, but nothing to do about it...

View File

@ -1,8 +1,8 @@
module.exports = function(originalModule) { module.exports = function(originalModule) {
if(!originalModule.webpackPolyfill) { if (!originalModule.webpackPolyfill) {
var module = Object.create(originalModule); var module = Object.create(originalModule);
// module.parent = undefined by default // module.parent = undefined by default
if(!module.children) module.children = []; if (!module.children) module.children = [];
Object.defineProperty(module, "loaded", { Object.defineProperty(module, "loaded", {
enumerable: true, enumerable: true,
get: function() { get: function() {
@ -16,7 +16,7 @@ module.exports = function(originalModule) {
} }
}); });
Object.defineProperty(module, "exports", { Object.defineProperty(module, "exports", {
enumerable: true, enumerable: true
}); });
module.webpackPolyfill = 1; module.webpackPolyfill = 1;
} }

View File

@ -1,9 +1,9 @@
module.exports = function(module) { module.exports = function(module) {
if(!module.webpackPolyfill) { if (!module.webpackPolyfill) {
module.deprecate = function() {}; module.deprecate = function() {};
module.paths = []; module.paths = [];
// module.parent = undefined by default // module.parent = undefined by default
if(!module.children) module.children = []; if (!module.children) module.children = [];
Object.defineProperty(module, "loaded", { Object.defineProperty(module, "loaded", {
enumerable: true, enumerable: true,
get: function() { get: function() {

View File

@ -95,12 +95,12 @@ module.exports = {
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }

View File

@ -1,10 +1,12 @@
module.exports = { module.exports = {
// mode: "development || "production", // mode: "development || "production",
module: { module: {
rules: [{ rules: [
test: /\.coffee$/, {
loader: "coffee-loader" test: /\.coffee$/,
}] loader: "coffee-loader"
}
]
}, },
resolve: { resolve: {
extensions: [".web.coffee", ".web.js", ".coffee", ".js"] extensions: [".web.coffee", ".web.js", ".coffee", ".js"]

View File

@ -178,12 +178,12 @@ module.exports = "utility3";
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }
@ -351,12 +351,12 @@ module.exports = "utility1";
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }
@ -510,12 +510,12 @@ module.exports = "pageB";
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }

View File

@ -1,4 +1,4 @@
This example illustrates how common modules from deep ancestors of an entry point can be split into a seperate common chunk This example illustrates how common modules from deep ancestors of an entry point can be split into a separate common chunk
* `pageA` and `pageB` are dynamically required * `pageA` and `pageB` are dynamically required
* `pageC` and `pageA` both require the `reusableComponent` * `pageC` and `pageA` both require the `reusableComponent`
@ -93,7 +93,7 @@ module.exports = {
}, },
optimization: { optimization: {
splitChunks: { splitChunks: {
minSize: 0 // This example is too small, in pratice you can use the defaults minSize: 0 // This example is too small, in practice you can use the defaults
}, },
occurrenceOrder: true // To keep filename consistent between different modes (for example building only) occurrenceOrder: true // To keep filename consistent between different modes (for example building only)
}, },

View File

@ -1,4 +1,4 @@
This example illustrates how common modules from deep ancestors of an entry point can be split into a seperate common chunk This example illustrates how common modules from deep ancestors of an entry point can be split into a separate common chunk
* `pageA` and `pageB` are dynamically required * `pageA` and `pageB` are dynamically required
* `pageC` and `pageA` both require the `reusableComponent` * `pageC` and `pageA` both require the `reusableComponent`

View File

@ -8,7 +8,7 @@ module.exports = {
}, },
optimization: { optimization: {
splitChunks: { splitChunks: {
minSize: 0 // This example is too small, in pratice you can use the defaults minSize: 0 // This example is too small, in practice you can use the defaults
}, },
occurrenceOrder: true // To keep filename consistent between different modes (for example building only) occurrenceOrder: true // To keep filename consistent between different modes (for example building only)
}, },

View File

@ -1,6 +1,6 @@
This is the vendor build part. This is the vendor build part.
It's built separatly from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle. It's built separately from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle.
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment. The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.

View File

@ -1,6 +1,6 @@
This is the vendor build part. This is the vendor build part.
It's built separatly from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle. It's built separately from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle.
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment. The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.

View File

@ -8,12 +8,12 @@ module.exports = {
output: { output: {
filename: "vendor.js", // best use [hash] here too filename: "vendor.js", // best use [hash] here too
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "dist"),
library: "vendor_lib_[hash]", library: "vendor_lib_[hash]"
}, },
plugins: [ plugins: [
new webpack.DllPlugin({ new webpack.DllPlugin({
name: "vendor_lib_[hash]", name: "vendor_lib_[hash]",
path: path.resolve(__dirname, "dist/vendor-manifest.json"), path: path.resolve(__dirname, "dist/vendor-manifest.json")
}), })
], ]
}; };

View File

@ -7,12 +7,12 @@ module.exports = {
entry: "./example-app", entry: "./example-app",
output: { output: {
filename: "app.js", filename: "app.js",
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "dist")
}, },
plugins: [ plugins: [
new webpack.DllReferencePlugin({ new webpack.DllReferencePlugin({
context: ".", context: ".",
manifest: require("../0-vendor/dist/vendor-manifest.json"), // eslint-disable-line manifest: require("../0-vendor/dist/vendor-manifest.json") // eslint-disable-line
}), })
], ]
}; };

View File

@ -1,7 +1,6 @@
var path = require("path"); var path = require("path");
var webpack = require("../../"); var webpack = require("../../");
module.exports = [ module.exports = [
{ {
name: "vendor", name: "vendor",
// mode: "development || "production", // mode: "development || "production",
@ -38,5 +37,4 @@ module.exports = [
}) })
] ]
} }
]; ];

View File

@ -6,7 +6,7 @@ module.exports = {
externals: [ externals: [
"add", "add",
{ {
"subtract": { subtract: {
root: "subtract", root: "subtract",
commonjs2: "./subtract", commonjs2: "./subtract",
commonjs: ["./math", "subtract"], commonjs: ["./math", "subtract"],

View File

@ -16,7 +16,7 @@ The example entry references two chunks:
These chunks share modules `a` and `b`. The optimization extract these into chunk Z: These chunks share modules `a` and `b`. The optimization extract these into chunk Z:
Note: Actually the optimization compare size of chunk Z to some minimum value, but this is disabled from this example. In pratice there is no configuration needed for this. Note: Actually the optimization compare size of chunk Z to some minimum value, but this is disabled from this example. In practice there is no configuration needed for this.
* entry chunk * entry chunk
* async require -> chunk X & Z * async require -> chunk X & Z

View File

@ -16,7 +16,7 @@ The example entry references two chunks:
These chunks share modules `a` and `b`. The optimization extract these into chunk Z: These chunks share modules `a` and `b`. The optimization extract these into chunk Z:
Note: Actually the optimization compare size of chunk Z to some minimum value, but this is disabled from this example. In pratice there is no configuration needed for this. Note: Actually the optimization compare size of chunk Z to some minimum value, but this is disabled from this example. In practice there is no configuration needed for this.
* entry chunk * entry chunk
* async require -> chunk X & Z * async require -> chunk X & Z

View File

@ -29,7 +29,7 @@ exports.readFile = function() {};
// using module.exports would be equivalent, // using module.exports would be equivalent,
// webpack doesn't care which syntax is used // webpack doesn't care which syntax is used
// AMD modules are also possible and equvivalent to CommonJs modules // AMD modules are also possible and equivalent to CommonJs modules
``` ```
# reexport-commonjs.js # reexport-commonjs.js
@ -192,7 +192,7 @@ exports.readFile = function() {};
// using module.exports would be equivalent, // using module.exports would be equivalent,
// webpack doesn't care which syntax is used // webpack doesn't care which syntax is used
// AMD modules are also possible and equvivalent to CommonJs modules // AMD modules are also possible and equivalent to CommonJs modules
/***/ }), /***/ }),

View File

@ -4,4 +4,4 @@ exports.readFile = function() {};
// using module.exports would be equivalent, // using module.exports would be equivalent,
// webpack doesn't care which syntax is used // webpack doesn't care which syntax is used
// AMD modules are also possible and equvivalent to CommonJs modules // AMD modules are also possible and equivalent to CommonJs modules

View File

@ -214,12 +214,12 @@ module.exports = webpackAsyncContext;
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }

View File

@ -5,7 +5,7 @@ module.exports = {
// The entry points for the pages // The entry points for the pages
// They also contains router // They also contains router
pageA: ["./aEntry", "./router"], pageA: ["./aEntry", "./router"],
pageB: ["./bEntry", "./router"], pageB: ["./bEntry", "./router"]
}, },
output: { output: {
path: path.join(__dirname, "dist"), path: path.join(__dirname, "dist"),

View File

@ -1,8 +1,8 @@
var path = require("path"); var path = require("path");
var I18nPlugin = require("i18n-webpack-plugin"); var I18nPlugin = require("i18n-webpack-plugin");
var languages = { var languages = {
"en": null, en: null,
"de": require("./de.json") de: require("./de.json")
}; };
module.exports = Object.keys(languages).map(function(language) { module.exports = Object.keys(languages).map(function(language) {
return { return {
@ -13,10 +13,6 @@ module.exports = Object.keys(languages).map(function(language) {
path: path.join(__dirname, "dist"), path: path.join(__dirname, "dist"),
filename: language + ".output.js" filename: language + ".output.js"
}, },
plugins: [ plugins: [new I18nPlugin(languages[language])]
new I18nPlugin(
languages[language]
)
]
}; };
}); });

View File

@ -1,9 +1,11 @@
module.exports = { module.exports = {
// mode: "development || "production", // mode: "development || "production",
module: { module: {
rules: [{ rules: [
test: /\.css$/, {
loader: "css-loader" test: /\.css$/,
}] loader: "css-loader"
}
]
} }
}; };

View File

@ -1,7 +1,6 @@
var path = require("path"); var path = require("path");
var webpack = require("../../"); var webpack = require("../../");
module.exports = [ module.exports = [
{ {
name: "mobile", name: "mobile",
// mode: "development || "production", // mode: "development || "production",
@ -31,5 +30,4 @@ module.exports = [
}) })
] ]
} }
]; ];

View File

@ -4,15 +4,15 @@ In this example you have two (HTML) pages `pageA` and `pageB`. You want to creat
You can see how to define multiple entry points via the `entry` option. You can see how to define multiple entry points via the `entry` option.
You can use You can use
You can see the output files: You can see the output files:
* `commons.js` contains: * `commons.js` contains:
* the module system
* chunk loading logic
* module `common.js` which is used in both pages * module `common.js` which is used in both pages
* `pageA.js` contains: (`pageB.js` is similar) * `pageA.js` contains: (`pageB.js` is similar)
* the module system
* chunk loading logic
* the entry point `pageA.js` * the entry point `pageA.js`
* it would contain any other module that is only used by `pageA` * it would contain any other module that is only used by `pageA`
* `0.chunk.js` is an additional chunk which is used by both pages. It contains: * `0.chunk.js` is an additional chunk which is used by both pages. It contains:
@ -143,12 +143,12 @@ module.exports = "Common";
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }
@ -366,12 +366,12 @@ __webpack_require__.e(/*! AMD require */ 0).then(function() { var __WEBPACK_AMD_
/******/ var result; /******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) { /******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i]; /******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true; /******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; j++) { /******/ for(var j = 1; j < deferredModule.length; j++) {
/******/ var depId = deferredModule[j]; /******/ var depId = deferredModule[j];
/******/ if(installedChunks[depId] !== 0) fullfilled = false; /******/ if(installedChunks[depId] !== 0) fulfilled = false;
/******/ } /******/ }
/******/ if(fullfilled) { /******/ if(fulfilled) {
/******/ deferredModules.splice(i--, 1); /******/ deferredModules.splice(i--, 1);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ } /******/ }
@ -572,7 +572,7 @@ module.exports = function(msg) {
``` ```
Hash: 0a1b2c3d4e5f6a7b8c9d Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.0.0-beta.2 Version: webpack 4.0.0-beta.1
Asset Size Chunks Chunk Names Asset Size Chunks Chunk Names
0.js 363 bytes 0 [emitted] 0.js 363 bytes 0 [emitted]
commons.js 267 bytes 1 [emitted] commons commons.js 267 bytes 1 [emitted] commons
@ -588,8 +588,8 @@ chunk {0} 0.js 91 bytes <{1}> <{2}> <{3}> [rendered]
cjs require ./shared [2] ./pageB.js 3:14-33 cjs require ./shared [2] ./pageB.js 3:14-33
amd require ./shared [3] ./pageA.js 2:0-4:2 amd require ./shared [3] ./pageA.js 2:0-4:2
chunk {1} commons.js (commons) 26 bytes ={2}= ={3}= >{0}< [initial] [rendered] split chunk (cache group: commons) (name: commons) chunk {1} commons.js (commons) 26 bytes ={2}= ={3}= >{0}< [initial] [rendered] split chunk (cache group: commons) (name: commons)
> ./pageA pageA
> ./pageB pageB > ./pageB pageB
> ./pageA pageA
[1] ./common.js 26 bytes {1} [built] [1] ./common.js 26 bytes {1} [built]
cjs require ./common [0] ./shared.js 1:13-32 cjs require ./common [0] ./shared.js 1:13-32
cjs require ./common [2] ./pageB.js 1:13-32 cjs require ./common [2] ./pageB.js 1:13-32
@ -608,7 +608,7 @@ chunk {3} pageA.js (pageA) 108 bytes ={1}= >{0}< [entry] [rendered]
``` ```
Hash: 0a1b2c3d4e5f6a7b8c9d Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.0.0-beta.2 Version: webpack 4.0.0-beta.1
Asset Size Chunks Chunk Names Asset Size Chunks Chunk Names
0.js 120 bytes 0 [emitted] 0.js 120 bytes 0 [emitted]
commons.js 95 bytes 1 [emitted] commons commons.js 95 bytes 1 [emitted] commons
@ -624,8 +624,8 @@ chunk {0} 0.js 91 bytes <{1}> <{2}> <{3}> [rendered]
cjs require ./shared [2] ./pageB.js 3:14-33 cjs require ./shared [2] ./pageB.js 3:14-33
amd require ./shared [3] ./pageA.js 2:0-4:2 amd require ./shared [3] ./pageA.js 2:0-4:2
chunk {1} commons.js (commons) 26 bytes ={2}= ={3}= >{0}< [initial] [rendered] split chunk (cache group: commons) (name: commons) chunk {1} commons.js (commons) 26 bytes ={2}= ={3}= >{0}< [initial] [rendered] split chunk (cache group: commons) (name: commons)
> ./pageA pageA
> ./pageB pageB > ./pageB pageB
> ./pageA pageA
[1] ./common.js 26 bytes {1} [built] [1] ./common.js 26 bytes {1} [built]
cjs require ./common [0] ./shared.js 1:13-32 cjs require ./common [0] ./shared.js 1:13-32
cjs require ./common [2] ./pageB.js 1:13-32 cjs require ./common [2] ./pageB.js 1:13-32

View File

@ -4,15 +4,15 @@ In this example you have two (HTML) pages `pageA` and `pageB`. You want to creat
You can see how to define multiple entry points via the `entry` option. You can see how to define multiple entry points via the `entry` option.
You can use You can use
You can see the output files: You can see the output files:
* `commons.js` contains: * `commons.js` contains:
* the module system
* chunk loading logic
* module `common.js` which is used in both pages * module `common.js` which is used in both pages
* `pageA.js` contains: (`pageB.js` is similar) * `pageA.js` contains: (`pageB.js` is similar)
* the module system
* chunk loading logic
* the entry point `pageA.js` * the entry point `pageA.js`
* it would contain any other module that is only used by `pageA` * it would contain any other module that is only used by `pageA`
* `0.chunk.js` is an additional chunk which is used by both pages. It contains: * `0.chunk.js` is an additional chunk which is used by both pages. It contains:

View File

@ -12,7 +12,7 @@ delete require.cache[aId];
// require module again, it should be reexecuted // require module again, it should be reexecuted
var a2 = require("./a"); var a2 = require("./a");
// vertify it // verify it
if(a == a2) throw new Error("Cache clear failed :("); if(a == a2) throw new Error("Cache clear failed :(");
``` ```
@ -123,7 +123,7 @@ delete __webpack_require__.c[aId];
// require module again, it should be reexecuted // require module again, it should be reexecuted
var a2 = __webpack_require__(/*! ./a */ 1); var a2 = __webpack_require__(/*! ./a */ 1);
// vertify it // verify it
if(a == a2) throw new Error("Cache clear failed :("); if(a == a2) throw new Error("Cache clear failed :(");
/***/ }), /***/ }),

View File

@ -9,5 +9,5 @@ delete require.cache[aId];
// require module again, it should be reexecuted // require module again, it should be reexecuted
var a2 = require("./a"); var a2 = require("./a");
// vertify it // verify it
if(a == a2) throw new Error("Cache clear failed :("); if(a == a2) throw new Error("Cache clear failed :(");

View File

@ -18,7 +18,7 @@ webpack therefore uses a approach called **"Partial Scope Hoisting"** or "Module
![](graph3.png) ![](graph3.png)
While module concatentation identifiers in modules are renamed to avoid conflicts and internal imports are simplified. External imports and exports from the root module use the existing ESM constructs. While module concatenation identifiers in modules are renamed to avoid conflicts and internal imports are simplified. External imports and exports from the root module use the existing ESM constructs.
# example.js # example.js

View File

@ -18,7 +18,7 @@ webpack therefore uses a approach called **"Partial Scope Hoisting"** or "Module
![](graph3.png) ![](graph3.png)
While module concatentation identifiers in modules are renamed to avoid conflicts and internal imports are simplified. External imports and exports from the root module use the existing ESM constructs. While module concatenation identifiers in modules are renamed to avoid conflicts and internal imports are simplified. External imports and exports from the root module use the existing ESM constructs.
# example.js # example.js

View File

@ -10,15 +10,15 @@ module.exports = [
"hidden-source-map", "hidden-source-map",
"inline-source-map", "inline-source-map",
"nosources-source-map", "nosources-source-map",
"source-map", "source-map"
].map(devtool => ({ ].map(devtool => ({
mode: "development", mode: "development",
entry: { entry: {
bundle: "coffee-loader!./example.coffee", bundle: "coffee-loader!./example.coffee"
}, },
output: { output: {
path: path.join(__dirname, "dist"), path: path.join(__dirname, "dist"),
filename: `./[name]-${devtool}.js`, filename: `./[name]-${devtool}.js`
}, },
devtool, devtool,
optimization: { optimization: {

View File

@ -242,7 +242,7 @@ export function fibonacciJavascript(i) {
/******/ // on error function for async loading /******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; }; /******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
/******/ /******/
/******/ // object with all compiled WebAssmbly.Modules /******/ // object with all compiled WebAssembly.Modules
/******/ __webpack_require__.w = {}; /******/ __webpack_require__.w = {};
/******/ /******/
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; /******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];

View File

@ -5,10 +5,12 @@ module.exports = {
publicPath: "js/" publicPath: "js/"
}, },
module: { module: {
rules: [{ rules: [
test: /\.wasm$/, {
type: "webassembly/experimental" test: /\.wasm$/,
}] type: "webassembly/experimental"
}
]
}, },
optimization: { optimization: {
occurrenceOrder: true // To keep filename consistent between different modes (for example building only) occurrenceOrder: true // To keep filename consistent between different modes (for example building only)

View File

@ -5,5 +5,4 @@
"rules": { "rules": {
"node/exports-style": ["off"] "node/exports-style": ["off"]
} }
} }

View File

@ -3,46 +3,54 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
/*globals window __webpack_hash__ */ /*globals window __webpack_hash__ */
if(module.hot) { if (module.hot) {
var lastHash; var lastHash;
var upToDate = function upToDate() { var upToDate = function upToDate() {
return lastHash.indexOf(__webpack_hash__) >= 0; return lastHash.indexOf(__webpack_hash__) >= 0;
}; };
var log = require("./log"); var log = require("./log");
var check = function check() { var check = function check() {
module.hot.check(true).then(function(updatedModules) { module.hot
if(!updatedModules) { .check(true)
log("warning", "[HMR] Cannot find update. Need to do a full reload!"); .then(function(updatedModules) {
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)"); if (!updatedModules) {
window.location.reload(); log("warning", "[HMR] Cannot find update. Need to do a full reload!");
return; log(
} "warning",
"[HMR] (Probably because of restarting the webpack-dev-server)"
);
window.location.reload();
return;
}
if(!upToDate()) { if (!upToDate()) {
check(); check();
} }
require("./log-apply-result")(updatedModules, updatedModules); require("./log-apply-result")(updatedModules, updatedModules);
if(upToDate()) { if (upToDate()) {
log("info", "[HMR] App is up to date."); log("info", "[HMR] App is up to date.");
} }
})
}).catch(function(err) { .catch(function(err) {
var status = module.hot.status(); var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) { if (["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update. Need to do a full reload!"); log(
log("warning", "[HMR] " + err.stack || err.message); "warning",
window.location.reload(); "[HMR] Cannot apply update. Need to do a full reload!"
} else { );
log("warning", "[HMR] Update failed: " + err.stack || err.message); log("warning", "[HMR] " + err.stack || err.message);
} window.location.reload();
}); } else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
}; };
var hotEmitter = require("./emitter"); var hotEmitter = require("./emitter");
hotEmitter.on("webpackHotUpdate", function(currentHash) { hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash; lastHash = currentHash;
if(!upToDate() && module.hot.status() === "idle") { if (!upToDate() && module.hot.status() === "idle") {
log("info", "[HMR] Checking for updates on the server..."); log("info", "[HMR] Checking for updates on the server...");
check(); check();
} }

View File

@ -8,19 +8,22 @@ module.exports = function(updatedModules, renewedModules) {
}); });
var log = require("./log"); var log = require("./log");
if(unacceptedModules.length > 0) { if (unacceptedModules.length > 0) {
log("warning", "[HMR] The following modules couldn't be hot updated: (They would need a full reload!)"); log(
"warning",
"[HMR] The following modules couldn't be hot updated: (They would need a full reload!)"
);
unacceptedModules.forEach(function(moduleId) { unacceptedModules.forEach(function(moduleId) {
log("warning", "[HMR] - " + moduleId); log("warning", "[HMR] - " + moduleId);
}); });
} }
if(!renewedModules || renewedModules.length === 0) { if (!renewedModules || renewedModules.length === 0) {
log("info", "[HMR] Nothing hot updated."); log("info", "[HMR] Nothing hot updated.");
} else { } else {
log("info", "[HMR] Updated modules:"); log("info", "[HMR] Updated modules:");
renewedModules.forEach(function(moduleId) { renewedModules.forEach(function(moduleId) {
if(typeof moduleId === "string" && moduleId.indexOf("!") !== -1) { if (typeof moduleId === "string" && moduleId.indexOf("!") !== -1) {
var parts = moduleId.split("!"); var parts = moduleId.split("!");
log.groupCollapsed("info", "[HMR] - " + parts.pop()); log.groupCollapsed("info", "[HMR] - " + parts.pop());
log("info", "[HMR] - " + moduleId); log("info", "[HMR] - " + moduleId);
@ -32,7 +35,10 @@ module.exports = function(updatedModules, renewedModules) {
var numberIds = renewedModules.every(function(moduleId) { var numberIds = renewedModules.every(function(moduleId) {
return typeof moduleId === "number"; return typeof moduleId === "number";
}); });
if(numberIds) if (numberIds)
log("info", "[HMR] Consider using the NamedModulesPlugin for module names."); log(
"info",
"[HMR] Consider using the NamedModulesPlugin for module names."
);
} }
}; };

View File

@ -3,7 +3,8 @@ var logLevel = "info";
function dummy() {} function dummy() {}
function shouldLog(level) { function shouldLog(level) {
var shouldLog = (logLevel === "info" && level === "info") || var shouldLog =
(logLevel === "info" && level === "info") ||
(["info", "warning"].indexOf(logLevel) >= 0 && level === "warning") || (["info", "warning"].indexOf(logLevel) >= 0 && level === "warning") ||
(["info", "warning", "error"].indexOf(logLevel) >= 0 && level === "error"); (["info", "warning", "error"].indexOf(logLevel) >= 0 && level === "error");
return shouldLog; return shouldLog;
@ -11,19 +12,19 @@ function shouldLog(level) {
function logGroup(logFn) { function logGroup(logFn) {
return function(level, msg) { return function(level, msg) {
if(shouldLog(level)) { if (shouldLog(level)) {
logFn(msg); logFn(msg);
} }
}; };
} }
module.exports = function(level, msg) { module.exports = function(level, msg) {
if(shouldLog(level)) { if (shouldLog(level)) {
if(level === "info") { if (level === "info") {
console.log(msg); console.log(msg);
} else if(level === "warning") { } else if (level === "warning") {
console.warn(msg); console.warn(msg);
} else if(level === "error") { } else if (level === "error") {
console.error(msg); console.error(msg);
} }
} }

View File

@ -3,65 +3,99 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
/*globals __webpack_hash__ */ /*globals __webpack_hash__ */
if(module.hot) { if (module.hot) {
var lastHash; var lastHash;
var upToDate = function upToDate() { var upToDate = function upToDate() {
return lastHash.indexOf(__webpack_hash__) >= 0; return lastHash.indexOf(__webpack_hash__) >= 0;
}; };
var log = require("./log"); var log = require("./log");
var check = function check() { var check = function check() {
module.hot.check().then(function(updatedModules) { module.hot
if(!updatedModules) { .check()
log("warning", "[HMR] Cannot find update. Need to do a full reload!"); .then(function(updatedModules) {
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)"); if (!updatedModules) {
return; log("warning", "[HMR] Cannot find update. Need to do a full reload!");
} log(
"warning",
return module.hot.apply({ "[HMR] (Probably because of restarting the webpack-dev-server)"
ignoreUnaccepted: true, );
ignoreDeclined: true, return;
ignoreErrored: true,
onUnaccepted: function(data) {
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> "));
},
onDeclined: function(data) {
log("warning", "Ignored an update to declined module " + data.chain.join(" -> "));
},
onErrored: function(data) {
log("error", data.error);
log("warning", "Ignored an error while updating module " + data.moduleId + " (" + data.type + ")");
}
}).then(function(renewedModules) {
if(!upToDate()) {
check();
} }
require("./log-apply-result")(updatedModules, renewedModules); return module.hot
.apply({
ignoreUnaccepted: true,
ignoreDeclined: true,
ignoreErrored: true,
onUnaccepted: function(data) {
log(
"warning",
"Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
},
onDeclined: function(data) {
log(
"warning",
"Ignored an update to declined module " +
data.chain.join(" -> ")
);
},
onErrored: function(data) {
log("error", data.error);
log(
"warning",
"Ignored an error while updating module " +
data.moduleId +
" (" +
data.type +
")"
);
}
})
.then(function(renewedModules) {
if (!upToDate()) {
check();
}
if(upToDate()) { require("./log-apply-result")(updatedModules, renewedModules);
log("info", "[HMR] App is up to date.");
if (upToDate()) {
log("info", "[HMR] App is up to date.");
}
});
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log(
"warning",
"[HMR] Cannot check for update. Need to do a full reload!"
);
log("warning", "[HMR] " + err.stack || err.message);
} else {
log(
"warning",
"[HMR] Update check failed: " + err.stack || err.message
);
} }
}); });
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot check for update. Need to do a full reload!");
log("warning", "[HMR] " + err.stack || err.message);
} else {
log("warning", "[HMR] Update check failed: " + err.stack || err.message);
}
});
}; };
var hotEmitter = require("./emitter"); var hotEmitter = require("./emitter");
hotEmitter.on("webpackHotUpdate", function(currentHash) { hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash; lastHash = currentHash;
if(!upToDate()) { if (!upToDate()) {
var status = module.hot.status(); var status = module.hot.status();
if(status === "idle") { if (status === "idle") {
log("info", "[HMR] Checking for updates on the server..."); log("info", "[HMR] Checking for updates on the server...");
check(); check();
} else if(["abort", "fail"].indexOf(status) >= 0) { } else if (["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update as a previous update " + status + "ed. Need to do a full reload!"); log(
"warning",
"[HMR] Cannot apply update as a previous update " +
status +
"ed. Need to do a full reload!"
);
} }
} }
}); });

View File

@ -3,29 +3,32 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
/*globals __resourceQuery */ /*globals __resourceQuery */
if(module.hot) { if (module.hot) {
var hotPollInterval = +(__resourceQuery.substr(1)) || (10 * 60 * 1000); var hotPollInterval = +__resourceQuery.substr(1) || 10 * 60 * 1000;
var log = require("./log"); var log = require("./log");
var checkForUpdate = function checkForUpdate(fromUpdate) { var checkForUpdate = function checkForUpdate(fromUpdate) {
if(module.hot.status() === "idle") { if (module.hot.status() === "idle") {
module.hot.check(true).then(function(updatedModules) { module.hot
if(!updatedModules) { .check(true)
if(fromUpdate) log("info", "[HMR] Update applied."); .then(function(updatedModules) {
return; if (!updatedModules) {
} if (fromUpdate) log("info", "[HMR] Update applied.");
require("./log-apply-result")(updatedModules, updatedModules); return;
checkForUpdate(true); }
}).catch(function(err) { require("./log-apply-result")(updatedModules, updatedModules);
var status = module.hot.status(); checkForUpdate(true);
if(["abort", "fail"].indexOf(status) >= 0) { })
log("warning", "[HMR] Cannot apply update."); .catch(function(err) {
log("warning", "[HMR] " + err.stack || err.message); var status = module.hot.status();
log("warning", "[HMR] You need to restart the application!"); if (["abort", "fail"].indexOf(status) >= 0) {
} else { log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] Update failed: " + err.stack || err.message); log("warning", "[HMR] " + err.stack || err.message);
} log("warning", "[HMR] You need to restart the application!");
}); } else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
} }
}; };
setInterval(checkForUpdate, hotPollInterval); setInterval(checkForUpdate, hotPollInterval);

View File

@ -3,44 +3,54 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
/*globals __resourceQuery */ /*globals __resourceQuery */
if(module.hot) { if (module.hot) {
var log = require("./log"); var log = require("./log");
var checkForUpdate = function checkForUpdate(fromUpdate) { var checkForUpdate = function checkForUpdate(fromUpdate) {
module.hot.check().then(function(updatedModules) { module.hot
if(!updatedModules) { .check()
if(fromUpdate) .then(function(updatedModules) {
log("info", "[HMR] Update applied."); if (!updatedModules) {
else if (fromUpdate) log("info", "[HMR] Update applied.");
log("warning", "[HMR] Cannot find update."); else log("warning", "[HMR] Cannot find update.");
return; return;
} }
return module.hot.apply({ return module.hot
ignoreUnaccepted: true, .apply({
onUnaccepted: function(data) { ignoreUnaccepted: true,
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> ")); onUnaccepted: function(data) {
}, log(
}).then(function(renewedModules) { "warning",
require("./log-apply-result")(updatedModules, renewedModules); "Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
}
})
.then(function(renewedModules) {
require("./log-apply-result")(updatedModules, renewedModules);
checkForUpdate(true); checkForUpdate(true);
return null; return null;
});
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
}); });
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
}; };
process.on(__resourceQuery.substr(1) || "SIGUSR2", function() { process.on(__resourceQuery.substr(1) || "SIGUSR2", function() {
if(module.hot.status() !== "idle") { if (module.hot.status() !== "idle") {
log("warning", "[HMR] Got signal but currently in " + module.hot.status() + " state."); log(
"warning",
"[HMR] Got signal but currently in " + module.hot.status() + " state."
);
log("warning", "[HMR] Need to be in idle state to start hot update."); log("warning", "[HMR] Need to be in idle state to start hot update.");
return; return;
} }

View File

@ -33,23 +33,51 @@ const REPLACEMENT_TYPES = {
class APIPlugin { class APIPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("APIPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "APIPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory()); compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template()); compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = parser => { const handler = parser => {
Object.keys(REPLACEMENTS).forEach(key => { Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression.for(key).tap("APIPlugin", NO_WEBPACK_REQUIRE[key] ? ParserHelpers.toConstantDependency(parser, REPLACEMENTS[key]) : ParserHelpers.toConstantDependencyWithWebpackRequire(parser, REPLACEMENTS[key])); parser.hooks.expression
parser.hooks.evaluateTypeof.for(key).tap("APIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])); .for(key)
}); .tap(
}; "APIPlugin",
NO_WEBPACK_REQUIRE[key]
? ParserHelpers.toConstantDependency(
parser,
REPLACEMENTS[key]
)
: ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
REPLACEMENTS[key]
)
);
parser.hooks.evaluateTypeof
.for(key)
.tap(
"APIPlugin",
ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])
);
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("APIPlugin", handler); normalModuleFactory.hooks.parser
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("APIPlugin", handler); .for("javascript/auto")
normalModuleFactory.hooks.parser.for("javascript/esm").tap("APIPlugin", handler); .tap("APIPlugin", handler);
}); normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("APIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("APIPlugin", handler);
}
);
} }
} }

View File

@ -5,7 +5,7 @@
"use strict"; "use strict";
const ConcatSource = require("webpack-sources").ConcatSource; const { ConcatSource } = require("webpack-sources");
const Template = require("./Template"); const Template = require("./Template");
class AmdMainTemplatePlugin { class AmdMainTemplatePlugin {
@ -14,42 +14,56 @@ class AmdMainTemplatePlugin {
} }
apply(compilation) { apply(compilation) {
const { const { mainTemplate, chunkTemplate } = compilation;
mainTemplate,
chunkTemplate
} = compilation;
const onRenderWithEntry = (source, chunk, hash) => { const onRenderWithEntry = (source, chunk, hash) => {
const externals = chunk.getModules().filter((m) => m.external); const externals = chunk.getModules().filter(m => m.external);
const externalsDepsArray = JSON.stringify(externals.map((m) => const externalsDepsArray = JSON.stringify(
typeof m.request === "object" ? m.request.amd : m.request externals.map(
)); m => (typeof m.request === "object" ? m.request.amd : m.request)
const externalsArguments = externals.map((m) => )
`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__` );
).join(", "); const externalsArguments = externals
.map(
m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
)
.join(", ");
if(this.name) { if (this.name) {
const name = mainTemplate.getAssetPath(this.name, { const name = mainTemplate.getAssetPath(this.name, {
hash, hash,
chunk chunk
}); });
return new ConcatSource( return new ConcatSource(
`define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});" `define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
);
} else if (externalsArguments) {
return new ConcatSource(
`define(${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
); );
} else if(externalsArguments) {
return new ConcatSource(`define(${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});");
} else { } else {
return new ConcatSource("define(function() { return ", source, "});"); return new ConcatSource("define(function() { return ", source, "});");
} }
}; };
for(const template of [mainTemplate, chunkTemplate]) { for (const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap("AmdMainTemplatePlugin", onRenderWithEntry); template.hooks.renderWithEntry.tap(
"AmdMainTemplatePlugin",
onRenderWithEntry
);
} }
mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => { mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => {
if(this.name) paths.push(this.name); if (this.name) paths.push(this.name);
return paths; return paths;
}); });

View File

@ -25,9 +25,15 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
updateHash(hash) { updateHash(hash) {
hash.update(this.chunkName || ""); hash.update(this.chunkName || "");
hash.update(this.chunkGroup && this.chunkGroup.chunks.map(chunk => { hash.update(
return chunk.id !== null ? chunk.id : ""; (this.chunkGroup &&
}).join(",") || ""); this.chunkGroup.chunks
.map(chunk => {
return chunk.id !== null ? chunk.id : "";
})
.join(",")) ||
""
);
super.updateHash(hash); super.updateHash(hash);
} }

View File

@ -11,7 +11,9 @@ module.exports = class AsyncDependencyToInitialChunkError extends WebpackError {
super(); super();
this.name = "AsyncDependencyToInitialChunkError"; this.name = "AsyncDependencyToInitialChunkError";
this.message = `It's not allowed to load an initial chunk on demand. The chunk name "${chunkName}" is already used by an entrypoint.`; this.message = `It's not allowed to load an initial chunk on demand. The chunk name "${
chunkName
}" is already used by an entrypoint.`;
this.module = module; this.module = module;
this.origin = module; this.origin = module;
this.originLoc = loc; this.originLoc = loc;

View File

@ -10,13 +10,17 @@ const NormalModule = require("./NormalModule");
class AutomaticPrefetchPlugin { class AutomaticPrefetchPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("AutomaticPrefetchPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "AutomaticPrefetchPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(PrefetchDependency, normalModuleFactory); compilation.dependencyFactories.set(
}); PrefetchDependency,
normalModuleFactory
);
}
);
let lastModules = null; let lastModules = null;
compiler.hooks.afterCompile.tap("AutomaticPrefetchPlugin", (compilation) => { compiler.hooks.afterCompile.tap("AutomaticPrefetchPlugin", compilation => {
lastModules = compilation.modules lastModules = compilation.modules
.filter(m => m instanceof NormalModule) .filter(m => m instanceof NormalModule)
.map(m => ({ .map(m => ({
@ -24,12 +28,23 @@ class AutomaticPrefetchPlugin {
request: m.request request: m.request
})); }));
}); });
compiler.hooks.make.tapAsync("AutomaticPrefetchPlugin", (compilation, callback) => { compiler.hooks.make.tapAsync(
if(!lastModules) return callback(); "AutomaticPrefetchPlugin",
asyncLib.forEach(lastModules, (m, callback) => { (compilation, callback) => {
compilation.prefetch(m.context || compiler.context, new PrefetchDependency(m.request), callback); if (!lastModules) return callback();
}, callback); asyncLib.forEach(
}); lastModules,
(m, callback) => {
compilation.prefetch(
m.context || compiler.context,
new PrefetchDependency(m.request),
callback
);
},
callback
);
}
);
} }
} }
module.exports = AutomaticPrefetchPlugin; module.exports = AutomaticPrefetchPlugin;

View File

@ -5,47 +5,57 @@
"use strict"; "use strict";
const ConcatSource = require("webpack-sources").ConcatSource; const { ConcatSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const Template = require("./Template"); const Template = require("./Template");
const validateOptions = require("schema-utils"); const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json"); const schema = require("../schemas/plugins/BannerPlugin.json");
const wrapComment = (str) => { const wrapComment = str => {
if(!str.includes("\n")) return Template.toComment(str); if (!str.includes("\n")) return Template.toComment(str);
return `/*!\n * ${str.replace(/\*\//g, "* /").split("\n").join("\n * ")}\n */`; return `/*!\n * ${str
.replace(/\*\//g, "* /")
.split("\n")
.join("\n * ")}\n */`;
}; };
class BannerPlugin { class BannerPlugin {
constructor(options) { constructor(options) {
if(arguments.length > 1) if (arguments.length > 1)
throw new Error("BannerPlugin only takes one argument (pass an options object)"); throw new Error(
"BannerPlugin only takes one argument (pass an options object)"
);
validateOptions(schema, options, "Banner Plugin"); validateOptions(schema, options, "Banner Plugin");
if(typeof options === "string") if (typeof options === "string")
options = { options = {
banner: options banner: options
}; };
this.options = options || {}; this.options = options || {};
this.banner = this.options.raw ? options.banner : wrapComment(options.banner); this.banner = this.options.raw
? options.banner
: wrapComment(options.banner);
} }
apply(compiler) { apply(compiler) {
const options = this.options; const options = this.options;
const banner = this.banner; const banner = this.banner;
const matchObject = ModuleFilenameHelpers.matchObject.bind(undefined, options); const matchObject = ModuleFilenameHelpers.matchObject.bind(
undefined,
options
);
compiler.hooks.compilation.tap("BannerPlugin", (compilation) => { compiler.hooks.compilation.tap("BannerPlugin", compilation => {
compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", (chunks) => { compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
for(const chunk of chunks) { for (const chunk of chunks) {
if(options.entryOnly && !chunk.canBeInitial()) { if (options.entryOnly && !chunk.canBeInitial()) {
continue; continue;
} }
for(const file of chunk.files) { for (const file of chunk.files) {
if(!matchObject(file)) { if (!matchObject(file)) {
continue; continue;
} }
@ -55,14 +65,14 @@ class BannerPlugin {
const hash = compilation.hash; const hash = compilation.hash;
const querySplit = filename.indexOf("?"); const querySplit = filename.indexOf("?");
if(querySplit >= 0) { if (querySplit >= 0) {
query = filename.substr(querySplit); query = filename.substr(querySplit);
filename = filename.substr(0, querySplit); filename = filename.substr(0, querySplit);
} }
const lastSlashIndex = filename.lastIndexOf("/"); const lastSlashIndex = filename.lastIndexOf("/");
if(lastSlashIndex === -1) { if (lastSlashIndex === -1) {
basename = filename; basename = filename;
} else { } else {
basename = filename.substr(lastSlashIndex + 1); basename = filename.substr(lastSlashIndex + 1);
@ -73,10 +83,14 @@ class BannerPlugin {
chunk, chunk,
filename, filename,
basename, basename,
query, query
}); });
compilation.assets[file] = new ConcatSource(comment, "\n", compilation.assets[file]); compilation.assets[file] = new ConcatSource(
comment,
"\n",
compilation.assets[file]
);
} }
} }
}); });

View File

@ -19,7 +19,6 @@ const TypeWrapped = 10;
const TypeTemplateString = 11; const TypeTemplateString = 11;
class BasicEvaluatedExpression { class BasicEvaluatedExpression {
constructor() { constructor() {
this.type = TypeUnknown; this.type = TypeUnknown;
this.range = null; this.range = null;
@ -90,19 +89,23 @@ class BasicEvaluatedExpression {
} }
asBool() { asBool() {
if(this.truthy) return true; if (this.truthy) return true;
else if(this.falsy) return false; else if (this.falsy) return false;
else if(this.isBoolean()) return this.bool; else if (this.isBoolean()) return this.bool;
else if(this.isNull()) return false; else if (this.isNull()) return false;
else if(this.isString()) return this.string !== ""; else if (this.isString()) return this.string !== "";
else if(this.isNumber()) return this.number !== 0; else if (this.isNumber()) return this.number !== 0;
else if(this.isRegExp()) return true; else if (this.isRegExp()) return true;
else if(this.isArray()) return true; else if (this.isArray()) return true;
else if(this.isConstArray()) return true; else if (this.isConstArray()) return true;
else if(this.isWrapped()) return this.prefix && this.prefix.asBool() || this.postfix && this.postfix.asBool() ? true : undefined; else if (this.isWrapped())
else if(this.isTemplateString()) { return (this.prefix && this.prefix.asBool()) ||
for(const quasi of this.quasis) { (this.postfix && this.postfix.asBool())
if(quasi.asBool()) return true; ? true
: undefined;
else if (this.isTemplateString()) {
for (const quasi of this.quasis) {
if (quasi.asBool()) return true;
} }
// can't tell if string will be empty without executing // can't tell if string will be empty without executing
} }
@ -158,12 +161,11 @@ class BasicEvaluatedExpression {
} }
addOptions(options) { addOptions(options) {
if(!this.options) { if (!this.options) {
this.type = TypeConditional; this.type = TypeConditional;
this.options = []; this.options = [];
} }
for(const item of options) for (const item of options) this.options.push(item);
this.options.push(item);
return this; return this;
} }
@ -201,7 +203,6 @@ class BasicEvaluatedExpression {
this.range = range; this.range = range;
return this; return this;
} }
} }
module.exports = BasicEvaluatedExpression; module.exports = BasicEvaluatedExpression;

View File

@ -13,26 +13,29 @@ class CachePlugin {
} }
apply(compiler) { apply(compiler) {
if(Array.isArray(compiler.compilers)) { if (Array.isArray(compiler.compilers)) {
compiler.compilers.forEach((c, idx) => { compiler.compilers.forEach((c, idx) => {
new CachePlugin(this.cache[idx] = this.cache[idx] || {}).apply(c); new CachePlugin((this.cache[idx] = this.cache[idx] || {})).apply(c);
}); });
} else { } else {
const registerCacheToCompiler = (compiler, cache) => { const registerCacheToCompiler = (compiler, cache) => {
compiler.hooks.thisCompilation.tap("CachePlugin", compilation => { compiler.hooks.thisCompilation.tap("CachePlugin", compilation => {
compilation.cache = cache; compilation.cache = cache;
compilation.hooks.childCompiler.tap("CachePlugin", (childCompiler, compilerName, compilerIndex) => { compilation.hooks.childCompiler.tap(
if(cache) { "CachePlugin",
let childCache; (childCompiler, compilerName, compilerIndex) => {
if(!cache.children) cache.children = {}; if (cache) {
if(!cache.children[compilerName]) cache.children[compilerName] = []; let childCache;
if(cache.children[compilerName][compilerIndex]) if (!cache.children) cache.children = {};
childCache = cache.children[compilerName][compilerIndex]; if (!cache.children[compilerName])
else cache.children[compilerName] = [];
cache.children[compilerName].push(childCache = {}); if (cache.children[compilerName][compilerIndex])
registerCacheToCompiler(childCompiler, childCache); childCache = cache.children[compilerName][compilerIndex];
else cache.children[compilerName].push((childCache = {}));
registerCacheToCompiler(childCompiler, childCache);
}
} }
}); );
}); });
}; };
registerCacheToCompiler(compiler, this.cache); registerCacheToCompiler(compiler, this.cache);
@ -40,49 +43,52 @@ class CachePlugin {
this.watching = true; this.watching = true;
}); });
compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => { compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => {
if(!compiler._lastCompilationFileDependencies) return callback(); if (!compiler._lastCompilationFileDependencies) return callback();
const fs = compiler.inputFileSystem; const fs = compiler.inputFileSystem;
const fileTs = compiler.fileTimestamps = new Map(); const fileTs = (compiler.fileTimestamps = new Map());
asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => { asyncLib.forEach(
fs.stat(file, (err, stat) => { compiler._lastCompilationFileDependencies,
if(err) { (file, callback) => {
if(err.code === "ENOENT") return callback(); fs.stat(file, (err, stat) => {
return callback(err); if (err) {
if (err.code === "ENOENT") return callback();
return callback(err);
}
if (stat.mtime) this.applyMtime(+stat.mtime);
fileTs.set(file, +stat.mtime || Infinity);
callback();
});
},
err => {
if (err) return callback(err);
for (const [file, ts] of fileTs) {
fileTs.set(file, ts + this.FS_ACCURACY);
} }
if(stat.mtime)
this.applyMtime(+stat.mtime);
fileTs.set(file, +stat.mtime || Infinity);
callback(); callback();
});
}, err => {
if(err) return callback(err);
for(const [file, ts] of fileTs) {
fileTs.set(file, ts + this.FS_ACCURACY);
} }
);
callback();
});
}); });
compiler.hooks.afterCompile.tap("CachePlugin", compilation => { compiler.hooks.afterCompile.tap("CachePlugin", compilation => {
compilation.compiler._lastCompilationFileDependencies = compilation.fileDependencies; compilation.compiler._lastCompilationFileDependencies =
compilation.compiler._lastCompilationContextDependencies = compilation.contextDependencies; compilation.fileDependencies;
compilation.compiler._lastCompilationContextDependencies =
compilation.contextDependencies;
}); });
} }
} }
/* istanbul ignore next */ /* istanbul ignore next */
applyMtime(mtime) { applyMtime(mtime) {
if(this.FS_ACCURACY > 1 && mtime % 2 !== 0) if (this.FS_ACCURACY > 1 && mtime % 2 !== 0) this.FS_ACCURACY = 1;
this.FS_ACCURACY = 1; else if (this.FS_ACCURACY > 10 && mtime % 20 !== 0) this.FS_ACCURACY = 10;
else if(this.FS_ACCURACY > 10 && mtime % 20 !== 0) else if (this.FS_ACCURACY > 100 && mtime % 200 !== 0)
this.FS_ACCURACY = 10;
else if(this.FS_ACCURACY > 100 && mtime % 200 !== 0)
this.FS_ACCURACY = 100; this.FS_ACCURACY = 100;
else if(this.FS_ACCURACY > 1000 && mtime % 2000 !== 0) else if (this.FS_ACCURACY > 1000 && mtime % 2000 !== 0)
this.FS_ACCURACY = 1000; this.FS_ACCURACY = 1000;
} }
} }

View File

@ -28,24 +28,26 @@ ${modulesList}`;
a = a.identifier(); a = a.identifier();
b = b.identifier(); b = b.identifier();
/* istanbul ignore next */ /* istanbul ignore next */
if(a < b) return -1; if (a < b) return -1;
/* istanbul ignore next */ /* istanbul ignore next */
if(a > b) return 1; if (a > b) return 1;
/* istanbul ignore next */ /* istanbul ignore next */
return 0; return 0;
}); });
} }
_moduleMessages(modules) { _moduleMessages(modules) {
return modules.map((m) => { return modules
let message = `* ${m.identifier()}`; .map(m => {
const validReasons = m.reasons.filter((reason) => reason.module); let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter(reason => reason.module);
if(validReasons.length > 0) { if (validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`; message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].module.identifier()}`; message += `\n ${validReasons[0].module.identifier()}`;
} }
return message; return message;
}).join("\n"); })
.join("\n");
} }
}; };

View File

@ -9,24 +9,25 @@ const SortableSet = require("./util/SortableSet");
const GraphHelpers = require("./GraphHelpers"); const GraphHelpers = require("./GraphHelpers");
let debugId = 1000; let debugId = 1000;
const ERR_CHUNK_ENTRY = "Chunk.entry was removed. Use hasRuntime()"; const ERR_CHUNK_ENTRY = "Chunk.entry was removed. Use hasRuntime()";
const ERR_CHUNK_INITIAL = "Chunk.initial was removed. Use canBeInitial/isOnlyInitial()"; const ERR_CHUNK_INITIAL =
"Chunk.initial was removed. Use canBeInitial/isOnlyInitial()";
const sortById = (a, b) => { const sortById = (a, b) => {
if(a.id < b.id) return -1; if (a.id < b.id) return -1;
if(b.id < a.id) return 1; if (b.id < a.id) return 1;
return 0; return 0;
}; };
const sortByIdentifier = (a, b) => { const sortByIdentifier = (a, b) => {
if(a.identifier() > b.identifier()) return 1; if (a.identifier() > b.identifier()) return 1;
if(a.identifier() < b.identifier()) return -1; if (a.identifier() < b.identifier()) return -1;
return 0; return 0;
}; };
const getModulesIdent = set => { const getModulesIdent = set => {
set.sort(); set.sort();
let str = ""; let str = "";
for(const m of set) { for (const m of set) {
str += m.identifier() + "#"; str += m.identifier() + "#";
} }
return str; return str;
@ -36,14 +37,13 @@ const getArray = set => Array.from(set);
const getModulesSize = set => { const getModulesSize = set => {
let count = 0; let count = 0;
for(const module of set) { for (const module of set) {
count += module.size(); count += module.size();
} }
return count; return count;
}; };
class Chunk { class Chunk {
constructor(name) { constructor(name) {
this.id = null; this.id = null;
this.ids = null; this.ids = null;
@ -55,6 +55,7 @@ class Chunk {
this.files = []; this.files = [];
this.rendered = false; this.rendered = false;
this.hash = undefined; this.hash = undefined;
this.contentHash = Object.create(null);
this.renderedHash = undefined; this.renderedHash = undefined;
this.chunkReason = undefined; this.chunkReason = undefined;
this.extraAsync = false; this.extraAsync = false;
@ -77,7 +78,7 @@ class Chunk {
} }
hasRuntime() { hasRuntime() {
for(const chunkGroup of this._groups) { for (const chunkGroup of this._groups) {
// We only need to check the first one // We only need to check the first one
return chunkGroup.isInitial() && chunkGroup.getRuntimeChunk() === this; return chunkGroup.isInitial() && chunkGroup.getRuntimeChunk() === this;
} }
@ -85,18 +86,16 @@ class Chunk {
} }
canBeInitial() { canBeInitial() {
for(const chunkGroup of this._groups) { for (const chunkGroup of this._groups) {
if(chunkGroup.isInitial()) if (chunkGroup.isInitial()) return true;
return true;
} }
return false; return false;
} }
isOnlyInitial() { isOnlyInitial() {
if(this._groups.size <= 0) return false; if (this._groups.size <= 0) return false;
for(const chunkGroup of this._groups) { for (const chunkGroup of this._groups) {
if(!chunkGroup.isInitial()) if (!chunkGroup.isInitial()) return false;
return false;
} }
return true; return true;
} }
@ -106,7 +105,7 @@ class Chunk {
} }
addModule(module) { addModule(module) {
if(!this._modules.has(module)) { if (!this._modules.has(module)) {
this._modules.add(module); this._modules.add(module);
return true; return true;
} }
@ -114,7 +113,7 @@ class Chunk {
} }
removeModule(module) { removeModule(module) {
if(this._modules.delete(module)) { if (this._modules.delete(module)) {
module.removeChunk(this); module.removeChunk(this);
return true; return true;
} }
@ -134,15 +133,13 @@ class Chunk {
} }
addGroup(chunkGroup) { addGroup(chunkGroup) {
if(this._groups.has(chunkGroup)) if (this._groups.has(chunkGroup)) return false;
return false;
this._groups.add(chunkGroup); this._groups.add(chunkGroup);
return true; return true;
} }
removeGroup(chunkGroup) { removeGroup(chunkGroup) {
if(!this._groups.has(chunkGroup)) if (!this._groups.has(chunkGroup)) return false;
return false;
this._groups.delete(chunkGroup); this._groups.delete(chunkGroup);
return true; return true;
} }
@ -162,18 +159,19 @@ class Chunk {
compareTo(otherChunk) { compareTo(otherChunk) {
this._modules.sort(); this._modules.sort();
otherChunk._modules.sort(); otherChunk._modules.sort();
if(this._modules.size > otherChunk._modules.size) return -1; if (this._modules.size > otherChunk._modules.size) return -1;
if(this._modules.size < otherChunk._modules.size) return 1; if (this._modules.size < otherChunk._modules.size) return 1;
const a = this._modules[Symbol.iterator](); const a = this._modules[Symbol.iterator]();
const b = otherChunk._modules[Symbol.iterator](); const b = otherChunk._modules[Symbol.iterator]();
while(true) { // eslint-disable-line // eslint-disable-next-line
while (true) {
const aItem = a.next(); const aItem = a.next();
const bItem = b.next(); const bItem = b.next();
if(aItem.done) return 0; if (aItem.done) return 0;
const aModuleIdentifier = aItem.value.identifier(); const aModuleIdentifier = aItem.value.identifier();
const bModuleIdentifier = bItem.value.identifier(); const bModuleIdentifier = bItem.value.identifier();
if(aModuleIdentifier > bModuleIdentifier) return -1; if (aModuleIdentifier > bModuleIdentifier) return -1;
if(aModuleIdentifier < bModuleIdentifier) return 1; if (aModuleIdentifier < bModuleIdentifier) return 1;
} }
} }
@ -192,10 +190,10 @@ class Chunk {
remove(reason) { remove(reason) {
// cleanup modules // cleanup modules
// Array.from is used here to create a clone, because removeChunk modifies this._modules // Array.from is used here to create a clone, because removeChunk modifies this._modules
for(const module of Array.from(this._modules)) { for (const module of Array.from(this._modules)) {
module.removeChunk(this); module.removeChunk(this);
} }
for(const chunkGroup of this._groups) { for (const chunkGroup of this._groups) {
chunkGroup.removeChunk(this); chunkGroup.removeChunk(this);
} }
} }
@ -207,25 +205,28 @@ class Chunk {
} }
integrate(otherChunk, reason) { integrate(otherChunk, reason) {
if(!this.canBeIntegrated(otherChunk)) { if (!this.canBeIntegrated(otherChunk)) {
return false; return false;
} }
// Array.from is used here to create a clone, because moveModule modifies otherChunk._modules // Array.from is used here to create a clone, because moveModule modifies otherChunk._modules
for(const module of Array.from(otherChunk._modules)) { for (const module of Array.from(otherChunk._modules)) {
otherChunk.moveModule(module, this); otherChunk.moveModule(module, this);
} }
otherChunk._modules.clear(); otherChunk._modules.clear();
for(const chunkGroup of otherChunk._groups) { for (const chunkGroup of otherChunk._groups) {
chunkGroup.replaceChunk(otherChunk, this); chunkGroup.replaceChunk(otherChunk, this);
this.addGroup(chunkGroup); this.addGroup(chunkGroup);
} }
otherChunk._groups.clear(); otherChunk._groups.clear();
if(this.name && otherChunk.name) { if (this.name && otherChunk.name) {
if(this.name.length !== otherChunk.name.length) if (this.name.length !== otherChunk.name.length)
this.name = this.name.length < otherChunk.name.length ? this.name : otherChunk.name; this.name =
this.name.length < otherChunk.name.length
? this.name
: otherChunk.name;
else else
this.name = this.name < otherChunk.name ? this.name : otherChunk.name; this.name = this.name < otherChunk.name ? this.name : otherChunk.name;
} }
@ -234,7 +235,7 @@ class Chunk {
} }
split(newChunk) { split(newChunk) {
for(const chunkGroup of this._groups) { for (const chunkGroup of this._groups) {
chunkGroup.insertChunk(newChunk, this); chunkGroup.insertChunk(newChunk, this);
newChunk.addGroup(chunkGroup); newChunk.addGroup(chunkGroup);
} }
@ -248,7 +249,7 @@ class Chunk {
hash.update(`${this.id} `); hash.update(`${this.id} `);
hash.update(this.ids ? this.ids.join(",") : ""); hash.update(this.ids ? this.ids.join(",") : "");
hash.update(`${this.name || ""} `); hash.update(`${this.name || ""} `);
for(const m of this._modules) { for (const m of this._modules) {
hash.update(m.hash); hash.update(m.hash);
} }
} }
@ -256,31 +257,32 @@ class Chunk {
canBeIntegrated(otherChunk) { canBeIntegrated(otherChunk) {
const isAvailable = (a, b) => { const isAvailable = (a, b) => {
const queue = new Set(b.groupsIterable); const queue = new Set(b.groupsIterable);
for(const chunkGroup of queue) { for (const chunkGroup of queue) {
if(a.isInGroup(chunkGroup)) continue; if (a.isInGroup(chunkGroup)) continue;
if(chunkGroup.isInitial()) return false; if (chunkGroup.isInitial()) return false;
for(const parent of chunkGroup.parentsIterable) for (const parent of chunkGroup.parentsIterable) queue.add(parent);
queue.add(parent);
} }
return true; return true;
}; };
if(this.hasRuntime() !== otherChunk.hasRuntime()) { if (this.hasRuntime() !== otherChunk.hasRuntime()) {
if(this.hasRuntime()) { if (this.hasRuntime()) {
return isAvailable(this, otherChunk); return isAvailable(this, otherChunk);
} else if(otherChunk.hasRuntime()) { } else if (otherChunk.hasRuntime()) {
return isAvailable(otherChunk, this); return isAvailable(otherChunk, this);
} else { } else {
return false; return false;
} }
} }
if(this.hasEntryModule() || otherChunk.hasEntryModule()) if (this.hasEntryModule() || otherChunk.hasEntryModule()) return false;
return false;
return true; return true;
} }
addMultiplierAndOverhead(size, options) { addMultiplierAndOverhead(size, options) {
const overhead = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000; const overhead =
const multiplicator = this.canBeInitial() ? (options.entryChunkMultiplicator || 10) : 1; typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
const multiplicator = this.canBeInitial()
? options.entryChunkMultiplicator || 10
: 1;
return size * multiplicator + overhead; return size * multiplicator + overhead;
} }
@ -295,14 +297,14 @@ class Chunk {
integratedSize(otherChunk, options) { integratedSize(otherChunk, options) {
// Chunk if it's possible to integrate this chunk // Chunk if it's possible to integrate this chunk
if(!this.canBeIntegrated(otherChunk)) { if (!this.canBeIntegrated(otherChunk)) {
return false; return false;
} }
let integratedModulesSize = this.modulesSize(); let integratedModulesSize = this.modulesSize();
// only count modules that do not exist in this chunk! // only count modules that do not exist in this chunk!
for(const otherModule of otherChunk._modules) { for (const otherModule of otherChunk._modules) {
if(!this._modules.has(otherModule)) { if (!this._modules.has(otherModule)) {
integratedModulesSize += otherModule.size(); integratedModulesSize += otherModule.size();
} }
} }
@ -323,18 +325,15 @@ class Chunk {
const queue = new Set(this.groupsIterable); const queue = new Set(this.groupsIterable);
const chunks = new Set(); const chunks = new Set();
for(const chunkGroup of queue) { for (const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks) for (const chunk of chunkGroup.chunks) initialChunks.add(chunk);
initialChunks.add(chunk);
} }
for(const chunkGroup of queue) { for (const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks) { for (const chunk of chunkGroup.chunks) {
if(!initialChunks.has(chunk)) if (!initialChunks.has(chunk)) chunks.add(chunk);
chunks.add(chunk);
} }
for(const child of chunkGroup.childrenIterable) for (const child of chunkGroup.childrenIterable) queue.add(child);
queue.add(child);
} }
return chunks; return chunks;
@ -342,16 +341,22 @@ class Chunk {
getChunkMaps(realHash) { getChunkMaps(realHash) {
const chunkHashMap = Object.create(null); const chunkHashMap = Object.create(null);
const chunkContentHashMap = Object.create(null);
const chunkNameMap = Object.create(null); const chunkNameMap = Object.create(null);
for(const chunk of this.getAllAsyncChunks()) { for (const chunk of this.getAllAsyncChunks()) {
chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash; chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash;
if(chunk.name) for (const key of Object.keys(chunk.contentHash)) {
chunkNameMap[chunk.id] = chunk.name; if (!chunkContentHashMap[key])
chunkContentHashMap[key] = Object.create(null);
chunkContentHashMap[key][chunk.id] = chunk.contentHash[key];
}
if (chunk.name) chunkNameMap[chunk.id] = chunk.name;
} }
return { return {
hash: chunkHashMap, hash: chunkHashMap,
contentHash: chunkContentHashMap,
name: chunkNameMap name: chunkNameMap
}; };
} }
@ -360,11 +365,11 @@ class Chunk {
const chunkModuleIdMap = Object.create(null); const chunkModuleIdMap = Object.create(null);
const chunkModuleHashMap = Object.create(null); const chunkModuleHashMap = Object.create(null);
for(const chunk of this.getAllAsyncChunks()) { for (const chunk of this.getAllAsyncChunks()) {
let array; let array;
for(const module of chunk.modulesIterable) { for (const module of chunk.modulesIterable) {
if(filterFn(module)) { if (filterFn(module)) {
if(array === undefined) { if (array === undefined) {
array = []; array = [];
chunkModuleIdMap[chunk.id] = array; chunkModuleIdMap[chunk.id] = array;
} }
@ -372,7 +377,7 @@ class Chunk {
chunkModuleHashMap[module.id] = module.renderedHash; chunkModuleHashMap[module.id] = module.renderedHash;
} }
} }
if(array !== undefined) { if (array !== undefined) {
array.sort(); array.sort();
} }
} }
@ -387,19 +392,17 @@ class Chunk {
const queue = new Set(this.groupsIterable); const queue = new Set(this.groupsIterable);
const chunksProcessed = new Set(); const chunksProcessed = new Set();
for(const chunkGroup of queue) { for (const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks) { for (const chunk of chunkGroup.chunks) {
if(!chunksProcessed.has(chunk)) { if (!chunksProcessed.has(chunk)) {
chunksProcessed.add(chunk); chunksProcessed.add(chunk);
if(!filterChunkFn || filterChunkFn(chunk)) { if (!filterChunkFn || filterChunkFn(chunk)) {
for(const module of chunk.modulesIterable) for (const module of chunk.modulesIterable)
if(filterFn(module)) if (filterFn(module)) return true;
return true;
} }
} }
} }
for(const child of chunkGroup.childrenIterable) for (const child of chunkGroup.childrenIterable) queue.add(child);
queue.add(child);
} }
return false; return false;
} }
@ -462,7 +465,9 @@ Object.defineProperty(Chunk.prototype, "blocks", {
Object.defineProperty(Chunk.prototype, "entrypoints", { Object.defineProperty(Chunk.prototype, "entrypoints", {
configurable: false, configurable: false,
get() { get() {
throw new Error("Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead"); throw new Error(
"Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead"
);
}, },
set() { set() {
throw new Error("Chunk.entrypoints: Use Chunks.addGroup instead"); throw new Error("Chunk.entrypoints: Use Chunks.addGroup instead");

View File

@ -12,16 +12,16 @@ let debugId = 5000;
const getArray = set => Array.from(set); const getArray = set => Array.from(set);
const sortById = (a, b) => { const sortById = (a, b) => {
if(a.id < b.id) return -1; if (a.id < b.id) return -1;
if(b.id < a.id) return 1; if (b.id < a.id) return 1;
return 0; return 0;
}; };
const sortOrigin = (a, b) => { const sortOrigin = (a, b) => {
const aIdent = a.module ? a.module.identifier() : ""; const aIdent = a.module ? a.module.identifier() : "";
const bIdent = b.module ? b.module.identifier() : ""; const bIdent = b.module ? b.module.identifier() : "";
if(aIdent < bIdent) return -1; if (aIdent < bIdent) return -1;
if(aIdent > bIdent) return 1; if (aIdent > bIdent) return 1;
return compareLocations(a.loc, b.loc); return compareLocations(a.loc, b.loc);
}; };
@ -47,10 +47,10 @@ class ChunkGroup {
unshiftChunk(chunk) { unshiftChunk(chunk) {
const oldIdx = this.chunks.indexOf(chunk); const oldIdx = this.chunks.indexOf(chunk);
if(oldIdx > 0) { if (oldIdx > 0) {
this.chunks.splice(oldIdx, 1); this.chunks.splice(oldIdx, 1);
this.chunks.unshift(chunk); this.chunks.unshift(chunk);
} else if(oldIdx < 0) { } else if (oldIdx < 0) {
this.chunks.unshift(chunk); this.chunks.unshift(chunk);
return true; return true;
} }
@ -60,13 +60,13 @@ class ChunkGroup {
insertChunk(chunk, before) { insertChunk(chunk, before) {
const oldIdx = this.chunks.indexOf(chunk); const oldIdx = this.chunks.indexOf(chunk);
const idx = this.chunks.indexOf(before); const idx = this.chunks.indexOf(before);
if(idx < 0) { if (idx < 0) {
throw new Error("before chunk not found"); throw new Error("before chunk not found");
} }
if(oldIdx >= 0 && oldIdx > idx) { if (oldIdx >= 0 && oldIdx > idx) {
this.chunks.splice(oldIdx, 1); this.chunks.splice(oldIdx, 1);
this.chunks.splice(idx, 0, chunk); this.chunks.splice(idx, 0, chunk);
} else if(oldIdx < 0) { } else if (oldIdx < 0) {
this.chunks.splice(idx, 0, chunk); this.chunks.splice(idx, 0, chunk);
return true; return true;
} }
@ -75,7 +75,7 @@ class ChunkGroup {
pushChunk(chunk) { pushChunk(chunk) {
const oldIdx = this.chunks.indexOf(chunk); const oldIdx = this.chunks.indexOf(chunk);
if(oldIdx >= 0) { if (oldIdx >= 0) {
return false; return false;
} }
this.chunks.push(chunk); this.chunks.push(chunk);
@ -84,16 +84,16 @@ class ChunkGroup {
replaceChunk(oldChunk, newChunk) { replaceChunk(oldChunk, newChunk) {
const oldIdx = this.chunks.indexOf(oldChunk); const oldIdx = this.chunks.indexOf(oldChunk);
if(oldIdx < 0) return false; if (oldIdx < 0) return false;
const newIdx = this.chunks.indexOf(newChunk); const newIdx = this.chunks.indexOf(newChunk);
if(newIdx < 0) { if (newIdx < 0) {
this.chunks[oldIdx] = newChunk; this.chunks[oldIdx] = newChunk;
return true; return true;
} }
if(newIdx < oldIdx) { if (newIdx < oldIdx) {
this.chunks.splice(oldIdx, 1); this.chunks.splice(oldIdx, 1);
return true; return true;
} else if(newIdx !== oldIdx) { } else if (newIdx !== oldIdx) {
this.chunks[oldIdx] = newChunk; this.chunks[oldIdx] = newChunk;
this.chunks.splice(newIdx, 1); this.chunks.splice(newIdx, 1);
return true; return true;
@ -102,7 +102,7 @@ class ChunkGroup {
removeChunk(chunk) { removeChunk(chunk) {
const idx = this.chunks.indexOf(chunk); const idx = this.chunks.indexOf(chunk);
if(idx >= 0) { if (idx >= 0) {
this.chunks.splice(idx, 1); this.chunks.splice(idx, 1);
return true; return true;
} }
@ -114,7 +114,7 @@ class ChunkGroup {
} }
addChild(chunk) { addChild(chunk) {
if(this._children.has(chunk)) { if (this._children.has(chunk)) {
return false; return false;
} }
this._children.add(chunk); this._children.add(chunk);
@ -134,7 +134,7 @@ class ChunkGroup {
} }
removeChild(chunk) { removeChild(chunk) {
if(!this._children.has(chunk)) { if (!this._children.has(chunk)) {
return false; return false;
} }
@ -144,7 +144,7 @@ class ChunkGroup {
} }
addParent(parentChunk) { addParent(parentChunk) {
if(!this._parents.has(parentChunk)) { if (!this._parents.has(parentChunk)) {
this._parents.add(parentChunk); this._parents.add(parentChunk);
return true; return true;
} }
@ -157,8 +157,7 @@ class ChunkGroup {
setParents(newParents) { setParents(newParents) {
this._parents.clear(); this._parents.clear();
for(const p of newParents) for (const p of newParents) this._parents.add(p);
this._parents.add(p);
} }
getNumberOfParents() { getNumberOfParents() {
@ -174,7 +173,7 @@ class ChunkGroup {
} }
removeParent(chunk) { removeParent(chunk) {
if(this._parents.delete(chunk)) { if (this._parents.delete(chunk)) {
chunk.removeChunk(this); chunk.removeChunk(this);
return true; return true;
} }
@ -201,7 +200,7 @@ class ChunkGroup {
} }
addBlock(block) { addBlock(block) {
if(!this._blocks.has(block)) { if (!this._blocks.has(block)) {
this._blocks.add(block); this._blocks.add(block);
return true; return true;
} }
@ -217,21 +216,20 @@ class ChunkGroup {
} }
containsModule(module) { containsModule(module) {
for(const chunk of this.chunks) { for (const chunk of this.chunks) {
if(chunk.containsModule(module)) if (chunk.containsModule(module)) return true;
return true;
} }
return false; return false;
} }
remove(reason) { remove(reason) {
// cleanup parents // cleanup parents
for(const parentChunkGroup of this._parents) { for (const parentChunkGroup of this._parents) {
// remove this chunk from its parents // remove this chunk from its parents
parentChunkGroup._children.delete(this); parentChunkGroup._children.delete(this);
// cleanup "sub chunks" // cleanup "sub chunks"
for(const chunkGroup of this._children) { for (const chunkGroup of this._children) {
/** /**
* remove this chunk as "intermediary" and connect * remove this chunk as "intermediary" and connect
* it "sub chunks" and parents directly * it "sub chunks" and parents directly
@ -247,20 +245,20 @@ class ChunkGroup {
* we need to iterate again over the children * we need to iterate again over the children
* to remove this from the childs parents. * to remove this from the childs parents.
* This can not be done in the above loop * This can not be done in the above loop
* as it is not garuanteed that `this._parents` contains anything. * as it is not guaranteed that `this._parents` contains anything.
*/ */
for(const chunkGroup of this._children) { for (const chunkGroup of this._children) {
// remove this as parent of every "sub chunk" // remove this as parent of every "sub chunk"
chunkGroup._parents.delete(this); chunkGroup._parents.delete(this);
} }
// cleanup blocks // cleanup blocks
for(const block of this._blocks) { for (const block of this._blocks) {
block.chunkGroup = null; block.chunkGroup = null;
} }
// remove chunks // remove chunks
for(const chunk of this.chunks) { for (const chunk of this.chunks) {
chunk.removeGroup(this); chunk.removeGroup(this);
} }
} }
@ -273,13 +271,21 @@ class ChunkGroup {
checkConstraints() { checkConstraints() {
const chunk = this; const chunk = this;
for(const child of chunk._children) { for (const child of chunk._children) {
if(!child._parents.has(chunk)) if (!child._parents.has(chunk))
throw new Error(`checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`); throw new Error(
`checkConstraints: child missing parent ${chunk.debugId} -> ${
child.debugId
}`
);
} }
for(const parentChunk of chunk._parents) { for (const parentChunk of chunk._parents) {
if(!parentChunk._children.has(chunk)) if (!parentChunk._children.has(chunk))
throw new Error(`checkConstraints: parent missing child ${parentChunk.debugId} <- ${chunk.debugId}`); throw new Error(
`checkConstraints: parent missing child ${parentChunk.debugId} <- ${
chunk.debugId
}`
);
} }
} }
} }

View File

@ -4,9 +4,7 @@
*/ */
"use strict"; "use strict";
const Tapable = require("tapable").Tapable; const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable");
const SyncWaterfallHook = require("tapable").SyncWaterfallHook;
const SyncHook = require("tapable").SyncHook;
module.exports = class ChunkTemplate extends Tapable { module.exports = class ChunkTemplate extends Tapable {
constructor(outputOptions) { constructor(outputOptions) {
@ -14,11 +12,21 @@ module.exports = class ChunkTemplate extends Tapable {
this.outputOptions = outputOptions || {}; this.outputOptions = outputOptions || {};
this.hooks = { this.hooks = {
renderManifest: new SyncWaterfallHook(["result", "options"]), renderManifest: new SyncWaterfallHook(["result", "options"]),
modules: new SyncWaterfallHook(["source", "chunk", "moduleTemplate", "dependencyTemplates"]), modules: new SyncWaterfallHook([
render: new SyncWaterfallHook(["source", "chunk", "moduleTemplate", "dependencyTemplates"]), "source",
"chunk",
"moduleTemplate",
"dependencyTemplates"
]),
render: new SyncWaterfallHook([
"source",
"chunk",
"moduleTemplate",
"dependencyTemplates"
]),
renderWithEntry: new SyncWaterfallHook(["source", "chunk"]), renderWithEntry: new SyncWaterfallHook(["source", "chunk"]),
hash: new SyncHook(["hash"]), hash: new SyncHook(["hash"]),
hashForChunk: new SyncHook(["hash", "chunk"]), hashForChunk: new SyncHook(["hash", "chunk"])
}; };
} }

View File

@ -9,37 +9,55 @@ const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory"); const NullFactory = require("./NullFactory");
class CompatibilityPlugin { class CompatibilityPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("CompatibilityPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "CompatibilityPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory()); compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template()); compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
normalModuleFactory.hooks.parser.for("javascript/auto").tap("CompatibilityPlugin", (parser, parserOptions) => { normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("CompatibilityPlugin", (parser, parserOptions) => {
if (
typeof parserOptions.browserify !== "undefined" &&
!parserOptions.browserify
)
return;
if(typeof parserOptions.browserify !== "undefined" && !parserOptions.browserify) parser.hooks.call
return; .for("require")
.tap("CompatibilityPlugin", expr => {
parser.hooks.call.for("require").tap("CompatibilityPlugin", (expr) => { // support for browserify style require delegator: "require(o, !0)"
// support for browserify style require delegator: "require(o, !0)" if (expr.arguments.length !== 2) return;
if(expr.arguments.length !== 2) return; const second = parser.evaluateExpression(expr.arguments[1]);
const second = parser.evaluateExpression(expr.arguments[1]); if (!second.isBoolean()) return;
if(!second.isBoolean()) return; if (second.asBool() !== true) return;
if(second.asBool() !== true) return; const dep = new ConstDependency("require", expr.callee.range);
const dep = new ConstDependency("require", expr.callee.range); dep.loc = expr.loc;
dep.loc = expr.loc; if (parser.state.current.dependencies.length > 1) {
if(parser.state.current.dependencies.length > 1) { const last =
const last = parser.state.current.dependencies[parser.state.current.dependencies.length - 1]; parser.state.current.dependencies[
if(last.critical && last.options && last.options.request === "." && last.userRequest === "." && last.options.recursive) parser.state.current.dependencies.length - 1
parser.state.current.dependencies.pop(); ];
} if (
parser.state.current.addDependency(dep); last.critical &&
return true; last.options &&
}); last.options.request === "." &&
}); last.userRequest === "." &&
}); last.options.recursive
)
parser.state.current.dependencies.pop();
}
parser.state.current.addDependency(dep);
return true;
});
});
}
);
} }
} }
module.exports = CompatibilityPlugin; module.exports = CompatibilityPlugin;

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,13 @@
const asyncLib = require("neo-async"); const asyncLib = require("neo-async");
const path = require("path"); const path = require("path");
const util = require("util"); const util = require("util");
const Tapable = require("tapable").Tapable; const {
const SyncHook = require("tapable").SyncHook; Tapable,
const SyncBailHook = require("tapable").SyncBailHook; SyncHook,
const AsyncParallelHook = require("tapable").AsyncParallelHook; SyncBailHook,
const AsyncSeriesHook = require("tapable").AsyncSeriesHook; AsyncParallelHook,
AsyncSeriesHook
} = require("tapable");
const Compilation = require("./Compilation"); const Compilation = require("./Compilation");
const Stats = require("./Stats"); const Stats = require("./Stats");
@ -21,7 +23,8 @@ const ContextModuleFactory = require("./ContextModuleFactory");
const ResolverFactory = require("./ResolverFactory"); const ResolverFactory = require("./ResolverFactory");
const RequestShortener = require("./RequestShortener"); const RequestShortener = require("./RequestShortener");
const makePathsRelative = require("./util/identifier").makePathsRelative; const { makePathsRelative } = require("./util/identifier");
const ConcurrentCompilationError = require("./ConcurrentCompilationError");
class Compiler extends Tapable { class Compiler extends Tapable {
constructor(context) { constructor(context) {
@ -53,10 +56,10 @@ class Compiler extends Tapable {
afterEnvironment: new SyncHook([]), afterEnvironment: new SyncHook([]),
afterPlugins: new SyncHook(["compiler"]), afterPlugins: new SyncHook(["compiler"]),
afterResolvers: new SyncHook(["compiler"]), afterResolvers: new SyncHook(["compiler"]),
entryOption: new SyncBailHook(["context", "entry"]), entryOption: new SyncBailHook(["context", "entry"])
}; };
this._pluginCompat.tap("Compiler", options => { this._pluginCompat.tap("Compiler", options => {
switch(options.name) { switch (options.name) {
case "additional-pass": case "additional-pass":
case "before-run": case "before-run":
case "run": case "run":
@ -87,64 +90,40 @@ class Compiler extends Tapable {
// TODO remove in webpack 5 // TODO remove in webpack 5
this.resolvers = { this.resolvers = {
normal: { normal: {
plugins: util.deprecate( plugins: util.deprecate((hook, fn) => {
(hook, fn) => { this.resolverFactory.plugin("resolver normal", resolver => {
this.resolverFactory.plugin("resolver normal", resolver => { resolver.plugin(hook, fn);
resolver.plugin(hook, fn); });
}); }, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
}, apply: util.deprecate((...args) => {
"webpack: Using compiler.resolvers.normal is deprecated.\n" + this.resolverFactory.plugin("resolver normal", resolver => {
"Use compiler.resolverFactory.plugin(\"resolver normal\", resolver => {\n resolver.plugin(/* ... */);\n}); instead." resolver.apply(...args);
), });
apply: util.deprecate( }, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
(...args) => {
this.resolverFactory.plugin("resolver normal", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.normal is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver normal\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
}, },
loader: { loader: {
plugins: util.deprecate( plugins: util.deprecate((hook, fn) => {
(hook, fn) => { this.resolverFactory.plugin("resolver loader", resolver => {
this.resolverFactory.plugin("resolver loader", resolver => { resolver.plugin(hook, fn);
resolver.plugin(hook, fn); });
}); }, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
}, apply: util.deprecate((...args) => {
"webpack: Using compiler.resolvers.loader is deprecated.\n" + this.resolverFactory.plugin("resolver loader", resolver => {
"Use compiler.resolverFactory.plugin(\"resolver loader\", resolver => {\n resolver.plugin(/* ... */);\n}); instead." resolver.apply(...args);
), });
apply: util.deprecate( }, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
(...args) => {
this.resolverFactory.plugin("resolver loader", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.loader is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver loader\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
}, },
context: { context: {
plugins: util.deprecate( plugins: util.deprecate((hook, fn) => {
(hook, fn) => { this.resolverFactory.plugin("resolver context", resolver => {
this.resolverFactory.plugin("resolver context", resolver => { resolver.plugin(hook, fn);
resolver.plugin(hook, fn); });
}); }, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
}, apply: util.deprecate((...args) => {
"webpack: Using compiler.resolvers.context is deprecated.\n" + this.resolverFactory.plugin("resolver context", resolver => {
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.plugin(/* ... */);\n}); instead." resolver.apply(...args);
), });
apply: util.deprecate( }, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
(...args) => {
this.resolverFactory.plugin("resolver context", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.context is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
} }
}; };
@ -153,45 +132,60 @@ class Compiler extends Tapable {
this.context = context; this.context = context;
this.requestShortener = new RequestShortener(context); this.requestShortener = new RequestShortener(context);
this.running = false;
} }
watch(watchOptions, handler) { watch(watchOptions, handler) {
if (this.running) return handler(new ConcurrentCompilationError());
this.running = true;
this.fileTimestamps = new Map(); this.fileTimestamps = new Map();
this.contextTimestamps = new Map(); this.contextTimestamps = new Map();
return new Watching(this, watchOptions, handler); return new Watching(this, watchOptions, handler);
} }
run(callback) { run(callback) {
if (this.running) return callback(new ConcurrentCompilationError());
const finalCallback = (err, stats) => {
this.running = false;
if (callback !== undefined) return callback(err, stats);
};
const startTime = Date.now(); const startTime = Date.now();
const onCompiled = (err, compilation) => { this.running = true;
if(err) return callback(err);
if(this.hooks.shouldEmit.call(compilation) === false) { const onCompiled = (err, compilation) => {
if (err) return finalCallback(err);
if (this.hooks.shouldEmit.call(compilation) === false) {
const stats = new Stats(compilation); const stats = new Stats(compilation);
stats.startTime = startTime; stats.startTime = startTime;
stats.endTime = Date.now(); stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => { this.hooks.done.callAsync(stats, err => {
if(err) return callback(err); if (err) return finalCallback(err);
return callback(null, stats); return finalCallback(null, stats);
}); });
return; return;
} }
this.emitAssets(compilation, err => { this.emitAssets(compilation, err => {
if(err) return callback(err); if (err) return finalCallback(err);
if(compilation.hooks.needAdditionalPass.call()) { if (compilation.hooks.needAdditionalPass.call()) {
compilation.needAdditionalPass = true; compilation.needAdditionalPass = true;
const stats = new Stats(compilation); const stats = new Stats(compilation);
stats.startTime = startTime; stats.startTime = startTime;
stats.endTime = Date.now(); stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => { this.hooks.done.callAsync(stats, err => {
if(err) return callback(err); if (err) return finalCallback(err);
this.hooks.additionalPass.callAsync(err => { this.hooks.additionalPass.callAsync(err => {
if(err) return callback(err); if (err) return finalCallback(err);
this.compile(onCompiled); this.compile(onCompiled);
}); });
}); });
@ -199,27 +193,27 @@ class Compiler extends Tapable {
} }
this.emitRecords(err => { this.emitRecords(err => {
if(err) return callback(err); if (err) return finalCallback(err);
const stats = new Stats(compilation); const stats = new Stats(compilation);
stats.startTime = startTime; stats.startTime = startTime;
stats.endTime = Date.now(); stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => { this.hooks.done.callAsync(stats, err => {
if(err) return callback(err); if (err) return finalCallback(err);
return callback(null, stats); return finalCallback(null, stats);
}); });
}); });
}); });
}; };
this.hooks.beforeRun.callAsync(this, err => { this.hooks.beforeRun.callAsync(this, err => {
if(err) return callback(err); if (err) return finalCallback(err);
this.hooks.run.callAsync(this, err => { this.hooks.run.callAsync(this, err => {
if(err) return callback(err); if (err) return finalCallback(err);
this.readRecords(err => { this.readRecords(err => {
if(err) return callback(err); if (err) return finalCallback(err);
this.compile(onCompiled); this.compile(onCompiled);
}); });
@ -229,14 +223,17 @@ class Compiler extends Tapable {
runAsChild(callback) { runAsChild(callback) {
this.compile((err, compilation) => { this.compile((err, compilation) => {
if(err) return callback(err); if (err) return callback(err);
this.parentCompilation.children.push(compilation); this.parentCompilation.children.push(compilation);
for(const name of Object.keys(compilation.assets)) { for (const name of Object.keys(compilation.assets)) {
this.parentCompilation.assets[name] = compilation.assets[name]; this.parentCompilation.assets[name] = compilation.assets[name];
} }
const entries = Array.from(compilation.entrypoints.values(), ep => ep.chunks).reduce((array, chunks) => { const entries = Array.from(
compilation.entrypoints.values(),
ep => ep.chunks
).reduce((array, chunks) => {
return array.concat(chunks); return array.concat(chunks);
}, []); }, []);
@ -245,101 +242,114 @@ class Compiler extends Tapable {
} }
purgeInputFileSystem() { purgeInputFileSystem() {
if(this.inputFileSystem && this.inputFileSystem.purge) if (this.inputFileSystem && this.inputFileSystem.purge)
this.inputFileSystem.purge(); this.inputFileSystem.purge();
} }
emitAssets(compilation, callback) { emitAssets(compilation, callback) {
let outputPath; let outputPath;
const emitFiles = (err) => { const emitFiles = err => {
if(err) return callback(err); if (err) return callback(err);
asyncLib.forEach(compilation.assets, (source, file, callback) => { asyncLib.forEach(
compilation.assets,
(source, file, callback) => {
let targetFile = file;
const queryStringIdx = targetFile.indexOf("?");
if (queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx);
}
let targetFile = file; const writeOut = err => {
const queryStringIdx = targetFile.indexOf("?"); if (err) return callback(err);
if(queryStringIdx >= 0) { const targetPath = this.outputFileSystem.join(
targetFile = targetFile.substr(0, queryStringIdx); outputPath,
} targetFile
);
if (source.existsAt === targetPath) {
source.emitted = false;
return callback();
}
let content = source.source();
if (!Buffer.isBuffer(content)) {
content = Buffer.from(content, "utf8");
}
source.existsAt = targetPath;
source.emitted = true;
this.outputFileSystem.writeFile(targetPath, content, callback);
};
if (targetFile.match(/\/|\\/)) {
const dir = path.dirname(targetFile);
this.outputFileSystem.mkdirp(
this.outputFileSystem.join(outputPath, dir),
writeOut
);
} else writeOut();
},
err => {
if (err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, err => {
if (err) return callback(err);
const writeOut = (err) => {
if(err) return callback(err);
const targetPath = this.outputFileSystem.join(outputPath, targetFile);
if(source.existsAt === targetPath) {
source.emitted = false;
return callback(); return callback();
} });
let content = source.source(); }
);
if(!Buffer.isBuffer(content)) {
content = Buffer.from(content, "utf8");
}
source.existsAt = targetPath;
source.emitted = true;
this.outputFileSystem.writeFile(targetPath, content, callback);
};
if(targetFile.match(/\/|\\/)) {
const dir = path.dirname(targetFile);
this.outputFileSystem.mkdirp(this.outputFileSystem.join(outputPath, dir), writeOut);
} else writeOut();
}, err => {
if(err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, err => {
if(err) return callback(err);
return callback();
});
});
}; };
this.hooks.emit.callAsync(compilation, err => { this.hooks.emit.callAsync(compilation, err => {
if(err) return callback(err); if (err) return callback(err);
outputPath = compilation.getPath(this.outputPath); outputPath = compilation.getPath(this.outputPath);
this.outputFileSystem.mkdirp(outputPath, emitFiles); this.outputFileSystem.mkdirp(outputPath, emitFiles);
}); });
} }
emitRecords(callback) { emitRecords(callback) {
if(!this.recordsOutputPath) return callback(); if (!this.recordsOutputPath) return callback();
const idx1 = this.recordsOutputPath.lastIndexOf("/"); const idx1 = this.recordsOutputPath.lastIndexOf("/");
const idx2 = this.recordsOutputPath.lastIndexOf("\\"); const idx2 = this.recordsOutputPath.lastIndexOf("\\");
let recordsOutputPathDirectory = null; let recordsOutputPathDirectory = null;
if(idx1 > idx2) recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1); if (idx1 > idx2)
if(idx1 < idx2) recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2); recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1);
if (idx1 < idx2)
recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2);
const writeFile = () => { const writeFile = () => {
this.outputFileSystem.writeFile(this.recordsOutputPath, JSON.stringify(this.records, undefined, 2), callback); this.outputFileSystem.writeFile(
this.recordsOutputPath,
JSON.stringify(this.records, undefined, 2),
callback
);
}; };
if(!recordsOutputPathDirectory) if (!recordsOutputPathDirectory) return writeFile();
return writeFile();
this.outputFileSystem.mkdirp(recordsOutputPathDirectory, err => { this.outputFileSystem.mkdirp(recordsOutputPathDirectory, err => {
if(err) return callback(err); if (err) return callback(err);
writeFile(); writeFile();
}); });
} }
readRecords(callback) { readRecords(callback) {
if(!this.recordsInputPath) { if (!this.recordsInputPath) {
this.records = {}; this.records = {};
return callback(); return callback();
} }
this.inputFileSystem.stat(this.recordsInputPath, err => { this.inputFileSystem.stat(this.recordsInputPath, err => {
// It doesn't exist // It doesn't exist
// We can ignore this. // We can ignore this.
if(err) return callback(); if (err) return callback();
this.inputFileSystem.readFile(this.recordsInputPath, (err, content) => { this.inputFileSystem.readFile(this.recordsInputPath, (err, content) => {
if(err) return callback(err); if (err) return callback(err);
try { try {
this.records = JSON.parse(content.toString("utf-8")); this.records = JSON.parse(content.toString("utf-8"));
} catch(e) { } catch (e) {
e.message = "Cannot parse records: " + e.message; e.message = "Cannot parse records: " + e.message;
return callback(e); return callback(e);
} }
@ -349,14 +359,30 @@ class Compiler extends Tapable {
}); });
} }
createChildCompiler(compilation, compilerName, compilerIndex, outputOptions, plugins) { createChildCompiler(
compilation,
compilerName,
compilerIndex,
outputOptions,
plugins
) {
const childCompiler = new Compiler(this.context); const childCompiler = new Compiler(this.context);
if(Array.isArray(plugins)) { if (Array.isArray(plugins)) {
for(const plugin of plugins) plugin.apply(childCompiler); for (const plugin of plugins) plugin.apply(childCompiler);
} }
for(const name in this.hooks) { for (const name in this.hooks) {
if(!["make", "compile", "emit", "afterEmit", "invalid", "done", "thisCompilation"].includes(name)) { if (
if(childCompiler.hooks[name]) ![
"make",
"compile",
"emit",
"afterEmit",
"invalid",
"done",
"thisCompilation"
].includes(name)
) {
if (childCompiler.hooks[name])
childCompiler.hooks[name].taps = this.hooks[name].taps.slice(); childCompiler.hooks[name].taps = this.hooks[name].taps.slice();
} }
} }
@ -369,20 +395,24 @@ class Compiler extends Tapable {
childCompiler.contextTimestamps = this.contextTimestamps; childCompiler.contextTimestamps = this.contextTimestamps;
const relativeCompilerName = makePathsRelative(this.context, compilerName); const relativeCompilerName = makePathsRelative(this.context, compilerName);
if(!this.records[relativeCompilerName]) this.records[relativeCompilerName] = []; if (!this.records[relativeCompilerName])
if(this.records[relativeCompilerName][compilerIndex]) this.records[relativeCompilerName] = [];
if (this.records[relativeCompilerName][compilerIndex])
childCompiler.records = this.records[relativeCompilerName][compilerIndex]; childCompiler.records = this.records[relativeCompilerName][compilerIndex];
else else this.records[relativeCompilerName].push((childCompiler.records = {}));
this.records[relativeCompilerName].push(childCompiler.records = {});
childCompiler.options = Object.create(this.options); childCompiler.options = Object.create(this.options);
childCompiler.options.output = Object.create(childCompiler.options.output); childCompiler.options.output = Object.create(childCompiler.options.output);
for(const name in outputOptions) { for (const name in outputOptions) {
childCompiler.options.output[name] = outputOptions[name]; childCompiler.options.output[name] = outputOptions[name];
} }
childCompiler.parentCompilation = compilation; childCompiler.parentCompilation = compilation;
compilation.hooks.childCompiler.call(childCompiler, compilerName, compilerIndex); compilation.hooks.childCompiler.call(
childCompiler,
compilerName,
compilerIndex
);
return childCompiler; return childCompiler;
} }
@ -408,13 +438,20 @@ class Compiler extends Tapable {
} }
createNormalModuleFactory() { createNormalModuleFactory() {
const normalModuleFactory = new NormalModuleFactory(this.options.context, this.resolverFactory, this.options.module || {}); const normalModuleFactory = new NormalModuleFactory(
this.options.context,
this.resolverFactory,
this.options.module || {}
);
this.hooks.normalModuleFactory.call(normalModuleFactory); this.hooks.normalModuleFactory.call(normalModuleFactory);
return normalModuleFactory; return normalModuleFactory;
} }
createContextModuleFactory() { createContextModuleFactory() {
const contextModuleFactory = new ContextModuleFactory(this.resolverFactory, this.inputFileSystem); const contextModuleFactory = new ContextModuleFactory(
this.resolverFactory,
this.inputFileSystem
);
this.hooks.contextModuleFactory.call(contextModuleFactory); this.hooks.contextModuleFactory.call(contextModuleFactory);
return contextModuleFactory; return contextModuleFactory;
} }
@ -431,22 +468,22 @@ class Compiler extends Tapable {
compile(callback) { compile(callback) {
const params = this.newCompilationParams(); const params = this.newCompilationParams();
this.hooks.beforeCompile.callAsync(params, err => { this.hooks.beforeCompile.callAsync(params, err => {
if(err) return callback(err); if (err) return callback(err);
this.hooks.compile.call(params); this.hooks.compile.call(params);
const compilation = this.newCompilation(params); const compilation = this.newCompilation(params);
this.hooks.make.callAsync(compilation, err => { this.hooks.make.callAsync(compilation, err => {
if(err) return callback(err); if (err) return callback(err);
compilation.finish(); compilation.finish();
compilation.seal(err => { compilation.seal(err => {
if(err) return callback(err); if (err) return callback(err);
this.hooks.afterCompile.callAsync(compilation, err => { this.hooks.afterCompile.callAsync(compilation, err => {
if(err) return callback(err); if (err) return callback(err);
return callback(null, compilation); return callback(null, compilation);
}); });

View File

@ -0,0 +1,19 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Maksim Nazarjev @acupofspirt
*/
"use strict";
const WebpackError = require("./WebpackError");
module.exports = class ConcurrentCompilationError extends WebpackError {
constructor() {
super();
this.name = "ConcurrentCompilationError";
this.message =
"You ran Webpack twice. Each instance only supports a single concurrent compilation at a time.";
Error.captureStackTrace(this, this.constructor);
}
};

View File

@ -7,29 +7,27 @@ const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory"); const NullFactory = require("./NullFactory");
const ParserHelpers = require("./ParserHelpers"); const ParserHelpers = require("./ParserHelpers");
const getQuery = (request) => { const getQuery = request => {
const i = request.indexOf("?"); const i = request.indexOf("?");
return i !== -1 ? request.substr(i) : ""; return i !== -1 ? request.substr(i) : "";
}; };
const collectDeclaration = (declarations, pattern) => { const collectDeclaration = (declarations, pattern) => {
const stack = [pattern]; const stack = [pattern];
while(stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
switch(node.type) { switch (node.type) {
case "Identifier": case "Identifier":
declarations.add(node.name); declarations.add(node.name);
break; break;
case "ArrayPattern": case "ArrayPattern":
for(const element of node.elements) for (const element of node.elements) if (element) stack.push(element);
if(element) stack.push(element);
break; break;
case "AssignmentPattern": case "AssignmentPattern":
stack.push(node.left); stack.push(node.left);
break; break;
case "ObjectPattern": case "ObjectPattern":
for(const property of node.properties) for (const property of node.properties) stack.push(property.value);
stack.push(property.value);
break; break;
case "RestElement": case "RestElement":
stack.push(node.argument); stack.push(node.argument);
@ -41,17 +39,15 @@ const collectDeclaration = (declarations, pattern) => {
const getHoistedDeclarations = (branch, includeFunctionDeclarations) => { const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
const declarations = new Set(); const declarations = new Set();
const stack = [branch]; const stack = [branch];
while(stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
// Some node could be `null` or `undefined`. // Some node could be `null` or `undefined`.
if(!node) if (!node) continue;
continue; switch (node.type) {
switch(node.type) {
// Walk through control statements to look for hoisted declarations. // Walk through control statements to look for hoisted declarations.
// Some branches are skipped since they do not allow declarations. // Some branches are skipped since they do not allow declarations.
case "BlockStatement": case "BlockStatement":
for(const stmt of node.body) for (const stmt of node.body) stack.push(stmt);
stack.push(stmt);
break; break;
case "IfStatement": case "IfStatement":
stack.push(node.consequent); stack.push(node.consequent);
@ -72,23 +68,21 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
stack.push(node.body); stack.push(node.body);
break; break;
case "SwitchStatement": case "SwitchStatement":
for(const cs of node.cases) for (const cs of node.cases)
for(const consequent of cs.consequent) for (const consequent of cs.consequent) stack.push(consequent);
stack.push(consequent);
break; break;
case "TryStatement": case "TryStatement":
stack.push(node.block); stack.push(node.block);
if(node.handler) if (node.handler) stack.push(node.handler.body);
stack.push(node.handler.body);
stack.push(node.finalizer); stack.push(node.finalizer);
break; break;
case "FunctionDeclaration": case "FunctionDeclaration":
if(includeFunctionDeclarations) if (includeFunctionDeclarations)
collectDeclaration(declarations, node.id); collectDeclaration(declarations, node.id);
break; break;
case "VariableDeclaration": case "VariableDeclaration":
if(node.kind === "var") if (node.kind === "var")
for(const decl of node.declarations) for (const decl of node.declarations)
collectDeclaration(declarations, decl.id); collectDeclaration(declarations, decl.id);
break; break;
} }
@ -98,118 +92,150 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
class ConstPlugin { class ConstPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("ConstPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "ConstPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory()); compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template()); compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = parser => { const handler = parser => {
parser.hooks.statementIf.tap("ConstPlugin", statement => { parser.hooks.statementIf.tap("ConstPlugin", statement => {
const param = parser.evaluateExpression(statement.test); const param = parser.evaluateExpression(statement.test);
const bool = param.asBool(); const bool = param.asBool();
if(typeof bool === "boolean") { if (typeof bool === "boolean") {
if(statement.test.type !== "Literal") { if (statement.test.type !== "Literal") {
const dep = new ConstDependency(`${bool}`, param.range); const dep = new ConstDependency(`${bool}`, param.range);
dep.loc = statement.loc; dep.loc = statement.loc;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
}
const branchToRemove = bool ? statement.alternate : statement.consequent;
if(branchToRemove) {
// Before removing the dead branch, the hoisted declarations
// must be collected.
//
// Given the following code:
//
// if (true) f() else g()
// if (false) {
// function f() {}
// const g = function g() {}
// if (someTest) {
// let a = 1
// var x, {y, z} = obj
// }
// } else {
// …
// }
//
// the generated code is:
//
// if (true) f() else {}
// if (false) {
// var f, x, y, z; (in loose mode)
// var x, y, z; (in strict mode)
// } else {
// …
// }
//
// NOTE: When code runs in strict mode, `var` declarations
// are hoisted but `function` declarations don't.
//
let declarations;
if(parser.scope.isStrict) {
// If the code runs in strict mode, variable declarations
// using `var` must be hoisted.
declarations = getHoistedDeclarations(branchToRemove, false);
} else {
// Otherwise, collect all hoisted declaration.
declarations = getHoistedDeclarations(branchToRemove, true);
} }
let replacement; const branchToRemove = bool
if(declarations.length > 0) { ? statement.alternate
replacement = `{ var ${declarations.join(", ")}; }`; : statement.consequent;
} else { if (branchToRemove) {
replacement = "{}"; // Before removing the dead branch, the hoisted declarations
// must be collected.
//
// Given the following code:
//
// if (true) f() else g()
// if (false) {
// function f() {}
// const g = function g() {}
// if (someTest) {
// let a = 1
// var x, {y, z} = obj
// }
// } else {
// …
// }
//
// the generated code is:
//
// if (true) f() else {}
// if (false) {
// var f, x, y, z; (in loose mode)
// var x, y, z; (in strict mode)
// } else {
// …
// }
//
// NOTE: When code runs in strict mode, `var` declarations
// are hoisted but `function` declarations don't.
//
let declarations;
if (parser.scope.isStrict) {
// If the code runs in strict mode, variable declarations
// using `var` must be hoisted.
declarations = getHoistedDeclarations(branchToRemove, false);
} else {
// Otherwise, collect all hoisted declaration.
declarations = getHoistedDeclarations(branchToRemove, true);
}
let replacement;
if (declarations.length > 0) {
replacement = `{ var ${declarations.join(", ")}; }`;
} else {
replacement = "{}";
}
const dep = new ConstDependency(
replacement,
branchToRemove.range
);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
} }
const dep = new ConstDependency(replacement, branchToRemove.range); return bool;
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
} }
return bool; });
} parser.hooks.expressionConditionalOperator.tap(
}); "ConstPlugin",
parser.hooks.expressionConditionalOperator.tap("ConstPlugin", expression => { expression => {
const param = parser.evaluateExpression(expression.test); const param = parser.evaluateExpression(expression.test);
const bool = param.asBool(); const bool = param.asBool();
if(typeof bool === "boolean") { if (typeof bool === "boolean") {
if(expression.test.type !== "Literal") { if (expression.test.type !== "Literal") {
const dep = new ConstDependency(` ${bool}`, param.range); const dep = new ConstDependency(` ${bool}`, param.range);
dep.loc = expression.loc; dep.loc = expression.loc;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
}
// Expressions do not hoist.
// It is safe to remove the dead branch.
//
// Given the following code:
//
// false ? someExpression() : otherExpression();
//
// the generated code is:
//
// false ? undefined : otherExpression();
//
const branchToRemove = bool
? expression.alternate
: expression.consequent;
const dep = new ConstDependency(
"undefined",
branchToRemove.range
);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
return bool;
}
} }
// Expressions do not hoist. );
// It is safe to remove the dead branch. parser.hooks.evaluateIdentifier
// .for("__resourceQuery")
// Given the following code: .tap("ConstPlugin", expr => {
// if (!parser.state.module) return;
// false ? someExpression() : otherExpression(); return ParserHelpers.evaluateToString(
// getQuery(parser.state.module.resource)
// the generated code is: )(expr);
// });
// false ? undefined : otherExpression(); parser.hooks.expression
// .for("__resourceQuery")
const branchToRemove = bool ? expression.alternate : expression.consequent; .tap("ConstPlugin", () => {
const dep = new ConstDependency("undefined", branchToRemove.range); if (!parser.state.module) return;
dep.loc = branchToRemove.loc; parser.state.current.addVariable(
parser.state.current.addDependency(dep); "__resourceQuery",
return bool; JSON.stringify(getQuery(parser.state.module.resource))
} );
}); return true;
parser.hooks.evaluateIdentifier.for("__resourceQuery").tap("ConstPlugin", expr => { });
if(!parser.state.module) return; };
return ParserHelpers.evaluateToString(getQuery(parser.state.module.resource))(expr);
});
parser.hooks.expression.for("__resourceQuery").tap("ConstPlugin", () => {
if(!parser.state.module) return;
parser.state.current.addVariable("__resourceQuery", JSON.stringify(getQuery(parser.state.module.resource)));
return true;
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("ConstPlugin", handler); normalModuleFactory.hooks.parser
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("ConstPlugin", handler); .for("javascript/auto")
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ConstPlugin", handler); .tap("ConstPlugin", handler);
}); normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("ConstPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("ConstPlugin", handler);
}
);
} }
} }

View File

@ -6,8 +6,8 @@ class ContextExclusionPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.contextModuleFactory.tap("ContextExclusionPlugin", (cmf) => { compiler.hooks.contextModuleFactory.tap("ContextExclusionPlugin", cmf => {
cmf.hooks.contextModuleFiles.tap("ContextExclusionPlugin", (files) => { cmf.hooks.contextModuleFiles.tap("ContextExclusionPlugin", files => {
return files.filter(filePath => !this.negativeMatcher.test(filePath)); return files.filter(filePath => !this.negativeMatcher.test(filePath));
}); });
}); });

View File

@ -5,9 +5,8 @@
"use strict"; "use strict";
const path = require("path"); const path = require("path");
const util = require("util"); const util = require("util");
const { OriginalSource, RawSource } = require("webpack-sources");
const Module = require("./Module"); const Module = require("./Module");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const AsyncDependenciesBlock = require("./AsyncDependenciesBlock"); const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
const Template = require("./Template"); const Template = require("./Template");
@ -20,7 +19,7 @@ class ContextModule extends Module {
let resource; let resource;
let resourceQuery; let resourceQuery;
const queryIdx = options.resource.indexOf("?"); const queryIdx = options.resource.indexOf("?");
if(queryIdx >= 0) { if (queryIdx >= 0) {
resource = options.resource.substr(0, queryIdx); resource = options.resource.substr(0, queryIdx);
resourceQuery = options.resource.substr(queryIdx); resourceQuery = options.resource.substr(queryIdx);
} else { } else {
@ -36,13 +35,13 @@ class ContextModule extends Module {
resource: resource, resource: resource,
resourceQuery: resourceQuery resourceQuery: resourceQuery
}); });
if(options.resolveOptions !== undefined) if (options.resolveOptions !== undefined)
this.resolveOptions = options.resolveOptions; this.resolveOptions = options.resolveOptions;
// Info from Build // Info from Build
this._contextDependencies = new Set([this.context]); this._contextDependencies = new Set([this.context]);
if(typeof options.mode !== "string") if (typeof options.mode !== "string")
throw new Error("options.mode is a required option"); throw new Error("options.mode is a required option");
} }
@ -53,77 +52,66 @@ class ContextModule extends Module {
} }
contextify(context, request) { contextify(context, request) {
return request.split("!").map(subrequest => { return request
let rp = path.relative(context, subrequest); .split("!")
if(path.sep === "\\") .map(subrequest => {
rp = rp.replace(/\\/g, "/"); let rp = path.relative(context, subrequest);
if(rp.indexOf("../") !== 0) if (path.sep === "\\") rp = rp.replace(/\\/g, "/");
rp = "./" + rp; if (rp.indexOf("../") !== 0) rp = "./" + rp;
return rp; return rp;
}).join("!"); })
.join("!");
} }
identifier() { identifier() {
let identifier = this.context; let identifier = this.context;
if(this.options.resourceQuery) if (this.options.resourceQuery)
identifier += ` ${this.options.resourceQuery}`; identifier += ` ${this.options.resourceQuery}`;
if(this.options.mode) if (this.options.mode) identifier += ` ${this.options.mode}`;
identifier += ` ${this.options.mode}`; if (!this.options.recursive) identifier += " nonrecursive";
if(!this.options.recursive) if (this.options.addon) identifier += ` ${this.options.addon}`;
identifier += " nonrecursive"; if (this.options.regExp) identifier += ` ${this.options.regExp}`;
if(this.options.addon) if (this.options.include) identifier += ` include: ${this.options.include}`;
identifier += ` ${this.options.addon}`; if (this.options.exclude) identifier += ` exclude: ${this.options.exclude}`;
if(this.options.regExp) if (this.options.namespaceObject === "strict")
identifier += ` ${this.options.regExp}`;
if(this.options.include)
identifier += ` include: ${this.options.include}`;
if(this.options.exclude)
identifier += ` exclude: ${this.options.exclude}`;
if(this.options.namespaceObject === "strict")
identifier += " strict namespace object"; identifier += " strict namespace object";
else if(this.options.namespaceObject) else if (this.options.namespaceObject) identifier += " namespace object";
identifier += " namespace object";
return identifier; return identifier;
} }
readableIdentifier(requestShortener) { readableIdentifier(requestShortener) {
let identifier = requestShortener.shorten(this.context); let identifier = requestShortener.shorten(this.context);
if(this.options.resourceQuery) if (this.options.resourceQuery)
identifier += ` ${this.options.resourceQuery}`; identifier += ` ${this.options.resourceQuery}`;
if(this.options.mode) if (this.options.mode) identifier += ` ${this.options.mode}`;
identifier += ` ${this.options.mode}`; if (!this.options.recursive) identifier += " nonrecursive";
if(!this.options.recursive) if (this.options.addon)
identifier += " nonrecursive";
if(this.options.addon)
identifier += ` ${requestShortener.shorten(this.options.addon)}`; identifier += ` ${requestShortener.shorten(this.options.addon)}`;
if(this.options.regExp) if (this.options.regExp)
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`; identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if(this.options.include) if (this.options.include)
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`; identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if(this.options.exclude) if (this.options.exclude)
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`; identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
if(this.options.namespaceObject === "strict") if (this.options.namespaceObject === "strict")
identifier += " strict namespace object"; identifier += " strict namespace object";
else if(this.options.namespaceObject) else if (this.options.namespaceObject) identifier += " namespace object";
identifier += " namespace object";
return identifier; return identifier;
} }
libIdent(options) { libIdent(options) {
let identifier = this.contextify(options.context, this.context); let identifier = this.contextify(options.context, this.context);
if(this.options.mode) if (this.options.mode) identifier += ` ${this.options.mode}`;
identifier += ` ${this.options.mode}`; if (this.options.recursive) identifier += " recursive";
if(this.options.recursive) if (this.options.addon)
identifier += " recursive";
if(this.options.addon)
identifier += ` ${this.contextify(options.context, this.options.addon)}`; identifier += ` ${this.contextify(options.context, this.options.addon)}`;
if(this.options.regExp) if (this.options.regExp)
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`; identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if(this.options.include) if (this.options.include)
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`; identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if(this.options.exclude) if (this.options.exclude)
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`; identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
return identifier; return identifier;
@ -131,7 +119,7 @@ class ContextModule extends Module {
needRebuild(fileTimestamps, contextTimestamps) { needRebuild(fileTimestamps, contextTimestamps) {
const ts = contextTimestamps.get(this.context); const ts = contextTimestamps.get(this.context);
if(!ts) { if (!ts) {
return true; return true;
} }
@ -146,65 +134,74 @@ class ContextModule extends Module {
contextDependencies: this._contextDependencies contextDependencies: this._contextDependencies
}; };
this.resolveDependencies(fs, this.options, (err, dependencies) => { this.resolveDependencies(fs, this.options, (err, dependencies) => {
if(err) return callback(err); if (err) return callback(err);
// abort if something failed // abort if something failed
// this will create an empty context // this will create an empty context
if(!dependencies) { if (!dependencies) {
callback(); callback();
return; return;
} }
// enhance dependencies with meta info // enhance dependencies with meta info
for(const dep of dependencies) { for (const dep of dependencies) {
dep.loc = dep.userRequest; dep.loc = dep.userRequest;
dep.request = this.options.addon + dep.request; dep.request = this.options.addon + dep.request;
} }
if(this.options.mode === "sync" || this.options.mode === "eager") { if (this.options.mode === "sync" || this.options.mode === "eager") {
// if we have an sync or eager context // if we have an sync or eager context
// just add all dependencies and continue // just add all dependencies and continue
this.dependencies = dependencies; this.dependencies = dependencies;
} else if (this.options.mode === "lazy-once") {
} else if(this.options.mode === "lazy-once") {
// for the lazy-once mode create a new async dependency block // for the lazy-once mode create a new async dependency block
// and add that block to this context // and add that block to this context
if(dependencies.length > 0) { if (dependencies.length > 0) {
const block = new AsyncDependenciesBlock(this.options.chunkName, this); const block = new AsyncDependenciesBlock(
for(const dep of dependencies) { this.options.chunkName,
this
);
for (const dep of dependencies) {
block.addDependency(dep); block.addDependency(dep);
} }
this.addBlock(block); this.addBlock(block);
} }
} else if (
} else if(this.options.mode === "weak" || this.options.mode === "async-weak") { this.options.mode === "weak" ||
this.options.mode === "async-weak"
) {
// we mark all dependencies as weak // we mark all dependencies as weak
for(const dep of dependencies) { for (const dep of dependencies) {
dep.weak = true; dep.weak = true;
} }
this.dependencies = dependencies; this.dependencies = dependencies;
} else if (this.options.mode === "lazy") {
} else if(this.options.mode === "lazy") {
// if we are lazy create a new async dependency block per dependency // if we are lazy create a new async dependency block per dependency
// and add all blocks to this context // and add all blocks to this context
let index = 0; let index = 0;
for(const dep of dependencies) { for (const dep of dependencies) {
let chunkName = this.options.chunkName; let chunkName = this.options.chunkName;
if(chunkName) { if (chunkName) {
if(!/\[(index|request)\]/.test(chunkName)) if (!/\[(index|request)\]/.test(chunkName)) chunkName += "[index]";
chunkName += "[index]";
chunkName = chunkName.replace(/\[index\]/g, index++); chunkName = chunkName.replace(/\[index\]/g, index++);
chunkName = chunkName.replace(/\[request\]/g, Template.toPath(dep.userRequest)); chunkName = chunkName.replace(
/\[request\]/g,
Template.toPath(dep.userRequest)
);
} }
const block = new AsyncDependenciesBlock(chunkName, dep.module, dep.loc, dep.userRequest); const block = new AsyncDependenciesBlock(
chunkName,
dep.module,
dep.loc,
dep.userRequest
);
block.addDependency(dep); block.addDependency(dep);
this.addBlock(block); this.addBlock(block);
} }
} else { } else {
callback(new Error(`Unsupported mode "${this.options.mode}" in context`)); callback(
new Error(`Unsupported mode "${this.options.mode}" in context`)
);
return; return;
} }
callback(); callback();
@ -218,18 +215,19 @@ class ContextModule extends Module {
return dependencies return dependencies
.filter(dependency => dependency.module) .filter(dependency => dependency.module)
.sort((a, b) => { .sort((a, b) => {
if(a.userRequest === b.userRequest) { if (a.userRequest === b.userRequest) {
return 0; return 0;
} }
return a.userRequest < b.userRequest ? -1 : 1; return a.userRequest < b.userRequest ? -1 : 1;
}).reduce((map, dep) => { })
.reduce((map, dep) => {
map[dep.userRequest] = dep.module.id; map[dep.userRequest] = dep.module.id;
return map; return map;
}, Object.create(null)); }, Object.create(null));
} }
getFakeMap(dependencies) { getFakeMap(dependencies) {
if(!this.options.namespaceObject) return 1; if (!this.options.namespaceObject) return 1;
// if we filter first we get a new array // if we filter first we get a new array
// therefor we dont need to create a clone of dependencies explicitly // therefor we dont need to create a clone of dependencies explicitly
// therefore the order of this is !important! // therefore the order of this is !important!
@ -240,43 +238,52 @@ class ContextModule extends Module {
.filter(dependency => dependency.module) .filter(dependency => dependency.module)
.sort((a, b) => { .sort((a, b) => {
return b.module.id - a.module.id; return b.module.id - a.module.id;
}).reduce((map, dep) => { })
const exportsType = dep.module.buildMeta && dep.module.buildMeta.exportsType; .reduce((map, dep) => {
if(!exportsType) hasNonHarmony = true; const exportsType =
if(exportsType === "namespace") hasNamespace = true; dep.module.buildMeta && dep.module.buildMeta.exportsType;
if(exportsType === "named") hasNamed = true; if (!exportsType) hasNonHarmony = true;
map[dep.module.id] = { if (exportsType === "namespace") hasNamespace = true;
namespace: 1, if (exportsType === "named") hasNamed = true;
named: 2 map[dep.module.id] =
}[exportsType] || 0; {
namespace: 1,
named: 2
}[exportsType] || 0;
return map; return map;
}, Object.create(null)); }, Object.create(null));
if(!hasNamespace && hasNonHarmony && !hasNamed) return 0; if (!hasNamespace && hasNonHarmony && !hasNamed) return 0;
if(hasNamespace && !hasNonHarmony && !hasNamed) return 1; if (hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if(!hasNamespace && !hasNonHarmony && hasNamed) return 2; if (!hasNamespace && !hasNonHarmony && hasNamed) return 2;
if(!hasNamespace && !hasNonHarmony && !hasNamed) return 1; if (!hasNamespace && !hasNonHarmony && !hasNamed) return 1;
return fakeMap; return fakeMap;
} }
getFakeMapInitStatement(fakeMap) { getFakeMapInitStatement(fakeMap) {
return typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""; return typeof fakeMap === "object"
? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};`
: "";
} }
getReturn(type) { getReturn(type) {
if(type === 1) return "module"; if (type === 1) return "module";
if(type === 2) return "Object.assign({/* fake namespace object */}, module, { \"default\": module })"; if (type === 2)
if(type === 0) { return 'Object.assign({/* fake namespace object */}, typeof module === "object" && module, { "default": module })';
if(this.options.namespaceObject === "strict") { if (type === 0) {
return "/* fake namespace object */ { \"default\": module }"; if (this.options.namespaceObject === "strict") {
return '/* fake namespace object */ { "default": module }';
} else { } else {
return "(typeof module === \"object\" && module && module.__esModule ? module : /* fake namespace object */ { \"default\": module })"; return '(typeof module === "object" && module && module.__esModule ? module : Object.assign({/* fake namespace object */}, typeof module === "object" && module, { "default": module }))';
} }
} }
} }
getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") { getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") {
if(typeof fakeMap === "number") return `return ${this.getReturn(fakeMap)};`; if (typeof fakeMap === "number")
return `return ${fakeMapDataExpression} === 1 ? ${this.getReturn(1)} : ${fakeMapDataExpression} ? ${this.getReturn(2)} : ${this.getReturn(0)};`; return `return ${this.getReturn(fakeMap)};`;
return `return ${fakeMapDataExpression} === 1 ? ${this.getReturn(1)} : ${
fakeMapDataExpression
} ? ${this.getReturn(2)} : ${this.getReturn(0)};`;
} }
getSyncSource(dependencies, id) { getSyncSource(dependencies, id) {
@ -365,7 +372,7 @@ function webpackAsyncContext(req) {
} }
function webpackAsyncContextResolve(req) { function webpackAsyncContextResolve(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent // Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncatched exception popping up in devtools // uncaught exception popping up in devtools
return Promise.resolve().then(function() { return Promise.resolve().then(function() {
var id = map[req]; var id = map[req];
if(!(id + 1)) { // check for number or string if(!(id + 1)) { // check for number or string
@ -387,12 +394,13 @@ module.exports = webpackAsyncContext;`;
getEagerSource(dependencies, id) { getEagerSource(dependencies, id) {
const map = this.getUserRequestMap(dependencies); const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies); const fakeMap = this.getFakeMap(dependencies);
const thenFunction = fakeMap !== 1 ? const thenFunction =
`function(id) { fakeMap !== 1
? `function(id) {
var module = __webpack_require__(id); var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)} ${this.getReturnModuleObjectSource(fakeMap)}
}` : }`
"__webpack_require__"; : "__webpack_require__";
return `var map = ${JSON.stringify(map, null, "\t")}; return `var map = ${JSON.stringify(map, null, "\t")};
${this.getFakeMapInitStatement(fakeMap)} ${this.getFakeMapInitStatement(fakeMap)}
@ -401,7 +409,7 @@ function webpackAsyncContext(req) {
} }
function webpackAsyncContextResolve(req) { function webpackAsyncContextResolve(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent // Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncatched exception popping up in devtools // uncaught exception popping up in devtools
return Promise.resolve().then(function() { return Promise.resolve().then(function() {
var id = map[req]; var id = map[req];
if(!(id + 1)) { // check for number or string if(!(id + 1)) { // check for number or string
@ -427,12 +435,13 @@ module.exports = webpackAsyncContext;`;
}); });
const map = this.getUserRequestMap(dependencies); const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies); const fakeMap = this.getFakeMap(dependencies);
const thenFunction = fakeMap !== 1 ? const thenFunction =
`function(id) { fakeMap !== 1
? `function(id) {
var module = __webpack_require__(id); var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)}; ${this.getReturnModuleObjectSource(fakeMap)};
}` : }`
"__webpack_require__"; : "__webpack_require__";
return `var map = ${JSON.stringify(map, null, "\t")}; return `var map = ${JSON.stringify(map, null, "\t")};
${this.getFakeMapInitStatement(fakeMap)} ${this.getFakeMapInitStatement(fakeMap)}
@ -464,32 +473,41 @@ module.exports = webpackAsyncContext;`;
const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0])); const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0]));
const map = blocks const map = blocks
.filter(block => block.dependencies[0].module) .filter(block => block.dependencies[0].module)
.map((block) => ({ .map(block => ({
dependency: block.dependencies[0], dependency: block.dependencies[0],
block: block, block: block,
userRequest: block.dependencies[0].userRequest userRequest: block.dependencies[0].userRequest
})).sort((a, b) => { }))
if(a.userRequest === b.userRequest) return 0; .sort((a, b) => {
if (a.userRequest === b.userRequest) return 0;
return a.userRequest < b.userRequest ? -1 : 1; return a.userRequest < b.userRequest ? -1 : 1;
}).reduce((map, item) => { })
const chunks = item.block.chunkGroup && item.block.chunkGroup.chunks || []; .reduce((map, item) => {
if(chunks.length !== 1) { const chunks =
(item.block.chunkGroup && item.block.chunkGroup.chunks) || [];
if (chunks.length !== 1) {
hasMultipleOrNoChunks = true; hasMultipleOrNoChunks = true;
} }
const arrayStart = [item.dependency.module.id]; const arrayStart = [item.dependency.module.id];
if(typeof fakeMap === "object") if (typeof fakeMap === "object")
arrayStart.push(fakeMap[item.dependency.module.id]); arrayStart.push(fakeMap[item.dependency.module.id]);
map[item.userRequest] = arrayStart map[item.userRequest] = arrayStart.concat(
.concat(chunks.map(chunk => chunk.id)); chunks.map(chunk => chunk.id)
);
return map; return map;
}, Object.create(null)); }, Object.create(null));
const chunksStartPosition = typeof fakeMap === "object" ? 2 : 1; const chunksStartPosition = typeof fakeMap === "object" ? 2 : 1;
const requestPrefix = hasMultipleOrNoChunks ? const requestPrefix = hasMultipleOrNoChunks
`Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))` : ? `Promise.all(ids.slice(${
`__webpack_require__.e(ids[${chunksStartPosition}])`; chunksStartPosition
const returnModuleObject = this.getReturnModuleObjectSource(fakeMap, "ids[1]"); }).map(__webpack_require__.e))`
: `__webpack_require__.e(ids[${chunksStartPosition}])`;
const returnModuleObject = this.getReturnModuleObjectSource(
fakeMap,
"ids[1]"
);
return `var map = ${JSON.stringify(map, null, "\t")}; return `var map = ${JSON.stringify(map, null, "\t")};
function webpackAsyncContext(req) { function webpackAsyncContext(req) {
@ -528,7 +546,7 @@ webpackEmptyContext.id = ${JSON.stringify(id)};`;
getSourceForEmptyAsyncContext(id) { getSourceForEmptyAsyncContext(id) {
return `function webpackEmptyAsyncContext(req) { return `function webpackEmptyAsyncContext(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent // Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncatched exception popping up in devtools // uncaught exception popping up in devtools
return Promise.resolve().then(function() { return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".'); var e = new Error('Cannot find module "' + req + '".');
e.code = 'MODULE_NOT_FOUND'; e.code = 'MODULE_NOT_FOUND';
@ -542,44 +560,49 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
} }
getSourceString(asyncMode, runtimeTemplate) { getSourceString(asyncMode, runtimeTemplate) {
if(asyncMode === "lazy") { if (asyncMode === "lazy") {
if(this.blocks && this.blocks.length > 0) { if (this.blocks && this.blocks.length > 0) {
return this.getLazySource(this.blocks, this.id); return this.getLazySource(this.blocks, this.id);
} }
return this.getSourceForEmptyAsyncContext(this.id); return this.getSourceForEmptyAsyncContext(this.id);
} }
if(asyncMode === "eager") { if (asyncMode === "eager") {
if(this.dependencies && this.dependencies.length > 0) { if (this.dependencies && this.dependencies.length > 0) {
return this.getEagerSource(this.dependencies, this.id); return this.getEagerSource(this.dependencies, this.id);
} }
return this.getSourceForEmptyAsyncContext(this.id); return this.getSourceForEmptyAsyncContext(this.id);
} }
if(asyncMode === "lazy-once") { if (asyncMode === "lazy-once") {
const block = this.blocks[0]; const block = this.blocks[0];
if(block) { if (block) {
return this.getLazyOnceSource(block, block.dependencies, this.id, runtimeTemplate); return this.getLazyOnceSource(
block,
block.dependencies,
this.id,
runtimeTemplate
);
} }
return this.getSourceForEmptyAsyncContext(this.id); return this.getSourceForEmptyAsyncContext(this.id);
} }
if(asyncMode === "async-weak") { if (asyncMode === "async-weak") {
if(this.dependencies && this.dependencies.length > 0) { if (this.dependencies && this.dependencies.length > 0) {
return this.getAsyncWeakSource(this.dependencies, this.id); return this.getAsyncWeakSource(this.dependencies, this.id);
} }
return this.getSourceForEmptyAsyncContext(this.id); return this.getSourceForEmptyAsyncContext(this.id);
} }
if(asyncMode === "weak") { if (asyncMode === "weak") {
if(this.dependencies && this.dependencies.length > 0) { if (this.dependencies && this.dependencies.length > 0) {
return this.getWeakSyncSource(this.dependencies, this.id); return this.getWeakSyncSource(this.dependencies, this.id);
} }
} }
if(this.dependencies && this.dependencies.length > 0) { if (this.dependencies && this.dependencies.length > 0) {
return this.getSyncSource(this.dependencies, this.id); return this.getSyncSource(this.dependencies, this.id);
} }
return this.getSourceForEmptyContext(this.id); return this.getSourceForEmptyContext(this.id);
} }
getSource(sourceString) { getSource(sourceString) {
if(this.useSourceMap) { if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier()); return new OriginalSource(sourceString, this.identifier());
} }
return new RawSource(sourceString); return new RawSource(sourceString);
@ -596,8 +619,10 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
const initialSize = 160; const initialSize = 160;
// if we dont have dependencies we stop here. // if we dont have dependencies we stop here.
return this.dependencies return this.dependencies.reduce(
.reduce((size, dependency) => size + 5 + dependency.userRequest.length, initialSize); (size, dependency) => size + 5 + dependency.userRequest.length,
initialSize
);
} }
} }

View File

@ -7,9 +7,11 @@
const asyncLib = require("neo-async"); const asyncLib = require("neo-async");
const path = require("path"); const path = require("path");
const Tapable = require("tapable").Tapable; const {
const AsyncSeriesWaterfallHook = require("tapable").AsyncSeriesWaterfallHook; Tapable,
const SyncWaterfallHook = require("tapable").SyncWaterfallHook; AsyncSeriesWaterfallHook,
SyncWaterfallHook
} = require("tapable");
const ContextModule = require("./ContextModule"); const ContextModule = require("./ContextModule");
const ContextElementDependency = require("./dependencies/ContextElementDependency"); const ContextElementDependency = require("./dependencies/ContextElementDependency");
@ -25,7 +27,7 @@ module.exports = class ContextModuleFactory extends Tapable {
alternatives: new AsyncSeriesWaterfallHook(["modules"]) alternatives: new AsyncSeriesWaterfallHook(["modules"])
}; };
this._pluginCompat.tap("ContextModuleFactory", options => { this._pluginCompat.tap("ContextModuleFactory", options => {
switch(options.name) { switch (options.name) {
case "before-resolve": case "before-resolve":
case "after-resolve": case "after-resolve":
case "alternatives": case "alternatives":
@ -41,72 +43,120 @@ module.exports = class ContextModuleFactory extends Tapable {
const dependencies = data.dependencies; const dependencies = data.dependencies;
const resolveOptions = data.resolveOptions; const resolveOptions = data.resolveOptions;
const dependency = dependencies[0]; const dependency = dependencies[0];
this.hooks.beforeResolve.callAsync(Object.assign({ this.hooks.beforeResolve.callAsync(
context: context, Object.assign(
dependencies: dependencies, {
resolveOptions context: context,
}, dependency.options), (err, beforeResolveResult) => { dependencies: dependencies,
if(err) return callback(err); resolveOptions
// Ignored
if(!beforeResolveResult) return callback();
const context = beforeResolveResult.context;
const request = beforeResolveResult.request;
const resolveOptions = beforeResolveResult.resolveOptions;
let loaders, resource, loadersPrefix = "";
const idx = request.lastIndexOf("!");
if(idx >= 0) {
loaders = request.substr(0, idx + 1);
let i;
for(i = 0; i < loaders.length && loaders[i] === "!"; i++) {
loadersPrefix += "!";
}
loaders = loaders.substr(i).replace(/!+$/, "").replace(/!!+/g, "!");
if(loaders === "") loaders = [];
else loaders = loaders.split("!");
resource = request.substr(idx + 1);
} else {
loaders = [];
resource = request;
}
const contextResolver = this.resolverFactory.get("context", resolveOptions || EMPTY_RESOLVE_OPTIONS);
const loaderResolver = this.resolverFactory.get("loader", EMPTY_RESOLVE_OPTIONS);
asyncLib.parallel([
callback => {
contextResolver.resolve({}, context, resource, {}, (err, result) => {
if(err) return callback(err);
callback(null, result);
});
}, },
callback => { dependency.options
asyncLib.map(loaders, (loader, callback) => { ),
loaderResolver.resolve({}, context, loader, {}, (err, result) => { (err, beforeResolveResult) => {
if(err) return callback(err); if (err) return callback(err);
callback(null, result);
}); // Ignored
}, callback); if (!beforeResolveResult) return callback();
const context = beforeResolveResult.context;
const request = beforeResolveResult.request;
const resolveOptions = beforeResolveResult.resolveOptions;
let loaders,
resource,
loadersPrefix = "";
const idx = request.lastIndexOf("!");
if (idx >= 0) {
loaders = request.substr(0, idx + 1);
let i;
for (i = 0; i < loaders.length && loaders[i] === "!"; i++) {
loadersPrefix += "!";
}
loaders = loaders
.substr(i)
.replace(/!+$/, "")
.replace(/!!+/g, "!");
if (loaders === "") loaders = [];
else loaders = loaders.split("!");
resource = request.substr(idx + 1);
} else {
loaders = [];
resource = request;
} }
], (err, result) => {
if(err) return callback(err);
this.hooks.afterResolve.callAsync(Object.assign({ const contextResolver = this.resolverFactory.get(
addon: loadersPrefix + result[1].join("!") + (result[1].length > 0 ? "!" : ""), "context",
resource: result[0], resolveOptions || EMPTY_RESOLVE_OPTIONS
resolveDependencies: this.resolveDependencies.bind(this) );
}, beforeResolveResult), (err, result) => { const loaderResolver = this.resolverFactory.get(
if(err) return callback(err); "loader",
EMPTY_RESOLVE_OPTIONS
);
// Ignored asyncLib.parallel(
if(!result) return callback(); [
callback => {
contextResolver.resolve(
{},
context,
resource,
{},
(err, result) => {
if (err) return callback(err);
callback(null, result);
}
);
},
callback => {
asyncLib.map(
loaders,
(loader, callback) => {
loaderResolver.resolve(
{},
context,
loader,
{},
(err, result) => {
if (err) return callback(err);
callback(null, result);
}
);
},
callback
);
}
],
(err, result) => {
if (err) return callback(err);
return callback(null, new ContextModule(result.resolveDependencies, result)); this.hooks.afterResolve.callAsync(
}); Object.assign(
}); {
}); addon:
loadersPrefix +
result[1].join("!") +
(result[1].length > 0 ? "!" : ""),
resource: result[0],
resolveDependencies: this.resolveDependencies.bind(this)
},
beforeResolveResult
),
(err, result) => {
if (err) return callback(err);
// Ignored
if (!result) return callback();
return callback(
null,
new ContextModule(result.resolveDependencies, result)
);
}
);
}
);
}
);
} }
resolveDependencies(fs, options, callback) { resolveDependencies(fs, options, callback) {
@ -117,63 +167,76 @@ module.exports = class ContextModuleFactory extends Tapable {
let regExp = options.regExp; let regExp = options.regExp;
let include = options.include; let include = options.include;
let exclude = options.exclude; let exclude = options.exclude;
if(!regExp || !resource) if (!regExp || !resource) return callback(null, []);
return callback(null, []);
const addDirectory = (directory, callback) => { const addDirectory = (directory, callback) => {
fs.readdir(directory, (err, files) => { fs.readdir(directory, (err, files) => {
if(err) return callback(err); if (err) return callback(err);
files = cmf.hooks.contextModuleFiles.call(files); files = cmf.hooks.contextModuleFiles.call(files);
if(!files || files.length === 0) return callback(null, []); if (!files || files.length === 0) return callback(null, []);
asyncLib.map(files.filter(p => p.indexOf(".") !== 0), (seqment, callback) => { asyncLib.map(
files.filter(p => p.indexOf(".") !== 0),
(segment, callback) => {
const subResource = path.join(directory, segment);
const subResource = path.join(directory, seqment); if (!exclude || !subResource.match(exclude)) {
fs.stat(subResource, (err, stat) => {
if(!exclude || !subResource.match(exclude)) { if (err) {
fs.stat(subResource, (err, stat) => { if (err.code === "ENOENT") {
if(err) { // ENOENT is ok here because the file may have been deleted between
if(err.code === "ENOENT") { // the readdir and stat calls.
// ENOENT is ok here because the file may have been deleted between return callback();
// the readdir and stat calls. } else {
return callback(); return callback(err);
} else { }
return callback(err);
} }
}
if(stat.isDirectory()) { if (stat.isDirectory()) {
if (!recursive) return callback();
addDirectory.call(this, subResource, callback);
} else if (
stat.isFile() &&
(!include || subResource.match(include))
) {
const obj = {
context: resource,
request:
"." +
subResource.substr(resource.length).replace(/\\/g, "/")
};
if(!recursive) return callback(); this.hooks.alternatives.callAsync(
addDirectory.call(this, subResource, callback); [obj],
(err, alternatives) => {
if (err) return callback(err);
alternatives = alternatives
.filter(obj => regExp.test(obj.request))
.map(obj => {
const dep = new ContextElementDependency(
obj.request + resourceQuery,
obj.request
);
dep.optional = true;
return dep;
});
callback(null, alternatives);
}
);
} else callback();
});
} else callback();
},
(err, result) => {
if (err) return callback(err);
} else if(stat.isFile() && (!include || subResource.match(include))) { if (!result) return callback(null, []);
const obj = { callback(
context: resource, null,
request: "." + subResource.substr(resource.length).replace(/\\/g, "/") result.filter(Boolean).reduce((a, i) => a.concat(i), [])
}; );
}
this.hooks.alternatives.callAsync([obj], (err, alternatives) => { );
if(err) return callback(err);
alternatives = alternatives.filter(obj => regExp.test(obj.request)).map(obj => {
const dep = new ContextElementDependency(obj.request + resourceQuery, obj.request);
dep.optional = true;
return dep;
});
callback(null, alternatives);
});
} else callback();
});
} else callback();
}, (err, result) => {
if(err) return callback(err);
if(!result) return callback(null, []);
callback(null, result.filter(Boolean).reduce((a, i) => a.concat(i), []));
});
}); });
}; };

View File

@ -8,26 +8,37 @@ const path = require("path");
const ContextElementDependency = require("./dependencies/ContextElementDependency"); const ContextElementDependency = require("./dependencies/ContextElementDependency");
class ContextReplacementPlugin { class ContextReplacementPlugin {
constructor(resourceRegExp, newContentResource, newContentRecursive, newContentRegExp) { constructor(
resourceRegExp,
newContentResource,
newContentRecursive,
newContentRegExp
) {
this.resourceRegExp = resourceRegExp; this.resourceRegExp = resourceRegExp;
if(typeof newContentResource === "function") { if (typeof newContentResource === "function") {
this.newContentCallback = newContentResource; this.newContentCallback = newContentResource;
} else if(typeof newContentResource === "string" && typeof newContentRecursive === "object") { } else if (
typeof newContentResource === "string" &&
typeof newContentRecursive === "object"
) {
this.newContentResource = newContentResource; this.newContentResource = newContentResource;
this.newContentCreateContextMap = (fs, callback) => { this.newContentCreateContextMap = (fs, callback) => {
callback(null, newContentRecursive); callback(null, newContentRecursive);
}; };
} else if(typeof newContentResource === "string" && typeof newContentRecursive === "function") { } else if (
typeof newContentResource === "string" &&
typeof newContentRecursive === "function"
) {
this.newContentResource = newContentResource; this.newContentResource = newContentResource;
this.newContentCreateContextMap = newContentRecursive; this.newContentCreateContextMap = newContentRecursive;
} else { } else {
if(typeof newContentResource !== "string") { if (typeof newContentResource !== "string") {
newContentRegExp = newContentRecursive; newContentRegExp = newContentRecursive;
newContentRecursive = newContentResource; newContentRecursive = newContentResource;
newContentResource = undefined; newContentResource = undefined;
} }
if(typeof newContentRecursive !== "boolean") { if (typeof newContentRecursive !== "boolean") {
newContentRegExp = newContentRecursive; newContentRegExp = newContentRecursive;
newContentRecursive = undefined; newContentRecursive = undefined;
} }
@ -45,48 +56,48 @@ class ContextReplacementPlugin {
const newContentRegExp = this.newContentRegExp; const newContentRegExp = this.newContentRegExp;
const newContentCreateContextMap = this.newContentCreateContextMap; const newContentCreateContextMap = this.newContentCreateContextMap;
compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", (cmf) => { compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", cmf => {
cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", (result) => { cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", result => {
if(!result) return; if (!result) return;
if(resourceRegExp.test(result.request)) { if (resourceRegExp.test(result.request)) {
if(typeof newContentResource !== "undefined") if (typeof newContentResource !== "undefined")
result.request = newContentResource; result.request = newContentResource;
if(typeof newContentRecursive !== "undefined") if (typeof newContentRecursive !== "undefined")
result.recursive = newContentRecursive; result.recursive = newContentRecursive;
if(typeof newContentRegExp !== "undefined") if (typeof newContentRegExp !== "undefined")
result.regExp = newContentRegExp; result.regExp = newContentRegExp;
if(typeof newContentCallback === "function") { if (typeof newContentCallback === "function") {
newContentCallback(result); newContentCallback(result);
} else { } else {
for(const d of result.dependencies) { for (const d of result.dependencies) {
if(d.critical) if (d.critical) d.critical = false;
d.critical = false;
} }
} }
} }
return result; return result;
}); });
cmf.hooks.afterResolve.tap("ContextReplacementPlugin", (result) => { cmf.hooks.afterResolve.tap("ContextReplacementPlugin", result => {
if(!result) return; if (!result) return;
if(resourceRegExp.test(result.resource)) { if (resourceRegExp.test(result.resource)) {
if(typeof newContentResource !== "undefined") if (typeof newContentResource !== "undefined")
result.resource = path.resolve(result.resource, newContentResource); result.resource = path.resolve(result.resource, newContentResource);
if(typeof newContentRecursive !== "undefined") if (typeof newContentRecursive !== "undefined")
result.recursive = newContentRecursive; result.recursive = newContentRecursive;
if(typeof newContentRegExp !== "undefined") if (typeof newContentRegExp !== "undefined")
result.regExp = newContentRegExp; result.regExp = newContentRegExp;
if(typeof newContentCreateContextMap === "function") if (typeof newContentCreateContextMap === "function")
result.resolveDependencies = createResolveDependenciesFromContextMap(newContentCreateContextMap); result.resolveDependencies = createResolveDependenciesFromContextMap(
if(typeof newContentCallback === "function") { newContentCreateContextMap
);
if (typeof newContentCallback === "function") {
const origResource = result.resource; const origResource = result.resource;
newContentCallback(result); newContentCallback(result);
if(result.resource !== origResource) { if (result.resource !== origResource) {
result.resource = path.resolve(origResource, result.resource); result.resource = path.resolve(origResource, result.resource);
} }
} else { } else {
for(const d of result.dependencies) { for (const d of result.dependencies) {
if(d.critical) if (d.critical) d.critical = false;
d.critical = false;
} }
} }
} }
@ -96,12 +107,15 @@ class ContextReplacementPlugin {
} }
} }
const createResolveDependenciesFromContextMap = (createContextMap) => { const createResolveDependenciesFromContextMap = createContextMap => {
const resolveDependenciesFromContextMap = (fs, options, callback) => { const resolveDependenciesFromContextMap = (fs, options, callback) => {
createContextMap(fs, (err, map) => { createContextMap(fs, (err, map) => {
if(err) return callback(err); if (err) return callback(err);
const dependencies = Object.keys(map).map((key) => { const dependencies = Object.keys(map).map(key => {
return new ContextElementDependency(map[key] + options.resourceQuery, key); return new ContextElementDependency(
map[key] + options.resourceQuery,
key
);
}); });
callback(null, dependencies); callback(null, dependencies);
}); });

View File

@ -10,18 +10,25 @@ const ParserHelpers = require("./ParserHelpers");
const NullFactory = require("./NullFactory"); const NullFactory = require("./NullFactory");
const stringifyObj = obj => { const stringifyObj = obj => {
return "Object({" + Object.keys(obj).map((key) => { return (
const code = obj[key]; "Object({" +
return JSON.stringify(key) + ":" + toCode(code); Object.keys(obj)
}).join(",") + "})"; .map(key => {
const code = obj[key];
return JSON.stringify(key) + ":" + toCode(code);
})
.join(",") +
"})"
);
}; };
const toCode = code => { const toCode = code => {
if(code === null) return "null"; if (code === null) return "null";
else if(code === undefined) return "undefined"; else if (code === undefined) return "undefined";
else if(code instanceof RegExp && code.toString) return code.toString(); else if (code instanceof RegExp && code.toString) return code.toString();
else if(typeof code === "function" && code.toString) return "(" + code.toString() + ")"; else if (typeof code === "function" && code.toString)
else if(typeof code === "object") return stringifyObj(code); return "(" + code.toString() + ")";
else if (typeof code === "object") return stringifyObj(code);
else return code + ""; else return code + "";
}; };
@ -32,100 +39,159 @@ class DefinePlugin {
apply(compiler) { apply(compiler) {
const definitions = this.definitions; const definitions = this.definitions;
compiler.hooks.compilation.tap("DefinePlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "DefinePlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory()); compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template()); compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = (parser) => { const handler = parser => {
const walkDefinitions = (definitions, prefix) => { const walkDefinitions = (definitions, prefix) => {
Object.keys(definitions).forEach((key) => { Object.keys(definitions).forEach(key => {
const code = definitions[key]; const code = definitions[key];
if(code && typeof code === "object" && !(code instanceof RegExp)) { if (
walkDefinitions(code, prefix + key + "."); code &&
applyObjectDefine(prefix + key, code); typeof code === "object" &&
return; !(code instanceof RegExp)
) {
walkDefinitions(code, prefix + key + ".");
applyObjectDefine(prefix + key, code);
return;
}
applyDefineKey(prefix, key);
applyDefine(prefix + key, code);
});
};
const applyDefineKey = (prefix, key) => {
const splittedKey = key.split(".");
splittedKey.slice(1).forEach((_, i) => {
const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
parser.hooks.canRename
.for(fullKey)
.tap("DefinePlugin", ParserHelpers.approve);
});
};
const applyDefine = (key, code) => {
const isTypeof = /^typeof\s+/.test(key);
if (isTypeof) key = key.replace(/^typeof\s+/, "");
let recurse = false;
let recurseTypeof = false;
code = toCode(code);
if (!isTypeof) {
parser.hooks.canRename
.for(key)
.tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier
.for(key)
.tap("DefinePlugin", expr => {
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "a": "b",
* "b": "a"
* });
*/
if (recurse) return;
recurse = true;
const res = parser.evaluate(code);
recurse = false;
res.setRange(expr.range);
return res;
});
parser.hooks.expression
.for(key)
.tap(
"DefinePlugin",
/__webpack_require__/.test(code)
? ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
code
)
: ParserHelpers.toConstantDependency(parser, code)
);
} }
applyDefineKey(prefix, key); const typeofCode = isTypeof ? code : "typeof (" + code + ")";
applyDefine(prefix + key, code); parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => {
});
};
const applyDefineKey = (prefix, key) => {
const splittedKey = key.split(".");
splittedKey.slice(1).forEach((_, i) => {
const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
parser.hooks.canRename.for(fullKey).tap("DefinePlugin", ParserHelpers.approve);
});
};
const applyDefine = (key, code) => {
const isTypeof = /^typeof\s+/.test(key);
if(isTypeof) key = key.replace(/^typeof\s+/, "");
let recurse = false;
let recurseTypeof = false;
code = toCode(code);
if(!isTypeof) {
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => {
/** /**
* this is needed in case there is a recursion in the DefinePlugin * this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion * to prevent an endless recursion
* e.g.: new DefinePlugin({ * e.g.: new DefinePlugin({
* "a": "b", * "typeof a": "typeof b",
* "b": "a" * "typeof b": "typeof a"
* }); * });
*/ */
if(recurse) return; if (recurseTypeof) return;
recurse = true; recurseTypeof = true;
const res = parser.evaluate(code); const res = parser.evaluate(typeofCode);
recurse = false; recurseTypeof = false;
res.setRange(expr.range); res.setRange(expr.range);
return res; return res;
}); });
parser.hooks.expression.for(key).tap("DefinePlugin", /__webpack_require__/.test(code) ? ParserHelpers.toConstantDependencyWithWebpackRequire(parser, code) : ParserHelpers.toConstantDependency(parser, code)); parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
} const res = parser.evaluate(typeofCode);
const typeofCode = isTypeof ? code : "typeof (" + code + ")"; if (!res.isString()) return;
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", (expr) => { return ParserHelpers.toConstantDependency(
/** parser,
* this is needed in case there is a recursion in the DefinePlugin JSON.stringify(res.string)
* to prevent an endless recursion ).bind(parser)(expr);
* e.g.: new DefinePlugin({ });
* "typeof a": "tyepof b", };
* "typeof b": "typeof a"
* }); const applyObjectDefine = (key, obj) => {
*/ const code = stringifyObj(obj);
if(recurseTypeof) return; parser.hooks.canRename
recurseTypeof = true; .for(key)
const res = parser.evaluate(typeofCode); .tap("DefinePlugin", ParserHelpers.approve);
recurseTypeof = false; parser.hooks.evaluateIdentifier
res.setRange(expr.range); .for(key)
return res; .tap("DefinePlugin", expr =>
}); new BasicEvaluatedExpression().setTruthy().setRange(expr.range)
parser.hooks.typeof.for(key).tap("DefinePlugin", (expr) => { );
const res = parser.evaluate(typeofCode); parser.hooks.evaluateTypeof
if(!res.isString()) return; .for(key)
return ParserHelpers.toConstantDependency(parser, JSON.stringify(res.string)).bind(parser)(expr); .tap("DefinePlugin", ParserHelpers.evaluateToString("object"));
}); parser.hooks.expression
.for(key)
.tap(
"DefinePlugin",
/__webpack_require__/.test(code)
? ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
code
)
: ParserHelpers.toConstantDependency(parser, code)
);
parser.hooks.typeof
.for(key)
.tap(
"DefinePlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("object")
)
);
};
walkDefinitions(definitions, "");
}; };
const applyObjectDefine = (key, obj) => { normalModuleFactory.hooks.parser
const code = stringifyObj(obj); .for("javascript/auto")
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve); .tap("DefinePlugin", handler);
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => new BasicEvaluatedExpression().setTruthy().setRange(expr.range)); normalModuleFactory.hooks.parser
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", ParserHelpers.evaluateToString("object")); .for("javascript/dynamic")
parser.hooks.expression.for(key).tap("DefinePlugin", /__webpack_require__/.test(code) ? ParserHelpers.toConstantDependencyWithWebpackRequire(parser, code) : ParserHelpers.toConstantDependency(parser, code)); .tap("DefinePlugin", handler);
parser.hooks.typeof.for(key).tap("DefinePlugin", ParserHelpers.toConstantDependency(parser, JSON.stringify("object"))); normalModuleFactory.hooks.parser
}; .for("javascript/esm")
.tap("DefinePlugin", handler);
walkDefinitions(definitions, ""); }
}; );
normalModuleFactory.hooks.parser.for("javascript/auto").tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("DefinePlugin", handler);
});
} }
} }
module.exports = DefinePlugin; module.exports = DefinePlugin;

View File

@ -4,9 +4,9 @@
*/ */
"use strict"; "use strict";
const { OriginalSource, RawSource } = require("webpack-sources");
const Module = require("./Module"); const Module = require("./Module");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const WebpackMissingModule = require("./dependencies/WebpackMissingModule"); const WebpackMissingModule = require("./dependencies/WebpackMissingModule");
const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency"); const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency");
const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency"); const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency");
@ -25,11 +25,15 @@ class DelegatedModule extends Module {
} }
libIdent(options) { libIdent(options) {
return typeof this.originalRequest === "string" ? this.originalRequest : this.originalRequest.libIdent(options); return typeof this.originalRequest === "string"
? this.originalRequest
: this.originalRequest.libIdent(options);
} }
identifier() { identifier() {
return `delegated ${JSON.stringify(this.request)} from ${this.sourceRequest}`; return `delegated ${JSON.stringify(this.request)} from ${
this.sourceRequest
}`;
} }
readableIdentifier() { readableIdentifier() {
@ -45,7 +49,9 @@ class DelegatedModule extends Module {
this.buildMeta = Object.assign({}, this.delegateData.buildMeta); this.buildMeta = Object.assign({}, this.delegateData.buildMeta);
this.buildInfo = {}; this.buildInfo = {};
this.addDependency(new DelegatedSourceDependency(this.sourceRequest)); this.addDependency(new DelegatedSourceDependency(this.sourceRequest));
this.addDependency(new DelegatedExportsDependency(this, this.delegateData.exports || true)); this.addDependency(
new DelegatedExportsDependency(this, this.delegateData.exports || true)
);
callback(); callback();
} }
@ -54,7 +60,7 @@ class DelegatedModule extends Module {
const sourceModule = dep.module; const sourceModule = dep.module;
let str; let str;
if(!sourceModule) { if (!sourceModule) {
str = WebpackMissingModule.moduleCode(this.sourceRequest); str = WebpackMissingModule.moduleCode(this.sourceRequest);
} else { } else {
str = `module.exports = (${runtime.moduleExports({ str = `module.exports = (${runtime.moduleExports({
@ -62,7 +68,7 @@ class DelegatedModule extends Module {
request: dep.request request: dep.request
})})`; })})`;
switch(this.type) { switch (this.type) {
case "require": case "require":
str += `(${JSON.stringify(this.request)})`; str += `(${JSON.stringify(this.request)})`;
break; break;
@ -74,7 +80,7 @@ class DelegatedModule extends Module {
str += ";"; str += ";";
} }
if(this.useSourceMap) { if (this.useSourceMap) {
return new OriginalSource(str, this.identifier()); return new OriginalSource(str, this.identifier());
} else { } else {
return new RawSource(str); return new RawSource(str);

View File

@ -20,39 +20,69 @@ class DelegatedModuleFactoryPlugin {
apply(normalModuleFactory) { apply(normalModuleFactory) {
const scope = this.options.scope; const scope = this.options.scope;
if(scope) { if (scope) {
normalModuleFactory.hooks.factory.tap("DelegatedModuleFactoryPlugin", factory => (data, callback) => { normalModuleFactory.hooks.factory.tap(
const dependency = data.dependencies[0]; "DelegatedModuleFactoryPlugin",
const request = dependency.request; factory => (data, callback) => {
if(request && request.indexOf(scope + "/") === 0) { const dependency = data.dependencies[0];
const innerRequest = "." + request.substr(scope.length); const request = dependency.request;
let resolved; if (request && request.indexOf(scope + "/") === 0) {
if(innerRequest in this.options.content) { const innerRequest = "." + request.substr(scope.length);
resolved = this.options.content[innerRequest]; let resolved;
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, innerRequest, request)); if (innerRequest in this.options.content) {
} resolved = this.options.content[innerRequest];
for(let i = 0; i < this.options.extensions.length; i++) { return callback(
const extension = this.options.extensions[i]; null,
const requestPlusExt = innerRequest + extension; new DelegatedModule(
if(requestPlusExt in this.options.content) { this.options.source,
resolved = this.options.content[requestPlusExt]; resolved,
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, requestPlusExt, request + extension)); this.options.type,
innerRequest,
request
)
);
}
for (let i = 0; i < this.options.extensions.length; i++) {
const extension = this.options.extensions[i];
const requestPlusExt = innerRequest + extension;
if (requestPlusExt in this.options.content) {
resolved = this.options.content[requestPlusExt];
return callback(
null,
new DelegatedModule(
this.options.source,
resolved,
this.options.type,
requestPlusExt,
request + extension
)
);
}
} }
} }
return factory(data, callback);
} }
return factory(data, callback); );
});
} else { } else {
normalModuleFactory.hooks.module.tap("DelegatedModuleFactoryPlugin", module => { normalModuleFactory.hooks.module.tap(
if(module.libIdent) { "DelegatedModuleFactoryPlugin",
const request = module.libIdent(this.options); module => {
if(request && request in this.options.content) { if (module.libIdent) {
const resolved = this.options.content[request]; const request = module.libIdent(this.options);
return new DelegatedModule(this.options.source, resolved, this.options.type, request, module); if (request && request in this.options.content) {
const resolved = this.options.content[request];
return new DelegatedModule(
this.options.source,
resolved,
this.options.type,
request,
module
);
}
} }
return module;
} }
return module; );
});
} }
} }
} }

View File

@ -16,16 +16,21 @@ class DelegatedPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("DelegatedPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "DelegatedPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory()); DelegatedSourceDependency,
}); normalModuleFactory
);
compilation.dependencyFactories.set(
DelegatedExportsDependency,
new NullFactory()
);
}
);
compiler.hooks.compile.tap("DelegatedPlugin", ({ compiler.hooks.compile.tap("DelegatedPlugin", ({ normalModuleFactory }) => {
normalModuleFactory
}) => {
new DelegatedModuleFactoryPlugin(this.options).apply(normalModuleFactory); new DelegatedModuleFactoryPlugin(this.options).apply(normalModuleFactory);
}); });
} }

View File

@ -19,12 +19,14 @@ class DependenciesBlock {
} }
addVariable(name, expression, dependencies) { addVariable(name, expression, dependencies) {
for(let v of this.variables) { for (let v of this.variables) {
if(v.name === name && v.expression === expression) { if (v.name === name && v.expression === expression) {
return; return;
} }
} }
this.variables.push(new DependenciesBlockVariable(name, expression, dependencies)); this.variables.push(
new DependenciesBlockVariable(name, expression, dependencies)
);
} }
addDependency(dependency) { addDependency(dependency) {
@ -33,59 +35,47 @@ class DependenciesBlock {
removeDependency(dependency) { removeDependency(dependency) {
const idx = this.dependencies.indexOf(dependency); const idx = this.dependencies.indexOf(dependency);
if(idx >= 0) if (idx >= 0) this.dependencies.splice(idx, 1);
this.dependencies.splice(idx, 1);
} }
updateHash(hash) { updateHash(hash) {
for(const dep of this.dependencies) for (const dep of this.dependencies) dep.updateHash(hash);
dep.updateHash(hash); for (const block of this.blocks) block.updateHash(hash);
for(const block of this.blocks) for (const variable of this.variables) variable.updateHash(hash);
block.updateHash(hash);
for(const variable of this.variables)
variable.updateHash(hash);
} }
disconnect() { disconnect() {
for(const dep of this.dependencies) for (const dep of this.dependencies) dep.disconnect();
dep.disconnect(); for (const block of this.blocks) block.disconnect();
for(const block of this.blocks) for (const variable of this.variables) variable.disconnect();
block.disconnect();
for(const variable of this.variables)
variable.disconnect();
} }
unseal() { unseal() {
for(const block of this.blocks) for (const block of this.blocks) block.unseal();
block.unseal();
} }
hasDependencies(filter) { hasDependencies(filter) {
if(filter) { if (filter) {
for(const dep of this.dependencies) { for (const dep of this.dependencies) {
if(filter(dep)) if (filter(dep)) return true;
return true;
} }
} else { } else {
if(this.dependencies.length > 0) { if (this.dependencies.length > 0) {
return true; return true;
} }
} }
for(const block of this.blocks) { for (const block of this.blocks) {
if(block.hasDependencies(filter)) if (block.hasDependencies(filter)) return true;
return true;
} }
for(const variable of this.variables) { for (const variable of this.variables) {
if(variable.hasDependencies(filter)) if (variable.hasDependencies(filter)) return true;
return true;
} }
return false; return false;
} }
sortItems() { sortItems() {
for(const block of this.blocks) for (const block of this.blocks) block.sortItems();
block.sortItems();
} }
} }

View File

@ -4,8 +4,7 @@
*/ */
"use strict"; "use strict";
const ReplaceSource = require("webpack-sources").ReplaceSource; const { RawSource, ReplaceSource } = require("webpack-sources");
const RawSource = require("webpack-sources").RawSource;
class DependenciesBlockVariable { class DependenciesBlockVariable {
constructor(name, expression, dependencies) { constructor(name, expression, dependencies) {
@ -17,32 +16,33 @@ class DependenciesBlockVariable {
updateHash(hash) { updateHash(hash) {
hash.update(this.name); hash.update(this.name);
hash.update(this.expression); hash.update(this.expression);
for(const d of this.dependencies) { for (const d of this.dependencies) {
d.updateHash(hash); d.updateHash(hash);
} }
} }
expressionSource(dependencyTemplates, runtimeTemplate) { expressionSource(dependencyTemplates, runtimeTemplate) {
const source = new ReplaceSource(new RawSource(this.expression)); const source = new ReplaceSource(new RawSource(this.expression));
for(const dep of this.dependencies) { for (const dep of this.dependencies) {
const template = dependencyTemplates.get(dep.constructor); const template = dependencyTemplates.get(dep.constructor);
if(!template) throw new Error(`No template for dependency: ${dep.constructor.name}`); if (!template)
throw new Error(`No template for dependency: ${dep.constructor.name}`);
template.apply(dep, source, runtimeTemplate, dependencyTemplates); template.apply(dep, source, runtimeTemplate, dependencyTemplates);
} }
return source; return source;
} }
disconnect() { disconnect() {
for(const d of this.dependencies) { for (const d of this.dependencies) {
d.disconnect(); d.disconnect();
} }
} }
hasDependencies(filter) { hasDependencies(filter) {
if(filter) { if (filter) {
if(this.dependencies.some(filter)) return true; if (this.dependencies.some(filter)) return true;
} else { } else {
if(this.dependencies.length > 0) return true; if (this.dependencies.length > 0) return true;
} }
return false; return false;
} }

View File

@ -18,11 +18,11 @@ class Dependency {
// Returns the referenced module and export // Returns the referenced module and export
getReference() { getReference() {
if(!this.module) return null; if (!this.module) return null;
return { return {
module: this.module, module: this.module,
weak: this.weak, weak: this.weak,
importedNames: true, // true: full object, false: only sideeffects/no export, array of strings: the exports with this names importedNames: true // true: full object, false: only sideeffects/no export, array of strings: the exports with this names
}; };
} }

View File

@ -16,19 +16,34 @@ class DllEntryPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("DllEntryPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "DllEntryPlugin",
}) => { (compilation, { normalModuleFactory }) => {
const dllModuleFactory = new DllModuleFactory(); const dllModuleFactory = new DllModuleFactory();
compilation.dependencyFactories.set(DllEntryDependency, dllModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory); DllEntryDependency,
}); dllModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => { compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => {
compilation.addEntry(this.context, new DllEntryDependency(this.entries.map((e, idx) => { compilation.addEntry(
const dep = new SingleEntryDependency(e); this.context,
dep.loc = `${this.name}:${idx}`; new DllEntryDependency(
return dep; this.entries.map((e, idx) => {
}), this.name), this.name, callback); const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`;
return dep;
}),
this.name
),
this.name,
callback
);
}); });
} }
} }

View File

@ -4,8 +4,8 @@
*/ */
"use strict"; "use strict";
const { RawSource } = require("webpack-sources");
const Module = require("./Module"); const Module = require("./Module");
const RawSource = require("webpack-sources").RawSource;
class DllModule extends Module { class DllModule extends Module {
constructor(context, dependencies, name, type) { constructor(context, dependencies, name, type) {

View File

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
const Tapable = require("tapable").Tapable; const { Tapable } = require("tapable");
const DllModule = require("./DllModule"); const DllModule = require("./DllModule");
class DllModuleFactory extends Tapable { class DllModuleFactory extends Tapable {
@ -14,7 +14,15 @@ class DllModuleFactory extends Tapable {
} }
create(data, callback) { create(data, callback) {
const dependency = data.dependencies[0]; const dependency = data.dependencies[0];
callback(null, new DllModule(data.context, dependency.dependencies, dependency.name, dependency.type)); callback(
null,
new DllModule(
data.context,
dependency.dependencies,
dependency.name,
dependency.type
)
);
} }
} }

View File

@ -20,12 +20,10 @@ class DllPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => { compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
const itemToPlugin = (item, name) => { const itemToPlugin = (item, name) => {
if(Array.isArray(item)) if (Array.isArray(item)) return new DllEntryPlugin(context, item, name);
return new DllEntryPlugin(context, item, name); else throw new Error("DllPlugin: supply an Array as entry");
else
throw new Error("DllPlugin: supply an Array as entry");
}; };
if(typeof entry === "object" && !Array.isArray(entry)) { if (typeof entry === "object" && !Array.isArray(entry)) {
Object.keys(entry).forEach(name => { Object.keys(entry).forEach(name => {
itemToPlugin(entry[name], name).apply(compiler); itemToPlugin(entry[name], name).apply(compiler);
}); });

View File

@ -20,39 +20,54 @@ class DllReferencePlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("DllReferencePlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "DllReferencePlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory()); DelegatedSourceDependency,
}); normalModuleFactory
);
compiler.hooks.beforeCompile.tapAsync("DllReferencePlugin", (params, callback) => { compilation.dependencyFactories.set(
const manifest = this.options.manifest; DelegatedExportsDependency,
if(typeof manifest === "string") { new NullFactory()
params.compilationDependencies.add(manifest); );
compiler.inputFileSystem.readFile(manifest, (err, result) => {
if(err) return callback(err);
params["dll reference " + manifest] = JSON.parse(result.toString("utf-8"));
return callback();
});
} else {
return callback();
} }
}); );
compiler.hooks.compile.tap("DllReferencePlugin", (params) => { compiler.hooks.beforeCompile.tapAsync(
"DllReferencePlugin",
(params, callback) => {
const manifest = this.options.manifest;
if (typeof manifest === "string") {
params.compilationDependencies.add(manifest);
compiler.inputFileSystem.readFile(manifest, (err, result) => {
if (err) return callback(err);
params["dll reference " + manifest] = JSON.parse(
result.toString("utf-8")
);
return callback();
});
} else {
return callback();
}
}
);
compiler.hooks.compile.tap("DllReferencePlugin", params => {
let manifest = this.options.manifest; let manifest = this.options.manifest;
if(typeof manifest === "string") { if (typeof manifest === "string") {
manifest = params["dll reference " + manifest]; manifest = params["dll reference " + manifest];
} }
const name = this.options.name || manifest.name; const name = this.options.name || manifest.name;
const sourceType = this.options.sourceType || (manifest && manifest.type) || "var"; const sourceType =
this.options.sourceType || (manifest && manifest.type) || "var";
const externals = {}; const externals = {};
const source = "dll-reference " + name; const source = "dll-reference " + name;
externals[source] = name; externals[source] = name;
const normalModuleFactory = params.normalModuleFactory; const normalModuleFactory = params.normalModuleFactory;
new ExternalModuleFactoryPlugin(sourceType, externals).apply(normalModuleFactory); new ExternalModuleFactoryPlugin(sourceType, externals).apply(
normalModuleFactory
);
new DelegatedModuleFactoryPlugin({ new DelegatedModuleFactoryPlugin({
source: source, source: source,
type: this.options.type, type: this.options.type,

View File

@ -17,44 +17,55 @@ class DynamicEntryPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("DynamicEntryPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "DynamicEntryPlugin",
}) => { (compilation, { normalModuleFactory }) => {
const multiModuleFactory = new MultiModuleFactory(); const multiModuleFactory = new MultiModuleFactory();
compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory); MultiEntryDependency,
}); multiModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("DynamicEntryPlugin", (compilation, callback) => { compiler.hooks.make.tapAsync(
const addEntry = (entry, name) => { "DynamicEntryPlugin",
const dep = DynamicEntryPlugin.createDependency(entry, name); (compilation, callback) => {
return new Promise((resolve, reject) => { const addEntry = (entry, name) => {
compilation.addEntry(this.context, dep, name, (err) => { const dep = DynamicEntryPlugin.createDependency(entry, name);
if(err) return reject(err); return new Promise((resolve, reject) => {
resolve(); compilation.addEntry(this.context, dep, name, err => {
if (err) return reject(err);
resolve();
});
}); });
}); };
};
Promise.resolve(this.entry()).then((entry) => { Promise.resolve(this.entry()).then(entry => {
if(typeof entry === "string" || Array.isArray(entry)) { if (typeof entry === "string" || Array.isArray(entry)) {
addEntry(entry, "main").then(() => callback(), callback); addEntry(entry, "main").then(() => callback(), callback);
} else if(typeof entry === "object") { } else if (typeof entry === "object") {
Promise.all(Object.keys(entry).map((name) => { Promise.all(
return addEntry(entry[name], name); Object.keys(entry).map(name => {
})).then(() => callback(), callback); return addEntry(entry[name], name);
} })
}); ).then(() => callback(), callback);
}); }
});
}
);
} }
} }
module.exports = DynamicEntryPlugin; module.exports = DynamicEntryPlugin;
DynamicEntryPlugin.createDependency = (entry, name) => { DynamicEntryPlugin.createDependency = (entry, name) => {
if(Array.isArray(entry)) if (Array.isArray(entry))
return MultiEntryPlugin.createDependency(entry, name); return MultiEntryPlugin.createDependency(entry, name);
else else return SingleEntryPlugin.createDependency(entry, name);
return SingleEntryPlugin.createDependency(entry, name);
}; };

View File

@ -9,7 +9,7 @@ const MultiEntryPlugin = require("./MultiEntryPlugin");
const DynamicEntryPlugin = require("./DynamicEntryPlugin"); const DynamicEntryPlugin = require("./DynamicEntryPlugin");
const itemToPlugin = (context, item, name) => { const itemToPlugin = (context, item, name) => {
if(Array.isArray(item)) { if (Array.isArray(item)) {
return new MultiEntryPlugin(context, item, name); return new MultiEntryPlugin(context, item, name);
} }
return new SingleEntryPlugin(context, item, name); return new SingleEntryPlugin(context, item, name);
@ -18,13 +18,13 @@ const itemToPlugin = (context, item, name) => {
module.exports = class EntryOptionPlugin { module.exports = class EntryOptionPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => { compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => {
if(typeof entry === "string" || Array.isArray(entry)) { if (typeof entry === "string" || Array.isArray(entry)) {
itemToPlugin(context, entry, "main").apply(compiler); itemToPlugin(context, entry, "main").apply(compiler);
} else if(typeof entry === "object") { } else if (typeof entry === "object") {
for(const name of Object.keys(entry)) { for (const name of Object.keys(entry)) {
itemToPlugin(context, entry[name], name).apply(compiler); itemToPlugin(context, entry[name], name).apply(compiler);
} }
} else if(typeof entry === "function") { } else if (typeof entry === "function") {
new DynamicEntryPlugin(context, entry).apply(compiler); new DynamicEntryPlugin(context, entry).apply(compiler);
} }
return true; return true;

View File

@ -19,8 +19,8 @@ class Entrypoint extends ChunkGroup {
getFiles() { getFiles() {
const files = new Set(); const files = new Set();
for(const chunk of this.chunks) { for (const chunk of this.chunks) {
for(const file of chunk.files) { for (const file of chunk.files) {
files.add(file); files.add(file);
} }
} }

View File

@ -7,15 +7,16 @@
const DefinePlugin = require("./DefinePlugin"); const DefinePlugin = require("./DefinePlugin");
const needsEnvVarFix = ["8", "9"].indexOf(process.versions.node.split(".")[0]) >= 0 && const needsEnvVarFix =
["8", "9"].indexOf(process.versions.node.split(".")[0]) >= 0 &&
process.platform === "win32"; process.platform === "win32";
class EnvironmentPlugin { class EnvironmentPlugin {
constructor(...keys) { constructor(...keys) {
if(keys.length === 1 && Array.isArray(keys[0])) { if (keys.length === 1 && Array.isArray(keys[0])) {
this.keys = keys[0]; this.keys = keys[0];
this.defaultValues = {}; this.defaultValues = {};
} else if(keys.length === 1 && keys[0] && typeof keys[0] === "object") { } else if (keys.length === 1 && keys[0] && typeof keys[0] === "object") {
this.keys = Object.keys(keys[0]); this.keys = Object.keys(keys[0]);
this.defaultValues = keys[0]; this.defaultValues = keys[0];
} else { } else {
@ -31,16 +32,21 @@ class EnvironmentPlugin {
// affecting Node 8 & 9 by performing an OS-level // affecting Node 8 & 9 by performing an OS-level
// operation that always succeeds before reading // operation that always succeeds before reading
// environment variables: // environment variables:
if(needsEnvVarFix) require("os").cpus(); if (needsEnvVarFix) require("os").cpus();
const value = process.env[key] !== undefined ? process.env[key] : this.defaultValues[key]; const value =
process.env[key] !== undefined
? process.env[key]
: this.defaultValues[key];
if(value === undefined) { if (value === undefined) {
compiler.hooks.thisCompilation.tap("EnvironmentPlugin", (compilation) => { compiler.hooks.thisCompilation.tap("EnvironmentPlugin", compilation => {
const error = new Error( const error = new Error(
`EnvironmentPlugin - ${key} environment variable is undefined.\n\n` + `EnvironmentPlugin - ${
"You can pass an object with default values to suppress this warning.\n" + key
"See https://webpack.js.org/plugins/environment-plugin for example." } environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example."
); );
error.name = "EnvVariableNotDefinedError"; error.name = "EnvVariableNotDefinedError";
@ -48,7 +54,8 @@ class EnvironmentPlugin {
}); });
} }
defs[`process.env.${key}`] = typeof value === "undefined" ? "undefined" : JSON.stringify(value); defs[`process.env.${key}`] =
typeof value === "undefined" ? "undefined" : JSON.stringify(value);
return defs; return defs;
}, {}); }, {});

View File

@ -10,26 +10,33 @@ const webpackOptionsFlag = "WEBPACK_OPTIONS";
exports.cutOffByFlag = (stack, flag) => { exports.cutOffByFlag = (stack, flag) => {
stack = stack.split("\n"); stack = stack.split("\n");
for(let i = 0; i < stack.length; i++) for (let i = 0; i < stack.length; i++)
if(stack[i].includes(flag)) if (stack[i].includes(flag)) stack.length = i;
stack.length = i;
return stack.join("\n"); return stack.join("\n");
}; };
exports.cutOffLoaderExecution = (stack) => exports.cutOffByFlag(stack, loaderFlag); exports.cutOffLoaderExecution = stack =>
exports.cutOffByFlag(stack, loaderFlag);
exports.cutOffWebpackOptinos = (stack) => exports.cutOffByFlag(stack, webpackOptionsFlag); exports.cutOffWebpackOptions = stack =>
exports.cutOffByFlag(stack, webpackOptionsFlag);
exports.cutOffMultilineMessage = (stack, message) => { exports.cutOffMultilineMessage = (stack, message) => {
stack = stack.split("\n"); stack = stack.split("\n");
message = message.split("\n"); message = message.split("\n");
return stack.reduce((acc, line, idx) => line.includes(message[idx]) ? acc : acc.concat(line), []).join("\n"); return stack
.reduce(
(acc, line, idx) =>
line.includes(message[idx]) ? acc : acc.concat(line),
[]
)
.join("\n");
}; };
exports.cutOffMessage = (stack, message) => { exports.cutOffMessage = (stack, message) => {
const nextLine = stack.indexOf("\n"); const nextLine = stack.indexOf("\n");
if(nextLine === -1) { if (nextLine === -1) {
return stack === message ? "" : stack; return stack === message ? "" : stack;
} else { } else {
const firstLine = stack.substr(0, nextLine); const firstLine = stack.substr(0, nextLine);
@ -44,7 +51,7 @@ exports.cleanUp = (stack, message) => {
}; };
exports.cleanUpWebpackOptions = (stack, message) => { exports.cleanUpWebpackOptions = (stack, message) => {
stack = exports.cutOffWebpackOptinos(stack); stack = exports.cutOffWebpackOptions(stack);
stack = exports.cutOffMultilineMessage(stack, message); stack = exports.cutOffMultilineMessage(stack, message);
return stack; return stack;
}; };

View File

@ -14,7 +14,7 @@ class EvalDevToolModulePlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("EvalDevToolModulePlugin", (compilation) => { compiler.hooks.compilation.tap("EvalDevToolModulePlugin", compilation => {
new EvalDevToolModuleTemplatePlugin({ new EvalDevToolModuleTemplatePlugin({
sourceUrlComment: this.sourceUrlComment, sourceUrlComment: this.sourceUrlComment,
moduleFilenameTemplate: this.moduleFilenameTemplate, moduleFilenameTemplate: this.moduleFilenameTemplate,

View File

@ -4,31 +4,52 @@
*/ */
"use strict"; "use strict";
const RawSource = require("webpack-sources").RawSource; const { RawSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const cache = new WeakMap(); const cache = new WeakMap();
class EvalDevToolModuleTemplatePlugin { class EvalDevToolModuleTemplatePlugin {
constructor(options) { constructor(options) {
this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]"; this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]";
this.moduleFilenameTemplate = options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]?[loaders]"; this.moduleFilenameTemplate =
options.moduleFilenameTemplate ||
"webpack://[namespace]/[resourcePath]?[loaders]";
this.namespace = options.namespace || ""; this.namespace = options.namespace || "";
} }
apply(moduleTemplate) { apply(moduleTemplate) {
moduleTemplate.hooks.module.tap("EvalDevToolModuleTemplatePlugin", (source, module) => { moduleTemplate.hooks.module.tap(
const cacheEntry = cache.get(source); "EvalDevToolModuleTemplatePlugin",
if(cacheEntry !== undefined) return cacheEntry; (source, module) => {
const content = source.source(); const cacheEntry = cache.get(source);
const str = ModuleFilenameHelpers.createFilename(module, { if (cacheEntry !== undefined) return cacheEntry;
moduleFilenameTemplate: this.moduleFilenameTemplate, const content = source.source();
namespace: this.namespace const str = ModuleFilenameHelpers.createFilename(
}, moduleTemplate.runtimeTemplate.requestShortener); module,
const footer = "\n" + this.sourceUrlComment.replace(/\[url\]/g, encodeURI(str).replace(/%2F/g, "/").replace(/%20/g, "_").replace(/%5E/g, "^").replace(/%5C/g, "\\").replace(/^\//, "")); {
const result = new RawSource(`eval(${JSON.stringify(content + footer)});`); moduleFilenameTemplate: this.moduleFilenameTemplate,
cache.set(source, result); namespace: this.namespace
return result; },
}); moduleTemplate.runtimeTemplate.requestShortener
);
const footer =
"\n" +
this.sourceUrlComment.replace(
/\[url\]/g,
encodeURI(str)
.replace(/%2F/g, "/")
.replace(/%20/g, "_")
.replace(/%5E/g, "^")
.replace(/%5C/g, "\\")
.replace(/^\//, "")
);
const result = new RawSource(
`eval(${JSON.stringify(content + footer)});`
);
cache.set(source, result);
return result;
}
);
moduleTemplate.hooks.hash.tap("EvalDevToolModuleTemplatePlugin", hash => { moduleTemplate.hooks.hash.tap("EvalDevToolModuleTemplatePlugin", hash => {
hash.update("EvalDevToolModuleTemplatePlugin"); hash.update("EvalDevToolModuleTemplatePlugin");
hash.update("2"); hash.update("2");

View File

@ -4,14 +4,17 @@
*/ */
"use strict"; "use strict";
const RawSource = require("webpack-sources").RawSource; const { RawSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
class EvalSourceMapDevToolModuleTemplatePlugin { class EvalSourceMapDevToolModuleTemplatePlugin {
constructor(compilation, options) { constructor(compilation, options) {
this.compilation = compilation; this.compilation = compilation;
this.sourceMapComment = options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]"; this.sourceMapComment =
this.moduleFilenameTemplate = options.moduleFilenameTemplate || "webpack://[namespace]/[resource-path]?[hash]"; options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]";
this.moduleFilenameTemplate =
options.moduleFilenameTemplate ||
"webpack://[namespace]/[resource-path]?[hash]";
this.namespace = options.namespace || ""; this.namespace = options.namespace || "";
this.options = options; this.options = options;
} }
@ -19,61 +22,84 @@ class EvalSourceMapDevToolModuleTemplatePlugin {
apply(moduleTemplate) { apply(moduleTemplate) {
const self = this; const self = this;
const options = this.options; const options = this.options;
const matchModule = ModuleFilenameHelpers.matchObject.bind(ModuleFilenameHelpers, options); const matchModule = ModuleFilenameHelpers.matchObject.bind(
moduleTemplate.hooks.module.tap("EvalSourceMapDevToolModuleTemplatePlugin", (source, module) => { ModuleFilenameHelpers,
if(source.__EvalSourceMapDevToolData) options
);
moduleTemplate.hooks.module.tap(
"EvalSourceMapDevToolModuleTemplatePlugin",
(source, module) => {
if (source.__EvalSourceMapDevToolData)
return source.__EvalSourceMapDevToolData;
if (!matchModule(module.resource)) {
return source;
}
let sourceMap;
let content;
if (source.sourceAndMap) {
const sourceAndMap = source.sourceAndMap(options);
sourceMap = sourceAndMap.map;
content = sourceAndMap.source;
} else {
sourceMap = source.map(options);
content = source.source();
}
if (!sourceMap) {
return source;
}
// Clone (flat) the sourcemap to ensure that the mutations below do not persist.
sourceMap = Object.keys(sourceMap).reduce((obj, key) => {
obj[key] = sourceMap[key];
return obj;
}, {});
const modules = sourceMap.sources.map(source => {
const module = self.compilation.findModule(source);
return module || source;
});
let moduleFilenames = modules.map(module => {
return ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: self.moduleFilenameTemplate,
namespace: self.namespace
},
moduleTemplate.runtimeTemplate.requestShortener
);
});
moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(
moduleFilenames,
(filename, i, n) => {
for (let j = 0; j < n; j++) filename += "*";
return filename;
}
);
sourceMap.sources = moduleFilenames;
sourceMap.sourceRoot = options.sourceRoot || "";
sourceMap.file = `${module.id}.js`;
const footer =
self.sourceMapComment.replace(
/\[url\]/g,
`data:application/json;charset=utf-8;base64,${Buffer.from(
JSON.stringify(sourceMap),
"utf8"
).toString("base64")}`
) + `\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug
source.__EvalSourceMapDevToolData = new RawSource(
`eval(${JSON.stringify(content + footer)});`
);
return source.__EvalSourceMapDevToolData; return source.__EvalSourceMapDevToolData;
if(!matchModule(module.resource)) {
return source;
} }
);
let sourceMap; moduleTemplate.hooks.hash.tap(
let content; "EvalSourceMapDevToolModuleTemplatePlugin",
if(source.sourceAndMap) { hash => {
const sourceAndMap = source.sourceAndMap(options); hash.update("eval-source-map");
sourceMap = sourceAndMap.map; hash.update("2");
content = sourceAndMap.source;
} else {
sourceMap = source.map(options);
content = source.source();
} }
if(!sourceMap) { );
return source;
}
// Clone (flat) the sourcemap to ensure that the mutations below do not persist.
sourceMap = Object.keys(sourceMap).reduce((obj, key) => {
obj[key] = sourceMap[key];
return obj;
}, {});
const modules = sourceMap.sources.map(source => {
const module = self.compilation.findModule(source);
return module || source;
});
let moduleFilenames = modules.map(module => {
return ModuleFilenameHelpers.createFilename(module, {
moduleFilenameTemplate: self.moduleFilenameTemplate,
namespace: self.namespace
}, moduleTemplate.runtimeTemplate.requestShortener);
});
moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(moduleFilenames, (filename, i, n) => {
for(let j = 0; j < n; j++)
filename += "*";
return filename;
});
sourceMap.sources = moduleFilenames;
sourceMap.sourceRoot = options.sourceRoot || "";
sourceMap.file = `${module.id}.js`;
const footer = self.sourceMapComment.replace(/\[url\]/g, `data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(sourceMap), "utf8").toString("base64")}`) +
`\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug
source.__EvalSourceMapDevToolData = new RawSource(`eval(${JSON.stringify(content + footer)});`);
return source.__EvalSourceMapDevToolData;
});
moduleTemplate.hooks.hash.tap("EvalSourceMapDevToolModuleTemplatePlugin", hash => {
hash.update("eval-source-map");
hash.update("2");
});
} }
} }
module.exports = EvalSourceMapDevToolModuleTemplatePlugin; module.exports = EvalSourceMapDevToolModuleTemplatePlugin;

View File

@ -9,23 +9,31 @@ const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOpt
class EvalSourceMapDevToolPlugin { class EvalSourceMapDevToolPlugin {
constructor(options) { constructor(options) {
if(arguments.length > 1) if (arguments.length > 1)
throw new Error("EvalSourceMapDevToolPlugin only takes one argument (pass an options object)"); throw new Error(
if(typeof options === "string") { "EvalSourceMapDevToolPlugin only takes one argument (pass an options object)"
);
if (typeof options === "string") {
options = { options = {
append: options append: options
}; };
} }
if(!options) options = {}; if (!options) options = {};
this.options = options; this.options = options;
} }
apply(compiler) { apply(compiler) {
const options = this.options; const options = this.options;
compiler.hooks.compilation.tap("EvalSourceMapDevToolPlugin", (compilation) => { compiler.hooks.compilation.tap(
new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation); "EvalSourceMapDevToolPlugin",
new EvalSourceMapDevToolModuleTemplatePlugin(compilation, options).apply(compilation.moduleTemplates.javascript); compilation => {
}); new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
new EvalSourceMapDevToolModuleTemplatePlugin(
compilation,
options
).apply(compilation.moduleTemplates.javascript);
}
);
} }
} }

View File

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
const ConcatSource = require("webpack-sources").ConcatSource; const { ConcatSource } = require("webpack-sources");
const accessorToObjectAccess = accessor => { const accessorToObjectAccess = accessor => {
return accessor.map(a => `[${JSON.stringify(a)}]`).join(""); return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
@ -16,18 +16,18 @@ class ExportPropertyMainTemplatePlugin {
} }
apply(compilation) { apply(compilation) {
const { const { mainTemplate, chunkTemplate } = compilation;
mainTemplate,
chunkTemplate
} = compilation;
const onRenderWithEntry = (source, chunk, hash) => { const onRenderWithEntry = (source, chunk, hash) => {
const postfix = `${accessorToObjectAccess([].concat(this.property))}`; const postfix = `${accessorToObjectAccess([].concat(this.property))}`;
return new ConcatSource(source, postfix); return new ConcatSource(source, postfix);
}; };
for(const template of [mainTemplate, chunkTemplate]) { for (const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap("ExportPropertyMainTemplatePlugin", onRenderWithEntry); template.hooks.renderWithEntry.tap(
"ExportPropertyMainTemplatePlugin",
onRenderWithEntry
);
} }
mainTemplate.hooks.hash.tap("ExportPropertyMainTemplatePlugin", hash => { mainTemplate.hooks.hash.tap("ExportPropertyMainTemplatePlugin", hash => {

View File

@ -20,36 +20,64 @@ const REPLACEMENT_TYPES = {
class ExtendedAPIPlugin { class ExtendedAPIPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("ExtendedAPIPlugin", (compilation, { compiler.hooks.compilation.tap(
normalModuleFactory "ExtendedAPIPlugin",
}) => { (compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory()); compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template()); compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const mainTemplate = compilation.mainTemplate; const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.requireExtensions.tap("ExtendedAPIPlugin", (source, chunk, hash) => { mainTemplate.hooks.requireExtensions.tap(
const buf = [source]; "ExtendedAPIPlugin",
buf.push(""); (source, chunk, hash) => {
buf.push("// __webpack_hash__"); const buf = [source];
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`); buf.push("");
buf.push(""); buf.push("// __webpack_hash__");
buf.push("// __webpack_chunkname__"); buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push(`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`); buf.push("");
return Template.asString(buf); buf.push("// __webpack_chunkname__");
}); buf.push(
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true); `${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`
);
return Template.asString(buf);
}
);
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true);
const handler = (parser, parserOptions) => { const handler = (parser, parserOptions) => {
Object.keys(REPLACEMENTS).forEach(key => { Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression.for(key).tap("ExtendedAPIPlugin", ParserHelpers.toConstantDependencyWithWebpackRequire(parser, REPLACEMENTS[key])); parser.hooks.expression
parser.hooks.evaluateTypeof.for(key).tap("ExtendedAPIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])); .for(key)
}); .tap(
}; "ExtendedAPIPlugin",
ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
REPLACEMENTS[key]
)
);
parser.hooks.evaluateTypeof
.for(key)
.tap(
"ExtendedAPIPlugin",
ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])
);
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("ExtendedAPIPlugin", handler); normalModuleFactory.hooks.parser
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("ExtendedAPIPlugin", handler); .for("javascript/auto")
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ExtendedAPIPlugin", handler); .tap("ExtendedAPIPlugin", handler);
}); normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("ExtendedAPIPlugin", handler);
}
);
} }
} }

View File

@ -3,9 +3,9 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
"use strict"; "use strict";
const { OriginalSource, RawSource } = require("webpack-sources");
const Module = require("./Module"); const Module = require("./Module");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const WebpackMissingModule = require("./dependencies/WebpackMissingModule"); const WebpackMissingModule = require("./dependencies/WebpackMissingModule");
const Template = require("./Template"); const Template = require("./Template");
@ -48,64 +48,92 @@ class ExternalModule extends Module {
} }
getSourceForGlobalVariableExternal(variableName, type) { getSourceForGlobalVariableExternal(variableName, type) {
if(!Array.isArray(variableName)) { if (!Array.isArray(variableName)) {
// make it an array as the look up works the same basically // make it an array as the look up works the same basically
variableName = [variableName]; variableName = [variableName];
} }
// needed for e.g. window["some"]["thing"] // needed for e.g. window["some"]["thing"]
const objectLookup = variableName.map(r => `[${JSON.stringify(r)}]`).join(""); const objectLookup = variableName
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `(function() { module.exports = ${type}${objectLookup}; }());`; return `(function() { module.exports = ${type}${objectLookup}; }());`;
} }
getSourceForCommonJsExternal(moduleAndSpecifiers) { getSourceForCommonJsExternal(moduleAndSpecifiers) {
if(!Array.isArray(moduleAndSpecifiers)) { if (!Array.isArray(moduleAndSpecifiers)) {
return `module.exports = require(${JSON.stringify(moduleAndSpecifiers)});`; return `module.exports = require(${JSON.stringify(
moduleAndSpecifiers
)});`;
} }
const moduleName = moduleAndSpecifiers[0]; const moduleName = moduleAndSpecifiers[0];
const objectLookup = moduleAndSpecifiers.slice(1).map(r => `[${JSON.stringify(r)}]`).join(""); const objectLookup = moduleAndSpecifiers
.slice(1)
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `module.exports = require(${moduleName})${objectLookup};`; return `module.exports = require(${moduleName})${objectLookup};`;
} }
checkExternalVariable(variableToCheck, request) { checkExternalVariable(variableToCheck, request) {
return `if(typeof ${variableToCheck} === 'undefined') {${WebpackMissingModule.moduleCode(request)}}\n`; return `if(typeof ${
variableToCheck
} === 'undefined') {${WebpackMissingModule.moduleCode(request)}}\n`;
} }
getSourceForAmdOrUmdExternal(id, optional, request) { getSourceForAmdOrUmdExternal(id, optional, request) {
const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${id}`)}__`; const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
const missingModuleError = optional ? this.checkExternalVariable(externalVariable, request) : ""; `${id}`
)}__`;
const missingModuleError = optional
? this.checkExternalVariable(externalVariable, request)
: "";
return `${missingModuleError}module.exports = ${externalVariable};`; return `${missingModuleError}module.exports = ${externalVariable};`;
} }
getSourceForDefaultCase(optional, request) { getSourceForDefaultCase(optional, request) {
const missingModuleError = optional ? this.checkExternalVariable(request, request) : ""; const missingModuleError = optional
? this.checkExternalVariable(request, request)
: "";
return `${missingModuleError}module.exports = ${request};`; return `${missingModuleError}module.exports = ${request};`;
} }
getSourceString(runtime) { getSourceString(runtime) {
const request = typeof this.request === "object" ? this.request[this.externalType] : this.request; const request =
switch(this.externalType) { typeof this.request === "object"
? this.request[this.externalType]
: this.request;
switch (this.externalType) {
case "this": case "this":
case "window": case "window":
case "self": case "self":
return this.getSourceForGlobalVariableExternal(request, this.externalType); return this.getSourceForGlobalVariableExternal(
request,
this.externalType
);
case "global": case "global":
return this.getSourceForGlobalVariableExternal(runtime.outputOptions.globalObject, this.externalType); return this.getSourceForGlobalVariableExternal(
runtime.outputOptions.globalObject,
this.externalType
);
case "commonjs": case "commonjs":
case "commonjs2": case "commonjs2":
return this.getSourceForCommonJsExternal(request); return this.getSourceForCommonJsExternal(request);
case "amd": case "amd":
case "umd": case "umd":
case "umd2": case "umd2":
return this.getSourceForAmdOrUmdExternal(this.id, this.optional, request); return this.getSourceForAmdOrUmdExternal(
this.id,
this.optional,
request
);
default: default:
return this.getSourceForDefaultCase(this.optional, request); return this.getSourceForDefaultCase(this.optional, request);
} }
} }
getSource(sourceString) { getSource(sourceString) {
if(this.useSourceMap) { if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier()); return new OriginalSource(sourceString, this.identifier());
} }
@ -113,9 +141,7 @@ class ExternalModule extends Module {
} }
source(dependencyTemplates, runtime) { source(dependencyTemplates, runtime) {
return this.getSource( return this.getSource(this.getSourceString(runtime));
this.getSourceString(runtime)
);
} }
size() { size() {

View File

@ -14,83 +14,97 @@ class ExternalModuleFactoryPlugin {
apply(normalModuleFactory) { apply(normalModuleFactory) {
const globalType = this.type; const globalType = this.type;
normalModuleFactory.hooks.factory.tap("ExternalModuleFactoryPlugin", factory => (data, callback) => { normalModuleFactory.hooks.factory.tap(
const context = data.context; "ExternalModuleFactoryPlugin",
const dependency = data.dependencies[0]; factory => (data, callback) => {
const context = data.context;
const dependency = data.dependencies[0];
const handleExternal = (value, type, callback) => { const handleExternal = (value, type, callback) => {
if(typeof type === "function") { if (typeof type === "function") {
callback = type; callback = type;
type = undefined; type = undefined;
}
if(value === false) return factory(data, callback);
if(value === true) value = dependency.request;
if(typeof type === "undefined" && /^[a-z0-9]+ /.test(value)) {
const idx = value.indexOf(" ");
type = value.substr(0, idx);
value = value.substr(idx + 1);
}
callback(null, new ExternalModule(value, type || globalType, dependency.request));
return true;
};
const handleExternals = (externals, callback) => {
if(typeof externals === "string") {
if(externals === dependency.request) {
return handleExternal(dependency.request, callback);
} }
} else if(Array.isArray(externals)) { if (value === false) return factory(data, callback);
let i = 0; if (value === true) value = dependency.request;
const next = () => { if (typeof type === "undefined" && /^[a-z0-9]+ /.test(value)) {
let asyncFlag; const idx = value.indexOf(" ");
const handleExternalsAndCallback = (err, module) => { type = value.substr(0, idx);
if(err) return callback(err); value = value.substr(idx + 1);
if(!module) { }
if(asyncFlag) { callback(
asyncFlag = false; null,
return; new ExternalModule(value, type || globalType, dependency.request)
);
return true;
};
const handleExternals = (externals, callback) => {
if (typeof externals === "string") {
if (externals === dependency.request) {
return handleExternal(dependency.request, callback);
}
} else if (Array.isArray(externals)) {
let i = 0;
const next = () => {
let asyncFlag;
const handleExternalsAndCallback = (err, module) => {
if (err) return callback(err);
if (!module) {
if (asyncFlag) {
asyncFlag = false;
return;
}
return next();
} }
return next(); callback(null, module);
} };
callback(null, module);
do {
asyncFlag = true;
if (i >= externals.length) return callback();
handleExternals(externals[i++], handleExternalsAndCallback);
} while (!asyncFlag); // eslint-disable-line keyword-spacing
asyncFlag = false;
}; };
do { next();
asyncFlag = true; return;
if(i >= externals.length) return callback(); } else if (externals instanceof RegExp) {
handleExternals(externals[i++], handleExternalsAndCallback); if (externals.test(dependency.request)) {
} while (!asyncFlag); // eslint-disable-line keyword-spacing return handleExternal(dependency.request, callback);
asyncFlag = false;
};
next();
return;
} else if(externals instanceof RegExp) {
if(externals.test(dependency.request)) {
return handleExternal(dependency.request, callback);
}
} else if(typeof externals === "function") {
externals.call(null, context, dependency.request, (err, value, type) => {
if(err) return callback(err);
if(typeof value !== "undefined") {
handleExternal(value, type, callback);
} else {
callback();
} }
}); } else if (typeof externals === "function") {
return; externals.call(
} else if(typeof externals === "object" && Object.prototype.hasOwnProperty.call(externals, dependency.request)) { null,
return handleExternal(externals[dependency.request], callback); context,
} dependency.request,
callback(); (err, value, type) => {
}; if (err) return callback(err);
if (typeof value !== "undefined") {
handleExternal(value, type, callback);
} else {
callback();
}
}
);
return;
} else if (
typeof externals === "object" &&
Object.prototype.hasOwnProperty.call(externals, dependency.request)
) {
return handleExternal(externals[dependency.request], callback);
}
callback();
};
handleExternals(this.externals, (err, module) => { handleExternals(this.externals, (err, module) => {
if(err) return callback(err); if (err) return callback(err);
if(!module) return handleExternal(false, callback); if (!module) return handleExternal(false, callback);
return callback(null, module); return callback(null, module);
}); });
}); }
);
} }
} }
module.exports = ExternalModuleFactoryPlugin; module.exports = ExternalModuleFactoryPlugin;

View File

@ -12,10 +12,10 @@ class ExternalsPlugin {
this.externals = externals; this.externals = externals;
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compile.tap("ExternalsPlugin", ({ compiler.hooks.compile.tap("ExternalsPlugin", ({ normalModuleFactory }) => {
normalModuleFactory new ExternalModuleFactoryPlugin(this.type, this.externals).apply(
}) => { normalModuleFactory
new ExternalModuleFactoryPlugin(this.type, this.externals).apply(normalModuleFactory); );
}); });
} }
} }

View File

@ -8,8 +8,8 @@ const Queue = require("./util/Queue");
const addToSet = (a, b) => { const addToSet = (a, b) => {
let changed = false; let changed = false;
for(const item of b) { for (const item of b) {
if(!a.has(item)) { if (!a.has(item)) {
a.add(item); a.add(item);
changed = true; changed = true;
} }
@ -18,113 +18,128 @@ const addToSet = (a, b) => {
}; };
class FlagDependencyExportsPlugin { class FlagDependencyExportsPlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyExportsPlugin", (compilation) => { compiler.hooks.compilation.tap(
compilation.hooks.finishModules.tap("FlagDependencyExportsPlugin", (modules) => { "FlagDependencyExportsPlugin",
const dependencies = new Map(); compilation => {
compilation.hooks.finishModules.tap(
"FlagDependencyExportsPlugin",
modules => {
const dependencies = new Map();
const queue = new Queue(); const queue = new Queue();
let module; let module;
let moduleWithExports; let moduleWithExports;
let moduleProvidedExports; let moduleProvidedExports;
const processDependenciesBlock = depBlock => { const processDependenciesBlock = depBlock => {
for(const dep of depBlock.dependencies) { for (const dep of depBlock.dependencies) {
if(processDependency(dep)) if (processDependency(dep)) return true;
return true; }
} for (const variable of depBlock.variables) {
for(const variable of depBlock.variables) { for (const dep of variable.dependencies) {
for(const dep of variable.dependencies) { if (processDependency(dep)) return true;
if(processDependency(dep)) }
}
for (const block of depBlock.blocks) {
if (processDependenciesBlock(block)) return true;
}
return false;
};
const processDependency = dep => {
const exportDesc = dep.getExports && dep.getExports();
if (!exportDesc) return;
moduleWithExports = true;
const exports = exportDesc.exports;
// break early if it's only in the worst state
if (module.buildMeta.providedExports === true) {
return true; return true;
} }
} // break if it should move to the worst state
for(const block of depBlock.blocks) { if (exports === true) {
if(processDependenciesBlock(block)) module.buildMeta.providedExports = true;
return true; notifyDependencies();
} return true;
return false; }
}; // merge in new exports
if (Array.isArray(exports)) {
if (addToSet(moduleProvidedExports, exports)) {
notifyDependencies();
}
}
// store dependencies
const exportDeps = exportDesc.dependencies;
if (exportDeps) {
for (const exportDependency of exportDeps) {
// add dependency for this module
const set = dependencies.get(exportDependency);
if (set === undefined) {
dependencies.set(exportDependency, new Set([module]));
} else {
set.add(module);
}
}
}
return false;
};
const processDependency = dep => { const notifyDependencies = () => {
const exportDesc = dep.getExports && dep.getExports(); const deps = dependencies.get(module);
if(!exportDesc) return; if (deps !== undefined) {
moduleWithExports = true; for (const dep of deps) {
const exports = exportDesc.exports; queue.enqueue(dep);
// break early if it's only in the worst state }
if(module.buildMeta.providedExports === true) { }
return true; };
}
// break if it should move to the worst state // Start with all modules without provided exports
if(exports === true) { for (const module of modules) {
module.buildMeta.providedExports = true; if (!module.buildMeta.providedExports) {
notifyDependencies(); queue.enqueue(module);
return true; }
}
// merge in new exports
if(Array.isArray(exports)) {
if(addToSet(moduleProvidedExports, exports)) {
notifyDependencies();
} }
}
// store dependencies while (queue.length > 0) {
const exportDeps = exportDesc.dependencies; module = queue.dequeue();
if(exportDeps) {
for(const exportDependency of exportDeps) { if (module.buildMeta.providedExports !== true) {
// add dependency for this module moduleWithExports =
const set = dependencies.get(exportDependency); module.buildMeta && module.buildMeta.exportsType;
if(set === undefined) { moduleProvidedExports = Array.isArray(
dependencies.set(exportDependency, new Set([module])); module.buildMeta.providedExports
} else { )
set.add(module); ? new Set(module.buildMeta.providedExports)
: new Set();
processDependenciesBlock(module);
if (!moduleWithExports) {
module.buildMeta.providedExports = true;
notifyDependencies();
} else if (module.buildMeta.providedExports !== true) {
module.buildMeta.providedExports = Array.from(
moduleProvidedExports
);
}
} }
} }
} }
return false; );
}; const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap(
const notifyDependencies = () => { "FlagDependencyExportsPlugin",
const deps = dependencies.get(module); module => {
if(deps !== undefined) { providedExportsCache.set(module, module.buildMeta.providedExports);
for(const dep of deps) {
queue.enqueue(dep);
}
} }
}; );
compilation.hooks.finishRebuildingModule.tap(
// Start with all modules without provided exports "FlagDependencyExportsPlugin",
for(const module of modules) { module => {
if(!module.buildMeta.providedExports) { module.buildMeta.providedExports = providedExportsCache.get(module);
queue.enqueue(module);
} }
} );
}
while(queue.length > 0) { );
module = queue.dequeue();
if(module.buildMeta.providedExports !== true) {
moduleWithExports = module.buildMeta && module.buildMeta.exportsType;
moduleProvidedExports = Array.isArray(module.buildMeta.providedExports) ? new Set(module.buildMeta.providedExports) : new Set();
processDependenciesBlock(module);
if(!moduleWithExports) {
module.buildMeta.providedExports = true;
notifyDependencies();
} else if(module.buildMeta.providedExports !== true) {
module.buildMeta.providedExports = Array.from(moduleProvidedExports);
}
}
}
});
const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap("FlagDependencyExportsPlugin", module => {
providedExportsCache.set(module, module.buildMeta.providedExports);
});
compilation.hooks.finishRebuildingModule.tap("FlagDependencyExportsPlugin", module => {
module.buildMeta.providedExports = providedExportsCache.get(module);
});
});
} }
} }

View File

@ -5,92 +5,99 @@
"use strict"; "use strict";
const addToSet = (a, b) => { const addToSet = (a, b) => {
for(const item of b) { for (const item of b) {
if(!a.includes(item)) if (!a.includes(item)) a.push(item);
a.push(item);
} }
return a; return a;
}; };
const isSubset = (biggerSet, subset) => { const isSubset = (biggerSet, subset) => {
if(biggerSet === true) return true; if (biggerSet === true) return true;
if(subset === true) return false; if (subset === true) return false;
return subset.every(item => biggerSet.indexOf(item) >= 0); return subset.every(item => biggerSet.indexOf(item) >= 0);
}; };
class FlagDependencyUsagePlugin { class FlagDependencyUsagePlugin {
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", (compilation) => { compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => {
compilation.hooks.optimizeModulesAdvanced.tap("FlagDependencyUsagePlugin", (modules) => { compilation.hooks.optimizeModulesAdvanced.tap(
"FlagDependencyUsagePlugin",
modules => {
const processModule = (module, usedExports) => {
module.used = true;
if (module.usedExports === true) return;
else if (usedExports === true) module.usedExports = true;
else if (Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(
module.usedExports || [],
usedExports
);
if (module.usedExports.length === old) return;
} else if (Array.isArray(module.usedExports)) return;
else module.usedExports = false;
const processModule = (module, usedExports) => { // for a module without side effects we stop tracking usage here when no export is used
module.used = true; // This module won't be evaluated in this case
if(module.usedExports === true) if (module.factoryMeta.sideEffectFree) {
return; if (module.usedExports === false) return;
else if(usedExports === true) if (
module.usedExports = true; Array.isArray(module.usedExports) &&
else if(Array.isArray(usedExports)) { module.usedExports.length === 0
const old = module.usedExports ? module.usedExports.length : -1; )
module.usedExports = addToSet(module.usedExports || [], usedExports); return;
if(module.usedExports.length === old) }
return;
} else if(Array.isArray(module.usedExports))
return;
else
module.usedExports = false;
// for a module without side effects we stop tracking usage here when no export is used queue.push([module, module.usedExports]);
// This module won't be evaluated in this case };
if(module.factoryMeta.sideEffectFree) {
if(module.usedExports === false) return;
if(Array.isArray(module.usedExports) && module.usedExports.length === 0) return;
}
queue.push([module, module.usedExports]); const processDependenciesBlock = (depBlock, usedExports) => {
}; for (const dep of depBlock.dependencies) {
const processDependenciesBlock = (depBlock, usedExports) => {
for(const dep of depBlock.dependencies) {
processDependency(dep);
}
for(const variable of depBlock.variables) {
for(const dep of variable.dependencies) {
processDependency(dep); processDependency(dep);
} }
} for (const variable of depBlock.variables) {
for(const block of depBlock.blocks) { for (const dep of variable.dependencies) {
queue.push([block, usedExports]); processDependency(dep);
} }
}; }
for (const block of depBlock.blocks) {
queue.push([block, usedExports]);
}
};
const processDependency = dep => { const processDependency = dep => {
const reference = dep.getReference && dep.getReference(); const reference = dep.getReference && dep.getReference();
if(!reference) return; if (!reference) return;
const module = reference.module; const module = reference.module;
const importedNames = reference.importedNames; const importedNames = reference.importedNames;
const oldUsed = module.used; const oldUsed = module.used;
const oldUsedExports = module.usedExports; const oldUsedExports = module.usedExports;
if(!oldUsed || (importedNames && (!oldUsedExports || !isSubset(oldUsedExports, importedNames)))) { if (
processModule(module, importedNames); !oldUsed ||
(importedNames &&
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
) {
processModule(module, importedNames);
}
};
for (const module of modules) {
module.used = false;
} }
};
for(const module of modules) { const queue = [];
module.used = false; for (const chunk of compilation.chunks) {
} if (chunk.entryModule) {
processModule(chunk.entryModule, true);
}
}
const queue = []; while (queue.length) {
for(const chunk of compilation.chunks) { const queueItem = queue.pop();
if(chunk.entryModule) { processDependenciesBlock(queueItem[0], queueItem[1]);
processModule(chunk.entryModule, true);
} }
} }
);
while(queue.length) {
const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]);
}
});
}); });
} }
} }

View File

@ -10,20 +10,26 @@ class FlagInitialModulesAsUsedPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("FlagInitialModulesAsUsedPlugin", (compilation) => { compiler.hooks.compilation.tap(
compilation.hooks.afterOptimizeChunks.tap("FlagInitialModulesAsUsedPlugin", (chunks) => { "FlagInitialModulesAsUsedPlugin",
for(const chunk of chunks) { compilation => {
if(!chunk.isOnlyInitial()) { compilation.hooks.afterOptimizeChunks.tap(
return; "FlagInitialModulesAsUsedPlugin",
chunks => {
for (const chunk of chunks) {
if (!chunk.isOnlyInitial()) {
return;
}
for (const module of chunk.modulesIterable) {
module.used = true;
module.usedExports = true;
module.addReason(null, null, this.explanation);
}
}
} }
for(const module of chunk.modulesIterable) { );
module.used = true; }
module.usedExports = true; );
module.addReason(null, null, this.explanation);
}
}
});
});
} }
} }

View File

@ -12,8 +12,10 @@ class FunctionModulePlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("FunctionModulePlugin", (compilation) => { compiler.hooks.compilation.tap("FunctionModulePlugin", compilation => {
new FunctionModuleTemplatePlugin().apply(compilation.moduleTemplates.javascript); new FunctionModuleTemplatePlugin().apply(
compilation.moduleTemplates.javascript
);
}); });
} }
} }

View File

@ -4,67 +4,90 @@
*/ */
"use strict"; "use strict";
const ConcatSource = require("webpack-sources").ConcatSource; const { ConcatSource } = require("webpack-sources");
const Template = require("./Template"); const Template = require("./Template");
class FunctionModuleTemplatePlugin { class FunctionModuleTemplatePlugin {
apply(moduleTemplate) { apply(moduleTemplate) {
moduleTemplate.hooks.render.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => { moduleTemplate.hooks.render.tap(
const source = new ConcatSource(); "FunctionModuleTemplatePlugin",
const args = [module.moduleArgument]; (moduleSource, module) => {
// TODO remove HACK checking type for javascript
if(module.type && module.type.startsWith("javascript")) {
args.push(module.exportsArgument);
if(module.hasDependencies(d => d.requireWebpackRequire !== false)) {
args.push("__webpack_require__");
}
} else if(module.type && module.type.startsWith("json")) {
// no additional arguments needed
} else {
args.push(module.exportsArgument, "__webpack_require__");
}
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
if(module.buildInfo.strict) source.add("\"use strict\";\n");
source.add(moduleSource);
source.add("\n\n/***/ })");
return source;
});
moduleTemplate.hooks.package.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => {
if(moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
const source = new ConcatSource(); const source = new ConcatSource();
const req = module.readableIdentifier(moduleTemplate.runtimeTemplate.requestShortener); const args = [module.moduleArgument];
source.add("/*!****" + req.replace(/./g, "*") + "****!*\\\n"); // TODO remove HACK checking type for javascript
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n"); if (module.type && module.type.startsWith("javascript")) {
source.add(" \\****" + req.replace(/./g, "*") + "****/\n"); args.push(module.exportsArgument);
if(Array.isArray(module.buildMeta.providedExports) && module.buildMeta.providedExports.length === 0) if (module.hasDependencies(d => d.requireWebpackRequire !== false)) {
source.add(Template.toComment("no exports provided") + "\n"); args.push("__webpack_require__");
else if(Array.isArray(module.buildMeta.providedExports))
source.add(Template.toComment("exports provided: " + module.buildMeta.providedExports.join(", ")) + "\n");
else if(module.buildMeta.providedExports)
source.add(Template.toComment("no static exports found") + "\n");
if(Array.isArray(module.usedExports) && module.usedExports.length === 0)
source.add(Template.toComment("no exports used") + "\n");
else if(Array.isArray(module.usedExports))
source.add(Template.toComment("exports used: " + module.usedExports.join(", ")) + "\n");
else if(module.usedExports)
source.add(Template.toComment("all exports used") + "\n");
if(module.optimizationBailout) {
for(const text of module.optimizationBailout) {
let code;
if(typeof text === "function") {
code = text(moduleTemplate.runtimeTemplate.requestShortener);
} else {
code = text;
}
source.add(Template.toComment(`${code}`) + "\n");
} }
} else if (module.type && module.type.startsWith("json")) {
// no additional arguments needed
} else {
args.push(module.exportsArgument, "__webpack_require__");
} }
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSource); source.add(moduleSource);
source.add("\n\n/***/ })");
return source; return source;
} }
return moduleSource; );
});
moduleTemplate.hooks.package.tap(
"FunctionModuleTemplatePlugin",
(moduleSource, module) => {
if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
const source = new ConcatSource();
const req = module.readableIdentifier(
moduleTemplate.runtimeTemplate.requestShortener
);
source.add("/*!****" + req.replace(/./g, "*") + "****!*\\\n");
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
if (
Array.isArray(module.buildMeta.providedExports) &&
module.buildMeta.providedExports.length === 0
)
source.add(Template.toComment("no exports provided") + "\n");
else if (Array.isArray(module.buildMeta.providedExports))
source.add(
Template.toComment(
"exports provided: " +
module.buildMeta.providedExports.join(", ")
) + "\n"
);
else if (module.buildMeta.providedExports)
source.add(Template.toComment("no static exports found") + "\n");
if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
source.add(Template.toComment("no exports used") + "\n");
else if (Array.isArray(module.usedExports))
source.add(
Template.toComment(
"exports used: " + module.usedExports.join(", ")
) + "\n"
);
else if (module.usedExports)
source.add(Template.toComment("all exports used") + "\n");
if (module.optimizationBailout) {
for (const text of module.optimizationBailout) {
let code;
if (typeof text === "function") {
code = text(moduleTemplate.runtimeTemplate.requestShortener);
} else {
code = text;
}
source.add(Template.toComment(`${code}`) + "\n");
}
}
source.add(moduleSource);
return source;
}
return moduleSource;
}
);
moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => { moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => {
hash.update("FunctionModuleTemplatePlugin"); hash.update("FunctionModuleTemplatePlugin");

Some files were not shown because too many files have changed in this diff Show More