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>

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

@ -12,7 +12,9 @@ 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

@ -10,8 +10,7 @@ try {
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

@ -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

@ -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$/, test: /\.coffee$/,
loader: "coffee-loader" 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$/, test: /\.css$/,
loader: "css-loader" 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

@ -9,10 +9,10 @@ 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

@ -9,10 +9,10 @@ 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$/, test: /\.wasm$/,
type: "webassembly/experimental" 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

@ -10,10 +10,15 @@ if(module.hot) {
}; };
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
.check(true)
.then(function(updatedModules) {
if (!updatedModules) { if (!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!"); log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)"); log(
"warning",
"[HMR] (Probably because of restarting the webpack-dev-server)"
);
window.location.reload(); window.location.reload();
return; return;
} }
@ -27,11 +32,14 @@ if(module.hot) {
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(
"warning",
"[HMR] Cannot apply update. Need to do a full reload!"
);
log("warning", "[HMR] " + err.stack || err.message); log("warning", "[HMR] " + err.stack || err.message);
window.location.reload(); window.location.reload();
} else { } else {

View File

@ -9,7 +9,10 @@ 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);
}); });
@ -33,6 +36,9 @@ module.exports = function(updatedModules, renewedModules) {
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;

View File

@ -10,28 +10,50 @@ if(module.hot) {
}; };
var log = require("./log"); var log = require("./log");
var check = function check() { var check = function check() {
module.hot.check().then(function(updatedModules) { module.hot
.check()
.then(function(updatedModules) {
if (!updatedModules) { if (!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!"); log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)"); log(
"warning",
"[HMR] (Probably because of restarting the webpack-dev-server)"
);
return; return;
} }
return module.hot.apply({ return module.hot
.apply({
ignoreUnaccepted: true, ignoreUnaccepted: true,
ignoreDeclined: true, ignoreDeclined: true,
ignoreErrored: true, ignoreErrored: true,
onUnaccepted: function(data) { onUnaccepted: function(data) {
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> ")); log(
"warning",
"Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
}, },
onDeclined: function(data) { onDeclined: function(data) {
log("warning", "Ignored an update to declined module " + data.chain.join(" -> ")); log(
"warning",
"Ignored an update to declined module " +
data.chain.join(" -> ")
);
}, },
onErrored: function(data) { onErrored: function(data) {
log("error", data.error); log("error", data.error);
log("warning", "Ignored an error while updating module " + data.moduleId + " (" + data.type + ")"); log(
"warning",
"Ignored an error while updating module " +
data.moduleId +
" (" +
data.type +
")"
);
} }
}).then(function(renewedModules) { })
.then(function(renewedModules) {
if (!upToDate()) { if (!upToDate()) {
check(); check();
} }
@ -42,13 +64,20 @@ if(module.hot) {
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 check for update. Need to do a full reload!"); log(
"warning",
"[HMR] Cannot check for update. Need to do a full reload!"
);
log("warning", "[HMR] " + err.stack || err.message); log("warning", "[HMR] " + err.stack || err.message);
} else { } else {
log("warning", "[HMR] Update check failed: " + err.stack || err.message); log(
"warning",
"[HMR] Update check failed: " + err.stack || err.message
);
} }
}); });
}; };
@ -61,7 +90,12 @@ if(module.hot) {
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

@ -4,19 +4,22 @@
*/ */
/*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
.check(true)
.then(function(updatedModules) {
if (!updatedModules) { if (!updatedModules) {
if (fromUpdate) log("info", "[HMR] Update applied."); if (fromUpdate) log("info", "[HMR] Update applied.");
return; return;
} }
require("./log-apply-result")(updatedModules, updatedModules); require("./log-apply-result")(updatedModules, updatedModules);
checkForUpdate(true); checkForUpdate(true);
}).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."); log("warning", "[HMR] Cannot apply update.");

View File

@ -6,27 +6,34 @@
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
.check()
.then(function(updatedModules) {
if (!updatedModules) { if (!updatedModules) {
if(fromUpdate) if (fromUpdate) log("info", "[HMR] Update applied.");
log("info", "[HMR] Update applied."); else log("warning", "[HMR] Cannot find update.");
else
log("warning", "[HMR] Cannot find update.");
return; return;
} }
return module.hot.apply({ return module.hot
.apply({
ignoreUnaccepted: true, ignoreUnaccepted: true,
onUnaccepted: function(data) { onUnaccepted: function(data) {
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> ")); log(
}, "warning",
}).then(function(renewedModules) { "Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
}
})
.then(function(renewedModules) {
require("./log-apply-result")(updatedModules, renewedModules); require("./log-apply-result")(updatedModules, renewedModules);
checkForUpdate(true); checkForUpdate(true);
return null; return null;
}); });
}).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."); log("warning", "[HMR] Cannot apply update.");
@ -40,7 +47,10 @@ if(module.hot) {
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,19 +14,20 @@ 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, {
@ -35,17 +36,30 @@ class AmdMainTemplatePlugin {
}); });
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) { } else if (externalsArguments) {
return new ConcatSource(`define(${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});"); 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 => {

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(
(this.chunkGroup &&
this.chunkGroup.chunks
.map(chunk => {
return chunk.id !== null ? chunk.id : ""; return chunk.id !== null ? chunk.id : "";
}).join(",") || ""); })
.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(
"AutomaticPrefetchPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
PrefetchDependency,
normalModuleFactory 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(
"AutomaticPrefetchPlugin",
(compilation, callback) => {
if (!lastModules) return callback(); if (!lastModules) return callback();
asyncLib.forEach(lastModules, (m, callback) => { asyncLib.forEach(
compilation.prefetch(m.context || compiler.context, new PrefetchDependency(m.request), callback); lastModules,
}, callback); (m, callback) => {
}); compilation.prefetch(
m.context || compiler.context,
new PrefetchDependency(m.request),
callback
);
},
callback
);
}
);
} }
} }
module.exports = AutomaticPrefetchPlugin; module.exports = AutomaticPrefetchPlugin;

View File

@ -5,22 +5,27 @@
"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");
@ -29,16 +34,21 @@ class BannerPlugin {
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;
@ -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;
@ -99,7 +98,11 @@ class BasicEvaluatedExpression {
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())
return (this.prefix && this.prefix.asBool()) ||
(this.postfix && this.postfix.asBool())
? true
: undefined;
else if (this.isTemplateString()) { else if (this.isTemplateString()) {
for (const quasi of this.quasis) { for (const quasi of this.quasis) {
if (quasi.asBool()) return true; if (quasi.asBool()) return true;
@ -162,8 +165,7 @@ class BasicEvaluatedExpression {
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

@ -15,24 +15,27 @@ 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(
"CachePlugin",
(childCompiler, compilerName, compilerIndex) => {
if (cache) { if (cache) {
let childCache; let childCache;
if (!cache.children) cache.children = {}; if (!cache.children) cache.children = {};
if(!cache.children[compilerName]) cache.children[compilerName] = []; if (!cache.children[compilerName])
cache.children[compilerName] = [];
if (cache.children[compilerName][compilerIndex]) if (cache.children[compilerName][compilerIndex])
childCache = cache.children[compilerName][compilerIndex]; childCache = cache.children[compilerName][compilerIndex];
else else cache.children[compilerName].push((childCache = {}));
cache.children[compilerName].push(childCache = {});
registerCacheToCompiler(childCompiler, childCache); registerCacheToCompiler(childCompiler, childCache);
} }
}); }
);
}); });
}; };
registerCacheToCompiler(compiler, this.cache); registerCacheToCompiler(compiler, this.cache);
@ -42,22 +45,24 @@ class CachePlugin {
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(
compiler._lastCompilationFileDependencies,
(file, callback) => {
fs.stat(file, (err, stat) => { fs.stat(file, (err, stat) => {
if (err) { if (err) {
if (err.code === "ENOENT") return callback(); if (err.code === "ENOENT") return callback();
return callback(err); return callback(err);
} }
if(stat.mtime) if (stat.mtime) this.applyMtime(+stat.mtime);
this.applyMtime(+stat.mtime);
fileTs.set(file, +stat.mtime || Infinity); fileTs.set(file, +stat.mtime || Infinity);
callback(); callback();
}); });
}, err => { },
err => {
if (err) return callback(err); if (err) return callback(err);
for (const [file, ts] of fileTs) { for (const [file, ts] of fileTs) {
@ -65,21 +70,22 @@ class CachePlugin {
} }
callback(); 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)
this.FS_ACCURACY = 10;
else if (this.FS_ACCURACY > 100 && mtime % 200 !== 0) 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)

View File

@ -37,15 +37,17 @@ ${modulesList}`;
} }
_moduleMessages(modules) { _moduleMessages(modules) {
return modules.map((m) => { return modules
.map(m => {
let message = `* ${m.identifier()}`; let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter((reason) => reason.module); 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,7 +9,8 @@ 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;
@ -43,7 +44,6 @@ const getModulesSize = set => {
}; };
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;
@ -86,8 +87,7 @@ 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;
} }
@ -95,8 +95,7 @@ class Chunk {
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;
} }
@ -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;
} }
@ -166,7 +163,8 @@ class Chunk {
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;
@ -225,7 +223,10 @@ class Chunk {
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;
} }
@ -259,8 +260,7 @@ class Chunk {
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;
}; };
@ -273,14 +273,16 @@ class Chunk {
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;
} }
@ -324,17 +326,14 @@ class Chunk {
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
}; };
} }
@ -393,13 +398,11 @@ class 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

@ -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() {
@ -218,8 +217,7 @@ 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;
} }
@ -247,7 +245,7 @@ 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"
@ -275,11 +273,19 @@ class ChunkGroup {
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,20 +9,28 @@ 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")
if(typeof parserOptions.browserify !== "undefined" && !parserOptions.browserify) .tap("CompatibilityPlugin", (parser, parserOptions) => {
if (
typeof parserOptions.browserify !== "undefined" &&
!parserOptions.browserify
)
return; return;
parser.hooks.call.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]);
@ -31,15 +39,25 @@ class CompatibilityPlugin {
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 = parser.state.current.dependencies[parser.state.current.dependencies.length - 1]; const last =
if(last.critical && last.options && last.options.request === "." && last.userRequest === "." && last.options.recursive) parser.state.current.dependencies[
parser.state.current.dependencies.length - 1
];
if (
last.critical &&
last.options &&
last.options.request === "." &&
last.userRequest === "." &&
last.options.recursive
)
parser.state.current.dependencies.pop(); parser.state.current.dependencies.pop();
} }
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
return true; return true;
}); });
}); });
}); }
);
} }
} }
module.exports = CompatibilityPlugin; module.exports = CompatibilityPlugin;

View File

@ -6,11 +6,14 @@
const asyncLib = require("neo-async"); const asyncLib = require("neo-async");
const util = require("util"); const util = require("util");
const Tapable = require("tapable").Tapable; const { CachedSource } = require("webpack-sources");
const SyncHook = require("tapable").SyncHook; const {
const SyncBailHook = require("tapable").SyncBailHook; Tapable,
const SyncWaterfallHook = require("tapable").SyncWaterfallHook; SyncHook,
const AsyncSeriesHook = require("tapable").AsyncSeriesHook; SyncBailHook,
SyncWaterfallHook,
AsyncSeriesHook
} = require("tapable");
const EntryModuleNotFoundError = require("./EntryModuleNotFoundError"); const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
const ModuleNotFoundError = require("./ModuleNotFoundError"); const ModuleNotFoundError = require("./ModuleNotFoundError");
const ModuleDependencyWarning = require("./ModuleDependencyWarning"); const ModuleDependencyWarning = require("./ModuleDependencyWarning");
@ -26,7 +29,6 @@ const RuntimeTemplate = require("./RuntimeTemplate");
const Dependency = require("./Dependency"); const Dependency = require("./Dependency");
const ChunkRenderError = require("./ChunkRenderError"); const ChunkRenderError = require("./ChunkRenderError");
const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError"); const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError");
const CachedSource = require("webpack-sources").CachedSource;
const Stats = require("./Stats"); const Stats = require("./Stats");
const Semaphore = require("./util/Semaphore"); const Semaphore = require("./util/Semaphore");
const createHash = require("./util/createHash"); const createHash = require("./util/createHash");
@ -61,7 +63,11 @@ const byIndexOrIdentifier = (a, b) => {
}; };
const iterationBlockVariable = (variables, fn) => { const iterationBlockVariable = (variables, fn) => {
for(let indexVariable = 0; indexVariable < variables.length; indexVariable++) { for (
let indexVariable = 0;
indexVariable < variables.length;
indexVariable++
) {
const varDep = variables[indexVariable].dependencies; const varDep = variables[indexVariable].dependencies;
for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) { for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) {
fn(varDep[indexVDep]); fn(varDep[indexVDep]);
@ -140,6 +146,7 @@ class Compilation extends Tapable {
recordChunks: new SyncHook(["chunks", "records"]), recordChunks: new SyncHook(["chunks", "records"]),
beforeHash: new SyncHook([]), beforeHash: new SyncHook([]),
contentHash: new SyncHook(["chunk"]),
afterHash: new SyncHook([]), afterHash: new SyncHook([]),
recordHash: new SyncHook(["records"]), recordHash: new SyncHook(["records"]),
@ -169,7 +176,11 @@ class Compilation extends Tapable {
assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate
needAdditionalPass: new SyncBailHook([]), needAdditionalPass: new SyncBailHook([]),
childCompiler: new SyncHook(["childCompiler", "compilerName", "compilerIndex"]), childCompiler: new SyncHook([
"childCompiler",
"compilerName",
"compilerIndex"
]),
// TODO the following hooks are weirdly located here // TODO the following hooks are weirdly located here
// TODO move them for webpack 5 // TODO move them for webpack 5
@ -178,7 +189,7 @@ class Compilation extends Tapable {
optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]), optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]),
optimizeExtractedChunks: new SyncBailHook(["chunks"]), optimizeExtractedChunks: new SyncBailHook(["chunks"]),
optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]), optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]),
afterOptimizeExtractedChunks: new SyncHook(["chunks"]), afterOptimizeExtractedChunks: new SyncHook(["chunks"])
}; };
this._pluginCompat.tap("Compilation", options => { this._pluginCompat.tap("Compilation", options => {
switch (options.name) { switch (options.name) {
@ -196,7 +207,7 @@ class Compilation extends Tapable {
this.inputFileSystem = compiler.inputFileSystem; this.inputFileSystem = compiler.inputFileSystem;
this.requestShortener = compiler.requestShortener; this.requestShortener = compiler.requestShortener;
const options = this.options = compiler.options; const options = (this.options = compiler.options);
this.outputOptions = options && options.output; this.outputOptions = options && options.output;
this.bail = options && options.bail; this.bail = options && options.bail;
this.profile = options && options.profile; this.profile = options && options.profile;
@ -204,8 +215,13 @@ class Compilation extends Tapable {
this.mainTemplate = new MainTemplate(this.outputOptions); this.mainTemplate = new MainTemplate(this.outputOptions);
this.chunkTemplate = new ChunkTemplate(this.outputOptions); this.chunkTemplate = new ChunkTemplate(this.outputOptions);
this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(this.outputOptions); this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(
this.runtimeTemplate = new RuntimeTemplate(this.outputOptions, this.requestShortener); this.outputOptions
);
this.runtimeTemplate = new RuntimeTemplate(
this.outputOptions,
this.requestShortener
);
this.moduleTemplates = { this.moduleTemplates = {
javascript: new ModuleTemplate(this.runtimeTemplate), javascript: new ModuleTemplate(this.runtimeTemplate),
webassembly: new ModuleTemplate(this.runtimeTemplate) webassembly: new ModuleTemplate(this.runtimeTemplate)
@ -263,7 +279,10 @@ class Compilation extends Tapable {
let rebuild = true; let rebuild = true;
if (this.fileTimestamps && this.contextTimestamps) { if (this.fileTimestamps && this.contextTimestamps) {
rebuild = cacheModule.needRebuild(this.fileTimestamps, this.contextTimestamps); rebuild = cacheModule.needRebuild(
this.fileTimestamps,
this.contextTimestamps
);
} }
if (!rebuild) { if (!rebuild) {
@ -319,7 +338,7 @@ class Compilation extends Tapable {
callbackList.push(thisCallback); callbackList.push(thisCallback);
return; return;
} }
this._buildingModules.set(module, callbackList = [thisCallback]); this._buildingModules.set(module, (callbackList = [thisCallback]));
const callback = err => { const callback = err => {
this._buildingModules.delete(module); this._buildingModules.delete(module);
@ -327,20 +346,27 @@ class Compilation extends Tapable {
}; };
this.hooks.buildModule.call(module); this.hooks.buildModule.call(module);
module.build(this.options, this, this.resolverFactory.get("normal", module.resolveOptions), this.inputFileSystem, (error) => { module.build(
this.options,
this,
this.resolverFactory.get("normal", module.resolveOptions),
this.inputFileSystem,
error => {
const errors = module.errors; const errors = module.errors;
for (let indexError = 0; indexError < errors.length; indexError++) { for (let indexError = 0; indexError < errors.length; indexError++) {
const err = errors[indexError]; const err = errors[indexError];
err.origin = origin; err.origin = origin;
err.dependencies = dependencies; err.dependencies = dependencies;
if(optional) if (optional) this.warnings.push(err);
this.warnings.push(err); else this.errors.push(err);
else
this.errors.push(err);
} }
const warnings = module.warnings; const warnings = module.warnings;
for(let indexWarning = 0; indexWarning < warnings.length; indexWarning++) { for (
let indexWarning = 0;
indexWarning < warnings.length;
indexWarning++
) {
const war = warnings[indexWarning]; const war = warnings[indexWarning];
war.origin = origin; war.origin = origin;
war.dependencies = dependencies; war.dependencies = dependencies;
@ -353,7 +379,8 @@ class Compilation extends Tapable {
} }
this.hooks.succeedModule.call(module); this.hooks.succeedModule.call(module);
return callback(); return callback();
}); }
);
} }
processModuleDependencies(module, callback) { processModuleDependencies(module, callback) {
@ -364,13 +391,16 @@ class Compilation extends Tapable {
if (resourceIdent) { if (resourceIdent) {
const factory = this.dependencyFactories.get(dep.constructor); const factory = this.dependencyFactories.get(dep.constructor);
if (factory === undefined) if (factory === undefined)
throw new Error(`No module factory available for dependency type: ${dep.constructor.name}`); throw new Error(
`No module factory available for dependency type: ${
dep.constructor.name
}`
);
let innerMap = dependencies.get(factory); let innerMap = dependencies.get(factory);
if (innerMap === undefined) if (innerMap === undefined)
dependencies.set(factory, innerMap = new Map()); dependencies.set(factory, (innerMap = new Map()));
let list = innerMap.get(resourceIdent); let list = innerMap.get(resourceIdent);
if(list === undefined) if (list === undefined) innerMap.set(resourceIdent, (list = []));
innerMap.set(resourceIdent, list = []);
list.push(dep); list.push(dep);
} }
}; };
@ -404,15 +434,31 @@ class Compilation extends Tapable {
} }
} }
this.addModuleDependencies(module, sortedDependencies, this.bail, null, true, callback); this.addModuleDependencies(
module,
sortedDependencies,
this.bail,
null,
true,
callback
);
} }
addModuleDependencies(module, dependencies, bail, cacheGroup, recursive, callback) { addModuleDependencies(
module,
dependencies,
bail,
cacheGroup,
recursive,
callback
) {
let _this = this; let _this = this;
const start = _this.profile && Date.now(); const start = _this.profile && Date.now();
const currentProfile = _this.profile && {}; const currentProfile = _this.profile && {};
asyncLib.forEach(dependencies, (item, callback) => { asyncLib.forEach(
dependencies,
(item, callback) => {
const dependencies = item.dependencies; const dependencies = item.dependencies;
const errorAndCallback = err => { const errorAndCallback = err => {
@ -435,7 +481,8 @@ class Compilation extends Tapable {
if (_this === null) return semaphore.release(); if (_this === null) return semaphore.release();
const factory = item.factory; const factory = item.factory;
factory.create({ factory.create(
{
contextInfo: { contextInfo: {
issuer: module.nameForCondition && module.nameForCondition(), issuer: module.nameForCondition && module.nameForCondition(),
compiler: _this.compiler.name compiler: _this.compiler.name
@ -443,7 +490,8 @@ class Compilation extends Tapable {
resolveOptions: module.resolveOptions, resolveOptions: module.resolveOptions,
context: module.context, context: module.context,
dependencies: dependencies dependencies: dependencies
}, (err, dependentModule) => { },
(err, dependentModule) => {
if (_this === null) return semaphore.release(); if (_this === null) return semaphore.release();
let afterFactory; let afterFactory;
@ -462,7 +510,9 @@ class Compilation extends Tapable {
if (err) { if (err) {
semaphore.release(); semaphore.release();
return errorOrWarningAndCallback(new ModuleNotFoundError(module, err, dependencies)); return errorOrWarningAndCallback(
new ModuleNotFoundError(module, err, dependencies)
);
} }
if (!dependentModule) { if (!dependentModule) {
semaphore.release(); semaphore.release();
@ -481,7 +531,10 @@ class Compilation extends Tapable {
} }
}; };
const addModuleResult = _this.addModule(dependentModule, cacheGroup); const addModuleResult = _this.addModule(
dependentModule,
cacheGroup
);
dependentModule = addModuleResult.module; dependentModule = addModuleResult.module;
iterationDependencies(dependencies); iterationDependencies(dependencies);
@ -508,7 +561,10 @@ class Compilation extends Tapable {
if (_this.profile) { if (_this.profile) {
if (module.profile) { if (module.profile) {
const time = Date.now() - start; const time = Date.now() - start;
if(!module.profile.dependencies || time > module.profile.dependencies) { if (
!module.profile.dependencies ||
time > module.profile.dependencies
) {
module.profile.dependencies = time; module.profile.dependencies = time;
} }
} }
@ -516,7 +572,12 @@ class Compilation extends Tapable {
} }
if (addModuleResult.build) { if (addModuleResult.build) {
_this.buildModule(dependentModule, isOptional(), module, dependencies, err => { _this.buildModule(
dependentModule,
isOptional(),
module,
dependencies,
err => {
if (_this === null) return semaphore.release(); if (_this === null) return semaphore.release();
if (err) { if (err) {
@ -531,14 +592,17 @@ class Compilation extends Tapable {
semaphore.release(); semaphore.release();
afterBuild(); afterBuild();
}); }
);
} else { } else {
semaphore.release(); semaphore.release();
_this.waitForBuildingFinished(dependentModule, afterBuild); _this.waitForBuildingFinished(dependentModule, afterBuild);
} }
}
);
}); });
}); },
}, err => { err => {
// In V8, the Error objects keep a reference to the functions on the stack. These warnings & // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
// errors are created inside closures that keep a reference to the Compilation, so errors are // errors are created inside closures that keep a reference to the Compilation, so errors are
// leaking the Compilation object. // leaking the Compilation object.
@ -549,39 +613,52 @@ class Compilation extends Tapable {
} }
return process.nextTick(callback); return process.nextTick(callback);
}); }
);
} }
_addModuleChain(context, dependency, onModule, callback) { _addModuleChain(context, dependency, onModule, callback) {
const start = this.profile && Date.now(); const start = this.profile && Date.now();
const currentProfile = this.profile && {}; const currentProfile = this.profile && {};
const errorAndCallback = this.bail ? (err) => { const errorAndCallback = this.bail
? err => {
callback(err); callback(err);
} : (err) => { }
: err => {
err.dependencies = [dependency]; err.dependencies = [dependency];
this.errors.push(err); this.errors.push(err);
callback(); callback();
}; };
if(typeof dependency !== "object" || dependency === null || !dependency.constructor) { if (
typeof dependency !== "object" ||
dependency === null ||
!dependency.constructor
) {
throw new Error("Parameter 'dependency' must be a Dependency"); throw new Error("Parameter 'dependency' must be a Dependency");
} }
const moduleFactory = this.dependencyFactories.get(dependency.constructor); const moduleFactory = this.dependencyFactories.get(dependency.constructor);
if (!moduleFactory) { if (!moduleFactory) {
throw new Error(`No dependency factory available for this dependency type: ${dependency.constructor.name}`); throw new Error(
`No dependency factory available for this dependency type: ${
dependency.constructor.name
}`
);
} }
this.semaphore.acquire(() => { this.semaphore.acquire(() => {
moduleFactory.create({ moduleFactory.create(
{
contextInfo: { contextInfo: {
issuer: "", issuer: "",
compiler: this.compiler.name compiler: this.compiler.name
}, },
context: context, context: context,
dependencies: [dependency] dependencies: [dependency]
}, (err, module) => { },
(err, module) => {
if (err) { if (err) {
this.semaphore.release(); this.semaphore.release();
return errorAndCallback(new EntryModuleNotFoundError(err)); return errorAndCallback(new EntryModuleNotFoundError(err));
@ -643,7 +720,8 @@ class Compilation extends Tapable {
this.semaphore.release(); this.semaphore.release();
this.waitForBuildingFinished(module, afterBuild); this.waitForBuildingFinished(module, afterBuild);
} }
}); }
);
}); });
} }
@ -654,11 +732,13 @@ class Compilation extends Tapable {
module: null module: null
}; };
this._preparedEntrypoints.push(slot); this._preparedEntrypoints.push(slot);
this._addModuleChain(context, entry, (module) => { this._addModuleChain(
context,
entry,
module => {
this.entries.push(module); this.entries.push(module);
},
}, (err, module) => { (err, module) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@ -670,15 +750,19 @@ class Compilation extends Tapable {
this._preparedEntrypoints.splice(idx, 1); this._preparedEntrypoints.splice(idx, 1);
} }
return callback(null, module); return callback(null, module);
}); }
);
} }
prefetch(context, dependency, callback) { prefetch(context, dependency, callback) {
this._addModuleChain(context, dependency, module => { this._addModuleChain(
context,
dependency,
module => {
module.prefetched = true; module.prefetched = true;
},
}, callback); callback
);
} }
rebuildModule(module, thisCallback) { rebuildModule(module, thisCallback) {
@ -687,7 +771,7 @@ class Compilation extends Tapable {
callbackList.push(thisCallback); callbackList.push(thisCallback);
return; return;
} }
this._rebuildingModules.set(module, callbackList = [thisCallback]); this._rebuildingModules.set(module, (callbackList = [thisCallback]));
const callback = err => { const callback = err => {
this._rebuildingModules.delete(module); this._rebuildingModules.delete(module);
@ -699,13 +783,13 @@ class Compilation extends Tapable {
const oldVariables = module.variables.slice(); const oldVariables = module.variables.slice();
const oldBlocks = module.blocks.slice(); const oldBlocks = module.blocks.slice();
module.unbuild(); module.unbuild();
this.buildModule(module, false, module, null, (err) => { this.buildModule(module, false, module, null, err => {
if (err) { if (err) {
this.hooks.finishRebuildingModule.call(module); this.hooks.finishRebuildingModule.call(module);
return callback(err); return callback(err);
} }
this.processModuleDependencies(module, (err) => { this.processModuleDependencies(module, err => {
if (err) return callback(err); if (err) return callback(err);
this.removeReasonsOfDependencyBlock(module, { this.removeReasonsOfDependencyBlock(module, {
dependencies: oldDependencies, dependencies: oldDependencies,
@ -715,7 +799,6 @@ class Compilation extends Tapable {
this.hooks.finishRebuildingModule.call(module); this.hooks.finishRebuildingModule.call(module);
callback(); callback();
}); });
}); });
} }
@ -745,9 +828,13 @@ class Compilation extends Tapable {
seal(callback) { seal(callback) {
this.hooks.seal.call(); this.hooks.seal.call();
while(this.hooks.optimizeDependenciesBasic.call(this.modules) || while (
this.hooks.optimizeDependenciesBasic.call(this.modules) ||
this.hooks.optimizeDependencies.call(this.modules) || this.hooks.optimizeDependencies.call(this.modules) ||
this.hooks.optimizeDependenciesAdvanced.call(this.modules)) { /* empty */ } this.hooks.optimizeDependenciesAdvanced.call(this.modules)
) {
/* empty */
}
this.hooks.afterOptimizeDependencies.call(this.modules); this.hooks.afterOptimizeDependencies.call(this.modules);
this.nextFreeModuleIndex = 0; this.nextFreeModuleIndex = 0;
@ -776,14 +863,22 @@ class Compilation extends Tapable {
this.sortModules(this.modules); this.sortModules(this.modules);
this.hooks.optimize.call(); this.hooks.optimize.call();
while(this.hooks.optimizeModulesBasic.call(this.modules) || while (
this.hooks.optimizeModulesBasic.call(this.modules) ||
this.hooks.optimizeModules.call(this.modules) || this.hooks.optimizeModules.call(this.modules) ||
this.hooks.optimizeModulesAdvanced.call(this.modules)) { /* empty */ } this.hooks.optimizeModulesAdvanced.call(this.modules)
) {
/* empty */
}
this.hooks.afterOptimizeModules.call(this.modules); this.hooks.afterOptimizeModules.call(this.modules);
while(this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) || while (
this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) ||
this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) || this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) ||
this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)) { /* empty */ } this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)
) {
/* empty */
}
this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups); this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => { this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
@ -793,9 +888,13 @@ class Compilation extends Tapable {
this.hooks.afterOptimizeTree.call(this.chunks, this.modules); this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
while(this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) || while (
this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) ||
this.hooks.optimizeChunkModules.call(this.chunks, this.modules) || this.hooks.optimizeChunkModules.call(this.chunks, this.modules) ||
this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules)) { /* empty */ } this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules)
) {
/* empty */
}
this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules); this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
const shouldRecord = this.hooks.shouldRecord.call() !== false; const shouldRecord = this.hooks.shouldRecord.call() !== false;
@ -822,15 +921,13 @@ class Compilation extends Tapable {
if (shouldRecord) if (shouldRecord)
this.hooks.recordModules.call(this.modules, this.records); this.hooks.recordModules.call(this.modules, this.records);
if(shouldRecord) if (shouldRecord) this.hooks.recordChunks.call(this.chunks, this.records);
this.hooks.recordChunks.call(this.chunks, this.records);
this.hooks.beforeHash.call(); this.hooks.beforeHash.call();
this.createHash(); this.createHash();
this.hooks.afterHash.call(); this.hooks.afterHash.call();
if(shouldRecord) if (shouldRecord) this.hooks.recordHash.call(this.records);
this.hooks.recordHash.call(this.records);
this.hooks.beforeModuleAssets.call(); this.hooks.beforeModuleAssets.call();
this.createModuleAssets(); this.createModuleAssets();
@ -840,8 +937,7 @@ class Compilation extends Tapable {
} }
this.hooks.additionalChunkAssets.call(this.chunks); this.hooks.additionalChunkAssets.call(this.chunks);
this.summarizeDependencies(); this.summarizeDependencies();
if(shouldRecord) if (shouldRecord) this.hooks.record.call(this, this.records);
this.hooks.record.call(this, this.records);
this.hooks.additionalAssets.callAsync(err => { this.hooks.additionalAssets.callAsync(err => {
if (err) { if (err) {
@ -915,8 +1011,7 @@ class Compilation extends Tapable {
} }
} }
const chunkGroup = new ChunkGroup(name); const chunkGroup = new ChunkGroup(name);
if(module) if (module) chunkGroup.addOrigin(module, loc, request);
chunkGroup.addOrigin(module, loc, request);
const chunk = this.addChunk(name); const chunk = this.addChunk(name);
GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk); GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk);
@ -952,7 +1047,7 @@ class Compilation extends Tapable {
module.index = _this.nextFreeModuleIndex++; module.index = _this.nextFreeModuleIndex++;
// leave module // leave module
queue.push(() => module.index2 = _this.nextFreeModuleIndex2++); queue.push(() => (module.index2 = _this.nextFreeModuleIndex2++));
// enter it as block // enter it as block
assignIndexToDependencyBlock(module); assignIndexToDependencyBlock(module);
@ -970,7 +1065,8 @@ class Compilation extends Tapable {
const iteratorDependency = d => allDependencies.push(d); const iteratorDependency = d => allDependencies.push(d);
const iteratorBlock = b => queue.push(() => assignIndexToDependencyBlock(b)); const iteratorBlock = b =>
queue.push(() => assignIndexToDependencyBlock(b));
if (block.variables) { if (block.variables) {
iterationBlockVariable(block.variables, iteratorDependency); iterationBlockVariable(block.variables, iteratorDependency);
@ -993,9 +1089,11 @@ class Compilation extends Tapable {
} }
}; };
const queue = [() => { const queue = [
() => {
assignIndexToModule(module); assignIndexToModule(module);
}]; }
];
const iteratorAllDependencies = d => { const iteratorAllDependencies = d => {
queue.push(() => assignIndexToDependency(d)); queue.push(() => assignIndexToDependency(d));
@ -1007,45 +1105,44 @@ class Compilation extends Tapable {
} }
assignDepth(module) { assignDepth(module) {
const assignDepthToModule = (module, depth) => { const queue = new Set([module]);
// enter module let depth;
if(typeof module.depth === "number" && module.depth <= depth) return;
module.depth = depth;
// enter it as block module.depth = 0;
assignDepthToDependencyBlock(module, depth + 1);
const enqueueJob = module => {
const d = module.depth;
if (typeof d === "number" && d <= depth) return;
queue.add(module);
module.depth = depth;
}; };
const assignDepthToDependency = (dependency, depth) => { const assignDepthToDependency = (dependency, depth) => {
if (dependency.module) { if (dependency.module) {
queue.push(() => assignDepthToModule(dependency.module, depth)); enqueueJob(dependency.module);
} }
}; };
const assignDepthToDependencyBlock = (block, depth) => { const assignDepthToDependencyBlock = block => {
const iteratorDependency = d => assignDepthToDependency(d, depth);
const iteratorBlock = b => assignDepthToDependencyBlock(b, depth);
if (block.variables) { if (block.variables) {
iterationBlockVariable(block.variables, iteratorDependency); iterationBlockVariable(block.variables, assignDepthToDependency);
} }
if (block.dependencies) { if (block.dependencies) {
iterationOfArrayCallback(block.dependencies, iteratorDependency); iterationOfArrayCallback(block.dependencies, assignDepthToDependency);
} }
if (block.blocks) { if (block.blocks) {
iterationOfArrayCallback(block.blocks, iteratorBlock); iterationOfArrayCallback(block.blocks, assignDepthToDependencyBlock);
} }
}; };
const queue = [() => { for (module of queue) {
assignDepthToModule(module, 0); queue.delete(module);
}]; depth = module.depth;
while(queue.length) { depth++;
queue.pop()(); assignDepthToDependencyBlock(module);
} }
} }
@ -1084,7 +1181,9 @@ class Compilation extends Tapable {
if (c === undefined) { if (c === undefined) {
c = this.namedChunkGroups.get(b.chunkName); c = this.namedChunkGroups.get(b.chunkName);
if (c && c.isInitial()) { if (c && c.isInitial()) {
this.errors.push(new AsyncDependencyToInitialChunkError(b.chunkName, module, b.loc)); this.errors.push(
new AsyncDependencyToInitialChunkError(b.chunkName, module, b.loc)
);
c = chunkGroup; c = chunkGroup;
} else { } else {
c = this.addChunkInGroup(b.chunkName, module, b.loc, b.request); c = this.addChunkInGroup(b.chunkName, module, b.loc, b.request);
@ -1097,7 +1196,7 @@ class Compilation extends Tapable {
// 2. We store the Block+Chunk mapping as dependency for the chunk // 2. We store the Block+Chunk mapping as dependency for the chunk
let deps = chunkDependencies.get(chunkGroup); let deps = chunkDependencies.get(chunkGroup);
if(!deps) chunkDependencies.set(chunkGroup, deps = []); if (!deps) chunkDependencies.set(chunkGroup, (deps = []));
deps.push({ deps.push({
block: b, block: b,
chunkGroup: c chunkGroup: c
@ -1169,17 +1268,18 @@ class Compilation extends Tapable {
let availableModules; let availableModules;
let newAvailableModules; let newAvailableModules;
const queue2 = new Queue(inputChunkGroups.map(chunkGroup => ({ const queue2 = new Queue(
inputChunkGroups.map(chunkGroup => ({
chunkGroup, chunkGroup,
availableModules: new Set() availableModules: new Set()
}))); }))
);
// Helper function to check if all modules of a chunk are available // Helper function to check if all modules of a chunk are available
const areModulesAvailable = (chunkGroup, availableModules) => { const areModulesAvailable = (chunkGroup, availableModules) => {
for (const chunk of chunkGroup.chunks) { for (const chunk of chunkGroup.chunks) {
for (const module of chunk.modulesIterable) { for (const module of chunk.modulesIterable) {
if(!availableModules.has(module)) if (!availableModules.has(module)) return false;
return false;
} }
} }
return true; return true;
@ -1190,8 +1290,7 @@ class Compilation extends Tapable {
// Filter egdes that are not needed because all modules are already available // Filter egdes that are not needed because all modules are already available
// This also filters circular dependencies in the chunks graph // This also filters circular dependencies in the chunks graph
const depChunkGroup = dep.chunkGroup; const depChunkGroup = dep.chunkGroup;
if(areModulesAvailable(depChunkGroup, newAvailableModules)) if (areModulesAvailable(depChunkGroup, newAvailableModules)) return false; // break all modules are already available
return false; // break all modules are already available
return true; return true;
}; };
@ -1218,8 +1317,7 @@ class Compilation extends Tapable {
deletedModules = true; deletedModules = true;
} }
} }
if(!deletedModules) if (!deletedModules) continue;
continue;
availableModules = minAvailableModules; availableModules = minAvailableModules;
} }
@ -1231,8 +1329,7 @@ class Compilation extends Tapable {
// 3. Create a new Set of available modules at this points // 3. Create a new Set of available modules at this points
newAvailableModules = new Set(availableModules); newAvailableModules = new Set(availableModules);
for (const chunk of chunkGroup.chunks) for (const chunk of chunkGroup.chunks)
for(const m of chunk.modulesIterable) for (const m of chunk.modulesIterable) newAvailableModules.add(m);
newAvailableModules.add(m);
// 4. Filter edges with available modules // 4. Filter edges with available modules
const filteredDeps = deps.filter(filterFn); const filteredDeps = deps.filter(filterFn);
@ -1244,8 +1341,11 @@ class Compilation extends Tapable {
const depChunkGroup = dep.chunkGroup; const depChunkGroup = dep.chunkGroup;
const depBlock = dep.block; const depBlock = dep.block;
// 6. Connnect block with chunk // 6. Connect block with chunk
GraphHelpers.connectDependenciesBlockAndChunkGroup(depBlock, depChunkGroup); GraphHelpers.connectDependenciesBlockAndChunkGroup(
depBlock,
depChunkGroup
);
// 7. Connect chunk with parent // 7. Connect chunk with parent
GraphHelpers.connectChunkGroupParentAndChild(chunkGroup, depChunkGroup); GraphHelpers.connectChunkGroupParentAndChild(chunkGroup, depChunkGroup);
@ -1267,8 +1367,7 @@ class Compilation extends Tapable {
if (chunkGroup.getNumberOfParents() === 0) { if (chunkGroup.getNumberOfParents() === 0) {
for (const chunk of chunkGroup.chunks) { for (const chunk of chunkGroup.chunks) {
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);
chunk.remove("unconnected"); chunk.remove("unconnected");
} }
chunkGroup.remove("unconnected"); chunkGroup.remove("unconnected");
@ -1289,7 +1388,9 @@ class Compilation extends Tapable {
}; };
if (block.blocks) { if (block.blocks) {
iterationOfArrayCallback(block.blocks, block => this.removeReasonsOfDependencyBlock(module, block)); iterationOfArrayCallback(block.blocks, block =>
this.removeReasonsOfDependencyBlock(module, block)
);
} }
if (block.dependencies) { if (block.dependencies) {
@ -1368,7 +1469,7 @@ class Compilation extends Tapable {
usedIdMax = Math.max(usedIdMax, usedIdKey); usedIdMax = Math.max(usedIdMax, usedIdKey);
} }
let lengthFreeModules = nextFreeModuleId = usedIdMax + 1; let lengthFreeModules = (nextFreeModuleId = usedIdMax + 1);
while (lengthFreeModules--) { while (lengthFreeModules--) {
if (!usedIds.has(lengthFreeModules)) { if (!usedIds.has(lengthFreeModules)) {
@ -1381,10 +1482,8 @@ class Compilation extends Tapable {
for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) { for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
const module2 = modules2[indexModule2]; const module2 = modules2[indexModule2];
if (module2.id === null) { if (module2.id === null) {
if(unusedIds.length > 0) if (unusedIds.length > 0) module2.id = unusedIds.pop();
module2.id = unusedIds.pop(); else module2.id = nextFreeModuleId++;
else
module2.id = nextFreeModuleId++;
} }
} }
} }
@ -1395,7 +1494,6 @@ class Compilation extends Tapable {
// Get used ids from usedChunkIds property (i. e. from records) // Get used ids from usedChunkIds property (i. e. from records)
if (this.usedChunkIds) { if (this.usedChunkIds) {
for (const id of this.usedChunkIds) { for (const id of this.usedChunkIds) {
if (typeof id !== "number") { if (typeof id !== "number") {
continue; continue;
} }
@ -1439,10 +1537,8 @@ class Compilation extends Tapable {
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
const chunk = chunks[indexChunk]; const chunk = chunks[indexChunk];
if (chunk.id === null) { if (chunk.id === null) {
if(unusedIds.length > 0) if (unusedIds.length > 0) chunk.id = unusedIds.pop();
chunk.id = unusedIds.pop(); else chunk.id = nextFreeChunkId++;
else
chunk.id = nextFreeChunkId++;
} }
if (!chunk.ids) { if (!chunk.ids) {
chunk.ids = [chunk.id]; chunk.ids = [chunk.id];
@ -1471,7 +1567,11 @@ class Compilation extends Tapable {
this.chunks.sort(byId); this.chunks.sort(byId);
for(let indexModule = 0; indexModule < this.modules.length; indexModule++) { for (
let indexModule = 0;
indexModule < this.modules.length;
indexModule++
) {
this.modules[indexModule].sortItems(true); this.modules[indexModule].sortItems(true);
} }
@ -1497,7 +1597,11 @@ class Compilation extends Tapable {
this.contextDependencies = new SortableSet(); this.contextDependencies = new SortableSet();
this.missingDependencies = new SortableSet(); this.missingDependencies = new SortableSet();
for(let indexChildren = 0; indexChildren < this.children.length; indexChildren++) { for (
let indexChildren = 0;
indexChildren < this.children.length;
indexChildren++
) {
const child = this.children[indexChildren]; const child = this.children[indexChildren];
addAllToSet(this.fileDependencies, child.fileDependencies); addAllToSet(this.fileDependencies, child.fileDependencies);
@ -1505,18 +1609,29 @@ class Compilation extends Tapable {
addAllToSet(this.missingDependencies, child.missingDependencies); addAllToSet(this.missingDependencies, child.missingDependencies);
} }
for(let indexModule = 0; indexModule < this.modules.length; indexModule++) { for (
let indexModule = 0;
indexModule < this.modules.length;
indexModule++
) {
const module = this.modules[indexModule]; const module = this.modules[indexModule];
if (module.buildInfo.fileDependencies) { if (module.buildInfo.fileDependencies) {
addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies); addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies);
} }
if (module.buildInfo.contextDependencies) { if (module.buildInfo.contextDependencies) {
addAllToSet(this.contextDependencies, module.buildInfo.contextDependencies); addAllToSet(
this.contextDependencies,
module.buildInfo.contextDependencies
);
} }
} }
for (const error of this.errors) { for (const error of this.errors) {
if(typeof error.missing === "object" && error.missing && error.missing[Symbol.iterator]) { if (
typeof error.missing === "object" &&
error.missing &&
error.missing[Symbol.iterator]
) {
addAllToSet(this.missingDependencies, error.missing); addAllToSet(this.missingDependencies, error.missing);
} }
} }
@ -1531,11 +1646,11 @@ class Compilation extends Tapable {
const hashDigest = outputOptions.hashDigest; const hashDigest = outputOptions.hashDigest;
const hashDigestLength = outputOptions.hashDigestLength; const hashDigestLength = outputOptions.hashDigestLength;
const hash = createHash(hashFunction); const hash = createHash(hashFunction);
if(outputOptions.hashSalt) if (outputOptions.hashSalt) hash.update(outputOptions.hashSalt);
hash.update(outputOptions.hashSalt);
this.mainTemplate.updateHash(hash); this.mainTemplate.updateHash(hash);
this.chunkTemplate.updateHash(hash); this.chunkTemplate.updateHash(hash);
for(const key of Object.keys(this.moduleTemplates).sort()) this.moduleTemplates[key].updateHash(hash); for (const key of Object.keys(this.moduleTemplates).sort())
this.moduleTemplates[key].updateHash(hash);
for (const child of this.children) hash.update(child.hash); for (const child of this.children) hash.update(child.hash);
for (const warning of this.warnings) hash.update(`${warning.message}`); for (const warning of this.warnings) hash.update(`${warning.message}`);
for (const error of this.errors) hash.update(`${error.message}`); for (const error of this.errors) hash.update(`${error.message}`);
@ -1564,18 +1679,17 @@ class Compilation extends Tapable {
for (let i = 0; i < chunks.length; i++) { for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i]; const chunk = chunks[i];
const chunkHash = createHash(hashFunction); const chunkHash = createHash(hashFunction);
if(outputOptions.hashSalt) if (outputOptions.hashSalt) chunkHash.update(outputOptions.hashSalt);
chunkHash.update(outputOptions.hashSalt);
chunk.updateHash(chunkHash); chunk.updateHash(chunkHash);
if(chunk.hasRuntime()) { const template = chunk.hasRuntime()
this.mainTemplate.updateHashForChunk(chunkHash, chunk); ? this.mainTemplate
} else { : this.chunkTemplate;
this.chunkTemplate.updateHashForChunk(chunkHash, chunk); template.updateHashForChunk(chunkHash, chunk);
}
this.hooks.chunkHash.call(chunk, chunkHash); this.hooks.chunkHash.call(chunk, chunkHash);
chunk.hash = chunkHash.digest(hashDigest); chunk.hash = chunkHash.digest(hashDigest);
hash.update(chunk.hash); hash.update(chunk.hash);
chunk.renderedHash = chunk.hash.substr(0, hashDigestLength); chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
this.hooks.contentHash.call(chunk);
} }
this.fullHash = hash.digest(hashDigest); this.fullHash = hash.digest(hashDigest);
this.hash = this.fullHash.substr(0, hashDigestLength); this.hash = this.fullHash.substr(0, hashDigestLength);
@ -1616,7 +1730,9 @@ class Compilation extends Tapable {
let file; let file;
let filenameTemplate; let filenameTemplate;
try { try {
const template = chunk.hasRuntime() ? this.mainTemplate : this.chunkTemplate; const template = chunk.hasRuntime()
? this.mainTemplate
: this.chunkTemplate;
const manifest = template.getRenderManifest({ const manifest = template.getRenderManifest({
chunk, chunk,
hash: this.hash, hash: this.hash,
@ -1629,7 +1745,11 @@ class Compilation extends Tapable {
const cacheName = fileManifest.identifier; const cacheName = fileManifest.identifier;
const usedHash = fileManifest.hash; const usedHash = fileManifest.hash;
filenameTemplate = fileManifest.filenameTemplate; filenameTemplate = fileManifest.filenameTemplate;
if(this.cache && this.cache[cacheName] && this.cache[cacheName].hash === usedHash) { if (
this.cache &&
this.cache[cacheName] &&
this.cache[cacheName].hash === usedHash
) {
source = this.cache[cacheName].source; source = this.cache[cacheName].source;
} else { } else {
source = fileManifest.render(); source = fileManifest.render();
@ -1653,13 +1773,17 @@ class Compilation extends Tapable {
} }
file = this.getPath(filenameTemplate, fileManifest.pathOptions); file = this.getPath(filenameTemplate, fileManifest.pathOptions);
if (this.assets[file] && this.assets[file] !== source) if (this.assets[file] && this.assets[file] !== source)
throw new Error(`Conflict: Multiple assets emit to the same filename ${file}`); throw new Error(
`Conflict: Multiple assets emit to the same filename ${file}`
);
this.assets[file] = source; this.assets[file] = source;
chunk.files.push(file); chunk.files.push(file);
this.hooks.chunkAsset.call(chunk, file); this.hooks.chunkAsset.call(chunk, file);
} }
} catch (err) { } catch (err) {
this.errors.push(new ChunkRenderError(chunk, file || filenameTemplate, err)); this.errors.push(
new ChunkRenderError(chunk, file || filenameTemplate, err)
);
} }
} }
} }
@ -1671,9 +1795,15 @@ class Compilation extends Tapable {
} }
createChildCompiler(name, outputOptions, plugins) { createChildCompiler(name, outputOptions, plugins) {
const idx = (this.childrenCounters[name] || 0); const idx = this.childrenCounters[name] || 0;
this.childrenCounters[name] = idx + 1; this.childrenCounters[name] = idx + 1;
return this.compiler.createChildCompiler(this, name, idx, outputOptions, plugins); return this.compiler.createChildCompiler(
this,
name,
idx,
outputOptions,
plugins
);
} }
checkConstraints() { checkConstraints() {
@ -1692,7 +1822,9 @@ class Compilation extends Tapable {
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
const chunk = chunks[indexChunk]; const chunk = chunks[indexChunk];
if (chunks.indexOf(chunk) !== indexChunk) if (chunks.indexOf(chunk) !== indexChunk)
throw new Error(`checkConstraints: duplicate chunk in compilation ${chunk.debugId}`); throw new Error(
`checkConstraints: duplicate chunk in compilation ${chunk.debugId}`
);
} }
for (const chunkGroup of this.chunkGroups) { for (const chunkGroup of this.chunkGroups) {
@ -1703,7 +1835,9 @@ class Compilation extends Tapable {
// TODO remove in webpack 5 // TODO remove in webpack 5
Compilation.prototype.applyPlugins = util.deprecate(function(name, ...args) { Compilation.prototype.applyPlugins = util.deprecate(function(name, ...args) {
this.hooks[name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())].call(...args); this.hooks[
name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())
].call(...args);
}, "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead"); }, "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead");
// TODO remove in webpack 5 // TODO remove in webpack 5

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,7 +56,7 @@ 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) {
@ -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.'),
"webpack: Using compiler.resolvers.normal is deprecated.\n" + apply: util.deprecate((...args) => {
"Use compiler.resolverFactory.plugin(\"resolver normal\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver normal", resolver => { this.resolverFactory.plugin("resolver normal", resolver => {
resolver.apply(...args); resolver.apply(...args);
}); });
}, }, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
"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.'),
"webpack: Using compiler.resolvers.loader is deprecated.\n" + apply: util.deprecate((...args) => {
"Use compiler.resolverFactory.plugin(\"resolver loader\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver loader", resolver => { this.resolverFactory.plugin("resolver loader", resolver => {
resolver.apply(...args); resolver.apply(...args);
}); });
}, }, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
"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.'),
"webpack: Using compiler.resolvers.context is deprecated.\n" + apply: util.deprecate((...args) => {
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver context", resolver => { this.resolverFactory.plugin("resolver context", resolver => {
resolver.apply(...args); resolver.apply(...args);
}); });
}, }, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
"webpack: Using compiler.resolvers.context is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
} }
}; };
@ -153,33 +132,48 @@ 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();
this.running = true;
const onCompiled = (err, compilation) => { const onCompiled = (err, compilation) => {
if(err) return callback(err); if (err) return finalCallback(err);
if (this.hooks.shouldEmit.call(compilation) === false) { 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;
@ -188,10 +182,10 @@ class Compiler extends Tapable {
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);
}); });
@ -236,7 +230,10 @@ class Compiler extends Tapable {
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);
}, []); }, []);
@ -252,20 +249,24 @@ class Compiler extends Tapable {
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; let targetFile = file;
const queryStringIdx = targetFile.indexOf("?"); const queryStringIdx = targetFile.indexOf("?");
if (queryStringIdx >= 0) { if (queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx); targetFile = targetFile.substr(0, queryStringIdx);
} }
const writeOut = (err) => { const writeOut = err => {
if (err) return callback(err); if (err) return callback(err);
const targetPath = this.outputFileSystem.join(outputPath, targetFile); const targetPath = this.outputFileSystem.join(
outputPath,
targetFile
);
if (source.existsAt === targetPath) { if (source.existsAt === targetPath) {
source.emitted = false; source.emitted = false;
return callback(); return callback();
@ -283,10 +284,13 @@ class Compiler extends Tapable {
if (targetFile.match(/\/|\\/)) { if (targetFile.match(/\/|\\/)) {
const dir = path.dirname(targetFile); const dir = path.dirname(targetFile);
this.outputFileSystem.mkdirp(this.outputFileSystem.join(outputPath, dir), writeOut); this.outputFileSystem.mkdirp(
this.outputFileSystem.join(outputPath, dir),
writeOut
);
} else writeOut(); } else writeOut();
},
}, err => { err => {
if (err) return callback(err); if (err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, err => { this.hooks.afterEmit.callAsync(compilation, err => {
@ -294,7 +298,8 @@ class Compiler extends Tapable {
return callback(); return callback();
}); });
}); }
);
}; };
this.hooks.emit.callAsync(compilation, err => { this.hooks.emit.callAsync(compilation, err => {
@ -309,15 +314,20 @@ class Compiler extends Tapable {
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();
@ -349,13 +359,29 @@ 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 (
![
"make",
"compile",
"emit",
"afterEmit",
"invalid",
"done",
"thisCompilation"
].includes(name)
) {
if (childCompiler.hooks[name]) if (childCompiler.hooks[name])
childCompiler.hooks[name].taps = this.hooks[name].taps.slice(); childCompiler.hooks[name].taps = this.hooks[name].taps.slice();
} }
@ -369,11 +395,11 @@ 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])
this.records[relativeCompilerName] = [];
if (this.records[relativeCompilerName][compilerIndex]) 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);
@ -382,7 +408,11 @@ class Compiler extends Tapable {
} }
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;
} }

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,7 +7,7 @@ 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) : "";
}; };
@ -21,15 +21,13 @@ const collectDeclaration = (declarations, pattern) => {
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);
@ -44,14 +42,12 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
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);
@ -73,13 +69,11 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
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":
@ -98,11 +92,14 @@ 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 => {
@ -114,7 +111,9 @@ class ConstPlugin {
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; const branchToRemove = bool
? statement.alternate
: statement.consequent;
if (branchToRemove) { if (branchToRemove) {
// Before removing the dead branch, the hoisted declarations // Before removing the dead branch, the hoisted declarations
// must be collected. // must be collected.
@ -161,14 +160,19 @@ class ConstPlugin {
} else { } else {
replacement = "{}"; replacement = "{}";
} }
const dep = new ConstDependency(replacement, branchToRemove.range); const dep = new ConstDependency(
replacement,
branchToRemove.range
);
dep.loc = branchToRemove.loc; dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
} }
return bool; return bool;
} }
}); });
parser.hooks.expressionConditionalOperator.tap("ConstPlugin", expression => { parser.hooks.expressionConditionalOperator.tap(
"ConstPlugin",
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") {
@ -188,28 +192,50 @@ class ConstPlugin {
// //
// false ? undefined : otherExpression(); // false ? undefined : otherExpression();
// //
const branchToRemove = bool ? expression.alternate : expression.consequent; const branchToRemove = bool
const dep = new ConstDependency("undefined", branchToRemove.range); ? expression.alternate
: expression.consequent;
const dep = new ConstDependency(
"undefined",
branchToRemove.range
);
dep.loc = branchToRemove.loc; dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep); parser.state.current.addDependency(dep);
return bool; return bool;
} }
}); }
parser.hooks.evaluateIdentifier.for("__resourceQuery").tap("ConstPlugin", expr => { );
parser.hooks.evaluateIdentifier
.for("__resourceQuery")
.tap("ConstPlugin", expr => {
if (!parser.state.module) return; if (!parser.state.module) return;
return ParserHelpers.evaluateToString(getQuery(parser.state.module.resource))(expr); return ParserHelpers.evaluateToString(
getQuery(parser.state.module.resource)
)(expr);
}); });
parser.hooks.expression.for("__resourceQuery").tap("ConstPlugin", () => { parser.hooks.expression
.for("__resourceQuery")
.tap("ConstPlugin", () => {
if (!parser.state.module) return; if (!parser.state.module) return;
parser.state.current.addVariable("__resourceQuery", JSON.stringify(getQuery(parser.state.module.resource))); parser.state.current.addVariable(
"__resourceQuery",
JSON.stringify(getQuery(parser.state.module.resource))
);
return true; 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");
@ -53,36 +52,30 @@ class ContextModule extends Module {
} }
contextify(context, request) { contextify(context, request) {
return request.split("!").map(subrequest => { return request
.split("!")
.map(subrequest => {
let rp = path.relative(context, subrequest); let rp = path.relative(context, subrequest);
if(path.sep === "\\") if (path.sep === "\\") rp = rp.replace(/\\/g, "/");
rp = rp.replace(/\\/g, "/"); if (rp.indexOf("../") !== 0) 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)
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") 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;
} }
@ -91,10 +84,8 @@ class ContextModule extends Module {
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)
identifier += " nonrecursive";
if (this.options.addon) if (this.options.addon)
identifier += ` ${requestShortener.shorten(this.options.addon)}`; identifier += ` ${requestShortener.shorten(this.options.addon)}`;
if (this.options.regExp) if (this.options.regExp)
@ -105,18 +96,15 @@ class ContextModule extends Module {
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)
identifier += " recursive";
if (this.options.addon) 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)
@ -162,31 +150,31 @@ class ContextModule extends Module {
} }
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(
this.options.chunkName,
this
);
for (const dep of dependencies) { 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
@ -194,17 +182,26 @@ class ContextModule extends Module {
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();
@ -222,7 +219,8 @@ class ContextModule extends Module {
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));
@ -240,12 +238,15 @@ 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) => {
const exportsType =
dep.module.buildMeta && dep.module.buildMeta.exportsType;
if (!exportsType) hasNonHarmony = true; if (!exportsType) hasNonHarmony = true;
if (exportsType === "namespace") hasNamespace = true; if (exportsType === "namespace") hasNamespace = true;
if (exportsType === "named") hasNamed = true; if (exportsType === "named") hasNamed = true;
map[dep.module.id] = { map[dep.module.id] =
{
namespace: 1, namespace: 1,
named: 2 named: 2
}[exportsType] || 0; }[exportsType] || 0;
@ -259,24 +260,30 @@ class ContextModule extends Module {
} }
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)
return 'Object.assign({/* fake namespace object */}, typeof module === "object" && module, { "default": module })';
if (type === 0) { if (type === 0) {
if (this.options.namespaceObject === "strict") { if (this.options.namespaceObject === "strict") {
return "/* fake namespace object */ { \"default\": module }"; 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) => { }))
.sort((a, b) => {
if (a.userRequest === b.userRequest) return 0; 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) => {
const chunks =
(item.block.chunkGroup && item.block.chunkGroup.chunks) || [];
if (chunks.length !== 1) { 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';
@ -557,7 +575,12 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(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);
} }
@ -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");
@ -41,11 +43,16 @@ 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(
Object.assign(
{
context: context, context: context,
dependencies: dependencies, dependencies: dependencies,
resolveOptions resolveOptions
}, dependency.options), (err, beforeResolveResult) => { },
dependency.options
),
(err, beforeResolveResult) => {
if (err) return callback(err); if (err) return callback(err);
// Ignored // Ignored
@ -55,7 +62,9 @@ module.exports = class ContextModuleFactory extends Tapable {
const request = beforeResolveResult.request; const request = beforeResolveResult.request;
const resolveOptions = beforeResolveResult.resolveOptions; const resolveOptions = beforeResolveResult.resolveOptions;
let loaders, resource, loadersPrefix = ""; let loaders,
resource,
loadersPrefix = "";
const idx = request.lastIndexOf("!"); const idx = request.lastIndexOf("!");
if (idx >= 0) { if (idx >= 0) {
loaders = request.substr(0, idx + 1); loaders = request.substr(0, idx + 1);
@ -63,7 +72,10 @@ module.exports = class ContextModuleFactory extends Tapable {
for (i = 0; i < loaders.length && loaders[i] === "!"; i++) { for (i = 0; i < loaders.length && loaders[i] === "!"; i++) {
loadersPrefix += "!"; loadersPrefix += "!";
} }
loaders = loaders.substr(i).replace(/!+$/, "").replace(/!!+/g, "!"); loaders = loaders
.substr(i)
.replace(/!+$/, "")
.replace(/!!+/g, "!");
if (loaders === "") loaders = []; if (loaders === "") loaders = [];
else loaders = loaders.split("!"); else loaders = loaders.split("!");
resource = request.substr(idx + 1); resource = request.substr(idx + 1);
@ -72,41 +84,79 @@ module.exports = class ContextModuleFactory extends Tapable {
resource = request; resource = request;
} }
const contextResolver = this.resolverFactory.get("context", resolveOptions || EMPTY_RESOLVE_OPTIONS); const contextResolver = this.resolverFactory.get(
const loaderResolver = this.resolverFactory.get("loader", EMPTY_RESOLVE_OPTIONS); "context",
resolveOptions || EMPTY_RESOLVE_OPTIONS
);
const loaderResolver = this.resolverFactory.get(
"loader",
EMPTY_RESOLVE_OPTIONS
);
asyncLib.parallel([ asyncLib.parallel(
[
callback => { callback => {
contextResolver.resolve({}, context, resource, {}, (err, result) => { contextResolver.resolve(
{},
context,
resource,
{},
(err, result) => {
if (err) return callback(err); if (err) return callback(err);
callback(null, result); callback(null, result);
}); }
);
}, },
callback => { callback => {
asyncLib.map(loaders, (loader, callback) => { asyncLib.map(
loaderResolver.resolve({}, context, loader, {}, (err, result) => { loaders,
(loader, callback) => {
loaderResolver.resolve(
{},
context,
loader,
{},
(err, result) => {
if (err) return callback(err); if (err) return callback(err);
callback(null, result); callback(null, result);
});
}, callback);
} }
], (err, result) => { );
},
callback
);
}
],
(err, result) => {
if (err) return callback(err); if (err) return callback(err);
this.hooks.afterResolve.callAsync(Object.assign({ this.hooks.afterResolve.callAsync(
addon: loadersPrefix + result[1].join("!") + (result[1].length > 0 ? "!" : ""), Object.assign(
{
addon:
loadersPrefix +
result[1].join("!") +
(result[1].length > 0 ? "!" : ""),
resource: result[0], resource: result[0],
resolveDependencies: this.resolveDependencies.bind(this) resolveDependencies: this.resolveDependencies.bind(this)
}, beforeResolveResult), (err, result) => { },
beforeResolveResult
),
(err, result) => {
if (err) return callback(err); if (err) return callback(err);
// Ignored // Ignored
if (!result) return callback(); if (!result) return callback();
return callback(null, new ContextModule(result.resolveDependencies, result)); return callback(
}); null,
}); new ContextModule(result.resolveDependencies, result)
}); );
}
);
}
);
}
);
} }
resolveDependencies(fs, options, callback) { resolveDependencies(fs, options, callback) {
@ -117,17 +167,17 @@ 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),
const subResource = path.join(directory, seqment); (segment, callback) => {
const subResource = path.join(directory, segment);
if (!exclude || !subResource.match(exclude)) { if (!exclude || !subResource.match(exclude)) {
fs.stat(subResource, (err, stat) => { fs.stat(subResource, (err, stat) => {
@ -142,38 +192,51 @@ module.exports = class ContextModuleFactory extends Tapable {
} }
if (stat.isDirectory()) { if (stat.isDirectory()) {
if (!recursive) return callback(); if (!recursive) return callback();
addDirectory.call(this, subResource, callback); addDirectory.call(this, subResource, callback);
} else if (
} else if(stat.isFile() && (!include || subResource.match(include))) { stat.isFile() &&
(!include || subResource.match(include))
) {
const obj = { const obj = {
context: resource, context: resource,
request: "." + subResource.substr(resource.length).replace(/\\/g, "/") request:
"." +
subResource.substr(resource.length).replace(/\\/g, "/")
}; };
this.hooks.alternatives.callAsync([obj], (err, alternatives) => { this.hooks.alternatives.callAsync(
[obj],
(err, alternatives) => {
if (err) return callback(err); if (err) return callback(err);
alternatives = alternatives.filter(obj => regExp.test(obj.request)).map(obj => { alternatives = alternatives
const dep = new ContextElementDependency(obj.request + resourceQuery, obj.request); .filter(obj => regExp.test(obj.request))
.map(obj => {
const dep = new ContextElementDependency(
obj.request + resourceQuery,
obj.request
);
dep.optional = true; dep.optional = true;
return dep; return dep;
}); });
callback(null, alternatives); callback(null, alternatives);
}); }
);
} else callback(); } else callback();
}); });
} else callback(); } else callback();
}, (err, result) => { },
(err, result) => {
if (err) return callback(err); if (err) return callback(err);
if (!result) return callback(null, []); if (!result) return callback(null, []);
callback(null, result.filter(Boolean).reduce((a, i) => a.concat(i), [])); callback(
}); null,
result.filter(Boolean).reduce((a, i) => a.concat(i), [])
);
}
);
}); });
}; };

View File

@ -8,17 +8,28 @@ 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 {
@ -45,8 +56,8 @@ 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")
@ -59,14 +70,13 @@ class ContextReplacementPlugin {
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")
@ -76,7 +86,9 @@ class ContextReplacementPlugin {
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(
newContentCreateContextMap
);
if (typeof newContentCallback === "function") { if (typeof newContentCallback === "function") {
const origResource = result.resource; const origResource = result.resource;
newContentCallback(result); newContentCallback(result);
@ -85,8 +97,7 @@ class ContextReplacementPlugin {
} }
} 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,17 +10,24 @@ 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 (
"Object({" +
Object.keys(obj)
.map(key => {
const code = obj[key]; const code = obj[key];
return JSON.stringify(key) + ":" + toCode(code); return JSON.stringify(key) + ":" + toCode(code);
}).join(",") + "})"; })
.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)
return "(" + code.toString() + ")";
else if (typeof code === "object") return stringifyObj(code); else if (typeof code === "object") return stringifyObj(code);
else return code + ""; else return code + "";
}; };
@ -32,17 +39,24 @@ 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 (
code &&
typeof code === "object" &&
!(code instanceof RegExp)
) {
walkDefinitions(code, prefix + key + "."); walkDefinitions(code, prefix + key + ".");
applyObjectDefine(prefix + key, code); applyObjectDefine(prefix + key, code);
return; return;
@ -56,7 +70,9 @@ class DefinePlugin {
const splittedKey = key.split("."); const splittedKey = key.split(".");
splittedKey.slice(1).forEach((_, i) => { splittedKey.slice(1).forEach((_, i) => {
const fullKey = prefix + splittedKey.slice(0, i + 1).join("."); const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
parser.hooks.canRename.for(fullKey).tap("DefinePlugin", ParserHelpers.approve); parser.hooks.canRename
.for(fullKey)
.tap("DefinePlugin", ParserHelpers.approve);
}); });
}; };
@ -67,8 +83,12 @@ class DefinePlugin {
let recurseTypeof = false; let recurseTypeof = false;
code = toCode(code); code = toCode(code);
if (!isTypeof) { if (!isTypeof) {
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve); parser.hooks.canRename
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => { .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
@ -84,15 +104,25 @@ class DefinePlugin {
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.expression
.for(key)
.tap(
"DefinePlugin",
/__webpack_require__/.test(code)
? ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
code
)
: ParserHelpers.toConstantDependency(parser, code)
);
} }
const typeofCode = isTypeof ? code : "typeof (" + code + ")"; const typeofCode = isTypeof ? code : "typeof (" + code + ")";
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", (expr) => { parser.hooks.evaluateTypeof.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({
* "typeof a": "tyepof b", * "typeof a": "typeof b",
* "typeof b": "typeof a" * "typeof b": "typeof a"
* }); * });
*/ */
@ -103,29 +133,65 @@ class DefinePlugin {
res.setRange(expr.range); res.setRange(expr.range);
return res; return res;
}); });
parser.hooks.typeof.for(key).tap("DefinePlugin", (expr) => { parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
const res = parser.evaluate(typeofCode); const res = parser.evaluate(typeofCode);
if (!res.isString()) return; if (!res.isString()) return;
return ParserHelpers.toConstantDependency(parser, JSON.stringify(res.string)).bind(parser)(expr); return ParserHelpers.toConstantDependency(
parser,
JSON.stringify(res.string)
).bind(parser)(expr);
}); });
}; };
const applyObjectDefine = (key, obj) => { const applyObjectDefine = (key, obj) => {
const code = stringifyObj(obj); const code = stringifyObj(obj);
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve); parser.hooks.canRename
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => new BasicEvaluatedExpression().setTruthy().setRange(expr.range)); .for(key)
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", ParserHelpers.evaluateToString("object")); .tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.expression.for(key).tap("DefinePlugin", /__webpack_require__/.test(code) ? ParserHelpers.toConstantDependencyWithWebpackRequire(parser, code) : ParserHelpers.toConstantDependency(parser, code)); parser.hooks.evaluateIdentifier
parser.hooks.typeof.for(key).tap("DefinePlugin", ParserHelpers.toConstantDependency(parser, JSON.stringify("object"))); .for(key)
.tap("DefinePlugin", expr =>
new BasicEvaluatedExpression().setTruthy().setRange(expr.range)
);
parser.hooks.evaluateTypeof
.for(key)
.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, ""); walkDefinitions(definitions, "");
}; };
normalModuleFactory.hooks.parser.for("javascript/auto").tap("DefinePlugin", handler); normalModuleFactory.hooks.parser
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("DefinePlugin", handler); .for("javascript/auto")
normalModuleFactory.hooks.parser.for("javascript/esm").tap("DefinePlugin", handler); .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();
} }

View File

@ -21,7 +21,9 @@ 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(
"DelegatedModuleFactoryPlugin",
factory => (data, callback) => {
const dependency = data.dependencies[0]; const dependency = data.dependencies[0];
const request = dependency.request; const request = dependency.request;
if (request && request.indexOf(scope + "/") === 0) { if (request && request.indexOf(scope + "/") === 0) {
@ -29,30 +31,58 @@ class DelegatedModuleFactoryPlugin {
let resolved; let resolved;
if (innerRequest in this.options.content) { if (innerRequest in this.options.content) {
resolved = this.options.content[innerRequest]; resolved = this.options.content[innerRequest];
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, innerRequest, request)); return callback(
null,
new DelegatedModule(
this.options.source,
resolved,
this.options.type,
innerRequest,
request
)
);
} }
for (let i = 0; i < this.options.extensions.length; i++) { for (let i = 0; i < this.options.extensions.length; i++) {
const extension = this.options.extensions[i]; const extension = this.options.extensions[i];
const requestPlusExt = innerRequest + extension; const requestPlusExt = innerRequest + extension;
if (requestPlusExt in this.options.content) { if (requestPlusExt in this.options.content) {
resolved = this.options.content[requestPlusExt]; resolved = this.options.content[requestPlusExt];
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, requestPlusExt, request + extension)); 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(
"DelegatedModuleFactoryPlugin",
module => {
if (module.libIdent) { if (module.libIdent) {
const request = module.libIdent(this.options); const request = module.libIdent(this.options);
if (request && request in this.options.content) { if (request && request in this.options.content) {
const resolved = this.options.content[request]; const resolved = this.options.content[request];
return new DelegatedModule(this.options.source, resolved, this.options.type, request, module); 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(
"DelegatedPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
DelegatedSourceDependency,
normalModuleFactory normalModuleFactory
}) => { );
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory()); 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

@ -24,7 +24,9 @@ class DependenciesBlock {
return; return;
} }
} }
this.variables.push(new DependenciesBlockVariable(name, expression, dependencies)); this.variables.push(
new DependenciesBlockVariable(name, expression, dependencies)
);
} }
addDependency(dependency) { addDependency(dependency) {
@ -33,38 +35,29 @@ 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) {
@ -73,19 +66,16 @@ class DependenciesBlock {
} }
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) {
@ -26,7 +25,8 @@ class DependenciesBlockVariable {
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;

View File

@ -22,7 +22,7 @@ class Dependency {
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(
this.context,
new DllEntryDependency(
this.entries.map((e, idx) => {
const dep = new SingleEntryDependency(e); const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`; dep.loc = `${this.name}:${idx}`;
return dep; return dep;
}), this.name), this.name, callback); }),
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,10 +20,8 @@ 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 => {

View File

@ -20,39 +20,54 @@ class DllReferencePlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("DllReferencePlugin", (compilation, { compiler.hooks.compilation.tap(
"DllReferencePlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
DelegatedSourceDependency,
normalModuleFactory normalModuleFactory
}) => { );
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory()); DelegatedExportsDependency,
}); new NullFactory()
);
}
);
compiler.hooks.beforeCompile.tapAsync("DllReferencePlugin", (params, callback) => { compiler.hooks.beforeCompile.tapAsync(
"DllReferencePlugin",
(params, callback) => {
const manifest = this.options.manifest; const manifest = this.options.manifest;
if (typeof manifest === "string") { if (typeof manifest === "string") {
params.compilationDependencies.add(manifest); params.compilationDependencies.add(manifest);
compiler.inputFileSystem.readFile(manifest, (err, result) => { compiler.inputFileSystem.readFile(manifest, (err, result) => {
if (err) return callback(err); if (err) return callback(err);
params["dll reference " + manifest] = JSON.parse(result.toString("utf-8")); params["dll reference " + manifest] = JSON.parse(
result.toString("utf-8")
);
return callback(); return callback();
}); });
} else { } else {
return callback(); return callback();
} }
}); }
);
compiler.hooks.compile.tap("DllReferencePlugin", (params) => { 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,36 +17,48 @@ 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(
"DynamicEntryPlugin",
(compilation, callback) => {
const addEntry = (entry, name) => { const addEntry = (entry, name) => {
const dep = DynamicEntryPlugin.createDependency(entry, name); const dep = DynamicEntryPlugin.createDependency(entry, name);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
compilation.addEntry(this.context, dep, name, (err) => { compilation.addEntry(this.context, dep, name, err => {
if (err) return reject(err); if (err) return reject(err);
resolve(); 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(
Object.keys(entry).map(name => {
return addEntry(entry[name], name); return addEntry(entry[name], name);
})).then(() => callback(), callback); })
).then(() => callback(), callback);
} }
}); });
}); }
);
} }
} }
@ -55,6 +67,5 @@ 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

@ -7,7 +7,8 @@
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 {
@ -33,12 +34,17 @@ class EnvironmentPlugin {
// 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 - ${
key
} environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" + "You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example." "See https://webpack.js.org/plugins/environment-plugin for example."
); );
@ -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

@ -11,20 +11,27 @@ 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) => {
@ -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(
"EvalDevToolModuleTemplatePlugin",
(source, module) => {
const cacheEntry = cache.get(source); const cacheEntry = cache.get(source);
if (cacheEntry !== undefined) return cacheEntry; if (cacheEntry !== undefined) return cacheEntry;
const content = source.source(); const content = source.source();
const str = ModuleFilenameHelpers.createFilename(module, { const str = ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: this.moduleFilenameTemplate, moduleFilenameTemplate: this.moduleFilenameTemplate,
namespace: this.namespace namespace: this.namespace
}, 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(/^\//, "")); moduleTemplate.runtimeTemplate.requestShortener
const result = new RawSource(`eval(${JSON.stringify(content + footer)});`); );
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); cache.set(source, result);
return 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,8 +22,13 @@ 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,
options
);
moduleTemplate.hooks.module.tap(
"EvalSourceMapDevToolModuleTemplatePlugin",
(source, module) => {
if (source.__EvalSourceMapDevToolData) if (source.__EvalSourceMapDevToolData)
return source.__EvalSourceMapDevToolData; return source.__EvalSourceMapDevToolData;
if (!matchModule(module.resource)) { if (!matchModule(module.resource)) {
@ -51,29 +59,47 @@ class EvalSourceMapDevToolModuleTemplatePlugin {
return module || source; return module || source;
}); });
let moduleFilenames = modules.map(module => { let moduleFilenames = modules.map(module => {
return ModuleFilenameHelpers.createFilename(module, { return ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: self.moduleFilenameTemplate, moduleFilenameTemplate: self.moduleFilenameTemplate,
namespace: self.namespace namespace: self.namespace
}, moduleTemplate.runtimeTemplate.requestShortener); },
moduleTemplate.runtimeTemplate.requestShortener
);
}); });
moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(moduleFilenames, (filename, i, n) => { moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(
for(let j = 0; j < n; j++) moduleFilenames,
filename += "*"; (filename, i, n) => {
for (let j = 0; j < n; j++) filename += "*";
return filename; return filename;
}); }
);
sourceMap.sources = moduleFilenames; sourceMap.sources = moduleFilenames;
sourceMap.sourceRoot = options.sourceRoot || ""; sourceMap.sourceRoot = options.sourceRoot || "";
sourceMap.file = `${module.id}.js`; 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")}`) + const footer =
`\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug self.sourceMapComment.replace(
source.__EvalSourceMapDevToolData = new RawSource(`eval(${JSON.stringify(content + footer)});`); /\[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;
}); }
moduleTemplate.hooks.hash.tap("EvalSourceMapDevToolModuleTemplatePlugin", hash => { );
moduleTemplate.hooks.hash.tap(
"EvalSourceMapDevToolModuleTemplatePlugin",
hash => {
hash.update("eval-source-map"); hash.update("eval-source-map");
hash.update("2"); hash.update("2");
}); }
);
} }
} }
module.exports = EvalSourceMapDevToolModuleTemplatePlugin; module.exports = EvalSourceMapDevToolModuleTemplatePlugin;

View File

@ -10,7 +10,9 @@ 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(
"EvalSourceMapDevToolPlugin only takes one argument (pass an options object)"
);
if (typeof options === "string") { if (typeof options === "string") {
options = { options = {
append: options append: options
@ -22,10 +24,16 @@ class EvalSourceMapDevToolPlugin {
apply(compiler) { apply(compiler) {
const options = this.options; const options = this.options;
compiler.hooks.compilation.tap("EvalSourceMapDevToolPlugin", (compilation) => { compiler.hooks.compilation.tap(
"EvalSourceMapDevToolPlugin",
compilation => {
new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation); new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
new EvalSourceMapDevToolModuleTemplatePlugin(compilation, options).apply(compilation.moduleTemplates.javascript); 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,10 +16,7 @@ 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))}`;
@ -27,7 +24,10 @@ class ExportPropertyMainTemplatePlugin {
}; };
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(
"ExtendedAPIPlugin",
(source, chunk, hash) => {
const buf = [source]; const buf = [source];
buf.push(""); buf.push("");
buf.push("// __webpack_hash__"); buf.push("// __webpack_hash__");
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`); buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push(""); buf.push("");
buf.push("// __webpack_chunkname__"); buf.push("// __webpack_chunkname__");
buf.push(`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`); buf.push(
`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`
);
return Template.asString(buf); return Template.asString(buf);
}); }
);
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true); 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");
@ -54,51 +54,79 @@ class ExternalModule extends Module {
} }
// 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 =
typeof this.request === "object"
? this.request[this.externalType]
: this.request;
switch (this.externalType) { 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);
} }
@ -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,7 +14,9 @@ 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(
"ExternalModuleFactoryPlugin",
factory => (data, callback) => {
const context = data.context; const context = data.context;
const dependency = data.dependencies[0]; const dependency = data.dependencies[0];
@ -30,7 +32,10 @@ class ExternalModuleFactoryPlugin {
type = value.substr(0, idx); type = value.substr(0, idx);
value = value.substr(idx + 1); value = value.substr(idx + 1);
} }
callback(null, new ExternalModule(value, type || globalType, dependency.request)); callback(
null,
new ExternalModule(value, type || globalType, dependency.request)
);
return true; return true;
}; };
@ -70,16 +75,24 @@ class ExternalModuleFactoryPlugin {
return handleExternal(dependency.request, callback); return handleExternal(dependency.request, callback);
} }
} else if (typeof externals === "function") { } else if (typeof externals === "function") {
externals.call(null, context, dependency.request, (err, value, type) => { externals.call(
null,
context,
dependency.request,
(err, value, type) => {
if (err) return callback(err); if (err) return callback(err);
if (typeof value !== "undefined") { if (typeof value !== "undefined") {
handleExternal(value, type, callback); handleExternal(value, type, callback);
} else { } else {
callback(); callback();
} }
}); }
);
return; return;
} else if(typeof externals === "object" && Object.prototype.hasOwnProperty.call(externals, dependency.request)) { } else if (
typeof externals === "object" &&
Object.prototype.hasOwnProperty.call(externals, dependency.request)
) {
return handleExternal(externals[dependency.request], callback); return handleExternal(externals[dependency.request], callback);
} }
callback(); callback();
@ -90,7 +103,8 @@ class ExternalModuleFactoryPlugin {
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 }) => {
new ExternalModuleFactoryPlugin(this.type, this.externals).apply(
normalModuleFactory normalModuleFactory
}) => { );
new ExternalModuleFactoryPlugin(this.type, this.externals).apply(normalModuleFactory);
}); });
} }
} }

View File

@ -18,10 +18,13 @@ 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",
compilation => {
compilation.hooks.finishModules.tap(
"FlagDependencyExportsPlugin",
modules => {
const dependencies = new Map(); const dependencies = new Map();
const queue = new Queue(); const queue = new Queue();
@ -32,18 +35,15 @@ class FlagDependencyExportsPlugin {
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)) if (processDependency(dep)) return true;
return true;
} }
} }
for (const block of depBlock.blocks) { for (const block of depBlock.blocks) {
if(processDependenciesBlock(block)) if (processDependenciesBlock(block)) return true;
return true;
} }
return false; return false;
}; };
@ -105,26 +105,41 @@ class FlagDependencyExportsPlugin {
module = queue.dequeue(); module = queue.dequeue();
if (module.buildMeta.providedExports !== true) { if (module.buildMeta.providedExports !== true) {
moduleWithExports = module.buildMeta && module.buildMeta.exportsType; moduleWithExports =
moduleProvidedExports = Array.isArray(module.buildMeta.providedExports) ? new Set(module.buildMeta.providedExports) : new Set(); module.buildMeta && module.buildMeta.exportsType;
moduleProvidedExports = Array.isArray(
module.buildMeta.providedExports
)
? new Set(module.buildMeta.providedExports)
: new Set();
processDependenciesBlock(module); processDependenciesBlock(module);
if (!moduleWithExports) { if (!moduleWithExports) {
module.buildMeta.providedExports = true; module.buildMeta.providedExports = true;
notifyDependencies(); notifyDependencies();
} else if (module.buildMeta.providedExports !== true) { } else if (module.buildMeta.providedExports !== true) {
module.buildMeta.providedExports = Array.from(moduleProvidedExports); module.buildMeta.providedExports = Array.from(
moduleProvidedExports
);
} }
} }
} }
}); }
);
const providedExportsCache = new WeakMap(); const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap("FlagDependencyExportsPlugin", module => { compilation.hooks.rebuildModule.tap(
"FlagDependencyExportsPlugin",
module => {
providedExportsCache.set(module, module.buildMeta.providedExports); providedExportsCache.set(module, module.buildMeta.providedExports);
}); }
compilation.hooks.finishRebuildingModule.tap("FlagDependencyExportsPlugin", module => { );
compilation.hooks.finishRebuildingModule.tap(
"FlagDependencyExportsPlugin",
module => {
module.buildMeta.providedExports = providedExportsCache.get(module); module.buildMeta.providedExports = providedExportsCache.get(module);
}); }
}); );
}
);
} }
} }

View File

@ -6,8 +6,7 @@
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;
}; };
@ -20,30 +19,33 @@ const isSubset = (biggerSet, subset) => {
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) => { const processModule = (module, usedExports) => {
module.used = true; module.used = true;
if(module.usedExports === true) if (module.usedExports === true) return;
return; else if (usedExports === true) module.usedExports = true;
else if(usedExports === true)
module.usedExports = true;
else if (Array.isArray(usedExports)) { else if (Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1; const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(module.usedExports || [], usedExports); module.usedExports = addToSet(
if(module.usedExports.length === old) module.usedExports || [],
return; usedExports
} else if(Array.isArray(module.usedExports)) );
return; if (module.usedExports.length === old) return;
else } else if (Array.isArray(module.usedExports)) return;
module.usedExports = false; else module.usedExports = false;
// for a module without side effects we stop tracking usage here when no export is used // for a module without side effects we stop tracking usage here when no export is used
// This module won't be evaluated in this case // This module won't be evaluated in this case
if (module.factoryMeta.sideEffectFree) { if (module.factoryMeta.sideEffectFree) {
if (module.usedExports === false) return; if (module.usedExports === false) return;
if(Array.isArray(module.usedExports) && module.usedExports.length === 0) return; if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
return;
} }
queue.push([module, module.usedExports]); queue.push([module, module.usedExports]);
@ -70,7 +72,11 @@ class FlagDependencyUsagePlugin {
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 (
!oldUsed ||
(importedNames &&
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
) {
processModule(module, importedNames); processModule(module, importedNames);
} }
}; };
@ -90,7 +96,8 @@ class FlagDependencyUsagePlugin {
const queueItem = queue.pop(); const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]); processDependenciesBlock(queueItem[0], queueItem[1]);
} }
}); }
);
}); });
} }
} }

View File

@ -10,8 +10,12 @@ class FlagInitialModulesAsUsedPlugin {
} }
apply(compiler) { apply(compiler) {
compiler.hooks.compilation.tap("FlagInitialModulesAsUsedPlugin", (compilation) => { compiler.hooks.compilation.tap(
compilation.hooks.afterOptimizeChunks.tap("FlagInitialModulesAsUsedPlugin", (chunks) => { "FlagInitialModulesAsUsedPlugin",
compilation => {
compilation.hooks.afterOptimizeChunks.tap(
"FlagInitialModulesAsUsedPlugin",
chunks => {
for (const chunk of chunks) { for (const chunk of chunks) {
if (!chunk.isOnlyInitial()) { if (!chunk.isOnlyInitial()) {
return; return;
@ -22,8 +26,10 @@ class FlagInitialModulesAsUsedPlugin {
module.addReason(null, null, this.explanation); 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,12 +4,14 @@
*/ */
"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(
"FunctionModuleTemplatePlugin",
(moduleSource, module) => {
const source = new ConcatSource(); const source = new ConcatSource();
const args = [module.moduleArgument]; const args = [module.moduleArgument];
// TODO remove HACK checking type for javascript // TODO remove HACK checking type for javascript
@ -24,29 +26,49 @@ class FunctionModuleTemplatePlugin {
args.push(module.exportsArgument, "__webpack_require__"); args.push(module.exportsArgument, "__webpack_require__");
} }
source.add("/***/ (function(" + args.join(", ") + ") {\n\n"); source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
if(module.buildInfo.strict) source.add("\"use strict\";\n"); if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSource); source.add(moduleSource);
source.add("\n\n/***/ })"); source.add("\n\n/***/ })");
return source; return source;
}); }
);
moduleTemplate.hooks.package.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => { moduleTemplate.hooks.package.tap(
"FunctionModuleTemplatePlugin",
(moduleSource, module) => {
if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) { if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
const source = new ConcatSource(); const source = new ConcatSource();
const req = module.readableIdentifier(moduleTemplate.runtimeTemplate.requestShortener); 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"); 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) if (
Array.isArray(module.buildMeta.providedExports) &&
module.buildMeta.providedExports.length === 0
)
source.add(Template.toComment("no exports provided") + "\n"); source.add(Template.toComment("no exports provided") + "\n");
else if (Array.isArray(module.buildMeta.providedExports)) else if (Array.isArray(module.buildMeta.providedExports))
source.add(Template.toComment("exports provided: " + module.buildMeta.providedExports.join(", ")) + "\n"); source.add(
Template.toComment(
"exports provided: " +
module.buildMeta.providedExports.join(", ")
) + "\n"
);
else if (module.buildMeta.providedExports) else if (module.buildMeta.providedExports)
source.add(Template.toComment("no static exports found") + "\n"); source.add(Template.toComment("no static exports found") + "\n");
if(Array.isArray(module.usedExports) && module.usedExports.length === 0) if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
source.add(Template.toComment("no exports used") + "\n"); source.add(Template.toComment("no exports used") + "\n");
else if (Array.isArray(module.usedExports)) else if (Array.isArray(module.usedExports))
source.add(Template.toComment("exports used: " + module.usedExports.join(", ")) + "\n"); source.add(
Template.toComment(
"exports used: " + module.usedExports.join(", ")
) + "\n"
);
else if (module.usedExports) else if (module.usedExports)
source.add(Template.toComment("all exports used") + "\n"); source.add(Template.toComment("all exports used") + "\n");
if (module.optimizationBailout) { if (module.optimizationBailout) {
@ -64,7 +86,8 @@ class FunctionModuleTemplatePlugin {
return source; return source;
} }
return moduleSource; return moduleSource;
}); }
);
moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => { moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => {
hash.update("FunctionModuleTemplatePlugin"); hash.update("FunctionModuleTemplatePlugin");

View File

@ -12,19 +12,24 @@ class HashedModuleIdsPlugin {
constructor(options) { constructor(options) {
validateOptions(schema, options || {}, "Hashed Module Ids Plugin"); validateOptions(schema, options || {}, "Hashed Module Ids Plugin");
this.options = Object.assign({ this.options = Object.assign(
{
context: null, context: null,
hashFunction: "md4", hashFunction: "md4",
hashDigest: "base64", hashDigest: "base64",
hashDigestLength: 4 hashDigestLength: 4
}, options); },
options
);
} }
apply(compiler) { apply(compiler) {
const options = this.options; const options = this.options;
compiler.hooks.compilation.tap("HashedModuleIdsPlugin", (compilation) => { compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => {
const usedIds = new Set(); const usedIds = new Set();
compilation.hooks.beforeModuleIds.tap("HashedModuleIdsPlugin", (modules) => { compilation.hooks.beforeModuleIds.tap(
"HashedModuleIdsPlugin",
modules => {
for (const module of modules) { for (const module of modules) {
if (module.id === null && module.libIdent) { if (module.id === null && module.libIdent) {
const id = module.libIdent({ const id = module.libIdent({
@ -34,13 +39,13 @@ class HashedModuleIdsPlugin {
hash.update(id); hash.update(id);
const hashId = hash.digest(options.hashDigest); const hashId = hash.digest(options.hashDigest);
let len = options.hashDigestLength; let len = options.hashDigestLength;
while(usedIds.has(hashId.substr(0, len))) while (usedIds.has(hashId.substr(0, len))) len++;
len++;
module.id = hashId.substr(0, len); module.id = hashId.substr(0, len);
usedIds.add(module.id); usedIds.add(module.id);
} }
} }
}); }
);
}); });
} }
} }

View File

@ -4,7 +4,6 @@
*/ */
/*global $hash$ $requestTimeout$ installedModules $require$ hotDownloadManifest hotDownloadUpdateChunk hotDisposeChunk modules */ /*global $hash$ $requestTimeout$ installedModules $require$ hotDownloadManifest hotDownloadUpdateChunk hotDisposeChunk modules */
module.exports = function() { module.exports = function() {
var hotApplyOnUpdate = true; var hotApplyOnUpdate = true;
var hotCurrentHash = $hash$; // eslint-disable-line no-unused-vars var hotCurrentHash = $hash$; // eslint-disable-line no-unused-vars
var hotRequestTimeout = $requestTimeout$; var hotRequestTimeout = $requestTimeout$;
@ -13,22 +12,27 @@ module.exports = function() {
var hotCurrentParents = []; // eslint-disable-line no-unused-vars var hotCurrentParents = []; // eslint-disable-line no-unused-vars
var hotCurrentParentsTemp = []; // eslint-disable-line no-unused-vars var hotCurrentParentsTemp = []; // eslint-disable-line no-unused-vars
function hotCreateRequire(moduleId) { // eslint-disable-line no-unused-vars // eslint-disable-next-line no-unused-vars
function hotCreateRequire(moduleId) {
var me = installedModules[moduleId]; var me = installedModules[moduleId];
if (!me) return $require$; if (!me) return $require$;
var fn = function(request) { var fn = function(request) {
if (me.hot.active) { if (me.hot.active) {
if (installedModules[request]) { if (installedModules[request]) {
if(!installedModules[request].parents.includes(moduleId)) if (installedModules[request].parents.indexOf(moduleId) === -1)
installedModules[request].parents.push(moduleId); installedModules[request].parents.push(moduleId);
} else { } else {
hotCurrentParents = [moduleId]; hotCurrentParents = [moduleId];
hotCurrentChildModule = request; hotCurrentChildModule = request;
} }
if(!me.children.includes(request)) if (me.children.indexOf(request) === -1) me.children.push(request);
me.children.push(request);
} else { } else {
console.warn("[HMR] unexpected require(" + request + ") from disposed module " + moduleId); console.warn(
"[HMR] unexpected require(" +
request +
") from disposed module " +
moduleId
);
hotCurrentParents = []; hotCurrentParents = [];
} }
return $require$(request); return $require$(request);
@ -46,13 +50,15 @@ module.exports = function() {
}; };
}; };
for (var name in $require$) { for (var name in $require$) {
if(Object.prototype.hasOwnProperty.call($require$, name) && name !== "e") { if (
Object.prototype.hasOwnProperty.call($require$, name) &&
name !== "e"
) {
Object.defineProperty(fn, name, ObjectFactory(name)); Object.defineProperty(fn, name, ObjectFactory(name));
} }
} }
fn.e = function(chunkId) { fn.e = function(chunkId) {
if(hotStatus === "ready") if (hotStatus === "ready") hotSetStatus("prepare");
hotSetStatus("prepare");
hotChunksLoading++; hotChunksLoading++;
return $require$.e(chunkId).then(finishChunkLoading, function(err) { return $require$.e(chunkId).then(finishChunkLoading, function(err) {
finishChunkLoading(); finishChunkLoading();
@ -74,7 +80,8 @@ module.exports = function() {
return fn; return fn;
} }
function hotCreateModule(moduleId) { // eslint-disable-line no-unused-vars // eslint-disable-next-line no-unused-vars
function hotCreateModule(moduleId) {
var hot = { var hot = {
// private stuff // private stuff
_acceptedDependencies: {}, _acceptedDependencies: {},
@ -87,24 +94,19 @@ module.exports = function() {
// Module API // Module API
active: true, active: true,
accept: function(dep, callback) { accept: function(dep, callback) {
if(typeof dep === "undefined") if (typeof dep === "undefined") hot._selfAccepted = true;
hot._selfAccepted = true; else if (typeof dep === "function") hot._selfAccepted = dep;
else if(typeof dep === "function")
hot._selfAccepted = dep;
else if (typeof dep === "object") else if (typeof dep === "object")
for (var i = 0; i < dep.length; i++) for (var i = 0; i < dep.length; i++)
hot._acceptedDependencies[dep[i]] = callback || function() {}; hot._acceptedDependencies[dep[i]] = callback || function() {};
else else hot._acceptedDependencies[dep] = callback || function() {};
hot._acceptedDependencies[dep] = callback || function() {};
}, },
decline: function(dep) { decline: function(dep) {
if(typeof dep === "undefined") if (typeof dep === "undefined") hot._selfDeclined = true;
hot._selfDeclined = true;
else if (typeof dep === "object") else if (typeof dep === "object")
for (var i = 0; i < dep.length; i++) for (var i = 0; i < dep.length; i++)
hot._declinedDependencies[dep[i]] = true; hot._declinedDependencies[dep[i]] = true;
else else hot._declinedDependencies[dep] = true;
hot._declinedDependencies[dep] = true;
}, },
dispose: function(callback) { dispose: function(callback) {
hot._disposeHandlers.push(callback); hot._disposeHandlers.push(callback);
@ -160,12 +162,13 @@ module.exports = function() {
var hotUpdate, hotUpdateNewHash; var hotUpdate, hotUpdateNewHash;
function toModuleId(id) { function toModuleId(id) {
var isNumber = (+id) + "" === id; var isNumber = +id + "" === id;
return isNumber ? +id : id; return isNumber ? +id : id;
} }
function hotCheck(apply) { function hotCheck(apply) {
if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status"); if (hotStatus !== "idle")
throw new Error("check() is only allowed in idle status");
hotApplyOnUpdate = apply; hotApplyOnUpdate = apply;
hotSetStatus("check"); hotSetStatus("check");
return hotDownloadManifest(hotRequestTimeout).then(function(update) { return hotDownloadManifest(hotRequestTimeout).then(function(update) {
@ -187,18 +190,24 @@ module.exports = function() {
}); });
hotUpdate = {}; hotUpdate = {};
/*foreachInstalledChunks*/ /*foreachInstalledChunks*/
{ // eslint-disable-line no-lone-blocks {
// eslint-disable-line no-lone-blocks
/*globals chunkId */ /*globals chunkId */
hotEnsureUpdateChunk(chunkId); hotEnsureUpdateChunk(chunkId);
} }
if(hotStatus === "prepare" && hotChunksLoading === 0 && hotWaitingFiles === 0) { if (
hotStatus === "prepare" &&
hotChunksLoading === 0 &&
hotWaitingFiles === 0
) {
hotUpdateDownloaded(); hotUpdateDownloaded();
} }
return promise; return promise;
}); });
} }
function hotAddUpdateChunk(chunkId, moreModules) { // eslint-disable-line no-unused-vars // eslint-disable-next-line no-unused-vars
function hotAddUpdateChunk(chunkId, moreModules) {
if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId]) if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
return; return;
hotRequestedFilesMap[chunkId] = false; hotRequestedFilesMap[chunkId] = false;
@ -231,9 +240,11 @@ module.exports = function() {
// Wrap deferred object in Promise to mark it as a well-handled Promise to // Wrap deferred object in Promise to mark it as a well-handled Promise to
// avoid triggering uncaught exception warning in Chrome. // avoid triggering uncaught exception warning in Chrome.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=465666 // See https://bugs.chromium.org/p/chromium/issues/detail?id=465666
Promise.resolve().then(function() { Promise.resolve()
.then(function() {
return hotApply(hotApplyOnUpdate); return hotApply(hotApplyOnUpdate);
}).then( })
.then(
function(result) { function(result) {
deferred.resolve(result); deferred.resolve(result);
}, },
@ -253,7 +264,8 @@ module.exports = function() {
} }
function hotApply(options) { function hotApply(options) {
if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status"); if (hotStatus !== "ready")
throw new Error("apply() is only allowed in ready status");
options = options || {}; options = options || {};
var cb; var cb;
@ -277,8 +289,7 @@ module.exports = function() {
var moduleId = queueItem.id; var moduleId = queueItem.id;
var chain = queueItem.chain; var chain = queueItem.chain;
module = installedModules[moduleId]; module = installedModules[moduleId];
if(!module || module.hot._selfAccepted) if (!module || module.hot._selfAccepted) continue;
continue;
if (module.hot._selfDeclined) { if (module.hot._selfDeclined) {
return { return {
type: "self-declined", type: "self-declined",
@ -305,7 +316,7 @@ module.exports = function() {
parentId: parentId parentId: parentId
}; };
} }
if(outdatedModules.includes(parentId)) continue; if (outdatedModules.indexOf(parentId) !== -1) continue;
if (parent.hot._acceptedDependencies[moduleId]) { if (parent.hot._acceptedDependencies[moduleId]) {
if (!outdatedDependencies[parentId]) if (!outdatedDependencies[parentId])
outdatedDependencies[parentId] = []; outdatedDependencies[parentId] = [];
@ -332,8 +343,7 @@ module.exports = function() {
function addAllToSet(a, b) { function addAllToSet(a, b) {
for (var i = 0; i < b.length; i++) { for (var i = 0; i < b.length; i++) {
var item = b[i]; var item = b[i];
if(!a.includes(item)) if (a.indexOf(item) === -1) a.push(item);
a.push(item);
} }
} }
@ -344,7 +354,9 @@ module.exports = function() {
var appliedUpdate = {}; var appliedUpdate = {};
var warnUnexpectedRequire = function warnUnexpectedRequire() { var warnUnexpectedRequire = function warnUnexpectedRequire() {
console.warn("[HMR] unexpected require(" + result.moduleId + ") to disposed module"); console.warn(
"[HMR] unexpected require(" + result.moduleId + ") to disposed module"
);
}; };
for (var id in hotUpdate) { for (var id in hotUpdate) {
@ -368,31 +380,38 @@ module.exports = function() {
} }
switch (result.type) { switch (result.type) {
case "self-declined": case "self-declined":
if(options.onDeclined) if (options.onDeclined) options.onDeclined(result);
options.onDeclined(result);
if (!options.ignoreDeclined) if (!options.ignoreDeclined)
abortError = new Error("Aborted because of self decline: " + result.moduleId + chainInfo); abortError = new Error(
"Aborted because of self decline: " +
result.moduleId +
chainInfo
);
break; break;
case "declined": case "declined":
if(options.onDeclined) if (options.onDeclined) options.onDeclined(result);
options.onDeclined(result);
if (!options.ignoreDeclined) if (!options.ignoreDeclined)
abortError = new Error("Aborted because of declined dependency: " + result.moduleId + " in " + result.parentId + chainInfo); abortError = new Error(
"Aborted because of declined dependency: " +
result.moduleId +
" in " +
result.parentId +
chainInfo
);
break; break;
case "unaccepted": case "unaccepted":
if(options.onUnaccepted) if (options.onUnaccepted) options.onUnaccepted(result);
options.onUnaccepted(result);
if (!options.ignoreUnaccepted) if (!options.ignoreUnaccepted)
abortError = new Error("Aborted because " + moduleId + " is not accepted" + chainInfo); abortError = new Error(
"Aborted because " + moduleId + " is not accepted" + chainInfo
);
break; break;
case "accepted": case "accepted":
if(options.onAccepted) if (options.onAccepted) options.onAccepted(result);
options.onAccepted(result);
doApply = true; doApply = true;
break; break;
case "disposed": case "disposed":
if(options.onDisposed) if (options.onDisposed) options.onDisposed(result);
options.onDisposed(result);
doDispose = true; doDispose = true;
break; break;
default: default:
@ -406,10 +425,18 @@ module.exports = function() {
appliedUpdate[moduleId] = hotUpdate[moduleId]; appliedUpdate[moduleId] = hotUpdate[moduleId];
addAllToSet(outdatedModules, result.outdatedModules); addAllToSet(outdatedModules, result.outdatedModules);
for (moduleId in result.outdatedDependencies) { for (moduleId in result.outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(result.outdatedDependencies, moduleId)) { if (
Object.prototype.hasOwnProperty.call(
result.outdatedDependencies,
moduleId
)
) {
if (!outdatedDependencies[moduleId]) if (!outdatedDependencies[moduleId])
outdatedDependencies[moduleId] = []; outdatedDependencies[moduleId] = [];
addAllToSet(outdatedDependencies[moduleId], result.outdatedDependencies[moduleId]); addAllToSet(
outdatedDependencies[moduleId],
result.outdatedDependencies[moduleId]
);
} }
} }
} }
@ -424,7 +451,10 @@ module.exports = function() {
var outdatedSelfAcceptedModules = []; var outdatedSelfAcceptedModules = [];
for (i = 0; i < outdatedModules.length; i++) { for (i = 0; i < outdatedModules.length; i++) {
moduleId = outdatedModules[i]; moduleId = outdatedModules[i];
if(installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted) if (
installedModules[moduleId] &&
installedModules[moduleId].hot._selfAccepted
)
outdatedSelfAcceptedModules.push({ outdatedSelfAcceptedModules.push({
module: moduleId, module: moduleId,
errorHandler: installedModules[moduleId].hot._selfAccepted errorHandler: installedModules[moduleId].hot._selfAccepted
@ -480,7 +510,9 @@ module.exports = function() {
var dependency; var dependency;
var moduleOutdatedDependencies; var moduleOutdatedDependencies;
for (moduleId in outdatedDependencies) { for (moduleId in outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) { if (
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
) {
module = installedModules[moduleId]; module = installedModules[moduleId];
if (module) { if (module) {
moduleOutdatedDependencies = outdatedDependencies[moduleId]; moduleOutdatedDependencies = outdatedDependencies[moduleId];
@ -508,7 +540,9 @@ module.exports = function() {
// call accept handlers // call accept handlers
var error = null; var error = null;
for (moduleId in outdatedDependencies) { for (moduleId in outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) { if (
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
) {
module = installedModules[moduleId]; module = installedModules[moduleId];
if (module) { if (module) {
moduleOutdatedDependencies = outdatedDependencies[moduleId]; moduleOutdatedDependencies = outdatedDependencies[moduleId];
@ -517,7 +551,7 @@ module.exports = function() {
dependency = moduleOutdatedDependencies[i]; dependency = moduleOutdatedDependencies[i];
cb = module.hot._acceptedDependencies[dependency]; cb = module.hot._acceptedDependencies[dependency];
if (cb) { if (cb) {
if(callbacks.includes(cb)) continue; if (callbacks.indexOf(cb) !== -1) continue;
callbacks.push(cb); callbacks.push(cb);
} }
} }
@ -535,8 +569,7 @@ module.exports = function() {
}); });
} }
if (!options.ignoreErrored) { if (!options.ignoreErrored) {
if(!error) if (!error) error = err;
error = err;
} }
} }
} }
@ -565,11 +598,9 @@ module.exports = function() {
}); });
} }
if (!options.ignoreErrored) { if (!options.ignoreErrored) {
if(!error) if (!error) error = err2;
error = err2;
} }
if(!error) if (!error) error = err;
error = err;
} }
} else { } else {
if (options.onErrored) { if (options.onErrored) {
@ -580,8 +611,7 @@ module.exports = function() {
}); });
} }
if (!options.ignoreErrored) { if (!options.ignoreErrored) {
if(!error) if (!error) error = err;
error = err;
} }
} }
} }

View File

@ -3,15 +3,16 @@
Author Tobias Koppers @sokra Author Tobias Koppers @sokra
*/ */
"use strict"; "use strict";
const { SyncBailHook } = require("tapable");
const { RawSource } = require("webpack-sources");
const Template = require("./Template"); const Template = require("./Template");
const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency"); const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency");
const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency"); const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency");
const RawSource = require("webpack-sources").RawSource;
const ConstDependency = require("./dependencies/ConstDependency"); const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory"); const NullFactory = require("./NullFactory");
const ParserHelpers = require("./ParserHelpers"); const ParserHelpers = require("./ParserHelpers");
const createHash = require("./util/createHash"); const createHash = require("./util/createHash");
const SyncBailHook = require("tapable").SyncBailHook;
module.exports = class HotModuleReplacementPlugin { module.exports = class HotModuleReplacementPlugin {
constructor(options) { constructor(options) {
@ -25,29 +26,49 @@ module.exports = class HotModuleReplacementPlugin {
const multiStep = this.multiStep; const multiStep = this.multiStep;
const fullBuildTimeout = this.fullBuildTimeout; const fullBuildTimeout = this.fullBuildTimeout;
const requestTimeout = this.requestTimeout; const requestTimeout = this.requestTimeout;
const hotUpdateChunkFilename = compiler.options.output.hotUpdateChunkFilename; const hotUpdateChunkFilename =
compiler.options.output.hotUpdateChunkFilename;
const hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename; const hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename;
compiler.hooks.additionalPass.tapAsync("HotModuleReplacementPlugin", (callback) => { compiler.hooks.additionalPass.tapAsync(
if(multiStep) "HotModuleReplacementPlugin",
return setTimeout(callback, fullBuildTimeout); callback => {
if (multiStep) return setTimeout(callback, fullBuildTimeout);
return callback(); return callback();
}); }
compiler.hooks.compilation.tap("HotModuleReplacementPlugin", (compilation, { );
normalModuleFactory compiler.hooks.compilation.tap(
}) => { "HotModuleReplacementPlugin",
(compilation, { normalModuleFactory }) => {
const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate; const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate;
if (!hotUpdateChunkTemplate) return; if (!hotUpdateChunkTemplate) return;
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()
);
compilation.dependencyFactories.set(ModuleHotAcceptDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyTemplates.set(ModuleHotAcceptDependency, new ModuleHotAcceptDependency.Template()); ModuleHotAcceptDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ModuleHotAcceptDependency,
new ModuleHotAcceptDependency.Template()
);
compilation.dependencyFactories.set(ModuleHotDeclineDependency, normalModuleFactory); compilation.dependencyFactories.set(
compilation.dependencyTemplates.set(ModuleHotDeclineDependency, new ModuleHotDeclineDependency.Template()); ModuleHotDeclineDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ModuleHotDeclineDependency,
new ModuleHotDeclineDependency.Template()
);
compilation.hooks.record.tap("HotModuleReplacementPlugin", (compilation, records) => { compilation.hooks.record.tap(
"HotModuleReplacementPlugin",
(compilation, records) => {
if (records.hash === compilation.hash) return; if (records.hash === compilation.hash) return;
records.hash = compilation.hash; records.hash = compilation.hash;
records.moduleHashs = {}; records.moduleHashs = {};
@ -63,9 +84,13 @@ module.exports = class HotModuleReplacementPlugin {
} }
records.chunkModuleIds = {}; records.chunkModuleIds = {};
for (const chunk of compilation.chunks) { for (const chunk of compilation.chunks) {
records.chunkModuleIds[chunk.id] = Array.from(chunk.modulesIterable, m => m.id); records.chunkModuleIds[chunk.id] = Array.from(
chunk.modulesIterable,
m => m.id
);
} }
}); }
);
let initialPass = false; let initialPass = false;
let recompilation = false; let recompilation = false;
compilation.hooks.afterHash.tap("HotModuleReplacementPlugin", () => { compilation.hooks.afterHash.tap("HotModuleReplacementPlugin", () => {
@ -74,8 +99,7 @@ module.exports = class HotModuleReplacementPlugin {
initialPass = true; initialPass = true;
return; return;
} }
if(!records.hash) if (!records.hash) initialPass = true;
initialPass = true;
const preHash = records.preHash || "x"; const preHash = records.preHash || "x";
const prepreHash = records.prepreHash || "x"; const prepreHash = records.prepreHash || "x";
if (preHash === compilation.hash) { if (preHash === compilation.hash) {
@ -87,18 +111,29 @@ module.exports = class HotModuleReplacementPlugin {
records.preHash = compilation.hash; records.preHash = compilation.hash;
compilation.modifyHash(records.prepreHash); compilation.modifyHash(records.prepreHash);
}); });
compilation.hooks.shouldGenerateChunkAssets.tap("HotModuleReplacementPlugin", () => { compilation.hooks.shouldGenerateChunkAssets.tap(
if(multiStep && !recompilation && !initialPass) "HotModuleReplacementPlugin",
return false; () => {
}); if (multiStep && !recompilation && !initialPass) return false;
compilation.hooks.needAdditionalPass.tap("HotModuleReplacementPlugin", () => { }
if(multiStep && !recompilation && !initialPass) );
return true; compilation.hooks.needAdditionalPass.tap(
}); "HotModuleReplacementPlugin",
compilation.hooks.additionalChunkAssets.tap("HotModuleReplacementPlugin", () => { () => {
if (multiStep && !recompilation && !initialPass) return true;
}
);
compilation.hooks.additionalChunkAssets.tap(
"HotModuleReplacementPlugin",
() => {
const records = compilation.records; const records = compilation.records;
if (records.hash === compilation.hash) return; if (records.hash === compilation.hash) return;
if(!records.moduleHashs || !records.chunkHashs || !records.chunkModuleIds) return; if (
!records.moduleHashs ||
!records.chunkHashs ||
!records.chunkModuleIds
)
return;
for (const module of compilation.modules) { for (const module of compilation.modules) {
const identifier = module.identifier(); const identifier = module.identifier();
let hash = createHash(compilation.outputOptions.hashFunction); let hash = createHash(compilation.outputOptions.hashFunction);
@ -108,20 +143,33 @@ module.exports = class HotModuleReplacementPlugin {
} }
const hotUpdateMainContent = { const hotUpdateMainContent = {
h: compilation.hash, h: compilation.hash,
c: {}, c: {}
}; };
for (let chunkId of Object.keys(records.chunkHashs)) { for (let chunkId of Object.keys(records.chunkHashs)) {
chunkId = isNaN(+chunkId) ? chunkId : +chunkId; chunkId = isNaN(+chunkId) ? chunkId : +chunkId;
const currentChunk = compilation.chunks.find(chunk => chunk.id === chunkId); const currentChunk = compilation.chunks.find(
chunk => chunk.id === chunkId
);
if (currentChunk) { if (currentChunk) {
const newModules = currentChunk.getModules().filter(module => module.hotUpdate); const newModules = currentChunk
.getModules()
.filter(module => module.hotUpdate);
const allModules = new Set(); const allModules = new Set();
for (const module of currentChunk.modulesIterable) { for (const module of currentChunk.modulesIterable) {
allModules.add(module.id); allModules.add(module.id);
} }
const removedModules = records.chunkModuleIds[chunkId].filter(id => !allModules.has(id)); const removedModules = records.chunkModuleIds[chunkId].filter(
id => !allModules.has(id)
);
if (newModules.length > 0 || removedModules.length > 0) { if (newModules.length > 0 || removedModules.length > 0) {
const source = hotUpdateChunkTemplate.render(chunkId, newModules, removedModules, compilation.hash, compilation.moduleTemplates.javascript, compilation.dependencyTemplates); const source = hotUpdateChunkTemplate.render(
chunkId,
newModules,
removedModules,
compilation.hash,
compilation.moduleTemplates.javascript,
compilation.dependencyTemplates
);
const filename = compilation.getPath(hotUpdateChunkFilename, { const filename = compilation.getPath(hotUpdateChunkFilename, {
hash: records.hash, hash: records.hash,
chunk: currentChunk chunk: currentChunk
@ -130,7 +178,11 @@ module.exports = class HotModuleReplacementPlugin {
compilation.assets[filename] = source; compilation.assets[filename] = source;
hotUpdateMainContent.c[chunkId] = true; hotUpdateMainContent.c[chunkId] = true;
currentChunk.files.push(filename); currentChunk.files.push(filename);
compilation.hooks.chunkAsset.call("HotModuleReplacementPlugin", currentChunk, filename); compilation.hooks.chunkAsset.call(
"HotModuleReplacementPlugin",
currentChunk,
filename
);
} }
} else { } else {
hotUpdateMainContent.c[chunkId] = false; hotUpdateMainContent.c[chunkId] = false;
@ -141,7 +193,8 @@ module.exports = class HotModuleReplacementPlugin {
hash: records.hash hash: records.hash
}); });
compilation.assets[filename] = source; compilation.assets[filename] = source;
}); }
);
const mainTemplate = compilation.mainTemplate; const mainTemplate = compilation.mainTemplate;
@ -149,17 +202,26 @@ module.exports = class HotModuleReplacementPlugin {
hash.update("HotMainTemplateDecorator"); hash.update("HotMainTemplateDecorator");
}); });
mainTemplate.hooks.moduleRequire.tap("HotModuleReplacementPlugin", (_, chunk, hash, varModuleId) => { mainTemplate.hooks.moduleRequire.tap(
"HotModuleReplacementPlugin",
(_, chunk, hash, varModuleId) => {
return `hotCreateRequire(${varModuleId})`; return `hotCreateRequire(${varModuleId})`;
}); }
);
mainTemplate.hooks.requireExtensions.tap("HotModuleReplacementPlugin", source => { mainTemplate.hooks.requireExtensions.tap(
"HotModuleReplacementPlugin",
source => {
const buf = [source]; const buf = [source];
buf.push(""); buf.push("");
buf.push("// __webpack_hash__"); buf.push("// __webpack_hash__");
buf.push(mainTemplate.requireFn + ".h = function() { return hotCurrentHash; };"); buf.push(
mainTemplate.requireFn +
".h = function() { return hotCurrentHash; };"
);
return Template.asString(buf); return Template.asString(buf);
}); }
);
const needChunkLoadingCode = chunk => { const needChunkLoadingCode = chunk => {
for (const chunkGroup of chunk.groupsIterable) { for (const chunkGroup of chunk.groupsIterable) {
@ -169,7 +231,9 @@ module.exports = class HotModuleReplacementPlugin {
return false; return false;
}; };
mainTemplate.hooks.bootstrap.tap("HotModuleReplacementPlugin", (source, chunk, hash) => { mainTemplate.hooks.bootstrap.tap(
"HotModuleReplacementPlugin",
(source, chunk, hash) => {
source = mainTemplate.hooks.hotBootstrap.call(source, chunk, hash); source = mainTemplate.hooks.hotBootstrap.call(source, chunk, hash);
return Template.asString([ return Template.asString([
source, source,
@ -178,41 +242,85 @@ module.exports = class HotModuleReplacementPlugin {
.replace(/\$require\$/g, mainTemplate.requireFn) .replace(/\$require\$/g, mainTemplate.requireFn)
.replace(/\$hash\$/g, JSON.stringify(hash)) .replace(/\$hash\$/g, JSON.stringify(hash))
.replace(/\$requestTimeout\$/g, requestTimeout) .replace(/\$requestTimeout\$/g, requestTimeout)
.replace(/\/\*foreachInstalledChunks\*\//g, needChunkLoadingCode(chunk) ? "for(var chunkId in installedChunks)" : `var chunkId = ${JSON.stringify(chunk.id)};`) .replace(
/\/\*foreachInstalledChunks\*\//g,
needChunkLoadingCode(chunk)
? "for(var chunkId in installedChunks)"
: `var chunkId = ${JSON.stringify(chunk.id)};`
)
]); ]);
}); }
);
mainTemplate.hooks.globalHash.tap("HotModuleReplacementPlugin", () => true); mainTemplate.hooks.globalHash.tap(
"HotModuleReplacementPlugin",
() => true
);
mainTemplate.hooks.currentHash.tap("HotModuleReplacementPlugin", (_, length) => { mainTemplate.hooks.currentHash.tap(
if(isFinite(length)) "HotModuleReplacementPlugin",
return `hotCurrentHash.substr(0, ${length})`; (_, length) => {
else if (isFinite(length)) return `hotCurrentHash.substr(0, ${length})`;
return "hotCurrentHash"; else return "hotCurrentHash";
}); }
);
mainTemplate.hooks.moduleObj.tap("HotModuleReplacementPlugin", (source, chunk, hash, varModuleId) => { mainTemplate.hooks.moduleObj.tap(
"HotModuleReplacementPlugin",
(source, chunk, hash, varModuleId) => {
return Template.asString([ return Template.asString([
`${source},`, `${source},`,
`hot: hotCreateModule(${varModuleId}),`, `hot: hotCreateModule(${varModuleId}),`,
"parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),", "parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),",
"children: []" "children: []"
]); ]);
}); }
);
const handler = (parser, parserOptions) => { const handler = (parser, parserOptions) => {
parser.hooks.expression.for("__webpack_hash__").tap("HotModuleReplacementPlugin", ParserHelpers.toConstantDependencyWithWebpackRequire(parser, "__webpack_require__.h()")); parser.hooks.expression
parser.hooks.evaluateTypeof.for("__webpack_hash__").tap("HotModuleReplacementPlugin", ParserHelpers.evaluateToString("string")); .for("__webpack_hash__")
parser.hooks.evaluateIdentifier.for("module.hot").tap("HotModuleReplacementPlugin", expr => { .tap(
return ParserHelpers.evaluateToIdentifier("module.hot", !!parser.state.compilation.hotUpdateChunkTemplate)(expr); "HotModuleReplacementPlugin",
}); ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
"__webpack_require__.h()"
)
);
parser.hooks.evaluateTypeof
.for("__webpack_hash__")
.tap(
"HotModuleReplacementPlugin",
ParserHelpers.evaluateToString("string")
);
parser.hooks.evaluateIdentifier.for("module.hot").tap(
{
name: "HotModuleReplacementPlugin",
before: "NodeStuffPlugin"
},
expr => {
return ParserHelpers.evaluateToIdentifier(
"module.hot",
!!parser.state.compilation.hotUpdateChunkTemplate
)(expr);
}
);
// TODO webpack 5: refactor this, no custom hooks // TODO webpack 5: refactor this, no custom hooks
if (!parser.hooks.hotAcceptCallback) if (!parser.hooks.hotAcceptCallback)
parser.hooks.hotAcceptCallback = new SyncBailHook(["expression", "requests"]); parser.hooks.hotAcceptCallback = new SyncBailHook([
"expression",
"requests"
]);
if (!parser.hooks.hotAcceptWithoutCallback) if (!parser.hooks.hotAcceptWithoutCallback)
parser.hooks.hotAcceptWithoutCallback = new SyncBailHook(["expression", "requests"]); parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([
parser.hooks.call.for("module.hot.accept").tap("HotModuleReplacementPlugin", expr => { "expression",
if(!parser.state.compilation.hotUpdateChunkTemplate) return false; "requests"
]);
parser.hooks.call
.for("module.hot.accept")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
return false;
if (expr.arguments.length >= 1) { if (expr.arguments.length >= 1) {
const arg = parser.evaluateExpression(expr.arguments[0]); const arg = parser.evaluateExpression(expr.arguments[0]);
let params = []; let params = [];
@ -225,7 +333,10 @@ module.exports = class HotModuleReplacementPlugin {
if (params.length > 0) { if (params.length > 0) {
params.forEach((param, idx) => { params.forEach((param, idx) => {
const request = param.string; const request = param.string;
const dep = new ModuleHotAcceptDependency(request, param.range); const dep = new ModuleHotAcceptDependency(
request,
param.range
);
dep.optional = true; dep.optional = true;
dep.loc = Object.create(expr.loc); dep.loc = Object.create(expr.loc);
dep.loc.index = idx; dep.loc.index = idx;
@ -233,14 +344,20 @@ module.exports = class HotModuleReplacementPlugin {
requests.push(request); requests.push(request);
}); });
if (expr.arguments.length > 1) if (expr.arguments.length > 1)
parser.hooks.hotAcceptCallback.call(expr.arguments[1], requests); parser.hooks.hotAcceptCallback.call(
expr.arguments[1],
requests
);
else else
parser.hooks.hotAcceptWithoutCallback.call(expr, requests); parser.hooks.hotAcceptWithoutCallback.call(expr, requests);
} }
} }
}); });
parser.hooks.call.for("module.hot.decline").tap("HotModuleReplacementPlugin", expr => { parser.hooks.call
if(!parser.state.compilation.hotUpdateChunkTemplate) return false; .for("module.hot.decline")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
return false;
if (expr.arguments.length === 1) { if (expr.arguments.length === 1) {
const arg = parser.evaluateExpression(expr.arguments[0]); const arg = parser.evaluateExpression(expr.arguments[0]);
let params = []; let params = [];
@ -250,7 +367,10 @@ module.exports = class HotModuleReplacementPlugin {
params = arg.items.filter(param => param.isString()); params = arg.items.filter(param => param.isString());
} }
params.forEach((param, idx) => { params.forEach((param, idx) => {
const dep = new ModuleHotDeclineDependency(param.string, param.range); const dep = new ModuleHotDeclineDependency(
param.string,
param.range
);
dep.optional = true; dep.optional = true;
dep.loc = Object.create(expr.loc); dep.loc = Object.create(expr.loc);
dep.loc.index = idx; dep.loc.index = idx;
@ -258,19 +378,30 @@ module.exports = class HotModuleReplacementPlugin {
}); });
} }
}); });
parser.hooks.expression.for("module.hot").tap("HotModuleReplacementPlugin", ParserHelpers.skipTraversal); parser.hooks.expression
.for("module.hot")
.tap("HotModuleReplacementPlugin", ParserHelpers.skipTraversal);
}; };
// TODO add HMR support for javascript/esm // TODO add HMR support for javascript/esm
normalModuleFactory.hooks.parser.for("javascript/auto").tap("HotModuleReplacementPlugin", handler); normalModuleFactory.hooks.parser
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("HotModuleReplacementPlugin", handler); .for("javascript/auto")
.tap("HotModuleReplacementPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("HotModuleReplacementPlugin", handler);
compilation.hooks.normalModuleLoader.tap("HotModuleReplacementPlugin", context => { compilation.hooks.normalModuleLoader.tap(
"HotModuleReplacementPlugin",
context => {
context.hot = true; context.hot = true;
});
});
} }
);
}
);
}
}; };
const hotInitCode = Template.getFunctionContent(require("./HotModuleReplacement.runtime.js")); const hotInitCode = Template.getFunctionContent(
require("./HotModuleReplacement.runtime.js")
);

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