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
max_line_length = 233
[*.json]
[.prettierrc]
indent_style = space
indent_size = 2
[*.yml]
indent_style = space
indent_size = 2
[*.yaml]
[*.{yml,yaml,json}]
indent_style = space
indent_size = 2

View File

@ -1,15 +1,16 @@
module.exports = {
"root": true,
"plugins": ["node"],
"extends": ["eslint:recommended", "plugin:node/recommended"],
"env": {
"node": true,
"es6": true,
"mocha": true,
root: true,
plugins: ["prettier", "node"],
extends: ["eslint:recommended", "plugin:node/recommended"],
env: {
node: true,
es6: true
},
"parserOptions": { "ecmaVersion": 2017 },
"rules": {
"quotes": ["error", "double"],
parserOptions: {
ecmaVersion: 2017
},
rules: {
"prettier/prettier": "error",
"no-undef": "error",
"no-extra-semi": "error",
"semi": "error",
@ -21,51 +22,34 @@ module.exports = {
"brace-style": "error",
"eol-last": "error",
"no-extra-bind": "warn",
"no-empty": "off",
"no-multiple-empty-lines": "error",
"no-multi-spaces": "error",
"no-process-exit": "warn",
"space-in-parens": "error",
"no-trailing-spaces": "error",
"no-use-before-define": "off",
"no-unused-vars": ["error", { "args": "none" }],
"key-spacing": "error",
"space-infix-ops": "error",
"no-unused-vars": ["error", { args: "none" }],
"no-unsafe-negation": "error",
"no-loop-func": "warn",
"space-before-function-paren": ["error", "never"],
"space-before-blocks": "error",
"object-curly-spacing": ["error", "always"],
"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",
"valid-jsdoc": "error",
"node/no-unsupported-features": "error",
"node/no-deprecated-api": "error",
"node/no-missing-import": "error",
"node/no-missing-require": [
"error",
{
"allowModules": [
"webpack"
]
}
],
"node/no-missing-require": ["error", { allowModules: ["webpack"] }],
"node/no-unpublished-bin": "error",
"node/no-unpublished-require": "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
```bash
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
```
[Setup your local webpack repository](_SETUP.md)
## Submitting Changes

View File

@ -1,6 +1,6 @@
<div align="center">
<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>
<br>
<br>
@ -15,7 +15,7 @@
[![licenses][licenses]][licenses-url]
<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">
</a>
<a href="https://opencollective.com/webpack#backer">
@ -33,7 +33,7 @@
<h1>webpack</h1>
<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.
<p>
</p>
</div>
<h2 align="center">Install</h2>
@ -81,14 +81,12 @@ within webpack itself use this plugin interface. This makes webpack very
|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)|
|[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|
|[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
[extract]: https://github.com/webpack/extract-text-webpack-plugin
[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|
|:--:|:----:|:----------|
|<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/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|
@ -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>
<p>Development</p>
<br>
<p>Sponsor<p>
<p>Sponsor</p>
<a href="https://codeyellow.nl/">
<img height="15px" src="https://cloud.githubusercontent.com/assets/1365881/20286583/ad62eb04-aac7-11e6-9c14-a0fef35b9b56.png">
</a>
@ -371,7 +369,7 @@ This is how we use the donations:
<h2 align="center">Premium Partners</h2>
<div align="center">
<a href="https://www.ag-grid.com/?utm_source=webpack&utm_medium=banner&utm_campaign=sponsorship" target="_blank"><img align="center" src="https://raw.githubusercontent.com/webpack/media/2b399d58/horiz-banner-ad-ag-grid.png">
</a>
@ -382,11 +380,11 @@ This is how we use the donations:
Before we started using OpenCollective, donations were made anonymously. Now that we have made the switch, we would like to acknowledge these sponsors (and the ones who continue to donate using OpenCollective). If we've missed someone, please send us a PR, and we'll add you to this list.
<div align="center">
[Google Angular Team](https://angular.io/), [Architects.io](http://architects.io/),
<a href="https://moonmail.io" target="_blank" title="Email Marketing Software"><img
src="https://static.moonmail.io/moonmail-logo.svg" height="30" alt="MoonMail"></a>
<a href="https://monei.net" target="_blank" title="Best payment gateway rates"><img
<a href="https://moonmail.io" target="_blank" title="Email Marketing Software"><img
src="https://static.moonmail.io/moonmail-logo.svg" height="30" alt="MoonMail"></a>
<a href="https://monei.net" target="_blank" title="Best payment gateway rates"><img
src="https://static.monei.net/monei-logo.svg" height="30" alt="MONEI"></a>
</div>

18
_SETUP.md Normal file
View File

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

View File

@ -4,15 +4,17 @@ let webpackCliInstalled = false;
try {
require.resolve("webpack-cli");
webpackCliInstalled = true;
} catch(e) {
} catch (e) {
webpackCliInstalled = false;
}
if(webpackCliInstalled) {
if (webpackCliInstalled) {
require("webpack-cli"); // eslint-disable-line node/no-missing-require, node/no-extraneous-require, node/no-unpublished-require
} else {
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 yarn: yarn add webpack-cli -D");
process.exitCode = 1;

View File

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

View File

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

View File

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

View File

@ -95,12 +95,12 @@ module.exports = {
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }

View File

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

View File

@ -178,12 +178,12 @@ module.exports = "utility3";
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
@ -351,12 +351,12 @@ module.exports = "utility1";
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
@ -510,12 +510,12 @@ module.exports = "pageB";
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ 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
* `pageC` and `pageA` both require the `reusableComponent`
@ -93,7 +93,7 @@ module.exports = {
},
optimization: {
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)
},

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
* `pageC` and `pageA` both require the `reusableComponent`

View File

@ -8,7 +8,7 @@ module.exports = {
},
optimization: {
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)
},

View File

@ -1,6 +1,6 @@
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.

View File

@ -1,6 +1,6 @@
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.

View File

@ -8,12 +8,12 @@ module.exports = {
output: {
filename: "vendor.js", // best use [hash] here too
path: path.resolve(__dirname, "dist"),
library: "vendor_lib_[hash]",
library: "vendor_lib_[hash]"
},
plugins: [
new webpack.DllPlugin({
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",
output: {
filename: "app.js",
path: path.resolve(__dirname, "dist"),
path: path.resolve(__dirname, "dist")
},
plugins: [
new webpack.DllReferencePlugin({
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 webpack = require("../../");
module.exports = [
{
name: "vendor",
// mode: "development || "production",
@ -38,5 +37,4 @@ module.exports = [
})
]
}
];

View File

@ -6,7 +6,7 @@ module.exports = {
externals: [
"add",
{
"subtract": {
subtract: {
root: "subtract",
commonjs2: "./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:
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
* 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:
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
* async require -> chunk X & Z

View File

@ -29,7 +29,7 @@ exports.readFile = function() {};
// using module.exports would be equivalent,
// 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
@ -192,7 +192,7 @@ exports.readFile = function() {};
// using module.exports would be equivalent,
// 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,
// 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;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }

View File

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

View File

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

View File

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

View File

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

View File

@ -4,15 +4,15 @@ In this example you have two (HTML) pages `pageA` and `pageB`. You want to creat
You can see how to define multiple entry points via the `entry` option.
You can use
You can use
You can see the output files:
* `commons.js` contains:
* the module system
* chunk loading logic
* module `common.js` which is used in both pages
* `pageA.js` contains: (`pageB.js` is similar)
* the module system
* chunk loading logic
* the entry point `pageA.js`
* 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:
@ -143,12 +143,12 @@ module.exports = "Common";
/******/ var result;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ 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;
/******/ for(var i = 0; i < deferredModules.length; i++) {
/******/ var deferredModule = deferredModules[i];
/******/ var fullfilled = true;
/******/ var fulfilled = true;
/******/ for(var j = 1; j < deferredModule.length; 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);
/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]);
/******/ }
@ -572,7 +572,7 @@ module.exports = function(msg) {
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.0.0-beta.2
Version: webpack 4.0.0-beta.1
Asset Size Chunks Chunk Names
0.js 363 bytes 0 [emitted]
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
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)
> ./pageA pageA
> ./pageB pageB
> ./pageA pageA
[1] ./common.js 26 bytes {1} [built]
cjs require ./common [0] ./shared.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
Version: webpack 4.0.0-beta.2
Version: webpack 4.0.0-beta.1
Asset Size Chunks Chunk Names
0.js 120 bytes 0 [emitted]
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
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)
> ./pageA pageA
> ./pageB pageB
> ./pageA pageA
[1] ./common.js 26 bytes {1} [built]
cjs require ./common [0] ./shared.js 1:13-32
cjs require ./common [2] ./pageB.js 1:13-32

View File

@ -4,15 +4,15 @@ In this example you have two (HTML) pages `pageA` and `pageB`. You want to creat
You can see how to define multiple entry points via the `entry` option.
You can use
You can use
You can see the output files:
* `commons.js` contains:
* the module system
* chunk loading logic
* module `common.js` which is used in both pages
* `pageA.js` contains: (`pageB.js` is similar)
* the module system
* chunk loading logic
* the entry point `pageA.js`
* 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:

View File

@ -12,7 +12,7 @@ delete require.cache[aId];
// require module again, it should be reexecuted
var a2 = require("./a");
// vertify it
// verify it
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
var a2 = __webpack_require__(/*! ./a */ 1);
// vertify it
// verify it
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
var a2 = require("./a");
// vertify it
// verify it
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)
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

View File

@ -18,7 +18,7 @@ webpack therefore uses a approach called **"Partial Scope Hoisting"** or "Module
![](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

View File

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

View File

@ -242,7 +242,7 @@ export function fibonacciJavascript(i) {
/******/ // on error function for async loading
/******/ __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 = {};
/******/
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,23 +33,51 @@ const REPLACEMENT_TYPES = {
class APIPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("APIPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"APIPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = parser => {
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.evaluateTypeof.for(key).tap("APIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key]));
});
};
const handler = parser => {
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.evaluateTypeof
.for(key)
.tap(
"APIPlugin",
ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])
);
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("APIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("APIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("APIPlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.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";
const ConcatSource = require("webpack-sources").ConcatSource;
const { ConcatSource } = require("webpack-sources");
const Template = require("./Template");
class AmdMainTemplatePlugin {
@ -14,42 +14,56 @@ class AmdMainTemplatePlugin {
}
apply(compilation) {
const {
mainTemplate,
chunkTemplate
} = compilation;
const { mainTemplate, chunkTemplate } = compilation;
const onRenderWithEntry = (source, chunk, hash) => {
const externals = chunk.getModules().filter((m) => m.external);
const externalsDepsArray = JSON.stringify(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 externals = chunk.getModules().filter(m => m.external);
const externalsDepsArray = JSON.stringify(
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(", ");
if(this.name) {
if (this.name) {
const name = mainTemplate.getAssetPath(this.name, {
hash,
chunk
});
return new ConcatSource(
`define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});"
`define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
);
} else if (externalsArguments) {
return new ConcatSource(
`define(${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
);
} else if(externalsArguments) {
return new ConcatSource(`define(${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});");
} else {
return new ConcatSource("define(function() { return ", source, "});");
}
};
for(const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap("AmdMainTemplatePlugin", onRenderWithEntry);
for (const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap(
"AmdMainTemplatePlugin",
onRenderWithEntry
);
}
mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => {
if(this.name) paths.push(this.name);
if (this.name) paths.push(this.name);
return paths;
});

View File

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

View File

@ -11,7 +11,9 @@ module.exports = class AsyncDependencyToInitialChunkError extends WebpackError {
super();
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.origin = module;
this.originLoc = loc;

View File

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

View File

@ -5,47 +5,57 @@
"use strict";
const ConcatSource = require("webpack-sources").ConcatSource;
const { ConcatSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const Template = require("./Template");
const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json");
const wrapComment = (str) => {
if(!str.includes("\n")) return Template.toComment(str);
return `/*!\n * ${str.replace(/\*\//g, "* /").split("\n").join("\n * ")}\n */`;
const wrapComment = str => {
if (!str.includes("\n")) return Template.toComment(str);
return `/*!\n * ${str
.replace(/\*\//g, "* /")
.split("\n")
.join("\n * ")}\n */`;
};
class BannerPlugin {
constructor(options) {
if(arguments.length > 1)
throw new Error("BannerPlugin only takes one argument (pass an options object)");
if (arguments.length > 1)
throw new Error(
"BannerPlugin only takes one argument (pass an options object)"
);
validateOptions(schema, options, "Banner Plugin");
if(typeof options === "string")
if (typeof options === "string")
options = {
banner: 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) {
const options = this.options;
const banner = this.banner;
const matchObject = ModuleFilenameHelpers.matchObject.bind(undefined, options);
const matchObject = ModuleFilenameHelpers.matchObject.bind(
undefined,
options
);
compiler.hooks.compilation.tap("BannerPlugin", (compilation) => {
compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", (chunks) => {
for(const chunk of chunks) {
if(options.entryOnly && !chunk.canBeInitial()) {
compiler.hooks.compilation.tap("BannerPlugin", compilation => {
compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
for (const chunk of chunks) {
if (options.entryOnly && !chunk.canBeInitial()) {
continue;
}
for(const file of chunk.files) {
if(!matchObject(file)) {
for (const file of chunk.files) {
if (!matchObject(file)) {
continue;
}
@ -55,14 +65,14 @@ class BannerPlugin {
const hash = compilation.hash;
const querySplit = filename.indexOf("?");
if(querySplit >= 0) {
if (querySplit >= 0) {
query = filename.substr(querySplit);
filename = filename.substr(0, querySplit);
}
const lastSlashIndex = filename.lastIndexOf("/");
if(lastSlashIndex === -1) {
if (lastSlashIndex === -1) {
basename = filename;
} else {
basename = filename.substr(lastSlashIndex + 1);
@ -73,10 +83,14 @@ class BannerPlugin {
chunk,
filename,
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;
class BasicEvaluatedExpression {
constructor() {
this.type = TypeUnknown;
this.range = null;
@ -90,19 +89,23 @@ class BasicEvaluatedExpression {
}
asBool() {
if(this.truthy) return true;
else if(this.falsy) return false;
else if(this.isBoolean()) return this.bool;
else if(this.isNull()) return false;
else if(this.isString()) return this.string !== "";
else if(this.isNumber()) return this.number !== 0;
else if(this.isRegExp()) return true;
else if(this.isArray()) 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.isTemplateString()) {
for(const quasi of this.quasis) {
if(quasi.asBool()) return true;
if (this.truthy) return true;
else if (this.falsy) return false;
else if (this.isBoolean()) return this.bool;
else if (this.isNull()) return false;
else if (this.isString()) return this.string !== "";
else if (this.isNumber()) return this.number !== 0;
else if (this.isRegExp()) return true;
else if (this.isArray()) 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.isTemplateString()) {
for (const quasi of this.quasis) {
if (quasi.asBool()) return true;
}
// can't tell if string will be empty without executing
}
@ -158,12 +161,11 @@ class BasicEvaluatedExpression {
}
addOptions(options) {
if(!this.options) {
if (!this.options) {
this.type = TypeConditional;
this.options = [];
}
for(const item of options)
this.options.push(item);
for (const item of options) this.options.push(item);
return this;
}
@ -201,7 +203,6 @@ class BasicEvaluatedExpression {
this.range = range;
return this;
}
}
module.exports = BasicEvaluatedExpression;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,8 +4,7 @@
*/
"use strict";
const ReplaceSource = require("webpack-sources").ReplaceSource;
const RawSource = require("webpack-sources").RawSource;
const { RawSource, ReplaceSource } = require("webpack-sources");
class DependenciesBlockVariable {
constructor(name, expression, dependencies) {
@ -17,32 +16,33 @@ class DependenciesBlockVariable {
updateHash(hash) {
hash.update(this.name);
hash.update(this.expression);
for(const d of this.dependencies) {
for (const d of this.dependencies) {
d.updateHash(hash);
}
}
expressionSource(dependencyTemplates, runtimeTemplate) {
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);
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);
}
return source;
}
disconnect() {
for(const d of this.dependencies) {
for (const d of this.dependencies) {
d.disconnect();
}
}
hasDependencies(filter) {
if(filter) {
if(this.dependencies.some(filter)) return true;
if (filter) {
if (this.dependencies.some(filter)) return true;
} else {
if(this.dependencies.length > 0) return true;
if (this.dependencies.length > 0) return true;
}
return false;
}

View File

@ -18,11 +18,11 @@ class Dependency {
// Returns the referenced module and export
getReference() {
if(!this.module) return null;
if (!this.module) return null;
return {
module: this.module,
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) {
compiler.hooks.compilation.tap("DllEntryPlugin", (compilation, {
normalModuleFactory
}) => {
const dllModuleFactory = new DllModuleFactory();
compilation.dependencyFactories.set(DllEntryDependency, dllModuleFactory);
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
});
compiler.hooks.compilation.tap(
"DllEntryPlugin",
(compilation, { normalModuleFactory }) => {
const dllModuleFactory = new DllModuleFactory();
compilation.dependencyFactories.set(
DllEntryDependency,
dllModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => {
compilation.addEntry(this.context, new DllEntryDependency(this.entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`;
return dep;
}), this.name), this.name, callback);
compilation.addEntry(
this.context,
new DllEntryDependency(
this.entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`;
return dep;
}),
this.name
),
this.name,
callback
);
});
}
}

View File

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

View File

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

View File

@ -20,12 +20,10 @@ class DllPlugin {
apply(compiler) {
compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
const itemToPlugin = (item, name) => {
if(Array.isArray(item))
return new DllEntryPlugin(context, item, name);
else
throw new Error("DllPlugin: supply an Array as entry");
if (Array.isArray(item)) return new DllEntryPlugin(context, item, name);
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 => {
itemToPlugin(entry[name], name).apply(compiler);
});

View File

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

View File

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

View File

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

View File

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

View File

@ -7,15 +7,16 @@
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";
class EnvironmentPlugin {
constructor(...keys) {
if(keys.length === 1 && Array.isArray(keys[0])) {
if (keys.length === 1 && Array.isArray(keys[0])) {
this.keys = keys[0];
this.defaultValues = {};
} else if(keys.length === 1 && keys[0] && typeof keys[0] === "object") {
} else if (keys.length === 1 && keys[0] && typeof keys[0] === "object") {
this.keys = Object.keys(keys[0]);
this.defaultValues = keys[0];
} else {
@ -31,16 +32,21 @@ class EnvironmentPlugin {
// affecting Node 8 & 9 by performing an OS-level
// operation that always succeeds before reading
// 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) {
compiler.hooks.thisCompilation.tap("EnvironmentPlugin", (compilation) => {
if (value === undefined) {
compiler.hooks.thisCompilation.tap("EnvironmentPlugin", compilation => {
const error = new Error(
`EnvironmentPlugin - ${key} environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example."
`EnvironmentPlugin - ${
key
} environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example."
);
error.name = "EnvVariableNotDefinedError";
@ -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;
}, {});

View File

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

View File

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

View File

@ -4,31 +4,52 @@
*/
"use strict";
const RawSource = require("webpack-sources").RawSource;
const { RawSource } = require("webpack-sources");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const cache = new WeakMap();
class EvalDevToolModuleTemplatePlugin {
constructor(options) {
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 || "";
}
apply(moduleTemplate) {
moduleTemplate.hooks.module.tap("EvalDevToolModuleTemplatePlugin", (source, module) => {
const cacheEntry = cache.get(source);
if(cacheEntry !== undefined) return cacheEntry;
const content = source.source();
const str = ModuleFilenameHelpers.createFilename(module, {
moduleFilenameTemplate: this.moduleFilenameTemplate,
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(/^\//, ""));
const result = new RawSource(`eval(${JSON.stringify(content + footer)});`);
cache.set(source, result);
return result;
});
moduleTemplate.hooks.module.tap(
"EvalDevToolModuleTemplatePlugin",
(source, module) => {
const cacheEntry = cache.get(source);
if (cacheEntry !== undefined) return cacheEntry;
const content = source.source();
const str = ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: this.moduleFilenameTemplate,
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(/^\//, "")
);
const result = new RawSource(
`eval(${JSON.stringify(content + footer)});`
);
cache.set(source, result);
return result;
}
);
moduleTemplate.hooks.hash.tap("EvalDevToolModuleTemplatePlugin", hash => {
hash.update("EvalDevToolModuleTemplatePlugin");
hash.update("2");

View File

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

View File

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

View File

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

View File

@ -20,36 +20,64 @@ const REPLACEMENT_TYPES = {
class ExtendedAPIPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("ExtendedAPIPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"ExtendedAPIPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.requireExtensions.tap("ExtendedAPIPlugin", (source, chunk, hash) => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push("");
buf.push("// __webpack_chunkname__");
buf.push(`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`);
return Template.asString(buf);
});
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true);
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.requireExtensions.tap(
"ExtendedAPIPlugin",
(source, chunk, hash) => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push("");
buf.push("// __webpack_chunkname__");
buf.push(
`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`
);
return Template.asString(buf);
}
);
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true);
const handler = (parser, parserOptions) => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression.for(key).tap("ExtendedAPIPlugin", ParserHelpers.toConstantDependencyWithWebpackRequire(parser, REPLACEMENTS[key]));
parser.hooks.evaluateTypeof.for(key).tap("ExtendedAPIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key]));
});
};
const handler = (parser, parserOptions) => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression
.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.for("javascript/dynamic").tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ExtendedAPIPlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.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
*/
"use strict";
const { OriginalSource, RawSource } = require("webpack-sources");
const Module = require("./Module");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const WebpackMissingModule = require("./dependencies/WebpackMissingModule");
const Template = require("./Template");
@ -48,64 +48,92 @@ class ExternalModule extends Module {
}
getSourceForGlobalVariableExternal(variableName, type) {
if(!Array.isArray(variableName)) {
if (!Array.isArray(variableName)) {
// make it an array as the look up works the same basically
variableName = [variableName];
}
// 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}; }());`;
}
getSourceForCommonJsExternal(moduleAndSpecifiers) {
if(!Array.isArray(moduleAndSpecifiers)) {
return `module.exports = require(${JSON.stringify(moduleAndSpecifiers)});`;
if (!Array.isArray(moduleAndSpecifiers)) {
return `module.exports = require(${JSON.stringify(
moduleAndSpecifiers
)});`;
}
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};`;
}
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) {
const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${id}`)}__`;
const missingModuleError = optional ? this.checkExternalVariable(externalVariable, request) : "";
const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
`${id}`
)}__`;
const missingModuleError = optional
? this.checkExternalVariable(externalVariable, request)
: "";
return `${missingModuleError}module.exports = ${externalVariable};`;
}
getSourceForDefaultCase(optional, request) {
const missingModuleError = optional ? this.checkExternalVariable(request, request) : "";
const missingModuleError = optional
? this.checkExternalVariable(request, request)
: "";
return `${missingModuleError}module.exports = ${request};`;
}
getSourceString(runtime) {
const request = typeof this.request === "object" ? this.request[this.externalType] : this.request;
switch(this.externalType) {
const request =
typeof this.request === "object"
? this.request[this.externalType]
: this.request;
switch (this.externalType) {
case "this":
case "window":
case "self":
return this.getSourceForGlobalVariableExternal(request, this.externalType);
return this.getSourceForGlobalVariableExternal(
request,
this.externalType
);
case "global":
return this.getSourceForGlobalVariableExternal(runtime.outputOptions.globalObject, this.externalType);
return this.getSourceForGlobalVariableExternal(
runtime.outputOptions.globalObject,
this.externalType
);
case "commonjs":
case "commonjs2":
return this.getSourceForCommonJsExternal(request);
case "amd":
case "umd":
case "umd2":
return this.getSourceForAmdOrUmdExternal(this.id, this.optional, request);
return this.getSourceForAmdOrUmdExternal(
this.id,
this.optional,
request
);
default:
return this.getSourceForDefaultCase(this.optional, request);
}
}
getSource(sourceString) {
if(this.useSourceMap) {
if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier());
}
@ -113,9 +141,7 @@ class ExternalModule extends Module {
}
source(dependencyTemplates, runtime) {
return this.getSource(
this.getSourceString(runtime)
);
return this.getSource(this.getSourceString(runtime));
}
size() {

View File

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

View File

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

View File

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

View File

@ -5,92 +5,99 @@
"use strict";
const addToSet = (a, b) => {
for(const item of b) {
if(!a.includes(item))
a.push(item);
for (const item of b) {
if (!a.includes(item)) a.push(item);
}
return a;
};
const isSubset = (biggerSet, subset) => {
if(biggerSet === true) return true;
if(subset === true) return false;
if (biggerSet === true) return true;
if (subset === true) return false;
return subset.every(item => biggerSet.indexOf(item) >= 0);
};
class FlagDependencyUsagePlugin {
apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", (compilation) => {
compilation.hooks.optimizeModulesAdvanced.tap("FlagDependencyUsagePlugin", (modules) => {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => {
compilation.hooks.optimizeModulesAdvanced.tap(
"FlagDependencyUsagePlugin",
modules => {
const processModule = (module, usedExports) => {
module.used = true;
if (module.usedExports === true) return;
else if (usedExports === true) module.usedExports = true;
else if (Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(
module.usedExports || [],
usedExports
);
if (module.usedExports.length === old) return;
} else if (Array.isArray(module.usedExports)) return;
else module.usedExports = false;
const processModule = (module, usedExports) => {
module.used = true;
if(module.usedExports === true)
return;
else if(usedExports === true)
module.usedExports = true;
else if(Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(module.usedExports || [], usedExports);
if(module.usedExports.length === old)
return;
} else if(Array.isArray(module.usedExports))
return;
else
module.usedExports = false;
// 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
if (module.factoryMeta.sideEffectFree) {
if (module.usedExports === false) return;
if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
return;
}
// 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
if(module.factoryMeta.sideEffectFree) {
if(module.usedExports === false) return;
if(Array.isArray(module.usedExports) && module.usedExports.length === 0) return;
}
queue.push([module, module.usedExports]);
};
queue.push([module, module.usedExports]);
};
const processDependenciesBlock = (depBlock, usedExports) => {
for(const dep of depBlock.dependencies) {
processDependency(dep);
}
for(const variable of depBlock.variables) {
for(const dep of variable.dependencies) {
const processDependenciesBlock = (depBlock, usedExports) => {
for (const dep of depBlock.dependencies) {
processDependency(dep);
}
}
for(const block of depBlock.blocks) {
queue.push([block, usedExports]);
}
};
for (const variable of depBlock.variables) {
for (const dep of variable.dependencies) {
processDependency(dep);
}
}
for (const block of depBlock.blocks) {
queue.push([block, usedExports]);
}
};
const processDependency = dep => {
const reference = dep.getReference && dep.getReference();
if(!reference) return;
const module = reference.module;
const importedNames = reference.importedNames;
const oldUsed = module.used;
const oldUsedExports = module.usedExports;
if(!oldUsed || (importedNames && (!oldUsedExports || !isSubset(oldUsedExports, importedNames)))) {
processModule(module, importedNames);
const processDependency = dep => {
const reference = dep.getReference && dep.getReference();
if (!reference) return;
const module = reference.module;
const importedNames = reference.importedNames;
const oldUsed = module.used;
const oldUsedExports = module.usedExports;
if (
!oldUsed ||
(importedNames &&
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
) {
processModule(module, importedNames);
}
};
for (const module of modules) {
module.used = false;
}
};
for(const module of modules) {
module.used = false;
}
const queue = [];
for (const chunk of compilation.chunks) {
if (chunk.entryModule) {
processModule(chunk.entryModule, true);
}
}
const queue = [];
for(const chunk of compilation.chunks) {
if(chunk.entryModule) {
processModule(chunk.entryModule, true);
while (queue.length) {
const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]);
}
}
while(queue.length) {
const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]);
}
});
);
});
}
}

View File

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

View File

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

View File

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

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