mirror of https://github.com/webpack/webpack.git
Merge branch 'master' into feature/asset-url
# Conflicts: # test/Defaults.unittest.js
This commit is contained in:
commit
4157166263
|
@ -204,10 +204,8 @@ jobs:
|
|||
pool:
|
||||
vmImage: macOS-latest
|
||||
strategy:
|
||||
maxParallel: 3
|
||||
maxParallel: 2
|
||||
matrix:
|
||||
node-10:
|
||||
node_version: ^10.13.0
|
||||
node-12:
|
||||
node_version: ^12.4.0
|
||||
node-14:
|
||||
|
|
|
@ -886,14 +886,6 @@ export interface Experiments {
|
|||
* Support WebAssembly as asynchronous EcmaScript Module.
|
||||
*/
|
||||
asyncWebAssembly?: boolean;
|
||||
/**
|
||||
* Allow 'import/export' syntax to import async modules.
|
||||
*/
|
||||
importAsync?: boolean;
|
||||
/**
|
||||
* Allow 'import/export await' syntax to import async modules.
|
||||
*/
|
||||
importAwait?: boolean;
|
||||
/**
|
||||
* Support .mjs files as way to define strict ESM file (node.js).
|
||||
*/
|
||||
|
|
|
@ -25,30 +25,26 @@ export const close = () => {
|
|||
But `db-connection.js` is no longer a normal module now.
|
||||
It's an **async module** now.
|
||||
Async modules have a different evaluation semantics.
|
||||
While normal modules evaluate synchronously way, async modules evaluate asynchronously.
|
||||
While normal modules evaluate synchronously, async modules evaluate asynchronously.
|
||||
|
||||
Async modules can't be imported with a normal `import`.
|
||||
They need to be imported with `import await`.
|
||||
Async modules can still be imported with a normal `import`.
|
||||
But importing an async module makes the importing module also an async module.
|
||||
|
||||
The main reason for this is to make the using module aware of the different evaluation semantics.
|
||||
The `import`s still hoist and are evaluated in parallel.
|
||||
|
||||
Using `import await` in a module also makes the module an async module.
|
||||
You can see it as a form of top-level-await, but it's a bit different because imports hoist, so does `import await`.
|
||||
All `import`s and `import await`s hoist and are evaluated in parallel.
|
||||
|
||||
`import await` doesn't affect tree shaking negatively.
|
||||
Tree shaking still works as usual.
|
||||
Here the `close` function is never used and will be removed from the output bundle in production mode.
|
||||
|
||||
# UserApi.js
|
||||
|
||||
```javascript
|
||||
import await { dbCall } from "./db-connection.js";
|
||||
import { dbCall } from "./db-connection.js";
|
||||
|
||||
export const createUser = async name => {
|
||||
command = `CREATE USER ${name}`;
|
||||
// This is a normal await, because it's in an async function
|
||||
await dbCall({ command });
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Now it looks like that this pattern will continue and will infect all using modules as async modules.
|
||||
|
@ -60,7 +56,7 @@ But you as a developer don't want this.
|
|||
You want to break the chain at a point in your module graph where it makes sense.
|
||||
Luckily there is a nice way to break the chain.
|
||||
|
||||
You can use `import("./UserApi.js")` to import the module instead of `import await`.
|
||||
You can use `import("./UserApi.js")` to import the module instead of `import`.
|
||||
As this returns a Promise it can be awaited to wait for module evaluation (including top-level-awaits) and handle failures.
|
||||
|
||||
Handling failures is an important point here.
|
||||
|
@ -99,8 +95,7 @@ export const AlternativeCreateUserAction = async name => {
|
|||
// except in rare cases. It will import modules sequentially.
|
||||
```
|
||||
|
||||
As `Actions.js` doesn't use any top-level-await nor `import await` it's not an async module.
|
||||
It's a normal module and can be used via `import`.
|
||||
As `Actions.js` doesn't use any top-level-await nor `import`s an async module directly so it's not an async module.
|
||||
|
||||
# example.js
|
||||
|
||||
|
@ -112,10 +107,6 @@ import { CreateUserAction } from "./Actions.js";
|
|||
})();
|
||||
```
|
||||
|
||||
Note that you may `import await` from a normal module too.
|
||||
This is legal, but mostly not required.
|
||||
`import await` may also be seen by developers as a hint that this dependency does some async actions and may delay evaluation.
|
||||
|
||||
As a guideline, you should prevent your application entry point to become an async module when compiling for web targets.
|
||||
Doing async actions at application bootstrap will delay your application startup and may be negative for UX.
|
||||
Use `import()` to do async action on-demand or in the background and use spinners or other indicators to inform the user about background actions.
|
||||
|
@ -128,22 +119,41 @@ When compiling for other targets like node.js, electron or WebWorkers, it may be
|
|||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ([
|
||||
/* 0 */,
|
||||
/* 0 */
|
||||
/*!********************!*\
|
||||
!*** ./example.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_require__.r, __webpack_exports__, __webpack_require__.* */
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _Actions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Actions.js */ 1);
|
||||
|
||||
|
||||
(async ()=> {
|
||||
await (0,_Actions_js__WEBPACK_IMPORTED_MODULE_0__.CreateUserAction)("John");
|
||||
})();
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/*!********************!*\
|
||||
!*** ./Actions.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! export AlternativeCreateUserAction [provided] [unused] [could be renamed] */
|
||||
/*! export CreateUserAction [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__.e, __webpack_require__, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/*! export AlternativeCreateUserAction [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export CreateUserAction [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, __webpack_require__.e, __webpack_require__, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "CreateUserAction": () => /* binding */ CreateUserAction
|
||||
/* harmony export */ "CreateUserAction": () => /* binding */ CreateUserAction,
|
||||
/* harmony export */ "AlternativeCreateUserAction": () => /* binding */ AlternativeCreateUserAction
|
||||
/* harmony export */ });
|
||||
/* unused harmony export AlternativeCreateUserAction */
|
||||
// import() doesn't care about whether a module is an async module or not
|
||||
const UserApi = __webpack_require__.e(/*! import() */ 497).then(__webpack_require__.bind(__webpack_require__, /*! ./UserApi.js */ 2));
|
||||
|
||||
|
@ -247,6 +257,52 @@ const AlternativeCreateUserAction = async name => {
|
|||
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/load script */
|
||||
/******/ (() => {
|
||||
/******/ var inProgress = {};
|
||||
/******/ // data-webpack is not used as build has no uniqueName
|
||||
/******/ // loadScript function to load a script via script tag
|
||||
/******/ __webpack_require__.l = (url, done, key) => {
|
||||
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
|
||||
/******/ var script, needAttach;
|
||||
/******/ if(key !== undefined) {
|
||||
/******/ var scripts = document.getElementsByTagName("script");
|
||||
/******/ for(var i = 0; i < scripts.length; i++) {
|
||||
/******/ var s = scripts[i];
|
||||
/******/ if(s.getAttribute("src") == url) { script = s; break; }
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(!script) {
|
||||
/******/ needAttach = true;
|
||||
/******/ script = document.createElement('script');
|
||||
/******/
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.timeout = 120;
|
||||
/******/ if (__webpack_require__.nc) {
|
||||
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ script.src = url;
|
||||
/******/ }
|
||||
/******/ inProgress[url] = [done];
|
||||
/******/ var onScriptComplete = (prev, event) => {
|
||||
/******/ // avoid mem leaks in IE.
|
||||
/******/ script.onerror = script.onload = null;
|
||||
/******/ clearTimeout(timeout);
|
||||
/******/ var doneFns = inProgress[url];
|
||||
/******/ delete inProgress[url];
|
||||
/******/ script.parentNode && script.parentNode.removeChild(script);
|
||||
/******/ doneFns && doneFns.forEach((fn) => fn(event));
|
||||
/******/ if(prev) return prev(event);
|
||||
/******/ }
|
||||
/******/ ;
|
||||
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
|
||||
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
|
||||
/******/ script.onload = onScriptComplete.bind(null, script.onload);
|
||||
/******/ needAttach && document.head.appendChild(script);
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
|
@ -291,49 +347,24 @@ const AlternativeCreateUserAction = async name => {
|
|||
/******/
|
||||
/******/ // start chunk loading
|
||||
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
|
||||
/******/ var loadingEnded = () => {
|
||||
/******/ // create error before stack unwound to get useful stacktrace later
|
||||
/******/ var error = new Error();
|
||||
/******/ var loadingEnded = (event) => {
|
||||
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
|
||||
/******/ installedChunkData = installedChunks[chunkId];
|
||||
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
|
||||
/******/ if(installedChunkData) return installedChunkData[1];
|
||||
/******/ if(installedChunkData) {
|
||||
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||
/******/ var realSrc = event && event.target && event.target.src;
|
||||
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||
/******/ error.name = 'ChunkLoadError';
|
||||
/******/ error.type = errorType;
|
||||
/******/ error.request = realSrc;
|
||||
/******/ installedChunkData[1](error);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ var script = document.createElement('script');
|
||||
/******/ var onScriptComplete;
|
||||
/******/
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.timeout = 120;
|
||||
/******/ if (__webpack_require__.nc) {
|
||||
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||
/******/ }
|
||||
/******/ script.src = url;
|
||||
/******/
|
||||
/******/ // create error before stack unwound to get useful stacktrace later
|
||||
/******/ var error = new Error();
|
||||
/******/ onScriptComplete = (event) => {
|
||||
/******/ onScriptComplete = () => {
|
||||
/******/
|
||||
/******/ }
|
||||
/******/ // avoid mem leaks in IE.
|
||||
/******/ script.onerror = script.onload = null;
|
||||
/******/ clearTimeout(timeout);
|
||||
/******/ var reportError = loadingEnded();
|
||||
/******/ if(reportError) {
|
||||
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||
/******/ var realSrc = event && event.target && event.target.src;
|
||||
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||
/******/ error.name = 'ChunkLoadError';
|
||||
/******/ error.type = errorType;
|
||||
/******/ error.request = realSrc;
|
||||
/******/ reportError(error);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ ;
|
||||
/******/ var timeout = setTimeout(() => {
|
||||
/******/ onScriptComplete({ type: 'timeout', target: script })
|
||||
/******/ }, 120000);
|
||||
/******/ script.onerror = script.onload = onScriptComplete;
|
||||
/******/ document.head.appendChild(script);
|
||||
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId);
|
||||
/******/ } else installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ }
|
||||
|
@ -390,22 +421,10 @@ const AlternativeCreateUserAction = async name => {
|
|||
</details>
|
||||
|
||||
``` js
|
||||
(() => {
|
||||
/*!********************!*\
|
||||
!*** ./example.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__ */
|
||||
/* harmony import */ var _Actions_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Actions.js */ 1);
|
||||
|
||||
|
||||
(async ()=> {
|
||||
await (0,_Actions_js__WEBPACK_IMPORTED_MODULE_0__.CreateUserAction)("John");
|
||||
})();
|
||||
|
||||
})();
|
||||
|
||||
/******/ // startup
|
||||
/******/ // Load entry module
|
||||
/******/ __webpack_require__(0);
|
||||
/******/ // This entry module used 'exports' so it can't be inlined
|
||||
/******/ })()
|
||||
;
|
||||
```
|
||||
|
@ -421,8 +440,8 @@ const AlternativeCreateUserAction = async name => {
|
|||
!*** ./UserApi.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! export createUser [provided] [maybe used (runtime-defined)] [usage prevents renaming] */
|
||||
/*! other exports [not provided] [maybe used (runtime-defined)] */
|
||||
/*! export createUser [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_require__.r, __webpack_exports__, module, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
|
@ -440,7 +459,7 @@ const createUser = async name => {
|
|||
command = `CREATE USER ${name}`;
|
||||
// This is a normal await, because it's in an async function
|
||||
await (0,_db_connection_js__WEBPACK_IMPORTED_MODULE_0__.dbCall)({ command });
|
||||
}
|
||||
};
|
||||
|
||||
return __webpack_exports__;
|
||||
})();
|
||||
|
@ -451,18 +470,19 @@ return __webpack_exports__;
|
|||
!*** ./db-connection.js ***!
|
||||
\**************************/
|
||||
/*! namespace exports */
|
||||
/*! export close [provided] [unused] [could be renamed] */
|
||||
/*! export dbCall [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: module, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/*! export close [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export dbCall [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, module, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
"use strict";
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "dbCall": () => /* binding */ dbCall
|
||||
/* harmony export */ "dbCall": () => /* binding */ dbCall,
|
||||
/* harmony export */ "close": () => /* binding */ close
|
||||
/* harmony export */ });
|
||||
/* unused harmony export close */
|
||||
const connectToDB = async url => {
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
};
|
||||
|
@ -499,34 +519,34 @@ return __webpack_exports__;
|
|||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
497.output.js 2.39 KiB [emitted]
|
||||
output.js 10.7 KiB [emitted] [name: main]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset 497.output.js 2.53 KiB [emitted]
|
||||
asset output.js 12.2 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js
|
||||
chunk output.js (main) 1.19 KiB (javascript) 4.76 KiB (runtime) [entry] [rendered]
|
||||
chunk output.js (main) 1.19 KiB (javascript) 5.46 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./Actions.js 1.09 KiB [built]
|
||||
[exports: AlternativeCreateUserAction, CreateUserAction]
|
||||
[only some exports used: CreateUserAction]
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./Actions.js ./example.js 1:0-48
|
||||
harmony import specifier ./Actions.js ./example.js 4:7-23
|
||||
./example.js 103 bytes [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
[used exports unknown]
|
||||
entry ./example.js main
|
||||
+ 7 hidden chunk modules
|
||||
chunk 497.output.js 622 bytes [rendered]
|
||||
+ 8 hidden chunk modules
|
||||
chunk 497.output.js 617 bytes [rendered]
|
||||
> ./UserApi.js ./Actions.js 22:30-52
|
||||
> ./UserApi.js ./Actions.js 2:16-38
|
||||
./UserApi.js 220 bytes [built]
|
||||
./UserApi.js 215 bytes [built]
|
||||
[exports: createUser]
|
||||
[used exports unknown]
|
||||
import() ./UserApi.js ./Actions.js 2:16-38
|
||||
import() ./UserApi.js ./Actions.js 22:30-52
|
||||
./db-connection.js 402 bytes [built]
|
||||
[exports: close, dbCall]
|
||||
[only some exports used: dbCall]
|
||||
harmony side effect evaluation ./db-connection.js ./UserApi.js 1:0-50
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./db-connection.js ./UserApi.js 1:0-44
|
||||
harmony import specifier ./db-connection.js ./UserApi.js 6:7-13
|
||||
```
|
||||
|
||||
|
@ -534,28 +554,27 @@ chunk 497.output.js 622 bytes [rendered]
|
|||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
497.output.js 475 bytes [emitted]
|
||||
output.js 1.65 KiB [emitted] [name: main]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset 497.output.js 475 bytes [emitted]
|
||||
asset output.js 2 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js
|
||||
chunk output.js (main) 1.19 KiB (javascript) 4.76 KiB (runtime) [entry] [rendered]
|
||||
chunk (runtime: main) output.js (main) 1.19 KiB (javascript) 5.46 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./example.js + 1 modules 1.19 KiB [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
entry ./example.js main
|
||||
+ 7 hidden chunk modules
|
||||
chunk 497.output.js 622 bytes [rendered]
|
||||
+ 8 hidden chunk modules
|
||||
chunk (runtime: main) 497.output.js 617 bytes [rendered]
|
||||
> ./UserApi.js ./Actions.js 22:30-52
|
||||
> ./UserApi.js ./Actions.js 2:16-38
|
||||
./UserApi.js 220 bytes [built]
|
||||
./UserApi.js 215 bytes [built]
|
||||
[exports: createUser]
|
||||
import() ./UserApi.js ./example.js + 1 modules ./Actions.js 2:16-38
|
||||
import() ./UserApi.js ./example.js + 1 modules ./Actions.js 22:30-52
|
||||
./db-connection.js 402 bytes [built]
|
||||
[exports: close, dbCall]
|
||||
[only some exports used: dbCall]
|
||||
harmony side effect evaluation ./db-connection.js ./UserApi.js 1:0-50
|
||||
harmony side effect evaluation ./db-connection.js ./UserApi.js 1:0-44
|
||||
harmony import specifier ./db-connection.js ./UserApi.js 6:7-13
|
||||
```
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import await { dbCall } from "./db-connection.js";
|
||||
import { dbCall } from "./db-connection.js";
|
||||
|
||||
export const createUser = async name => {
|
||||
command = `CREATE USER ${name}`;
|
||||
// This is a normal await, because it's in an async function
|
||||
await dbCall({ command });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -12,16 +12,12 @@ It's an **async module** now.
|
|||
Async modules have a different evaluation semantics.
|
||||
While normal modules evaluate synchronously, async modules evaluate asynchronously.
|
||||
|
||||
Async modules can't be imported with a normal `import`.
|
||||
They need to be imported with `import await`.
|
||||
Async modules can still be imported with a normal `import`.
|
||||
But importing an async module makes the importing module also an async module.
|
||||
|
||||
The main reason for this is to make the using module aware of the different evaluation semantics.
|
||||
The `import`s still hoist and are evaluated in parallel.
|
||||
|
||||
Using `import await` in a module also makes the module an async module.
|
||||
You can see it as a form of top-level-await, but it's a bit different because imports hoist, so does `import await`.
|
||||
All `import`s and `import await`s hoist and are evaluated in parallel.
|
||||
|
||||
`import await` doesn't affect tree shaking negatively.
|
||||
Tree shaking still works as usual.
|
||||
Here the `close` function is never used and will be removed from the output bundle in production mode.
|
||||
|
||||
# UserApi.js
|
||||
|
@ -39,7 +35,7 @@ But you as a developer don't want this.
|
|||
You want to break the chain at a point in your module graph where it makes sense.
|
||||
Luckily there is a nice way to break the chain.
|
||||
|
||||
You can use `import("./UserApi.js")` to import the module instead of `import await`.
|
||||
You can use `import("./UserApi.js")` to import the module instead of `import`.
|
||||
As this returns a Promise it can be awaited to wait for module evaluation (including top-level-awaits) and handle failures.
|
||||
|
||||
Handling failures is an important point here.
|
||||
|
@ -52,8 +48,7 @@ In this example connecting to the DB may fail.
|
|||
_{{Actions.js}}_
|
||||
```
|
||||
|
||||
As `Actions.js` doesn't use any top-level-await nor `import await` it's not an async module.
|
||||
It's a normal module and can be used via `import`.
|
||||
As `Actions.js` doesn't use any top-level-await nor `import`s an async module directly so it's not an async module.
|
||||
|
||||
# example.js
|
||||
|
||||
|
@ -61,10 +56,6 @@ It's a normal module and can be used via `import`.
|
|||
_{{example.js}}_
|
||||
```
|
||||
|
||||
Note that you may `import await` from a normal module too.
|
||||
This is legal, but mostly not required.
|
||||
`import await` may also be seen by developers as a hint that this dependency does some async actions and may delay evaluation.
|
||||
|
||||
As a guideline, you should prevent your application entry point to become an async module when compiling for web targets.
|
||||
Doing async actions at application bootstrap will delay your application startup and may be negative for UX.
|
||||
Use `import()` to do async action on-demand or in the background and use spinners or other indicators to inform the user about background actions.
|
||||
|
|
|
@ -3,7 +3,6 @@ module.exports = {
|
|||
chunkIds: "deterministic" // To keep filename consistent between different modes (for example building only)
|
||||
},
|
||||
experiments: {
|
||||
topLevelAwait: true,
|
||||
importAwait: true
|
||||
topLevelAwait: true
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# example.js
|
||||
|
||||
```javascript
|
||||
import await { get, set, getNumber } from "./magic.js";
|
||||
import { get, set, getNumber } from "./magic.js";
|
||||
|
||||
// accessing memory
|
||||
console.log(get());
|
||||
|
@ -20,7 +20,7 @@ console.log(getNumber());
|
|||
|
||||
```javascript
|
||||
// reexporting
|
||||
export await * from "./magic.wat";
|
||||
export * from "./magic.wat";
|
||||
```
|
||||
|
||||
# magic.wat
|
||||
|
@ -78,11 +78,12 @@ export const memory = await getMemoryFromParentInWorker();
|
|||
!*** ./example.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__, module, __webpack_exports__ */
|
||||
/*! exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_require__.r, __webpack_exports__, module, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _magic_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./magic.js */ 1);
|
||||
_magic_js__WEBPACK_IMPORTED_MODULE_0__ = await Promise.resolve(_magic_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||
|
||||
|
@ -108,14 +109,15 @@ return __webpack_exports__;
|
|||
!*** ./magic.js ***!
|
||||
\******************/
|
||||
/*! namespace exports */
|
||||
/*! export get [provided] [used] [could be renamed] */
|
||||
/*! export getNumber [provided] [used] [could be renamed] */
|
||||
/*! export set [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_exports__, __webpack_require__.d, module, __webpack_require__.* */
|
||||
/*! export get [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export getNumber [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export set [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_exports__, __webpack_require__.d, __webpack_require__.r, module, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "get": () => /* reexport safe */ _magic_wat__WEBPACK_IMPORTED_MODULE_0__.get,
|
||||
/* harmony export */ "getNumber": () => /* reexport safe */ _magic_wat__WEBPACK_IMPORTED_MODULE_0__.getNumber,
|
||||
|
@ -135,17 +137,17 @@ return __webpack_exports__;
|
|||
!*** ./magic.wat ***!
|
||||
\*******************/
|
||||
/*! namespace exports */
|
||||
/*! export get [provided] [used] [provision prevents renaming] */
|
||||
/*! export getNumber [provided] [used] [provision prevents renaming] */
|
||||
/*! export set [provided] [used] [provision prevents renaming] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! export get [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! export getNumber [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! export set [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: module, module.id, __webpack_exports__, __webpack_require__.v, __webpack_require__, __webpack_require__.* */
|
||||
/***/ ((module, exports, __webpack_require__) => {
|
||||
|
||||
/* harmony import */ var WEBPACK_IMPORTED_MODULE_0 = __webpack_require__(/*! ./memory.js */ 3);
|
||||
/* harmony import */ var WEBPACK_IMPORTED_MODULE_1 = __webpack_require__(/*! ./magic-number.js */ 4);
|
||||
module.exports = Promise.resolve(WEBPACK_IMPORTED_MODULE_0).then((WEBPACK_IMPORTED_MODULE_0) => {
|
||||
return __webpack_require__.v(exports, module.id, {
|
||||
return __webpack_require__.v(exports, module.id, "493198b38242c233ec44", {
|
||||
"./memory.js": {
|
||||
"memory": WEBPACK_IMPORTED_MODULE_0.memory
|
||||
},
|
||||
|
@ -161,12 +163,13 @@ module.exports = Promise.resolve(WEBPACK_IMPORTED_MODULE_0).then((WEBPACK_IMPORT
|
|||
!*** ./memory.js ***!
|
||||
\*******************/
|
||||
/*! namespace exports */
|
||||
/*! export memory [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: module, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/*! export memory [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, module, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "memory": () => /* binding */ memory
|
||||
/* harmony export */ });
|
||||
|
@ -187,16 +190,17 @@ return __webpack_exports__;
|
|||
!*** ./magic-number.js ***!
|
||||
\*************************/
|
||||
/*! namespace exports */
|
||||
/*! export getNumber [provided] [unused] [could be renamed] */
|
||||
/*! export getRandomNumber [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/*! export getNumber [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export getRandomNumber [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "getNumber": () => /* binding */ getNumber,
|
||||
/* harmony export */ "getRandomNumber": () => /* binding */ getRandomNumber
|
||||
/* harmony export */ });
|
||||
/* unused harmony export getNumber */
|
||||
function getNumber() {
|
||||
return 42;
|
||||
}
|
||||
|
@ -255,6 +259,17 @@ function getRandomNumber() {
|
|||
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/publicPath */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.p = "dist/";
|
||||
|
@ -262,16 +277,16 @@ function getRandomNumber() {
|
|||
/******/
|
||||
/******/ /* webpack/runtime/wasm chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.v = function(exports, wasmModuleId, importsObj) {
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"2":"4961ae1f00405983e33f"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ if(typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
/******/ __webpack_require__.v = (exports, wasmModuleId, wasmModuleHash, importsObj) => {
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + wasmModuleHash + ".module.wasm");
|
||||
/******/ if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
/******/ return WebAssembly.instantiateStreaming(req, importsObj)
|
||||
/******/ .then(function(res) { return Object.assign(exports, res.instance.exports); });
|
||||
/******/ .then((res) => Object.assign(exports, res.instance.exports));
|
||||
/******/ }
|
||||
/******/ return req
|
||||
/******/ .then(function(x) { return x.arrayBuffer(); })
|
||||
/******/ .then(function(bytes) { return WebAssembly.instantiate(bytes, importsObj); })
|
||||
/******/ .then(function(res) { return Object.assign(exports, res.instance.exports); });
|
||||
/******/ .then((x) => x.arrayBuffer())
|
||||
/******/ .then((bytes) => WebAssembly.instantiate(bytes, importsObj))
|
||||
/******/ .then((res) => Object.assign(exports, res.instance.exports));
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
|
@ -295,25 +310,24 @@ function getRandomNumber() {
|
|||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
4961ae1f00405983e33f.module.wasm 139 bytes [emitted] [immutable] [name: (main)]
|
||||
output.js 7.84 KiB [emitted] [name: main]
|
||||
Entrypoint main = output.js (4961ae1f00405983e33f.module.wasm)
|
||||
chunk output.js (main) 708 bytes (javascript) 139 bytes (webassembly) 1.01 KiB (runtime) [entry] [rendered]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset 493198b38242c233ec44.module.wasm 139 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset output.js 8.8 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js (493198b38242c233ec44.module.wasm)
|
||||
chunk output.js (main) 696 bytes (javascript) 139 bytes (webassembly) 1.2 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./example.js 253 bytes [built]
|
||||
./example.js 247 bytes [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
[used exports unknown]
|
||||
entry ./example.js main
|
||||
./magic-number.js 124 bytes [built]
|
||||
[exports: getNumber, getRandomNumber]
|
||||
[only some exports used: getRandomNumber]
|
||||
[used exports unknown]
|
||||
wasm import ./magic-number.js ./magic.wat
|
||||
./magic.js 50 bytes [built]
|
||||
./magic.js 44 bytes [built]
|
||||
[exports: get, getNumber, set]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./magic.js ./example.js 1:0-55
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./magic.js ./example.js 1:0-49
|
||||
harmony import specifier ./magic.js ./example.js 4:12-15
|
||||
harmony import specifier ./magic.js ./example.js 5:0-3
|
||||
harmony import specifier ./magic.js ./example.js 6:12-15
|
||||
|
@ -324,28 +338,27 @@ chunk output.js (main) 708 bytes (javascript) 139 bytes (webassembly) 1.01 KiB (
|
|||
harmony import specifier ./magic.js ./example.js 13:12-21
|
||||
./magic.wat 70 bytes (javascript) 139 bytes (webassembly) [built]
|
||||
[exports: get, getNumber, set]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./magic.wat ./magic.js 2:0-34
|
||||
harmony export imported specifier ./magic.wat ./magic.js 2:0-34
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./magic.wat ./magic.js 2:0-28
|
||||
harmony export imported specifier ./magic.wat ./magic.js 2:0-28
|
||||
./memory.js 211 bytes [built]
|
||||
[exports: memory]
|
||||
[all exports used]
|
||||
[used exports unknown]
|
||||
wasm import ./memory.js ./magic.wat
|
||||
+ 4 hidden chunk modules
|
||||
+ 5 hidden chunk modules
|
||||
```
|
||||
|
||||
## Production mode
|
||||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
4636ea8e62e0734a195f.module.wasm 139 bytes [emitted] [immutable] [name: (main)]
|
||||
output.js 1.52 KiB [emitted] [name: main]
|
||||
Entrypoint main = output.js (4636ea8e62e0734a195f.module.wasm)
|
||||
chunk output.js (main) 708 bytes (javascript) 139 bytes (webassembly) 1.01 KiB (runtime) [entry] [rendered]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset b873a21e71d2d93bad48.module.wasm 139 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset output.js 1.43 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js (b873a21e71d2d93bad48.module.wasm)
|
||||
chunk (runtime: main) output.js (main) 696 bytes (javascript) 139 bytes (webassembly) 950 bytes (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./example.js 253 bytes [built]
|
||||
./example.js 247 bytes [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
entry ./example.js main
|
||||
|
@ -353,10 +366,10 @@ chunk output.js (main) 708 bytes (javascript) 139 bytes (webassembly) 1.01 KiB (
|
|||
[exports: getNumber, getRandomNumber]
|
||||
[only some exports used: getRandomNumber]
|
||||
wasm import ./magic-number.js ./magic.wat
|
||||
./magic.js 50 bytes [built]
|
||||
./magic.js 44 bytes [built]
|
||||
[exports: get, getNumber, set]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./magic.js ./example.js 1:0-55
|
||||
harmony side effect evaluation ./magic.js ./example.js 1:0-49
|
||||
harmony import specifier ./magic.js ./example.js 4:12-15
|
||||
harmony import specifier ./magic.js ./example.js 5:0-3
|
||||
harmony import specifier ./magic.js ./example.js 6:12-15
|
||||
|
@ -368,8 +381,8 @@ chunk output.js (main) 708 bytes (javascript) 139 bytes (webassembly) 1.01 KiB (
|
|||
./magic.wat 70 bytes (javascript) 139 bytes (webassembly) [built]
|
||||
[exports: get, getNumber, set]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./magic.wat ./magic.js 2:0-34
|
||||
harmony export imported specifier ./magic.wat ./magic.js 2:0-34
|
||||
harmony side effect evaluation ./magic.wat ./magic.js 2:0-28
|
||||
harmony export imported specifier ./magic.wat ./magic.js 2:0-28
|
||||
./memory.js 211 bytes [built]
|
||||
[exports: memory]
|
||||
[all exports used]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import await { get, set, getNumber } from "./magic.js";
|
||||
import { get, set, getNumber } from "./magic.js";
|
||||
|
||||
// accessing memory
|
||||
console.log(get());
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// reexporting
|
||||
export await * from "./magic.wat";
|
||||
export * from "./magic.wat";
|
||||
|
|
|
@ -17,7 +17,6 @@ module.exports = {
|
|||
},
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
topLevelAwait: true,
|
||||
importAwait: true
|
||||
topLevelAwait: true
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
This is a simple example that shows the usage of WebAssembly.
|
||||
|
||||
WebAssembly modules can be imported like other async modules with `import await` or `import()`.
|
||||
WebAssembly modules can be imported like other async modules with `import` or `import()`.
|
||||
When importing, they are downloaded and instantiated in a streaming way.
|
||||
|
||||
# example.js
|
||||
|
||||
```javascript
|
||||
import await { add } from "./add.wasm";
|
||||
import await { add as mathAdd, factorial, factorialJavascript, fibonacci, fibonacciJavascript } from "./math";
|
||||
import { add } from "./add.wasm";
|
||||
import {
|
||||
add as mathAdd,
|
||||
factorial,
|
||||
factorialJavascript,
|
||||
fibonacci,
|
||||
fibonacciJavascript
|
||||
} from "./math";
|
||||
|
||||
console.log(add(22, 2200));
|
||||
console.log(mathAdd(10, 101));
|
||||
|
@ -21,34 +27,31 @@ timed("wasm fibonacci", () => fibonacci(22));
|
|||
timed("js fibonacci", () => fibonacciJavascript(22));
|
||||
|
||||
function timed(name, fn) {
|
||||
if(!console.time || !console.timeEnd)
|
||||
return fn();
|
||||
if (!console.time || !console.timeEnd) return fn();
|
||||
// warmup
|
||||
for(var i = 0; i < 10; i++)
|
||||
fn();
|
||||
console.time(name)
|
||||
for(var i = 0; i < 5000; i++)
|
||||
fn();
|
||||
console.timeEnd(name)
|
||||
for (var i = 0; i < 10; i++) fn();
|
||||
console.time(name);
|
||||
for (var i = 0; i < 5000; i++) fn();
|
||||
console.timeEnd(name);
|
||||
}
|
||||
```
|
||||
|
||||
# math.js
|
||||
|
||||
```javascript
|
||||
import await { add } from "./add.wasm";
|
||||
import await { factorial } from "./factorial.wasm";
|
||||
import await { fibonacci } from "./fibonacci.wasm";
|
||||
import { add } from "./add.wasm";
|
||||
import { factorial } from "./factorial.wasm";
|
||||
import { fibonacci } from "./fibonacci.wasm";
|
||||
|
||||
export { add, factorial, fibonacci };
|
||||
|
||||
export function factorialJavascript(i) {
|
||||
if(i < 1) return 1;
|
||||
if (i < 1) return 1;
|
||||
return i * factorialJavascript(i - 1);
|
||||
}
|
||||
|
||||
export function fibonacciJavascript(i) {
|
||||
if(i < 2) return 1;
|
||||
if (i < 2) return 1;
|
||||
return fibonacciJavascript(i - 1) + fibonacciJavascript(i - 2);
|
||||
}
|
||||
```
|
||||
|
@ -64,11 +67,12 @@ export function fibonacciJavascript(i) {
|
|||
!*** ./example.js ***!
|
||||
\********************/
|
||||
/*! namespace exports */
|
||||
/*! exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__, module, __webpack_exports__ */
|
||||
/*! exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_require__.r, __webpack_exports__, module, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _add_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./add.wasm */ 1);
|
||||
/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./math */ 2);
|
||||
([_math__WEBPACK_IMPORTED_MODULE_1__, _add_wasm__WEBPACK_IMPORTED_MODULE_0__] = await Promise.all([_math__WEBPACK_IMPORTED_MODULE_1__, _add_wasm__WEBPACK_IMPORTED_MODULE_0__]));
|
||||
|
@ -87,15 +91,12 @@ timed("wasm fibonacci", () => (0,_math__WEBPACK_IMPORTED_MODULE_1__.fibonacci)(2
|
|||
timed("js fibonacci", () => (0,_math__WEBPACK_IMPORTED_MODULE_1__.fibonacciJavascript)(22));
|
||||
|
||||
function timed(name, fn) {
|
||||
if(!console.time || !console.timeEnd)
|
||||
return fn();
|
||||
if (!console.time || !console.timeEnd) return fn();
|
||||
// warmup
|
||||
for(var i = 0; i < 10; i++)
|
||||
fn();
|
||||
console.time(name)
|
||||
for(var i = 0; i < 5000; i++)
|
||||
fn();
|
||||
console.timeEnd(name)
|
||||
for (var i = 0; i < 10; i++) fn();
|
||||
console.time(name);
|
||||
for (var i = 0; i < 5000; i++) fn();
|
||||
console.timeEnd(name);
|
||||
}
|
||||
|
||||
return __webpack_exports__;
|
||||
|
@ -107,12 +108,12 @@ return __webpack_exports__;
|
|||
!*** ./add.wasm ***!
|
||||
\******************/
|
||||
/*! namespace exports */
|
||||
/*! export add [provided] [used] [provision prevents renaming] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! export add [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: module, module.id, __webpack_exports__, __webpack_require__.v, __webpack_require__.* */
|
||||
/***/ ((module, exports, __webpack_require__) => {
|
||||
|
||||
module.exports = __webpack_require__.v(exports, module.id)
|
||||
module.exports = __webpack_require__.v(exports, module.id, "937efcc237fa853c54c5")
|
||||
|
||||
/***/ }),
|
||||
/* 2 */
|
||||
|
@ -120,16 +121,17 @@ module.exports = __webpack_require__.v(exports, module.id)
|
|||
!*** ./math.js ***!
|
||||
\*****************/
|
||||
/*! namespace exports */
|
||||
/*! export add [provided] [used] [could be renamed] */
|
||||
/*! export factorial [provided] [used] [could be renamed] */
|
||||
/*! export factorialJavascript [provided] [used] [could be renamed] */
|
||||
/*! export fibonacci [provided] [used] [could be renamed] */
|
||||
/*! export fibonacciJavascript [provided] [used] [could be renamed] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_exports__, __webpack_require__.d, module, __webpack_require__.* */
|
||||
/*! export add [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export factorial [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export factorialJavascript [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export fibonacci [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! export fibonacciJavascript [provided] [no usage info] [missing usage info prevents renaming] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: __webpack_require__, __webpack_exports__, __webpack_require__.d, __webpack_require__.r, module, __webpack_require__.* */
|
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
module.exports = (async () => {
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "add": () => /* reexport safe */ _add_wasm__WEBPACK_IMPORTED_MODULE_0__.add,
|
||||
/* harmony export */ "factorial": () => /* reexport safe */ _factorial_wasm__WEBPACK_IMPORTED_MODULE_1__.factorial,
|
||||
|
@ -148,12 +150,12 @@ module.exports = (async () => {
|
|||
|
||||
|
||||
function factorialJavascript(i) {
|
||||
if(i < 1) return 1;
|
||||
if (i < 1) return 1;
|
||||
return i * factorialJavascript(i - 1);
|
||||
}
|
||||
|
||||
function fibonacciJavascript(i) {
|
||||
if(i < 2) return 1;
|
||||
if (i < 2) return 1;
|
||||
return fibonacciJavascript(i - 1) + fibonacciJavascript(i - 2);
|
||||
}
|
||||
|
||||
|
@ -166,12 +168,12 @@ return __webpack_exports__;
|
|||
!*** ./factorial.wasm ***!
|
||||
\************************/
|
||||
/*! namespace exports */
|
||||
/*! export factorial [provided] [used] [provision prevents renaming] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! export factorial [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: module, module.id, __webpack_exports__, __webpack_require__.v, __webpack_require__.* */
|
||||
/***/ ((module, exports, __webpack_require__) => {
|
||||
|
||||
module.exports = __webpack_require__.v(exports, module.id)
|
||||
module.exports = __webpack_require__.v(exports, module.id, "39f1d275c85dc3f2ce74")
|
||||
|
||||
/***/ }),
|
||||
/* 4 */
|
||||
|
@ -179,12 +181,12 @@ module.exports = __webpack_require__.v(exports, module.id)
|
|||
!*** ./fibonacci.wasm ***!
|
||||
\************************/
|
||||
/*! namespace exports */
|
||||
/*! export fibonacci [provided] [used] [provision prevents renaming] */
|
||||
/*! other exports [not provided] [unused] */
|
||||
/*! export fibonacci [provided] [no usage info] [provision prevents renaming (no use info)] */
|
||||
/*! other exports [not provided] [no usage info] */
|
||||
/*! runtime requirements: module, module.id, __webpack_exports__, __webpack_require__.v, __webpack_require__.* */
|
||||
/***/ ((module, exports, __webpack_require__) => {
|
||||
|
||||
module.exports = __webpack_require__.v(exports, module.id)
|
||||
module.exports = __webpack_require__.v(exports, module.id, "8daa7a900abbba23d2f2")
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
|
@ -235,6 +237,17 @@ module.exports = __webpack_require__.v(exports, module.id)
|
|||
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/publicPath */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.p = "dist/";
|
||||
|
@ -242,16 +255,16 @@ module.exports = __webpack_require__.v(exports, module.id)
|
|||
/******/
|
||||
/******/ /* webpack/runtime/wasm chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.v = function(exports, wasmModuleId, importsObj) {
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"1":"1c8378066da027821f98","3":"9989aee1a31bab8d342f","4":"aa9360d4a460c66559cc"}[wasmModuleId] + ".wasm");
|
||||
/******/ if(typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
/******/ __webpack_require__.v = (exports, wasmModuleId, wasmModuleHash, importsObj) => {
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + wasmModuleHash + ".wasm");
|
||||
/******/ if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
/******/ return WebAssembly.instantiateStreaming(req, importsObj)
|
||||
/******/ .then(function(res) { return Object.assign(exports, res.instance.exports); });
|
||||
/******/ .then((res) => Object.assign(exports, res.instance.exports));
|
||||
/******/ }
|
||||
/******/ return req
|
||||
/******/ .then(function(x) { return x.arrayBuffer(); })
|
||||
/******/ .then(function(bytes) { return WebAssembly.instantiate(bytes, importsObj); })
|
||||
/******/ .then(function(res) { return Object.assign(exports, res.instance.exports); });
|
||||
/******/ .then((x) => x.arrayBuffer())
|
||||
/******/ .then((bytes) => WebAssembly.instantiate(bytes, importsObj))
|
||||
/******/ .then((res) => Object.assign(exports, res.instance.exports));
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
|
@ -275,98 +288,96 @@ module.exports = __webpack_require__.v(exports, module.id)
|
|||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
1c8378066da027821f98.wasm 41 bytes [emitted] [immutable] [name: (main)]
|
||||
9989aee1a31bab8d342f.wasm 62 bytes [emitted] [immutable] [name: (main)]
|
||||
aa9360d4a460c66559cc.wasm 67 bytes [emitted] [immutable] [name: (main)]
|
||||
output.js 8.2 KiB [emitted] [name: main]
|
||||
Entrypoint main = output.js (1c8378066da027821f98.wasm 9989aee1a31bab8d342f.wasm aa9360d4a460c66559cc.wasm)
|
||||
chunk output.js (main) 1.3 KiB (javascript) 170 bytes (webassembly) 1.06 KiB (runtime) [entry] [rendered]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset 39f1d275c85dc3f2ce74.wasm 62 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset 8daa7a900abbba23d2f2.wasm 67 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset 937efcc237fa853c54c5.wasm 41 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset output.js 8.97 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js (39f1d275c85dc3f2ce74.wasm 8daa7a900abbba23d2f2.wasm 937efcc237fa853c54c5.wasm)
|
||||
chunk output.js (main) 1.27 KiB (javascript) 170 bytes (webassembly) 1.19 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./add.wasm 50 bytes (javascript) 41 bytes (webassembly) [built]
|
||||
[exports: add]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./add.wasm ./example.js 1:0-39
|
||||
harmony import specifier ./add.wasm ./example.js 4:12-15
|
||||
harmony side effect evaluation ./add.wasm ./math.js 1:0-39
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./add.wasm ./example.js 1:0-33
|
||||
harmony import specifier ./add.wasm ./example.js 10:12-15
|
||||
harmony side effect evaluation ./add.wasm ./math.js 1:0-33
|
||||
harmony export imported specifier ./add.wasm ./math.js 5:0-37
|
||||
./example.js 761 bytes [built]
|
||||
./example.js 753 bytes [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
[used exports unknown]
|
||||
entry ./example.js main
|
||||
./factorial.wasm 50 bytes (javascript) 62 bytes (webassembly) [built]
|
||||
[exports: factorial]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./factorial.wasm ./math.js 2:0-51
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./factorial.wasm ./math.js 2:0-45
|
||||
harmony export imported specifier ./factorial.wasm ./math.js 5:0-37
|
||||
./fibonacci.wasm 50 bytes (javascript) 67 bytes (webassembly) [built]
|
||||
[exports: fibonacci]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./fibonacci.wasm ./math.js 3:0-51
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./fibonacci.wasm ./math.js 3:0-45
|
||||
harmony export imported specifier ./fibonacci.wasm ./math.js 5:0-37
|
||||
./math.js 418 bytes [built]
|
||||
./math.js 402 bytes [built]
|
||||
[exports: add, factorial, factorialJavascript, fibonacci, fibonacciJavascript]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./math ./example.js 2:0-110
|
||||
harmony import specifier ./math ./example.js 5:12-19
|
||||
harmony import specifier ./math ./example.js 6:12-21
|
||||
harmony import specifier ./math ./example.js 7:12-31
|
||||
harmony import specifier ./math ./example.js 8:12-21
|
||||
harmony import specifier ./math ./example.js 9:12-31
|
||||
harmony import specifier ./math ./example.js 10:30-39
|
||||
harmony import specifier ./math ./example.js 11:28-47
|
||||
harmony import specifier ./math ./example.js 12:30-39
|
||||
harmony import specifier ./math ./example.js 13:28-47
|
||||
+ 4 hidden chunk modules
|
||||
[used exports unknown]
|
||||
harmony side effect evaluation ./math ./example.js 2:0-8:16
|
||||
harmony import specifier ./math ./example.js 11:12-19
|
||||
harmony import specifier ./math ./example.js 12:12-21
|
||||
harmony import specifier ./math ./example.js 13:12-31
|
||||
harmony import specifier ./math ./example.js 14:12-21
|
||||
harmony import specifier ./math ./example.js 15:12-31
|
||||
harmony import specifier ./math ./example.js 16:30-39
|
||||
harmony import specifier ./math ./example.js 17:28-47
|
||||
harmony import specifier ./math ./example.js 18:30-39
|
||||
harmony import specifier ./math ./example.js 19:28-47
|
||||
+ 5 hidden chunk modules
|
||||
```
|
||||
|
||||
## Production mode
|
||||
|
||||
```
|
||||
Hash: 0a1b2c3d4e5f6a7b8c9d
|
||||
Version: webpack 5.0.0-beta.16
|
||||
Asset Size
|
||||
5ba3e3921117e9d828f5.wasm 67 bytes [emitted] [immutable] [name: (main)]
|
||||
5dd947250fab86306d49.wasm 62 bytes [emitted] [immutable] [name: (main)]
|
||||
6f6c0ffc52ce3a45ff7e.wasm 41 bytes [emitted] [immutable] [name: (main)]
|
||||
output.js 1.67 KiB [emitted] [name: main]
|
||||
Entrypoint main = output.js (5ba3e3921117e9d828f5.wasm 5dd947250fab86306d49.wasm 6f6c0ffc52ce3a45ff7e.wasm)
|
||||
chunk output.js (main) 1.3 KiB (javascript) 170 bytes (webassembly) 1.06 KiB (runtime) [entry] [rendered]
|
||||
Version: webpack 5.0.0-beta.23
|
||||
asset 402d0640d802f4390f09.wasm 41 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset 79f27550455ff7b728fb.wasm 62 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset c473e4ed21f109fed4d9.wasm 67 bytes [emitted] [immutable] (auxiliary name: main)
|
||||
asset output.js 1.58 KiB [emitted] (name: main)
|
||||
Entrypoint main = output.js (402d0640d802f4390f09.wasm 79f27550455ff7b728fb.wasm c473e4ed21f109fed4d9.wasm)
|
||||
chunk (runtime: main) output.js (main) 1.27 KiB (javascript) 170 bytes (webassembly) 943 bytes (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
./add.wasm 50 bytes (javascript) 41 bytes (webassembly) [built]
|
||||
[exports: add]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./add.wasm ./example.js 1:0-39
|
||||
harmony import specifier ./add.wasm ./example.js 4:12-15
|
||||
harmony side effect evaluation ./add.wasm ./math.js 1:0-39
|
||||
harmony side effect evaluation ./add.wasm ./example.js 1:0-33
|
||||
harmony import specifier ./add.wasm ./example.js 10:12-15
|
||||
harmony side effect evaluation ./add.wasm ./math.js 1:0-33
|
||||
harmony export imported specifier ./add.wasm ./math.js 5:0-37
|
||||
./example.js 761 bytes [built]
|
||||
./example.js 753 bytes [built]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
entry ./example.js main
|
||||
./factorial.wasm 50 bytes (javascript) 62 bytes (webassembly) [built]
|
||||
[exports: factorial]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./factorial.wasm ./math.js 2:0-51
|
||||
harmony side effect evaluation ./factorial.wasm ./math.js 2:0-45
|
||||
harmony export imported specifier ./factorial.wasm ./math.js 5:0-37
|
||||
./fibonacci.wasm 50 bytes (javascript) 67 bytes (webassembly) [built]
|
||||
[exports: fibonacci]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./fibonacci.wasm ./math.js 3:0-51
|
||||
harmony side effect evaluation ./fibonacci.wasm ./math.js 3:0-45
|
||||
harmony export imported specifier ./fibonacci.wasm ./math.js 5:0-37
|
||||
./math.js 418 bytes [built]
|
||||
./math.js 402 bytes [built]
|
||||
[exports: add, factorial, factorialJavascript, fibonacci, fibonacciJavascript]
|
||||
[all exports used]
|
||||
harmony side effect evaluation ./math ./example.js 2:0-110
|
||||
harmony import specifier ./math ./example.js 5:12-19
|
||||
harmony import specifier ./math ./example.js 6:12-21
|
||||
harmony import specifier ./math ./example.js 7:12-31
|
||||
harmony import specifier ./math ./example.js 8:12-21
|
||||
harmony import specifier ./math ./example.js 9:12-31
|
||||
harmony import specifier ./math ./example.js 10:30-39
|
||||
harmony import specifier ./math ./example.js 11:28-47
|
||||
harmony import specifier ./math ./example.js 12:30-39
|
||||
harmony import specifier ./math ./example.js 13:28-47
|
||||
harmony side effect evaluation ./math ./example.js 2:0-8:16
|
||||
harmony import specifier ./math ./example.js 11:12-19
|
||||
harmony import specifier ./math ./example.js 12:12-21
|
||||
harmony import specifier ./math ./example.js 13:12-31
|
||||
harmony import specifier ./math ./example.js 14:12-21
|
||||
harmony import specifier ./math ./example.js 15:12-31
|
||||
harmony import specifier ./math ./example.js 16:30-39
|
||||
harmony import specifier ./math ./example.js 17:28-47
|
||||
harmony import specifier ./math ./example.js 18:30-39
|
||||
harmony import specifier ./math ./example.js 19:28-47
|
||||
+ 4 hidden chunk modules
|
||||
```
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import await { add } from "./add.wasm";
|
||||
import await { add as mathAdd, factorial, factorialJavascript, fibonacci, fibonacciJavascript } from "./math";
|
||||
import { add } from "./add.wasm";
|
||||
import {
|
||||
add as mathAdd,
|
||||
factorial,
|
||||
factorialJavascript,
|
||||
fibonacci,
|
||||
fibonacciJavascript
|
||||
} from "./math";
|
||||
|
||||
console.log(add(22, 2200));
|
||||
console.log(mathAdd(10, 101));
|
||||
|
@ -13,13 +19,10 @@ timed("wasm fibonacci", () => fibonacci(22));
|
|||
timed("js fibonacci", () => fibonacciJavascript(22));
|
||||
|
||||
function timed(name, fn) {
|
||||
if(!console.time || !console.timeEnd)
|
||||
return fn();
|
||||
if (!console.time || !console.timeEnd) return fn();
|
||||
// warmup
|
||||
for(var i = 0; i < 10; i++)
|
||||
fn();
|
||||
console.time(name)
|
||||
for(var i = 0; i < 5000; i++)
|
||||
fn();
|
||||
console.timeEnd(name)
|
||||
for (var i = 0; i < 10; i++) fn();
|
||||
console.time(name);
|
||||
for (var i = 0; i < 5000; i++) fn();
|
||||
console.timeEnd(name);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import await { add } from "./add.wasm";
|
||||
import await { factorial } from "./factorial.wasm";
|
||||
import await { fibonacci } from "./fibonacci.wasm";
|
||||
import { add } from "./add.wasm";
|
||||
import { factorial } from "./factorial.wasm";
|
||||
import { fibonacci } from "./fibonacci.wasm";
|
||||
|
||||
export { add, factorial, fibonacci };
|
||||
|
||||
export function factorialJavascript(i) {
|
||||
if(i < 1) return 1;
|
||||
if (i < 1) return 1;
|
||||
return i * factorialJavascript(i - 1);
|
||||
}
|
||||
|
||||
export function fibonacciJavascript(i) {
|
||||
if(i < 2) return 1;
|
||||
if (i < 2) return 1;
|
||||
return fibonacciJavascript(i - 1) + fibonacciJavascript(i - 2);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
This is a simple example that shows the usage of WebAssembly.
|
||||
|
||||
WebAssembly modules can be imported like other async modules with `import await` or `import()`.
|
||||
WebAssembly modules can be imported like other async modules with `import` or `import()`.
|
||||
When importing, they are downloaded and instantiated in a streaming way.
|
||||
|
||||
# example.js
|
||||
|
|
|
@ -16,7 +16,6 @@ module.exports = {
|
|||
chunkIds: "deterministic" // To keep filename consistent between different modes (for example building only)
|
||||
},
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
importAwait: true
|
||||
asyncWebAssembly: true
|
||||
}
|
||||
};
|
||||
|
|
10
lib/Chunk.js
10
lib/Chunk.js
|
@ -9,6 +9,7 @@ const ChunkGraph = require("./ChunkGraph");
|
|||
const Entrypoint = require("./Entrypoint");
|
||||
const { intersect } = require("./util/SetHelpers");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const StringXor = require("./util/StringXor");
|
||||
const {
|
||||
compareModulesByIdentifier,
|
||||
compareChunkGroupsByIndex,
|
||||
|
@ -529,12 +530,11 @@ class Chunk {
|
|||
hash.update(`${this.id} `);
|
||||
hash.update(this.ids ? this.ids.join(",") : "");
|
||||
hash.update(`${this.name || ""} `);
|
||||
for (const m of chunkGraph.getOrderedChunkModulesIterable(
|
||||
this,
|
||||
compareModulesByIdentifier
|
||||
)) {
|
||||
hash.update(chunkGraph.getModuleHash(m, this.runtime));
|
||||
const xor = new StringXor();
|
||||
for (const m of chunkGraph.getChunkModulesIterable(this)) {
|
||||
xor.add(chunkGraph.getModuleHash(m, this.runtime));
|
||||
}
|
||||
xor.updateHash(hash);
|
||||
const entryModules = chunkGraph.getChunkEntryModulesWithChunkGroupIterable(
|
||||
this
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const util = require("util");
|
||||
const memorize = require("./util/memorize");
|
||||
|
||||
/** @typedef {import("../declarations/WebpackOptions").Output} OutputOptions */
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
|
||||
const getJavascriptModulesPlugin = memorize(() =>
|
||||
|
@ -17,7 +18,7 @@ const getJavascriptModulesPlugin = memorize(() =>
|
|||
// TODO webpack 6 remove this class
|
||||
class ChunkTemplate {
|
||||
/**
|
||||
* @param {TODO} outputOptions TODO
|
||||
* @param {OutputOptions} outputOptions output options
|
||||
* @param {Compilation} compilation the compilation
|
||||
*/
|
||||
constructor(outputOptions, compilation) {
|
||||
|
@ -124,7 +125,7 @@ Object.defineProperty(ChunkTemplate.prototype, "outputOptions", {
|
|||
get: util.deprecate(
|
||||
/**
|
||||
* @this {ChunkTemplate}
|
||||
* @returns {TODO} output options
|
||||
* @returns {OutputOptions} output options
|
||||
*/
|
||||
function () {
|
||||
return this._outputOptions;
|
||||
|
|
|
@ -1678,20 +1678,11 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|||
this.reportDependencyErrorsAndWarnings(module, [module]);
|
||||
const errors = module.getErrors();
|
||||
if (errors !== undefined) {
|
||||
if (module.isOptional(this.moduleGraph)) {
|
||||
for (const error of errors) {
|
||||
if (!error.module) {
|
||||
error.module = module;
|
||||
}
|
||||
this.warnings.push(error);
|
||||
}
|
||||
} else {
|
||||
for (const error of errors) {
|
||||
if (!error.module) {
|
||||
error.module = module;
|
||||
}
|
||||
this.errors.push(error);
|
||||
for (const error of errors) {
|
||||
if (!error.module) {
|
||||
error.module = module;
|
||||
}
|
||||
this.errors.push(error);
|
||||
}
|
||||
}
|
||||
const warnings = module.getWarnings();
|
||||
|
@ -2063,6 +2054,8 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
}
|
||||
|
||||
codeGeneration(callback) {
|
||||
let statModulesFromCache = 0;
|
||||
let statModulesGenerated = 0;
|
||||
const {
|
||||
chunkGraph,
|
||||
moduleGraph,
|
||||
|
@ -2113,6 +2106,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
if (err) return callback(err);
|
||||
let result;
|
||||
if (!cachedResult) {
|
||||
statModulesGenerated++;
|
||||
try {
|
||||
result = module.codeGeneration({
|
||||
chunkGraph,
|
||||
|
@ -2129,6 +2123,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
};
|
||||
}
|
||||
} else {
|
||||
statModulesFromCache++;
|
||||
result = cachedResult;
|
||||
}
|
||||
for (const runtime of runtimes) {
|
||||
|
@ -2151,6 +2146,12 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
this.errors.push(error);
|
||||
}
|
||||
}
|
||||
this.logger.log(
|
||||
`${Math.round(
|
||||
(100 * statModulesGenerated) /
|
||||
(statModulesGenerated + statModulesFromCache)
|
||||
)}% code generated (${statModulesGenerated} generated, ${statModulesFromCache} from cache)`
|
||||
);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
|
@ -2512,10 +2513,12 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
}
|
||||
|
||||
createModuleHashes() {
|
||||
let statModulesHashed = 0;
|
||||
const chunkGraph = this.chunkGraph;
|
||||
const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
|
||||
for (const module of this.modules) {
|
||||
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
||||
statModulesHashed++;
|
||||
const moduleHash = createHash(hashFunction);
|
||||
module.updateHash(moduleHash, {
|
||||
chunkGraph,
|
||||
|
@ -2532,6 +2535,11 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
);
|
||||
}
|
||||
}
|
||||
this.logger.log(
|
||||
`${statModulesHashed} modules hashed (${
|
||||
Math.round((100 * statModulesHashed) / this.modules.size) / 100
|
||||
} variants per module in average)`
|
||||
);
|
||||
}
|
||||
|
||||
createHash() {
|
||||
|
@ -2737,6 +2745,50 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} file file name
|
||||
*/
|
||||
deleteAsset(file) {
|
||||
if (!this.assets[file]) {
|
||||
return;
|
||||
}
|
||||
delete this.assets[file];
|
||||
const assetInfo = this.assetsInfo.get(file);
|
||||
this.assetsInfo.delete(file);
|
||||
const related = assetInfo && assetInfo.related;
|
||||
if (related) {
|
||||
for (const key of Object.keys(related)) {
|
||||
const checkUsedAndDelete = file => {
|
||||
// That's not super efficient, but let's assume the number of assets
|
||||
// is not super large and we are not deleting a lot of files
|
||||
// It could be refactored to track parents in emit/updateAsset
|
||||
// to make it easier to access this info in O(1)
|
||||
for (const assetInfo of this.assetsInfo.values()) {
|
||||
if (!assetInfo) continue;
|
||||
const related = assetInfo.related;
|
||||
if (!related) continue;
|
||||
const items = related[key];
|
||||
if (!items) continue;
|
||||
if (
|
||||
Array.isArray(items)
|
||||
? items.some(item => item === file)
|
||||
: items === file
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.deleteAsset(file);
|
||||
};
|
||||
const items = related[key];
|
||||
if (Array.isArray(items)) {
|
||||
for (const item of items) checkUsedAndDelete(item);
|
||||
} else {
|
||||
checkUsedAndDelete(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getAssets() {
|
||||
/** @type {Readonly<Asset>[]} */
|
||||
const array = [];
|
||||
|
|
|
@ -528,7 +528,7 @@ class Compiler {
|
|||
const caseInsensitiveTargetPath = targetPath.toLowerCase();
|
||||
if (caseInsensitiveMap.has(caseInsensitiveTargetPath)) {
|
||||
const other = caseInsensitiveMap.get(caseInsensitiveTargetPath);
|
||||
const err = new WebpackError(`Prevent writing to file that only differs in casing from already written file.
|
||||
const err = new WebpackError(`Prevent writing to file that only differs in casing or query string from already written file.
|
||||
This will lead to a race-condition and corrupted files on case-insensitive file systems.
|
||||
${targetPath}
|
||||
${other}`);
|
||||
|
|
|
@ -10,6 +10,8 @@ const ConstDependency = require("./dependencies/ConstDependency");
|
|||
const { evaluateToString } = require("./javascript/JavascriptParserHelpers");
|
||||
const { parseResource } = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("estree").Expression} ExpressionNode */
|
||||
/** @typedef {import("estree").Super} SuperNode */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
||||
const collectDeclaration = (declarations, pattern) => {
|
||||
|
@ -372,6 +374,59 @@ class ConstPlugin {
|
|||
}
|
||||
}
|
||||
);
|
||||
parser.hooks.optionalChaining.tap("ConstPlugin", expr => {
|
||||
/** @type {ExpressionNode[]} */
|
||||
const optionalExpressionsStack = [];
|
||||
/** @type {ExpressionNode|SuperNode} */
|
||||
let next = expr.expression;
|
||||
|
||||
while (
|
||||
next.type === "MemberExpression" ||
|
||||
next.type === "CallExpression"
|
||||
) {
|
||||
if (next.type === "MemberExpression") {
|
||||
if (next.optional) {
|
||||
// SuperNode can not be optional
|
||||
optionalExpressionsStack.push(
|
||||
/** @type {ExpressionNode} */ (next.object)
|
||||
);
|
||||
}
|
||||
next = next.object;
|
||||
} else {
|
||||
if (next.optional) {
|
||||
// SuperNode can not be optional
|
||||
optionalExpressionsStack.push(
|
||||
/** @type {ExpressionNode} */ (next.callee)
|
||||
);
|
||||
}
|
||||
next = next.callee;
|
||||
}
|
||||
}
|
||||
|
||||
while (optionalExpressionsStack.length) {
|
||||
const expression = optionalExpressionsStack.pop();
|
||||
const evaluated = parser.evaluateExpression(expression);
|
||||
|
||||
if (evaluated && evaluated.asNullish()) {
|
||||
// ------------------------------------------
|
||||
//
|
||||
// Given the following code:
|
||||
//
|
||||
// nullishMemberChain?.a.b();
|
||||
//
|
||||
// the generated code is:
|
||||
//
|
||||
// undefined;
|
||||
//
|
||||
// ------------------------------------------
|
||||
//
|
||||
const dep = new ConstDependency(" undefined", expr.range);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addPresentationalDependency(dep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
parser.hooks.evaluateIdentifier
|
||||
.for("__resourceQuery")
|
||||
.tap("ConstPlugin", expr => {
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
* @typedef {Object} ExportSpec
|
||||
* @property {string} name the name of the export
|
||||
* @property {boolean=} canMangle can the export be renamed (defaults to true)
|
||||
* @property {boolean=} terminalBinding is the export a terminal binding that should be checked for export star conflicts
|
||||
* @property {(string | ExportSpec)[]=} exports nested exports
|
||||
* @property {Module=} from when reexported: from which module
|
||||
* @property {string[] | null=} export when reexported: from which export
|
||||
|
@ -56,7 +57,9 @@
|
|||
* @typedef {Object} ExportsSpec
|
||||
* @property {(string | ExportSpec)[] | true | null} exports exported names, true for unknown exports or null for no exports
|
||||
* @property {Set<string>=} excludeExports when exports = true, list of unaffected exports
|
||||
* @property {Module=} from when reexported: from which module
|
||||
* @property {boolean=} canMangle can the export be renamed (defaults to true)
|
||||
* @property {boolean=} terminalBinding are the exports terminal bindings that should be checked for export star conflicts
|
||||
* @property {Module[]=} dependencies module on which the result depends on
|
||||
*/
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ const ConcatenatedModule = require("./optimize/ConcatenatedModule");
|
|||
const { absolutify } = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../declarations/WebpackOptions").DevTool} DevToolOptions */
|
||||
/** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
||||
/** @type {WeakMap<Source, Source>} */
|
||||
|
@ -31,13 +33,17 @@ const devtoolWarning = new RawSource(`/*
|
|||
|
||||
class EvalSourceMapDevToolPlugin {
|
||||
/**
|
||||
* @param {TODO} options Options object
|
||||
* @param {SourceMapDevToolPluginOptions|string} inputOptions Options object
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
if (typeof options === "string") {
|
||||
constructor(inputOptions) {
|
||||
/** @type {SourceMapDevToolPluginOptions} */
|
||||
let options;
|
||||
if (typeof inputOptions === "string") {
|
||||
options = {
|
||||
append: options
|
||||
append: inputOptions
|
||||
};
|
||||
} else {
|
||||
options = inputOptions;
|
||||
}
|
||||
this.sourceMapComment =
|
||||
options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]";
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { equals } = require("./util/ArrayHelpers");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const makeSerializable = require("./util/makeSerializable");
|
||||
const { forEachRuntime } = require("./util/runtime");
|
||||
|
||||
/** @typedef {import("./Dependency").RuntimeSpec} RuntimeSpec */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("./util/Hash")} Hash */
|
||||
|
||||
/** @typedef {typeof UsageState.OnlyPropertiesUsed | typeof UsageState.NoInfo | typeof UsageState.Unknown | typeof UsageState.Used} RuntimeUsageStateType */
|
||||
|
@ -23,20 +26,30 @@ const UsageState = Object.freeze({
|
|||
Used: /** @type {4} */ (4)
|
||||
});
|
||||
|
||||
const RETURNS_TRUE = () => true;
|
||||
|
||||
class RestoreProvidedData {
|
||||
constructor(exports, otherProvided, otherCanMangleProvide) {
|
||||
constructor(
|
||||
exports,
|
||||
otherProvided,
|
||||
otherCanMangleProvide,
|
||||
otherTerminalBinding
|
||||
) {
|
||||
this.exports = exports;
|
||||
this.otherProvided = otherProvided;
|
||||
this.otherCanMangleProvide = otherCanMangleProvide;
|
||||
this.otherTerminalBinding = otherTerminalBinding;
|
||||
}
|
||||
|
||||
serialize({ write }) {
|
||||
write(this.exports);
|
||||
write(this.otherProvided), write(this.otherCanMangleProvide);
|
||||
write(this.otherProvided);
|
||||
write(this.otherCanMangleProvide);
|
||||
write(this.otherTerminalBinding);
|
||||
}
|
||||
|
||||
static deserialize({ read }) {
|
||||
return new RestoreProvidedData(read(), read(), read());
|
||||
return new RestoreProvidedData(read(), read(), read(), read());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +237,17 @@ class ExportsInfo {
|
|||
return this._otherExportsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} name export name
|
||||
* @returns {ExportInfo | undefined} export info for this name
|
||||
*/
|
||||
getReadOnlyExportInfoRecursive(name) {
|
||||
const exportInfo = this.getReadOnlyExportInfo(name[0]);
|
||||
if (name.length === 1) return exportInfo;
|
||||
if (!exportInfo.exportsInfo) return undefined;
|
||||
return exportInfo.exportsInfo.getReadOnlyExportInfoRecursive(name.slice(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]=} name the export name
|
||||
* @returns {ExportsInfo | undefined} the nested exports info
|
||||
|
@ -240,9 +264,16 @@ class ExportsInfo {
|
|||
/**
|
||||
* @param {boolean=} canMangle true, if exports can still be mangled (defaults to false)
|
||||
* @param {Set<string>=} excludeExports list of unaffected exports
|
||||
* @param {any=} targetKey use this as key for the target
|
||||
* @param {Module=} targetModule set this module as target
|
||||
* @returns {boolean} true, if this call changed something
|
||||
*/
|
||||
setUnknownExportsProvided(canMangle, excludeExports) {
|
||||
setUnknownExportsProvided(
|
||||
canMangle,
|
||||
excludeExports,
|
||||
targetKey,
|
||||
targetModule
|
||||
) {
|
||||
let changed = false;
|
||||
if (excludeExports) {
|
||||
for (const name of excludeExports) {
|
||||
|
@ -260,10 +291,18 @@ class ExportsInfo {
|
|||
exportInfo.canMangleProvide = false;
|
||||
changed = true;
|
||||
}
|
||||
if (targetKey) {
|
||||
exportInfo.setTarget(targetKey, targetModule, [exportInfo.name]);
|
||||
}
|
||||
}
|
||||
if (this._redirectTo !== undefined) {
|
||||
if (
|
||||
this._redirectTo.setUnknownExportsProvided(canMangle, excludeExports)
|
||||
this._redirectTo.setUnknownExportsProvided(
|
||||
canMangle,
|
||||
excludeExports,
|
||||
targetKey,
|
||||
targetModule
|
||||
)
|
||||
) {
|
||||
changed = true;
|
||||
}
|
||||
|
@ -279,6 +318,9 @@ class ExportsInfo {
|
|||
this._otherExportsInfo.canMangleProvide = false;
|
||||
changed = true;
|
||||
}
|
||||
if (targetKey) {
|
||||
this._otherExportsInfo.setTarget(targetKey, targetModule, undefined);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
@ -643,17 +685,20 @@ class ExportsInfo {
|
|||
getRestoreProvidedData() {
|
||||
const otherProvided = this._otherExportsInfo.provided;
|
||||
const otherCanMangleProvide = this._otherExportsInfo.canMangleProvide;
|
||||
const otherTerminalBinding = this._otherExportsInfo.terminalBinding;
|
||||
const exports = [];
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
if (
|
||||
exportInfo.provided !== otherProvided ||
|
||||
exportInfo.canMangleProvide !== otherCanMangleProvide ||
|
||||
exportInfo.terminalBinding !== otherTerminalBinding ||
|
||||
exportInfo.exportsInfoOwned
|
||||
) {
|
||||
exports.push({
|
||||
name: exportInfo.name,
|
||||
provided: exportInfo.provided,
|
||||
canMangleProvide: exportInfo.canMangleProvide,
|
||||
terminalBinding: exportInfo.terminalBinding,
|
||||
exportsInfo: exportInfo.exportsInfoOwned
|
||||
? exportInfo.exportsInfo.getRestoreProvidedData()
|
||||
: undefined
|
||||
|
@ -663,21 +708,30 @@ class ExportsInfo {
|
|||
return new RestoreProvidedData(
|
||||
exports,
|
||||
otherProvided,
|
||||
otherCanMangleProvide
|
||||
otherCanMangleProvide,
|
||||
otherTerminalBinding
|
||||
);
|
||||
}
|
||||
|
||||
restoreProvided({ otherProvided, otherCanMangleProvide, exports }) {
|
||||
restoreProvided({
|
||||
otherProvided,
|
||||
otherCanMangleProvide,
|
||||
otherTerminalBinding,
|
||||
exports
|
||||
}) {
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
exportInfo.provided = otherProvided;
|
||||
exportInfo.canMangleProvide = otherCanMangleProvide;
|
||||
exportInfo.terminalBinding = otherTerminalBinding;
|
||||
}
|
||||
this._otherExportsInfo.provided = otherProvided;
|
||||
this._otherExportsInfo.canMangleProvide = otherCanMangleProvide;
|
||||
this._otherExportsInfo.terminalBinding = otherTerminalBinding;
|
||||
for (const exp of exports) {
|
||||
const exportInfo = this.getExportInfo(exp.name);
|
||||
exportInfo.provided = exp.provided;
|
||||
exportInfo.canMangleProvide = exp.canMangleProvide;
|
||||
exportInfo.terminalBinding = exp.terminalBinding;
|
||||
if (exp.exportsInfo) {
|
||||
const exportsInfo = exportInfo.createNestedExportsInfo();
|
||||
exportsInfo.restoreProvided(exp.exportsInfo);
|
||||
|
@ -713,6 +767,11 @@ class ExportInfo {
|
|||
* @type {boolean | null | undefined}
|
||||
*/
|
||||
this.provided = initFrom ? initFrom.provided : undefined;
|
||||
/**
|
||||
* is the export a terminal binding that should be checked for export star conflicts
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.terminalBinding = initFrom ? initFrom.terminalBinding : false;
|
||||
/**
|
||||
* true: it can be mangled
|
||||
* false: is can not be mangled
|
||||
|
@ -731,6 +790,17 @@ class ExportInfo {
|
|||
this.exportsInfoOwned = false;
|
||||
/** @type {ExportsInfo=} */
|
||||
this.exportsInfo = undefined;
|
||||
/** @type {Map<any, { module: Module, export: string[] } | null>=} */
|
||||
this._target = undefined;
|
||||
if (initFrom && initFrom._target) {
|
||||
this._target = new Map();
|
||||
for (const [key, value] of initFrom._target) {
|
||||
this._target.set(
|
||||
key,
|
||||
value ? { module: value.module, export: [name] } : null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO webpack 5 remove
|
||||
|
@ -903,6 +973,41 @@ class ExportInfo {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} key the key
|
||||
* @param {Module=} module the target module if a single one
|
||||
* @param {string[]=} exportName the exported name
|
||||
* @returns {boolean} true, if something has changed
|
||||
*/
|
||||
setTarget(key, module, exportName) {
|
||||
if (!this._target) {
|
||||
this._target = new Map();
|
||||
this._target.set(key, module ? { module, export: exportName } : null);
|
||||
return true;
|
||||
}
|
||||
const oldTarget = this._target.get(key);
|
||||
if (!oldTarget) {
|
||||
if (oldTarget === null && !module) return false;
|
||||
this._target.set(key, module ? { module, export: exportName } : null);
|
||||
return true;
|
||||
}
|
||||
if (!module) {
|
||||
this._target.set(key, null);
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
oldTarget.module !== module ||
|
||||
(exportName
|
||||
? !oldTarget.export || !equals(oldTarget.export, exportName)
|
||||
: oldTarget.export)
|
||||
) {
|
||||
oldTarget.module = module;
|
||||
oldTarget.export = exportName;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RuntimeSpec} runtime for this runtime
|
||||
* @returns {UsageStateType} usage state
|
||||
|
@ -983,11 +1088,103 @@ class ExportInfo {
|
|||
this._usedName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @returns {ExportInfo | ExportsInfo | undefined} the terminal binding export(s) info if known
|
||||
*/
|
||||
getTerminalBinding(moduleGraph) {
|
||||
if (this.terminalBinding) return this;
|
||||
const target = this.getTarget(moduleGraph);
|
||||
if (!target) return undefined;
|
||||
const exportsInfo = moduleGraph.getExportsInfo(target.module);
|
||||
if (!target.export) return exportsInfo;
|
||||
return exportsInfo.getReadOnlyExportInfoRecursive(target.export);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
|
||||
* @returns {{ module: Module, export: string[] | undefined } | undefined} the target
|
||||
*/
|
||||
getTarget(moduleGraph, resolveTargetFilter = RETURNS_TRUE) {
|
||||
return this._getTarget(moduleGraph, resolveTargetFilter, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
|
||||
* @param {Set<ExportInfo> | undefined} alreadyVisited set of already visited export info to avoid circular references
|
||||
* @returns {{ module: Module, export: string[] | undefined } | undefined} the target
|
||||
*/
|
||||
_getTarget(moduleGraph, resolveTargetFilter, alreadyVisited) {
|
||||
/**
|
||||
* @param {{ module: Module, export: string[] | undefined } | null} target unresolved target
|
||||
* @param {Set<ExportInfo>} alreadyVisited set of already visited export info to avoid circular references
|
||||
* @returns {{module: Module, export: string[] | undefined} | null} resolved target
|
||||
*/
|
||||
const resolveTarget = (target, alreadyVisited) => {
|
||||
if (!target) return null;
|
||||
if (!target.export) return target;
|
||||
if (!resolveTargetFilter(target)) return target;
|
||||
let alreadyVisitedOwned = false;
|
||||
for (;;) {
|
||||
const exportsInfo = moduleGraph.getExportsInfo(target.module);
|
||||
const exportInfo = exportsInfo.getExportInfo(target.export[0]);
|
||||
if (!exportInfo) return target;
|
||||
if (alreadyVisited.has(exportInfo)) return null;
|
||||
const newTarget = exportInfo._getTarget(
|
||||
moduleGraph,
|
||||
resolveTargetFilter,
|
||||
alreadyVisited
|
||||
);
|
||||
if (!newTarget) return target;
|
||||
if (newTarget.export || target.export.length === 1) return newTarget;
|
||||
target = {
|
||||
module: newTarget.module,
|
||||
export: target.export.slice(1)
|
||||
};
|
||||
if (!resolveTargetFilter(target)) return target;
|
||||
if (!alreadyVisitedOwned) {
|
||||
alreadyVisited = new Set(alreadyVisited);
|
||||
alreadyVisitedOwned = true;
|
||||
}
|
||||
alreadyVisited.add(exportInfo);
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._target || this._target.size === 0) return undefined;
|
||||
const newAlreadyVisited = new Set(alreadyVisited);
|
||||
newAlreadyVisited.add(this);
|
||||
if (this._target.size === 1) {
|
||||
return resolveTarget(
|
||||
this._target.values().next().value,
|
||||
newAlreadyVisited
|
||||
);
|
||||
}
|
||||
const values = this._target.values();
|
||||
const target = resolveTarget(values.next().value, newAlreadyVisited);
|
||||
if (target === null) return undefined;
|
||||
let result = values.next();
|
||||
while (!result.done) {
|
||||
const t = resolveTarget(result.value, newAlreadyVisited);
|
||||
if (t === null) return undefined;
|
||||
if (t.module !== target.module) return undefined;
|
||||
if (!t.export !== !target.export) return undefined;
|
||||
if (target.export && !equals(t.export, target.export)) return undefined;
|
||||
result = values.next();
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
createNestedExportsInfo() {
|
||||
if (this.exportsInfoOwned) return this.exportsInfo;
|
||||
this.exportsInfoOwned = true;
|
||||
const oldExportsInfo = this.exportsInfo;
|
||||
this.exportsInfo = new ExportsInfo();
|
||||
this.exportsInfo.setHasProvideInfo();
|
||||
if (oldExportsInfo) {
|
||||
this.exportsInfo.setRedirectNamedTo(oldExportsInfo);
|
||||
}
|
||||
return this.exportsInfo;
|
||||
}
|
||||
|
||||
|
@ -1000,6 +1197,7 @@ class ExportInfo {
|
|||
hash.update(`${this.getUsed(runtime)}`);
|
||||
hash.update(`${this.provided}`);
|
||||
hash.update(`${this.canMangle}`);
|
||||
hash.update(`${this.terminalBinding}`);
|
||||
}
|
||||
|
||||
getUsedInfo() {
|
||||
|
|
|
@ -10,6 +10,7 @@ const Module = require("./Module");
|
|||
const RuntimeGlobals = require("./RuntimeGlobals");
|
||||
const Template = require("./Template");
|
||||
const StaticExportsDependency = require("./dependencies/StaticExportsDependency");
|
||||
const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
|
||||
const makeSerializable = require("./util/makeSerializable");
|
||||
const propertyAccess = require("./util/propertyAccess");
|
||||
|
||||
|
@ -94,7 +95,7 @@ const getSourceForImportExternal = (moduleAndSpecifiers, runtimeTemplate) => {
|
|||
*/
|
||||
const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
|
||||
if (typeof urlAndGlobal === "string") {
|
||||
urlAndGlobal = urlAndGlobal.split("@").reverse();
|
||||
urlAndGlobal = extractUrlAndGlobal(urlAndGlobal);
|
||||
}
|
||||
const url = urlAndGlobal[0];
|
||||
const globalName = urlAndGlobal[1];
|
||||
|
|
|
@ -11,6 +11,7 @@ const Queue = require("./util/Queue");
|
|||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./Dependency").ExportSpec} ExportSpec */
|
||||
/** @typedef {import("./ExportsInfo")} ExportsInfo */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
|
@ -32,6 +33,10 @@ class FlagDependencyExportsPlugin {
|
|||
const logger = compilation.getLogger(
|
||||
"webpack.FlagDependencyExportsPlugin"
|
||||
);
|
||||
let statRestoredFromCache = 0;
|
||||
let statFlaggedUncached = 0;
|
||||
let statNotCached = 0;
|
||||
let statQueueItemsProcessed = 0;
|
||||
|
||||
/** @type {Queue<Module>} */
|
||||
const queue = new Queue();
|
||||
|
@ -45,6 +50,7 @@ class FlagDependencyExportsPlugin {
|
|||
module.buildInfo.cacheable !== true ||
|
||||
typeof module.buildInfo.hash !== "string"
|
||||
) {
|
||||
statFlaggedUncached++;
|
||||
// Enqueue uncacheable module for determining the exports
|
||||
queue.enqueue(module);
|
||||
moduleGraph.getExportsInfo(module).setHasProvideInfo();
|
||||
|
@ -57,10 +63,12 @@ class FlagDependencyExportsPlugin {
|
|||
if (err) return callback(err);
|
||||
|
||||
if (result !== undefined) {
|
||||
statRestoredFromCache++;
|
||||
moduleGraph
|
||||
.getExportsInfo(module)
|
||||
.restoreProvided(result);
|
||||
} else {
|
||||
statNotCached++;
|
||||
// Without cached info enqueue module for determining the exports
|
||||
queue.enqueue(module);
|
||||
moduleGraph.getExportsInfo(module).setHasProvideInfo();
|
||||
|
@ -109,96 +117,119 @@ class FlagDependencyExportsPlugin {
|
|||
const exportDesc = dep.getExports(moduleGraph);
|
||||
if (!exportDesc) return;
|
||||
const exports = exportDesc.exports;
|
||||
const canMangle = exportDesc.canMangle;
|
||||
const globalCanMangle = exportDesc.canMangle;
|
||||
const globalFrom = exportDesc.from;
|
||||
const globalTerminalBinding =
|
||||
exportDesc.terminalBinding || false;
|
||||
const exportDeps = exportDesc.dependencies;
|
||||
if (exports === true) {
|
||||
// unknown exports
|
||||
if (
|
||||
exportsInfo.setUnknownExportsProvided(
|
||||
canMangle,
|
||||
exportDesc.excludeExports
|
||||
globalCanMangle,
|
||||
exportDesc.excludeExports,
|
||||
globalFrom && dep,
|
||||
globalFrom
|
||||
)
|
||||
) {
|
||||
changed = true;
|
||||
}
|
||||
} else if (Array.isArray(exports)) {
|
||||
// merge in new exports
|
||||
/**
|
||||
* merge in new exports
|
||||
* @param {ExportsInfo} exportsInfo own exports info
|
||||
* @param {(ExportSpec | string)[]} exports list of exports
|
||||
*/
|
||||
const mergeExports = (exportsInfo, exports) => {
|
||||
for (const exportNameOrSpec of exports) {
|
||||
let name;
|
||||
let canMangle = globalCanMangle;
|
||||
let terminalBinding = globalTerminalBinding;
|
||||
let exports = undefined;
|
||||
let from = globalFrom;
|
||||
let fromExport = undefined;
|
||||
if (typeof exportNameOrSpec === "string") {
|
||||
const exportInfo = exportsInfo.getExportInfo(
|
||||
exportNameOrSpec
|
||||
);
|
||||
if (exportInfo.provided === false) {
|
||||
exportInfo.provided = true;
|
||||
changed = true;
|
||||
}
|
||||
if (
|
||||
canMangle === false &&
|
||||
exportInfo.canMangleProvide !== false
|
||||
) {
|
||||
exportInfo.canMangleProvide = false;
|
||||
changed = true;
|
||||
}
|
||||
name = exportNameOrSpec;
|
||||
} else {
|
||||
const exportInfo = exportsInfo.getExportInfo(
|
||||
exportNameOrSpec.name
|
||||
name = exportNameOrSpec.name;
|
||||
if (exportNameOrSpec.canMangle !== undefined)
|
||||
canMangle = exportNameOrSpec.canMangle;
|
||||
if (exportNameOrSpec.export !== undefined)
|
||||
fromExport = exportNameOrSpec.export;
|
||||
if (exportNameOrSpec.exports !== undefined)
|
||||
exports = exportNameOrSpec.exports;
|
||||
if (exportNameOrSpec.from !== undefined)
|
||||
from = exportNameOrSpec.from;
|
||||
if (exportNameOrSpec.terminalBinding !== undefined)
|
||||
terminalBinding = exportNameOrSpec.terminalBinding;
|
||||
}
|
||||
const exportInfo = exportsInfo.getExportInfo(name);
|
||||
|
||||
if (exportInfo.provided === false) {
|
||||
exportInfo.provided = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (
|
||||
exportInfo.canMangleProvide !== false &&
|
||||
canMangle === false
|
||||
) {
|
||||
exportInfo.canMangleProvide = false;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (terminalBinding && !exportInfo.terminalBinding) {
|
||||
exportInfo.terminalBinding = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (exports) {
|
||||
const nestedExportsInfo = exportInfo.createNestedExportsInfo();
|
||||
mergeExports(nestedExportsInfo, exports);
|
||||
}
|
||||
|
||||
if (
|
||||
exportInfo.setTarget(
|
||||
dep,
|
||||
from,
|
||||
fromExport === undefined ? [name] : fromExport
|
||||
)
|
||||
) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Recalculate target exportsInfo
|
||||
const target = exportInfo.getTarget(moduleGraph);
|
||||
let targetExportsInfo = undefined;
|
||||
if (target) {
|
||||
const targetModuleExportsInfo = moduleGraph.getExportsInfo(
|
||||
target.module
|
||||
);
|
||||
if (exportInfo.provided === false) {
|
||||
exportInfo.provided = true;
|
||||
targetExportsInfo = targetModuleExportsInfo.getNestedExportsInfo(
|
||||
target.export
|
||||
);
|
||||
// add dependency for this module
|
||||
const set = dependencies.get(target.module);
|
||||
if (set === undefined) {
|
||||
dependencies.set(target.module, new Set([module]));
|
||||
} else {
|
||||
set.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
if (exportInfo.exportsInfoOwned) {
|
||||
if (
|
||||
exportInfo.exportsInfo.setRedirectNamedTo(
|
||||
targetExportsInfo
|
||||
)
|
||||
) {
|
||||
changed = true;
|
||||
}
|
||||
if (
|
||||
exportInfo.canMangleProvide !== false &&
|
||||
(exportNameOrSpec.canMangle === false ||
|
||||
(canMangle === false &&
|
||||
exportNameOrSpec.canMangle === undefined))
|
||||
) {
|
||||
exportInfo.canMangleProvide = false;
|
||||
changed = true;
|
||||
}
|
||||
if (
|
||||
exportNameOrSpec.exports &&
|
||||
exportNameOrSpec.from
|
||||
) {
|
||||
const nestedExportsInfo = exportInfo.createNestedExportsInfo();
|
||||
const fromExportsInfo = moduleGraph.getExportsInfo(
|
||||
exportNameOrSpec.from
|
||||
);
|
||||
const fromNestedExportsInfo = fromExportsInfo.getNestedExportsInfo(
|
||||
exportNameOrSpec.export
|
||||
);
|
||||
mergeExports(
|
||||
nestedExportsInfo,
|
||||
exportNameOrSpec.exports
|
||||
);
|
||||
if (fromNestedExportsInfo) {
|
||||
if (
|
||||
nestedExportsInfo.setRedirectNamedTo(
|
||||
fromNestedExportsInfo
|
||||
)
|
||||
) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else if (exportNameOrSpec.exports) {
|
||||
const nestedExportsInfo = exportInfo.createNestedExportsInfo();
|
||||
mergeExports(
|
||||
nestedExportsInfo,
|
||||
exportNameOrSpec.exports
|
||||
);
|
||||
} else if (exportNameOrSpec.from) {
|
||||
const fromExportsInfo = moduleGraph.getExportsInfo(
|
||||
exportNameOrSpec.from
|
||||
);
|
||||
const nestedExportsInfo = fromExportsInfo.getNestedExportsInfo(
|
||||
exportNameOrSpec.export
|
||||
);
|
||||
if (!exportInfo.exportsInfo && nestedExportsInfo) {
|
||||
exportInfo.exportsInfo = nestedExportsInfo;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
exportInfo.exportsInfo !== targetExportsInfo
|
||||
) {
|
||||
exportInfo.exportsInfo = targetExportsInfo;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -232,33 +263,49 @@ class FlagDependencyExportsPlugin {
|
|||
while (queue.length > 0) {
|
||||
module = queue.dequeue();
|
||||
|
||||
statQueueItemsProcessed++;
|
||||
|
||||
exportsInfo = moduleGraph.getExportsInfo(module);
|
||||
if (exportsInfo.otherExportsInfo.provided !== null) {
|
||||
if (!module.buildMeta || !module.buildMeta.exportsType) {
|
||||
if (!module.buildMeta || !module.buildMeta.exportsType) {
|
||||
if (exportsInfo.otherExportsInfo.provided !== null) {
|
||||
// It's a module without declared exports
|
||||
exportsInfo.setUnknownExportsProvided();
|
||||
modulesToStore.add(module);
|
||||
notifyDependencies();
|
||||
} else {
|
||||
// It's a module with declared exports
|
||||
}
|
||||
} else {
|
||||
// It's a module with declared exports
|
||||
|
||||
cacheable = true;
|
||||
changed = false;
|
||||
cacheable = true;
|
||||
changed = false;
|
||||
|
||||
processDependenciesBlock(module);
|
||||
processDependenciesBlock(module);
|
||||
|
||||
if (cacheable) {
|
||||
modulesToStore.add(module);
|
||||
}
|
||||
if (cacheable) {
|
||||
modulesToStore.add(module);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
notifyDependencies();
|
||||
}
|
||||
if (changed) {
|
||||
notifyDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.timeEnd("figure out provided exports");
|
||||
|
||||
logger.log(
|
||||
`${Math.round(
|
||||
100 -
|
||||
(100 * statRestoredFromCache) /
|
||||
(statRestoredFromCache +
|
||||
statNotCached +
|
||||
statFlaggedUncached)
|
||||
)}% of exports of modules have been determined (${statNotCached} not cached, ${statFlaggedUncached} flagged uncacheable, ${statRestoredFromCache} from cache, ${
|
||||
statQueueItemsProcessed -
|
||||
statNotCached -
|
||||
statFlaggedUncached
|
||||
} additional calculations due to dependencies)`
|
||||
);
|
||||
|
||||
logger.time("store provided exports into cache");
|
||||
asyncLib.each(
|
||||
modulesToStore,
|
||||
|
|
|
@ -12,6 +12,7 @@ const memorize = require("./util/memorize");
|
|||
|
||||
/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../declarations/WebpackOptions").Output} OutputOptions */
|
||||
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
|
@ -37,11 +38,11 @@ const getJsonpTemplatePlugin = memorize(() =>
|
|||
class MainTemplate {
|
||||
/**
|
||||
*
|
||||
* @param {TODO} outputOptions output options for the MainTemplate
|
||||
* @param {OutputOptions} outputOptions output options for the MainTemplate
|
||||
* @param {Compilation} compilation the compilation
|
||||
*/
|
||||
constructor(outputOptions, compilation) {
|
||||
/** @type {TODO} */
|
||||
/** @type {OutputOptions} */
|
||||
this._outputOptions = outputOptions || {};
|
||||
this.hooks = Object.freeze({
|
||||
renderManifest: {
|
||||
|
@ -311,7 +312,7 @@ Object.defineProperty(MainTemplate.prototype, "outputOptions", {
|
|||
get: util.deprecate(
|
||||
/**
|
||||
* @this {MainTemplate}
|
||||
* @returns {TODO} output options
|
||||
* @returns {OutputOptions} output options
|
||||
*/
|
||||
function () {
|
||||
return this._outputOptions;
|
||||
|
|
|
@ -14,6 +14,7 @@ const { compareChunksById } = require("./util/comparators");
|
|||
const makeSerializable = require("./util/makeSerializable");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
|
||||
/** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
|
@ -112,7 +113,7 @@ class Module extends DependenciesBlock {
|
|||
this.debugId = debugId++;
|
||||
|
||||
// Info from Factory
|
||||
/** @type {TODO} */
|
||||
/** @type {ResolveOptions} */
|
||||
this.resolveOptions = EMPTY_RESOLVE_OPTIONS;
|
||||
/** @type {object | undefined} */
|
||||
this.factoryMeta = undefined;
|
||||
|
@ -597,8 +598,8 @@ class Module extends DependenciesBlock {
|
|||
|
||||
/**
|
||||
* @deprecated Use needBuild instead
|
||||
* @param {TODO} fileTimestamps timestamps of files
|
||||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @param {Map<string, number|null>} fileTimestamps timestamps of files
|
||||
* @param {Map<string, number|null>} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
|
|
|
@ -12,7 +12,7 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
class ModuleBuildError extends WebpackError {
|
||||
/**
|
||||
* @param {string | Error&any} err error thrown
|
||||
* @param {TODO} info additional info
|
||||
* @param {{from?: string|null}} info additional info
|
||||
*/
|
||||
constructor(err, { from = null } = {}) {
|
||||
let message = "Module build failed";
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const WebpackError = require("./WebpackError");
|
||||
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
class ModuleDependencyError extends WebpackError {
|
||||
|
@ -14,7 +15,7 @@ class ModuleDependencyError extends WebpackError {
|
|||
* Creates an instance of ModuleDependencyError.
|
||||
* @param {Module} module module tied to dependency
|
||||
* @param {Error} err error thrown
|
||||
* @param {TODO} loc location of dependency
|
||||
* @param {DependencyLocation} loc location of dependency
|
||||
*/
|
||||
constructor(module, err, loc) {
|
||||
super(err.message);
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
|
||||
const WebpackError = require("./WebpackError");
|
||||
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
module.exports = class ModuleDependencyWarning extends WebpackError {
|
||||
/**
|
||||
* @param {Module} module module tied to dependency
|
||||
* @param {Error} err error thrown
|
||||
* @param {TODO} loc location of dependency
|
||||
* @param {DependencyLocation} loc location of dependency
|
||||
*/
|
||||
constructor(module, err, loc) {
|
||||
super(err.message);
|
||||
|
|
|
@ -12,7 +12,7 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
class ModuleError extends WebpackError {
|
||||
/**
|
||||
* @param {Error} err error thrown
|
||||
* @param {TODO} info additional info
|
||||
* @param {{from?: string|null}} info additional info
|
||||
*/
|
||||
constructor(err, { from = null } = {}) {
|
||||
let message = "Module Error";
|
||||
|
|
|
@ -13,7 +13,9 @@ const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
|
|||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./ExportsInfo")} ExportsInfo */
|
||||
/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
|
||||
const joinIterableWithComma = iterable => {
|
||||
// This is more performant than Array.from().join(", ")
|
||||
|
@ -35,6 +37,8 @@ const joinIterableWithComma = iterable => {
|
|||
* @param {ConcatSource} source output
|
||||
* @param {string} indent spacing
|
||||
* @param {ExportsInfo} exportsInfo data
|
||||
* @param {ModuleGraph} moduleGraph moduleGraph
|
||||
* @param {RequestShortener} requestShortener requestShortener
|
||||
* @param {Set<ExportInfo>} alreadyPrinted deduplication set
|
||||
* @returns {void}
|
||||
*/
|
||||
|
@ -42,6 +46,8 @@ const printExportsInfoToSource = (
|
|||
source,
|
||||
indent,
|
||||
exportsInfo,
|
||||
moduleGraph,
|
||||
requestShortener,
|
||||
alreadyPrinted = new Set()
|
||||
) => {
|
||||
const otherExportsInfo = exportsInfo.otherExportsInfo;
|
||||
|
@ -68,12 +74,23 @@ const printExportsInfoToSource = (
|
|||
|
||||
// print the exports
|
||||
for (const exportInfo of printedExports) {
|
||||
const target = exportInfo.getTarget(moduleGraph);
|
||||
source.add(
|
||||
Template.toComment(
|
||||
`${indent}export ${JSON.stringify(exportInfo.name).slice(
|
||||
1,
|
||||
-1
|
||||
)} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]`
|
||||
)} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]${
|
||||
target
|
||||
? ` -> ${target.module.readableIdentifier(requestShortener)}${
|
||||
target.export
|
||||
? ` .${target.export
|
||||
.map(e => JSON.stringify(e).slice(1, -1))
|
||||
.join(".")}`
|
||||
: ""
|
||||
}`
|
||||
: ""
|
||||
}`
|
||||
) + "\n"
|
||||
);
|
||||
if (exportInfo.exportsInfo) {
|
||||
|
@ -81,6 +98,8 @@ const printExportsInfoToSource = (
|
|||
source,
|
||||
indent + " ",
|
||||
exportInfo.exportsInfo,
|
||||
moduleGraph,
|
||||
requestShortener,
|
||||
alreadyPrinted
|
||||
);
|
||||
}
|
||||
|
@ -95,7 +114,9 @@ const printExportsInfoToSource = (
|
|||
}
|
||||
|
||||
if (showOtherExports) {
|
||||
const target = otherExportsInfo.getTarget(moduleGraph);
|
||||
if (
|
||||
target ||
|
||||
otherExportsInfo.provided !== false ||
|
||||
otherExportsInfo.getUsed(undefined) !== UsageState.Unused
|
||||
) {
|
||||
|
@ -105,7 +126,11 @@ const printExportsInfoToSource = (
|
|||
: "exports";
|
||||
source.add(
|
||||
Template.toComment(
|
||||
`${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]`
|
||||
`${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]${
|
||||
target
|
||||
? ` -> ${target.module.readableIdentifier(requestShortener)}`
|
||||
: ""
|
||||
}`
|
||||
) + "\n"
|
||||
);
|
||||
}
|
||||
|
@ -127,10 +152,9 @@ class ModuleInfoHeaderPlugin {
|
|||
module,
|
||||
{ chunk, chunkGraph, moduleGraph, runtimeTemplate }
|
||||
) => {
|
||||
const { requestShortener } = runtimeTemplate;
|
||||
const source = new ConcatSource();
|
||||
const req = module.readableIdentifier(
|
||||
runtimeTemplate.requestShortener
|
||||
);
|
||||
const req = module.readableIdentifier(requestShortener);
|
||||
const reqStr = req.replace(/\*\//g, "*_/");
|
||||
const reqStrStar = "*".repeat(reqStr.length);
|
||||
source.add("/*!****" + reqStrStar + "****!*\\\n");
|
||||
|
@ -146,7 +170,13 @@ class ModuleInfoHeaderPlugin {
|
|||
);
|
||||
if (exportsType) {
|
||||
const exportsInfo = moduleGraph.getExportsInfo(module);
|
||||
printExportsInfoToSource(source, "", exportsInfo);
|
||||
printExportsInfoToSource(
|
||||
source,
|
||||
"",
|
||||
exportsInfo,
|
||||
moduleGraph,
|
||||
requestShortener
|
||||
);
|
||||
}
|
||||
source.add(
|
||||
Template.toComment(
|
||||
|
@ -162,7 +192,7 @@ class ModuleInfoHeaderPlugin {
|
|||
for (const text of optimizationBailout) {
|
||||
let code;
|
||||
if (typeof text === "function") {
|
||||
code = text(runtimeTemplate.requestShortener);
|
||||
code = text(requestShortener);
|
||||
} else {
|
||||
code = text;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const WebpackError = require("./WebpackError");
|
||||
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
const previouslyPolyfilledBuiltinModules = {
|
||||
|
@ -44,7 +45,7 @@ class ModuleNotFoundError extends WebpackError {
|
|||
/**
|
||||
* @param {Module} module module tied to dependency
|
||||
* @param {Error&any} err error thrown
|
||||
* @param {TODO} loc location of dependency
|
||||
* @param {DependencyLocation} loc location of dependency
|
||||
*/
|
||||
constructor(module, err, loc) {
|
||||
let message = `Module not found: ${err.toString()}`;
|
||||
|
|
|
@ -12,7 +12,7 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
class ModuleWarning extends WebpackError {
|
||||
/**
|
||||
* @param {Error} warning error thrown
|
||||
* @param {TODO} info additional info
|
||||
* @param {{from?: string|null}} info additional info
|
||||
*/
|
||||
constructor(warning, { from = null } = {}) {
|
||||
let message = "Module Warning";
|
||||
|
|
|
@ -729,7 +729,7 @@ class NormalModule extends Module {
|
|||
const hash = createHash(compilation.outputOptions.hashFunction);
|
||||
if (this._source) {
|
||||
hash.update("source");
|
||||
this._source.updateHash(/** @type {TODO} */ (hash));
|
||||
this._source.updateHash(hash);
|
||||
}
|
||||
hash.update("meta");
|
||||
hash.update(JSON.stringify(this.buildMeta));
|
||||
|
|
|
@ -32,6 +32,7 @@ const { parseResource } = require("./util/identifier");
|
|||
/** @typedef {import("./Generator")} Generator */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
||||
/** @typedef {import("./Parser")} Parser */
|
||||
/** @typedef {import("./ResolverFactory")} ResolverFactory */
|
||||
/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
|
||||
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
|
||||
|
@ -751,6 +752,11 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type type
|
||||
* @param {{[k: string]: any}} parserOptions parser options
|
||||
* @returns {Parser} parser
|
||||
*/
|
||||
createParser(type, parserOptions = {}) {
|
||||
const parser = this.hooks.createParser.for(type).call(parserOptions);
|
||||
if (!parser) {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* @property {NormalModule} current
|
||||
* @property {NormalModule} module
|
||||
* @property {Compilation} compilation
|
||||
* @property {TODO} options
|
||||
* @property {{[k: string]: any}} options
|
||||
*/
|
||||
|
||||
/** @typedef {Record<string, any> & ParserStateBase} ParserState */
|
||||
|
|
|
@ -182,8 +182,8 @@ class ProgressPlugin {
|
|||
const showActiveModules = this.showActiveModules;
|
||||
let lastActiveModule = "";
|
||||
let currentLoader = "";
|
||||
let lastModulesCount = this.modulesCount;
|
||||
let lastDependenciesCount = this.dependenciesCount;
|
||||
let lastModulesCount = 0;
|
||||
let lastDependenciesCount = 0;
|
||||
let lastEntriesCount = 0;
|
||||
let modulesCount = 0;
|
||||
let dependenciesCount = 0;
|
||||
|
@ -202,9 +202,11 @@ class ProgressPlugin {
|
|||
/** @type {string[]} */
|
||||
const items = [];
|
||||
const percentByModules =
|
||||
doneModules / Math.max(lastModulesCount, modulesCount);
|
||||
doneModules /
|
||||
Math.max(lastModulesCount || this.modulesCount, modulesCount);
|
||||
const percentByEntries =
|
||||
doneEntries / Math.max(lastEntriesCount, entriesCount);
|
||||
doneEntries /
|
||||
Math.max(lastEntriesCount || this.dependenciesCount, entriesCount);
|
||||
const percentByDependencies =
|
||||
doneDependencies / Math.max(lastDependenciesCount, dependenciesCount);
|
||||
let percentageFactor;
|
||||
|
@ -323,32 +325,30 @@ class ProgressPlugin {
|
|||
.getCache("ProgressPlugin")
|
||||
.getItemCache("counts", null);
|
||||
|
||||
compiler.hooks.beforeCompile.tapAsync(
|
||||
"ProgressPlugin",
|
||||
(params, callback) => {
|
||||
handler(0.06, "setup", "waiting for cache");
|
||||
cache.get((err, data) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
let cacheGetPromise;
|
||||
|
||||
compiler.hooks.beforeCompile.tap("ProgressPlugin", () => {
|
||||
if (!cacheGetPromise) {
|
||||
cacheGetPromise = cache.getPromise().then(
|
||||
data => {
|
||||
if (data) {
|
||||
lastModulesCount = lastModulesCount || data.modulesCount;
|
||||
lastDependenciesCount =
|
||||
lastDependenciesCount || data.dependenciesCount;
|
||||
}
|
||||
},
|
||||
err => {
|
||||
// Ignore error
|
||||
}
|
||||
|
||||
if (data) {
|
||||
lastModulesCount = lastModulesCount || data.modulesCount;
|
||||
lastDependenciesCount =
|
||||
lastDependenciesCount || data.dependenciesCount;
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
compiler.hooks.afterCompile.tapAsync(
|
||||
"ProgressPlugin",
|
||||
(compilation, callback) => {
|
||||
cache.store({ modulesCount, dependenciesCount }, callback);
|
||||
}
|
||||
);
|
||||
compiler.hooks.afterCompile.tapPromise("ProgressPlugin", compilation => {
|
||||
return cacheGetPromise.then(() =>
|
||||
cache.storePromise({ modulesCount, dependenciesCount })
|
||||
);
|
||||
});
|
||||
|
||||
compiler.hooks.compilation.tap("ProgressPlugin", compilation => {
|
||||
if (compilation.compiler.isChild()) return;
|
||||
|
|
|
@ -98,6 +98,8 @@ class RuntimeModule extends Module {
|
|||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash, context) {
|
||||
hash.update(this.name);
|
||||
hash.update(`${this.stage}`);
|
||||
// Do not use getGeneratedCode here, because i. e. compilation hash is not
|
||||
// ready at this point. We will cache it later instead.
|
||||
try {
|
||||
|
|
|
@ -22,6 +22,7 @@ const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectR
|
|||
const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
|
||||
const SystemContextRuntimeModule = require("./runtime/SystemContextRuntimeModule");
|
||||
const ShareRuntimeModule = require("./sharing/ShareRuntimeModule");
|
||||
const StringXor = require("./util/StringXor");
|
||||
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
@ -291,9 +292,11 @@ class RuntimePlugin {
|
|||
JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(
|
||||
"RuntimePlugin",
|
||||
(chunk, hash, { chunkGraph }) => {
|
||||
for (const m of chunkGraph.getChunkRuntimeModulesInOrder(chunk)) {
|
||||
hash.update(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
const xor = new StringXor();
|
||||
for (const m of chunkGraph.getChunkRuntimeModulesIterable(chunk)) {
|
||||
xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
}
|
||||
xor.updateHash(hash);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const InitFragment = require("./InitFragment");
|
||||
const RuntimeGlobals = require("./RuntimeGlobals");
|
||||
const Template = require("./Template");
|
||||
const { equals } = require("./util/ArrayHelpers");
|
||||
const propertyAccess = require("./util/propertyAccess");
|
||||
|
||||
/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
|
||||
|
@ -20,14 +21,6 @@ const propertyAccess = require("./util/propertyAccess");
|
|||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
|
||||
|
||||
const arrayEquals = (a, b) => {
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
|
@ -490,13 +483,12 @@ class RuntimeTemplate {
|
|||
}
|
||||
break;
|
||||
case "dynamic":
|
||||
fakeType |= 7;
|
||||
fakeType |= 4;
|
||||
/* fall through */
|
||||
case "default-with-named":
|
||||
fakeType |= 3;
|
||||
fakeType |= 2;
|
||||
/* fall through */
|
||||
case "default-only":
|
||||
fakeType |= 1;
|
||||
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
|
||||
if (chunkGraph.moduleGraph.isAsync(module)) {
|
||||
if (header) {
|
||||
|
@ -520,6 +512,7 @@ class RuntimeTemplate {
|
|||
"m"
|
||||
)})`;
|
||||
} else {
|
||||
fakeType |= 1;
|
||||
if (header) {
|
||||
const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, ${fakeType})`;
|
||||
appending = `.then(${this.basicFunction(
|
||||
|
@ -709,7 +702,7 @@ class RuntimeTemplate {
|
|||
);
|
||||
return `${comment} undefined`;
|
||||
}
|
||||
const comment = arrayEquals(used, exportName)
|
||||
const comment = equals(used, exportName)
|
||||
? ""
|
||||
: Template.toNormalComment(propertyAccess(exportName)) + " ";
|
||||
const access = `${importVar}${comment}${propertyAccess(used)}`;
|
||||
|
|
|
@ -11,6 +11,7 @@ const { compareIds } = require("./util/comparators");
|
|||
|
||||
/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../declarations/WebpackOptions").Output} OutputOptions */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./CodeGenerationResults")} CodeGenerationResults */
|
||||
|
@ -44,7 +45,7 @@ const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
|
|||
* @property {Chunk} chunk the chunk used to render
|
||||
* @property {string} hash
|
||||
* @property {string} fullHash
|
||||
* @property {TODO} outputOptions
|
||||
* @property {OutputOptions} outputOptions
|
||||
* @property {CodeGenerationResults} codeGenerationResults
|
||||
* @property {{javascript: ModuleTemplate}} moduleTemplates
|
||||
* @property {DependencyTemplates} dependencyTemplates
|
||||
|
|
|
@ -9,6 +9,7 @@ const { basename, extname } = require("path");
|
|||
const util = require("util");
|
||||
const Chunk = require("./Chunk");
|
||||
const Module = require("./Module");
|
||||
const { parseResource } = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
|
||||
/** @typedef {import("./Compilation").PathData} PathData */
|
||||
|
@ -96,26 +97,17 @@ const replacePathVariables = (path, data, assetInfo) => {
|
|||
//
|
||||
// Placeholders
|
||||
//
|
||||
// for /some/path/file.js?query:
|
||||
// for /some/path/file.js?query#fragment:
|
||||
// [file] - /some/path/file.js
|
||||
// [query] - ?query
|
||||
// [fragment] - #fragment
|
||||
// [base] - file.js
|
||||
// [path] - /some/path/
|
||||
// [name] - file
|
||||
// [ext] - .js
|
||||
if (data.filename) {
|
||||
if (typeof data.filename === "string") {
|
||||
const idx = data.filename.indexOf("?");
|
||||
|
||||
let file, query;
|
||||
|
||||
if (idx >= 0) {
|
||||
file = data.filename.substr(0, idx);
|
||||
query = data.filename.substr(idx);
|
||||
} else {
|
||||
file = data.filename;
|
||||
query = "";
|
||||
}
|
||||
const { path: file, query, fragment } = parseResource(data.filename);
|
||||
|
||||
const ext = extname(file);
|
||||
const base = basename(file);
|
||||
|
@ -124,6 +116,7 @@ const replacePathVariables = (path, data, assetInfo) => {
|
|||
|
||||
replacements.set("file", replacer(file));
|
||||
replacements.set("query", replacer(query, true));
|
||||
replacements.set("fragment", replacer(fragment, true));
|
||||
replacements.set("path", replacer(path, true));
|
||||
replacements.set("base", replacer(base));
|
||||
replacements.set("name", replacer(name));
|
||||
|
|
|
@ -307,13 +307,7 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
|
||||
new RuntimePlugin().apply(compiler);
|
||||
|
||||
new InferAsyncModulesPlugin({
|
||||
errorOnImport: options.experiments.importAsync
|
||||
? false
|
||||
: options.experiments.importAwait
|
||||
? "await"
|
||||
: true
|
||||
}).apply(compiler);
|
||||
new InferAsyncModulesPlugin().apply(compiler);
|
||||
|
||||
new BaseURIPlugin(options.output.baseURI).apply(compiler);
|
||||
new URLPlugin().apply(compiler);
|
||||
|
@ -323,8 +317,7 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
new CompatibilityPlugin().apply(compiler);
|
||||
new HarmonyModulesPlugin({
|
||||
module: options.module,
|
||||
topLevelAwait: options.experiments.topLevelAwait,
|
||||
importAwait: options.experiments.importAwait
|
||||
topLevelAwait: options.experiments.topLevelAwait
|
||||
}).apply(compiler);
|
||||
if (options.amd !== false) {
|
||||
const AMDPlugin = require("./dependencies/AMDPlugin");
|
||||
|
@ -558,6 +551,7 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
const PackFileCacheStrategy = require("./cache/PackFileCacheStrategy");
|
||||
new IdleFileCachePlugin(
|
||||
new PackFileCacheStrategy({
|
||||
compiler,
|
||||
fs: compiler.intermediateFileSystem,
|
||||
context: options.context,
|
||||
cacheLocation: cacheOptions.cacheLocation,
|
||||
|
|
|
@ -62,7 +62,7 @@ class AssetGenerator extends Generator {
|
|||
null,
|
||||
originalSource.source(),
|
||||
{
|
||||
filename: module.nameForCondition(),
|
||||
filename: module.matchResource || module.resource,
|
||||
module
|
||||
}
|
||||
);
|
||||
|
@ -131,7 +131,7 @@ class AssetGenerator extends Generator {
|
|||
} = this.compilation.getAssetPathWithInfo(assetModuleFilename, {
|
||||
module,
|
||||
runtime,
|
||||
filename: module.nameForCondition(),
|
||||
filename: module.matchResource || module.resource,
|
||||
chunkGraph,
|
||||
contentHash
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ class AssetParser extends Parser {
|
|||
|
||||
if (typeof this.dataUrlCondition === "function") {
|
||||
state.module.buildInfo.dataUrl = this.dataUrlCondition(source, {
|
||||
filename: state.module.nameForCondition(),
|
||||
filename: state.module.matchResource || state.module.resource,
|
||||
module: state.module
|
||||
});
|
||||
} else if (typeof this.dataUrlCondition === "boolean") {
|
||||
|
|
|
@ -5,21 +5,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const WebpackError = require("../WebpackError");
|
||||
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
||||
const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
|
||||
class InferAsyncModulesPlugin {
|
||||
/**
|
||||
* @param {Object} options options object
|
||||
* @param {boolean | "await"=} options.errorOnImport false: no error, true: error when importing async module, "await": error when import async module without import await
|
||||
*/
|
||||
constructor({ errorOnImport = false } = {}) {
|
||||
this.errorOnImport = errorOnImport;
|
||||
}
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
|
@ -47,20 +38,6 @@ class InferAsyncModulesPlugin {
|
|||
dep instanceof HarmonyImportDependency &&
|
||||
connection.isActive(undefined)
|
||||
) {
|
||||
if (
|
||||
this.errorOnImport &&
|
||||
dep instanceof HarmonyImportSideEffectDependency &&
|
||||
(this.errorOnImport === true || !dep.await)
|
||||
) {
|
||||
const error = new WebpackError(
|
||||
this.errorOnImport === true
|
||||
? "Tried to import async module with import/export (must enable experiments.importAsync to allow this)"
|
||||
: "Tried to import async module with normal import/export (must use 'import await'/'export await' instead)"
|
||||
);
|
||||
error.module = module;
|
||||
error.loc = dep.loc;
|
||||
compilation.errors.push(error);
|
||||
}
|
||||
queue.add(connection.originModule);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,6 +154,20 @@ const visitModules = (
|
|||
logger.time("visitModules: prepare");
|
||||
const blockModulesMap = extractBlockModulesMap(compilation);
|
||||
|
||||
let statProcessedQueueItems = 0;
|
||||
let statProcessedBlocks = 0;
|
||||
let statConnectedChunkGroups = 0;
|
||||
let statProcessedChunkGroupsForMerging = 0;
|
||||
let statMergedAvailableModuleSets = 0;
|
||||
let statForkedAvailableModules = 0;
|
||||
let statForkedAvailableModulesCount = 0;
|
||||
let statForkedAvailableModulesCountPlus = 0;
|
||||
let statForkedMergedModulesCount = 0;
|
||||
let statForkedMergedModulesCountPlus = 0;
|
||||
let statForkedResultModulesCount = 0;
|
||||
let statChunkGroupInfoUpdated = 0;
|
||||
let statChildChunkGroupsReconnected = 0;
|
||||
|
||||
let nextChunkGroupIndex = 0;
|
||||
let nextFreeModulePreOrderIndex = 0;
|
||||
let nextFreeModulePostOrderIndex = 0;
|
||||
|
@ -357,6 +371,7 @@ const visitModules = (
|
|||
* @returns {void}
|
||||
*/
|
||||
const processBlock = block => {
|
||||
statProcessedBlocks++;
|
||||
// get prepared block info
|
||||
const blockModules = blockModulesMap.get(block);
|
||||
|
||||
|
@ -423,6 +438,7 @@ const visitModules = (
|
|||
|
||||
const processQueue = () => {
|
||||
while (queue.length) {
|
||||
statProcessedQueueItems++;
|
||||
const queueItem = queue.pop();
|
||||
module = queueItem.module;
|
||||
block = queueItem.block;
|
||||
|
@ -552,16 +568,22 @@ const visitModules = (
|
|||
target.availableModulesToBeMerged.push(resultingAvailableModules);
|
||||
chunkGroupsForMerging.add(target);
|
||||
}
|
||||
|
||||
statConnectedChunkGroups += targets.size;
|
||||
}
|
||||
queueConnect.clear();
|
||||
};
|
||||
|
||||
const processChunkGroupsForMerging = () => {
|
||||
statProcessedChunkGroupsForMerging += chunkGroupsForMerging.size;
|
||||
|
||||
// Execute the merge
|
||||
for (const info of chunkGroupsForMerging) {
|
||||
const availableModulesToBeMerged = info.availableModulesToBeMerged;
|
||||
let cachedMinAvailableModules = info.minAvailableModules;
|
||||
|
||||
statMergedAvailableModuleSets += availableModulesToBeMerged.length;
|
||||
|
||||
// 1. Get minimal available modules
|
||||
// It doesn't make sense to traverse a chunk again with more available modules.
|
||||
// This step calculates the minimal available modules and skips traversal when
|
||||
|
@ -579,10 +601,109 @@ const visitModules = (
|
|||
} else {
|
||||
if (info.minAvailableModulesOwned) {
|
||||
// We own it and can modify it
|
||||
if (cachedMinAvailableModules.plus === availableModules.plus) {
|
||||
for (const m of cachedMinAvailableModules) {
|
||||
if (!availableModules.has(m)) {
|
||||
cachedMinAvailableModules.delete(m);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const m of cachedMinAvailableModules) {
|
||||
if (!availableModules.has(m) && !availableModules.plus.has(m)) {
|
||||
cachedMinAvailableModules.delete(m);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
for (const m of cachedMinAvailableModules.plus) {
|
||||
if (!availableModules.has(m) && !availableModules.plus.has(m)) {
|
||||
// We can't remove modules from the plus part
|
||||
// so we need to merge plus into the normal part to allow modifying it
|
||||
const iterator = cachedMinAvailableModules.plus[
|
||||
Symbol.iterator
|
||||
]();
|
||||
// fast forward add all modules until m
|
||||
/** @type {IteratorResult<Module>} */
|
||||
let it;
|
||||
while (!(it = iterator.next()).done) {
|
||||
const module = it.value;
|
||||
if (module === m) break;
|
||||
cachedMinAvailableModules.add(module);
|
||||
}
|
||||
// check the remaining modules before adding
|
||||
while (!(it = iterator.next()).done) {
|
||||
const module = it.value;
|
||||
if (
|
||||
availableModules.has(module) ||
|
||||
availableModules.plus.has(m)
|
||||
) {
|
||||
cachedMinAvailableModules.add(module);
|
||||
}
|
||||
}
|
||||
cachedMinAvailableModules.plus = EMPTY_SET;
|
||||
changed = true;
|
||||
continue merge;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (cachedMinAvailableModules.plus === availableModules.plus) {
|
||||
// Common and fast case when the plus part is shared
|
||||
// We only need to care about the normal part
|
||||
if (availableModules.size < cachedMinAvailableModules.size) {
|
||||
// the new availableModules is smaller so it's faster to
|
||||
// fork from the new availableModules
|
||||
statForkedAvailableModules++;
|
||||
statForkedAvailableModulesCount += availableModules.size;
|
||||
statForkedMergedModulesCount += cachedMinAvailableModules.size;
|
||||
// construct a new Set as intersection of cachedMinAvailableModules and availableModules
|
||||
const newSet = /** @type {ModuleSetPlus} */ (new Set());
|
||||
newSet.plus = availableModules.plus;
|
||||
for (const m of availableModules) {
|
||||
if (cachedMinAvailableModules.has(m)) {
|
||||
newSet.add(m);
|
||||
}
|
||||
}
|
||||
statForkedResultModulesCount += newSet.size;
|
||||
cachedMinAvailableModules = newSet;
|
||||
info.minAvailableModulesOwned = true;
|
||||
info.minAvailableModules = newSet;
|
||||
changed = true;
|
||||
continue merge;
|
||||
}
|
||||
for (const m of cachedMinAvailableModules) {
|
||||
if (!availableModules.has(m) && !availableModules.plus.has(m)) {
|
||||
cachedMinAvailableModules.delete(m);
|
||||
if (!availableModules.has(m)) {
|
||||
// cachedMinAvailableModules need to be modified
|
||||
// but we don't own it
|
||||
statForkedAvailableModules++;
|
||||
statForkedAvailableModulesCount +=
|
||||
cachedMinAvailableModules.size;
|
||||
statForkedMergedModulesCount += availableModules.size;
|
||||
// construct a new Set as intersection of cachedMinAvailableModules and availableModules
|
||||
// as the plus part is equal we can just take over this one
|
||||
const newSet = /** @type {ModuleSetPlus} */ (new Set());
|
||||
newSet.plus = availableModules.plus;
|
||||
const iterator = cachedMinAvailableModules[Symbol.iterator]();
|
||||
// fast forward add all modules until m
|
||||
/** @type {IteratorResult<Module>} */
|
||||
let it;
|
||||
while (!(it = iterator.next()).done) {
|
||||
const module = it.value;
|
||||
if (module === m) break;
|
||||
newSet.add(module);
|
||||
}
|
||||
// check the remaining modules before adding
|
||||
while (!(it = iterator.next()).done) {
|
||||
const module = it.value;
|
||||
if (availableModules.has(module)) {
|
||||
newSet.add(module);
|
||||
}
|
||||
}
|
||||
statForkedResultModulesCount += newSet.size;
|
||||
cachedMinAvailableModules = newSet;
|
||||
info.minAvailableModulesOwned = true;
|
||||
info.minAvailableModules = newSet;
|
||||
changed = true;
|
||||
continue merge;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -590,6 +711,13 @@ const visitModules = (
|
|||
if (!availableModules.has(m) && !availableModules.plus.has(m)) {
|
||||
// cachedMinAvailableModules need to be modified
|
||||
// but we don't own it
|
||||
statForkedAvailableModules++;
|
||||
statForkedAvailableModulesCount +=
|
||||
cachedMinAvailableModules.size;
|
||||
statForkedAvailableModulesCountPlus +=
|
||||
cachedMinAvailableModules.plus.size;
|
||||
statForkedMergedModulesCount += availableModules.size;
|
||||
statForkedMergedModulesCountPlus += availableModules.plus.size;
|
||||
// construct a new Set as intersection of cachedMinAvailableModules and availableModules
|
||||
const newSet = /** @type {ModuleSetPlus} */ (new Set());
|
||||
newSet.plus = EMPTY_SET;
|
||||
|
@ -621,6 +749,7 @@ const visitModules = (
|
|||
newSet.add(module);
|
||||
}
|
||||
}
|
||||
statForkedResultModulesCount += newSet.size;
|
||||
cachedMinAvailableModules = newSet;
|
||||
info.minAvailableModulesOwned = true;
|
||||
info.minAvailableModules = newSet;
|
||||
|
@ -632,6 +761,13 @@ const visitModules = (
|
|||
if (!availableModules.has(m) && !availableModules.plus.has(m)) {
|
||||
// cachedMinAvailableModules need to be modified
|
||||
// but we don't own it
|
||||
statForkedAvailableModules++;
|
||||
statForkedAvailableModulesCount +=
|
||||
cachedMinAvailableModules.size;
|
||||
statForkedAvailableModulesCountPlus +=
|
||||
cachedMinAvailableModules.plus.size;
|
||||
statForkedMergedModulesCount += availableModules.size;
|
||||
statForkedMergedModulesCountPlus += availableModules.plus.size;
|
||||
// construct a new Set as intersection of cachedMinAvailableModules and availableModules
|
||||
// we already know that all modules directly from cachedMinAvailableModules are in availableModules too
|
||||
const newSet = /** @type {ModuleSetPlus} */ (new Set(
|
||||
|
@ -659,6 +795,7 @@ const visitModules = (
|
|||
newSet.add(module);
|
||||
}
|
||||
}
|
||||
statForkedResultModulesCount += newSet.size;
|
||||
cachedMinAvailableModules = newSet;
|
||||
info.minAvailableModulesOwned = true;
|
||||
info.minAvailableModules = newSet;
|
||||
|
@ -675,6 +812,7 @@ const visitModules = (
|
|||
outdatedChunkGroupInfo.add(info);
|
||||
}
|
||||
}
|
||||
chunkGroupsForMerging.clear();
|
||||
};
|
||||
|
||||
const processChunkGroupsForCombining = () => {
|
||||
|
@ -709,6 +847,7 @@ const visitModules = (
|
|||
};
|
||||
|
||||
const processOutdatedChunkGroupInfo = () => {
|
||||
statChunkGroupInfoUpdated += outdatedChunkGroupInfo.size;
|
||||
// Revisit skipped elements
|
||||
for (const info of outdatedChunkGroupInfo) {
|
||||
// 1. Reconsider skipped items
|
||||
|
@ -734,6 +873,7 @@ const visitModules = (
|
|||
|
||||
// 2. Reconsider children chunk groups
|
||||
if (info.children !== undefined) {
|
||||
statChildChunkGroupsReconnected += info.children.size;
|
||||
for (const cgi of info.children) {
|
||||
let connectList = queueConnect.get(info);
|
||||
if (connectList === undefined) {
|
||||
|
@ -794,6 +934,17 @@ const visitModules = (
|
|||
queueDelayed = tempQueue;
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(
|
||||
`${statProcessedQueueItems} queue items processed (${statProcessedBlocks} blocks)`
|
||||
);
|
||||
logger.log(`${statConnectedChunkGroups} chunk groups connected`);
|
||||
logger.log(
|
||||
`${statProcessedChunkGroupsForMerging} chunk groups processed for merging (${statMergedAvailableModuleSets} module sets, ${statForkedAvailableModules} forked, ${statForkedAvailableModulesCount} + ${statForkedAvailableModulesCountPlus} modules forked, ${statForkedMergedModulesCount} + ${statForkedMergedModulesCountPlus} modules merged into fork, ${statForkedResultModulesCount} resulting modules)`
|
||||
);
|
||||
logger.log(
|
||||
`${statChunkGroupInfoUpdated} chunk group info updated (${statChildChunkGroupsReconnected} already connected chunk groups reconnected)`
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"use strict";
|
||||
|
||||
const Cache = require("../Cache");
|
||||
const ProgressPlugin = require("../ProgressPlugin");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
|
@ -87,11 +88,19 @@ class IdleFileCachePlugin {
|
|||
idleTimer = undefined;
|
||||
}
|
||||
isIdle = false;
|
||||
const promises = Array.from(pendingIdleTasks.values()).map(fn => fn());
|
||||
const reportProgress = ProgressPlugin.getReporter(compiler);
|
||||
const jobs = Array.from(pendingIdleTasks.values());
|
||||
if (reportProgress) reportProgress(0, "process pending cache items");
|
||||
const promises = jobs.map(fn => fn());
|
||||
pendingIdleTasks.clear();
|
||||
promises.push(currentIdlePromise);
|
||||
let promise = Promise.all(promises);
|
||||
const promise = Promise.all(promises);
|
||||
currentIdlePromise = promise.then(() => strategy.afterAllStored());
|
||||
if (reportProgress) {
|
||||
currentIdlePromise = currentIdlePromise.then(() => {
|
||||
reportProgress(1, `stored`);
|
||||
});
|
||||
}
|
||||
return currentIdlePromise;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
"use strict";
|
||||
|
||||
const FileSystemInfo = require("../FileSystemInfo");
|
||||
const ProgressPlugin = require("../ProgressPlugin");
|
||||
const LazySet = require("../util/LazySet");
|
||||
const makeSerializable = require("../util/makeSerializable");
|
||||
const memorize = require("../util/memorize");
|
||||
const { createFileSerializer } = require("../util/serialization");
|
||||
|
||||
/** @typedef {import("../Cache").Etag} Etag */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../logging/Logger").Logger} Logger */
|
||||
/** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */
|
||||
|
||||
|
@ -588,6 +590,7 @@ class PackContent {
|
|||
class PackFileCacheStrategy {
|
||||
/**
|
||||
* @param {Object} options options
|
||||
* @param {Compiler} options.compiler the compiler
|
||||
* @param {IntermediateFileSystem} options.fs the filesystem
|
||||
* @param {string} options.context the context directory
|
||||
* @param {string} options.cacheLocation the location of the cache data
|
||||
|
@ -597,6 +600,7 @@ class PackFileCacheStrategy {
|
|||
* @param {Iterable<string>} options.immutablePaths immutable paths
|
||||
*/
|
||||
constructor({
|
||||
compiler,
|
||||
fs,
|
||||
context,
|
||||
cacheLocation,
|
||||
|
@ -611,6 +615,7 @@ class PackFileCacheStrategy {
|
|||
immutablePaths,
|
||||
logger: logger.getChildLogger("webpack.FileSystemInfo")
|
||||
});
|
||||
this.compiler = compiler;
|
||||
this.context = context;
|
||||
this.cacheLocation = cacheLocation;
|
||||
this.version = version;
|
||||
|
@ -822,6 +827,7 @@ class PackFileCacheStrategy {
|
|||
}
|
||||
|
||||
afterAllStored() {
|
||||
const reportProgress = ProgressPlugin.getReporter(this.compiler);
|
||||
return this.packPromise
|
||||
.then(pack => {
|
||||
if (!pack.invalid) return;
|
||||
|
@ -836,6 +842,7 @@ class PackFileCacheStrategy {
|
|||
}
|
||||
this.newBuildDependencies.clear();
|
||||
if (newBuildDependencies.size > 0 || !this.buildSnapshot) {
|
||||
if (reportProgress) reportProgress(0.5, "resolve build dependencies");
|
||||
this.logger.debug(
|
||||
`Capturing build dependencies... (${Array.from(
|
||||
newBuildDependencies
|
||||
|
@ -865,6 +872,11 @@ class PackFileCacheStrategy {
|
|||
} else {
|
||||
this.resolveResults = resolveResults;
|
||||
}
|
||||
if (reportProgress)
|
||||
reportProgress(
|
||||
0.6,
|
||||
"snapshot build dependencies (timestamps)"
|
||||
);
|
||||
this.fileSystemInfo.createSnapshot(
|
||||
undefined,
|
||||
resolveDependencies.files,
|
||||
|
@ -890,6 +902,11 @@ class PackFileCacheStrategy {
|
|||
} else {
|
||||
this.resolveBuildDependenciesSnapshot = snapshot;
|
||||
}
|
||||
if (reportProgress)
|
||||
reportProgress(
|
||||
0.7,
|
||||
"snapshot build dependencies (hashes)"
|
||||
);
|
||||
this.fileSystemInfo.createSnapshot(
|
||||
undefined,
|
||||
files,
|
||||
|
@ -927,6 +944,7 @@ class PackFileCacheStrategy {
|
|||
promise = Promise.resolve();
|
||||
}
|
||||
return promise.then(() => {
|
||||
if (reportProgress) reportProgress(0.8, "serialize pack");
|
||||
this.logger.time(`store pack`);
|
||||
const content = new PackContainer(
|
||||
pack,
|
||||
|
|
|
@ -103,7 +103,7 @@ class ResolverCachePlugin {
|
|||
compilation.hooks.finishModules.tap("ResolverCachePlugin", () => {
|
||||
if (realResolves + cachedResolves > 0) {
|
||||
const logger = compilation.getLogger("webpack.ResolverCachePlugin");
|
||||
logger.debug(
|
||||
logger.log(
|
||||
`${Math.round(
|
||||
(100 * realResolves) / (realResolves + cachedResolves)
|
||||
)}% really resolved (${realResolves} real resolves with ${cacheInvalidResolves} cached but invalid, ${cachedResolves} cached valid, ${concurrentResolves} concurrent)`
|
||||
|
|
|
@ -223,8 +223,6 @@ const applyWebpackOptionsDefaults = options => {
|
|||
const applyExperimentsDefaults = experiments => {
|
||||
D(experiments, "asset", false);
|
||||
D(experiments, "mjs", false);
|
||||
D(experiments, "importAwait", false);
|
||||
D(experiments, "importAsync", false);
|
||||
D(experiments, "topLevelAwait", false);
|
||||
D(experiments, "syncWebAssembly", false);
|
||||
D(experiments, "asyncWebAssembly", false);
|
||||
|
@ -544,7 +542,7 @@ const applyOutputDefaults = (
|
|||
}
|
||||
return "[id].js";
|
||||
});
|
||||
D(output, "assetModuleFilename", "[hash][ext]");
|
||||
D(output, "assetModuleFilename", "[hash][ext][query]");
|
||||
D(output, "webassemblyModuleFilename", "[hash].module.wasm");
|
||||
D(output, "publicPath", "");
|
||||
D(output, "compareBeforeEmit", true);
|
||||
|
|
|
@ -21,7 +21,6 @@ class ContainerEntryDependency extends Dependency {
|
|||
this.name = name;
|
||||
this.exposes = exposes;
|
||||
this.shareScope = shareScope;
|
||||
this.optional = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,7 @@ const NullDependency = require("./NullDependency");
|
|||
class ConstDependency extends NullDependency {
|
||||
/**
|
||||
* @param {string} expression the expression
|
||||
* @param {TODO} range the source range
|
||||
* @param {number|[number, number]} range the source range
|
||||
* @param {string[]=} runtimeRequirements runtime requirements
|
||||
*/
|
||||
constructor(expression, range, runtimeRequirements) {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
const { parseResource } = require("../util/identifier");
|
||||
|
||||
/** @typedef {import("estree").Node} EsTreeNode */
|
||||
/** @typedef {import("../../declarations/WebpackOptions").ModuleOptions} ModuleOptions */
|
||||
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
|
||||
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
|
||||
/** @typedef {import("./ContextDependency")} ContextDependency */
|
||||
|
@ -34,8 +36,7 @@ const splitContextFromPrefix = prefix => {
|
|||
};
|
||||
};
|
||||
|
||||
// TODO Use Omit<> type for contextOptions when typescript >= 3.5
|
||||
/** @typedef {Partial<Pick<ContextDependencyOptions, Exclude<keyof ContextDependencyOptions, "resource"|"recursive"|"regExp">>>} PartialContextDependencyOptions */
|
||||
/** @typedef {Partial<Omit<ContextDependencyOptions, "resource"|"recursive"|"regExp">>} PartialContextDependencyOptions */
|
||||
|
||||
/** @typedef {{ new(options: ContextDependencyOptions, range: [number, number], valueRange: [number, number]): ContextDependency }} ContextDependencyConstructor */
|
||||
|
||||
|
@ -43,8 +44,8 @@ const splitContextFromPrefix = prefix => {
|
|||
* @param {ContextDependencyConstructor} Dep the Dependency class
|
||||
* @param {[number, number]} range source range
|
||||
* @param {BasicEvaluatedExpression} param context param
|
||||
* @param {TODO} expr the AST expression
|
||||
* @param {TODO} options options for context creation
|
||||
* @param {EsTreeNode} expr expr
|
||||
* @param {ModuleOptions} options options for context creation
|
||||
* @param {PartialContextDependencyOptions} contextOptions options for the ContextModule
|
||||
* @param {JavascriptParser} parser the parser
|
||||
* @returns {ContextDependency} the created Dependency
|
||||
|
@ -209,7 +210,7 @@ exports.create = (Dep, range, param, expr, options, contextOptions, parser) => {
|
|||
{
|
||||
request: options.exprContextRequest,
|
||||
recursive: options.exprContextRecursive,
|
||||
regExp: options.exprContextRegExp,
|
||||
regExp: /** @type {RegExp} */ (options.exprContextRegExp),
|
||||
mode: "sync",
|
||||
...contextOptions
|
||||
},
|
||||
|
|
|
@ -28,14 +28,6 @@ module.exports = class HarmonyDetectionParserPlugin {
|
|||
statement.type === "ExportAllDeclaration"
|
||||
);
|
||||
if (isHarmony) {
|
||||
const isAsync = ast.body.some(
|
||||
statement =>
|
||||
(statement.type === "ImportDeclaration" ||
|
||||
statement.type === "ExportDefaultDeclaration" ||
|
||||
statement.type === "ExportNamedDeclaration" ||
|
||||
statement.type === "ExportAllDeclaration") &&
|
||||
statement.await
|
||||
);
|
||||
const module = parser.state.module;
|
||||
const compatDep = new HarmonyCompatibilityDependency();
|
||||
compatDep.loc = {
|
||||
|
@ -53,7 +45,6 @@ module.exports = class HarmonyDetectionParserPlugin {
|
|||
DynamicExports.bailout(parser.state);
|
||||
HarmonyExports.enable(parser.state, isStrictHarmony);
|
||||
parser.scope.isStrict = true;
|
||||
module.buildMeta.async = isAsync;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ module.exports = class HarmonyExportDependencyParserPlugin {
|
|||
constructor(options) {
|
||||
const { module: moduleOptions } = options;
|
||||
this.strictExportPresence = moduleOptions.strictExportPresence;
|
||||
this.importAwait = options.importAwait;
|
||||
}
|
||||
|
||||
apply(parser) {
|
||||
|
@ -50,15 +49,9 @@ module.exports = class HarmonyExportDependencyParserPlugin {
|
|||
source,
|
||||
parser.state.lastHarmonyImportOrder
|
||||
);
|
||||
sideEffectDep.await = statement.await;
|
||||
sideEffectDep.loc = Object.create(statement.loc);
|
||||
sideEffectDep.loc.index = -1;
|
||||
parser.state.current.addDependency(sideEffectDep);
|
||||
if (statement.await && !this.importAwait) {
|
||||
throw new Error(
|
||||
"Used 'export await' but import-await experiment is not enabled (set experiments.importAwait: true to enable it)"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -134,7 +127,6 @@ module.exports = class HarmonyExportDependencyParserPlugin {
|
|||
null,
|
||||
this.strictExportPresence
|
||||
);
|
||||
dep.await = settings.await;
|
||||
} else {
|
||||
dep = new HarmonyExportSpecifierDependency(id, name);
|
||||
}
|
||||
|
@ -168,7 +160,6 @@ module.exports = class HarmonyExportDependencyParserPlugin {
|
|||
if (harmonyStarExports) {
|
||||
harmonyStarExports.push(dep);
|
||||
}
|
||||
dep.await = statement.await;
|
||||
dep.loc = Object.create(statement.loc);
|
||||
dep.loc.index = idx;
|
||||
parser.state.current.addDependency(dep);
|
||||
|
|
|
@ -37,6 +37,7 @@ class HarmonyExportExpressionDependency extends NullDependency {
|
|||
getExports(moduleGraph) {
|
||||
return {
|
||||
exports: ["default"],
|
||||
terminalBinding: true,
|
||||
dependencies: undefined
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const Dependency = require("../Dependency");
|
||||
const { UsageState } = require("../ExportsInfo");
|
||||
const HarmonyLinkingError = require("../HarmonyLinkingError");
|
||||
const InitFragment = require("../InitFragment");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
|
@ -138,7 +139,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
* @param {string[]} ids the requested export name of the imported module
|
||||
* @param {string | null} name the export name of for this module
|
||||
* @param {Set<string>} activeExports other named exports in the module
|
||||
* @param {Iterable<Dependency>} otherStarExports other star exports in the module
|
||||
* @param {Iterable<HarmonyExportImportedSpecifierDependency>} otherStarExports other star exports in the module
|
||||
* @param {boolean} strictExportPresence when true, missing exports in the imported module lead to errors instead of warnings
|
||||
*/
|
||||
constructor(
|
||||
|
@ -366,7 +367,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
const ignoredExports = new Set([
|
||||
"default",
|
||||
...this.activeExports,
|
||||
...this._discoverActiveExportsFromOtherStarExports(moduleGraph)
|
||||
...this._discoverActiveExportsFromOtherStarExports(moduleGraph).keys()
|
||||
]);
|
||||
|
||||
if (!noExtraExports && !noExtraImports) {
|
||||
|
@ -487,25 +488,22 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @returns {Set<string>} exported names
|
||||
* @returns {Map<string, HarmonyExportImportedSpecifierDependency>} exported names and their origin dependency
|
||||
*/
|
||||
_discoverActiveExportsFromOtherStarExports(moduleGraph) {
|
||||
if (!this.otherStarExports) {
|
||||
return new Set();
|
||||
return new Map();
|
||||
}
|
||||
|
||||
const result = new Set();
|
||||
const result = new Map();
|
||||
// try to learn impossible exports from other star exports with provided exports
|
||||
for (const otherStarExport of this.otherStarExports) {
|
||||
const otherImportedModule = moduleGraph.getModule(otherStarExport);
|
||||
if (otherImportedModule) {
|
||||
const providedExports = moduleGraph.getProvidedExports(
|
||||
otherImportedModule
|
||||
);
|
||||
|
||||
if (Array.isArray(providedExports)) {
|
||||
for (const exportName of providedExports) {
|
||||
result.add(exportName);
|
||||
const exportsInfo = moduleGraph.getExportsInfo(otherImportedModule);
|
||||
for (const exportInfo of exportsInfo.exports) {
|
||||
if (exportInfo.provided === true && !result.has(exportInfo.name)) {
|
||||
result.set(exportInfo.name, otherStarExport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -525,13 +523,16 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
switch (mode.type) {
|
||||
case "missing":
|
||||
return undefined;
|
||||
case "dynamic-reexport":
|
||||
case "dynamic-reexport": {
|
||||
const from = moduleGraph.getModule(this);
|
||||
return {
|
||||
exports: true,
|
||||
from,
|
||||
canMangle: false,
|
||||
excludeExports: mode.ignored,
|
||||
dependencies: [moduleGraph.getModule(this)]
|
||||
dependencies: [from]
|
||||
};
|
||||
}
|
||||
case "empty-star":
|
||||
return {
|
||||
exports: [],
|
||||
|
@ -548,7 +549,19 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
dependencies: [from]
|
||||
};
|
||||
}
|
||||
case "reexport-dynamic-default":
|
||||
case "reexport-dynamic-default": {
|
||||
const from = moduleGraph.getModule(this);
|
||||
return {
|
||||
exports: [
|
||||
{
|
||||
name: mode.name,
|
||||
from,
|
||||
export: ["default"]
|
||||
}
|
||||
],
|
||||
dependencies: [from]
|
||||
};
|
||||
}
|
||||
case "reexport-undefined":
|
||||
return {
|
||||
exports: [mode.name],
|
||||
|
@ -638,11 +651,68 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
|
|||
*/
|
||||
_getErrors(moduleGraph) {
|
||||
const ids = this.getIds(moduleGraph);
|
||||
return this.getLinkingErrors(
|
||||
let errors = this.getLinkingErrors(
|
||||
moduleGraph,
|
||||
ids,
|
||||
`(reexported as '${this.name}')`
|
||||
);
|
||||
if (ids.length === 0 && this.name === null) {
|
||||
const potentialConflicts = this._discoverActiveExportsFromOtherStarExports(
|
||||
moduleGraph
|
||||
);
|
||||
if (potentialConflicts.size > 0) {
|
||||
const importedModule = moduleGraph.getModule(this);
|
||||
if (importedModule) {
|
||||
const exportsInfo = moduleGraph.getExportsInfo(importedModule);
|
||||
const conflicts = new Map();
|
||||
for (const exportInfo of exportsInfo.orderedExports) {
|
||||
if (exportInfo.provided !== true) continue;
|
||||
if (exportInfo.name === "default") continue;
|
||||
if (this.activeExports.has(exportInfo.name)) continue;
|
||||
const conflictingDependency = potentialConflicts.get(
|
||||
exportInfo.name
|
||||
);
|
||||
if (!conflictingDependency) continue;
|
||||
const target = exportInfo.getTerminalBinding(moduleGraph);
|
||||
if (!target) continue;
|
||||
const conflictingModule = moduleGraph.getModule(
|
||||
conflictingDependency
|
||||
);
|
||||
if (conflictingModule === importedModule) continue;
|
||||
const conflictingExportInfo = moduleGraph.getExportInfo(
|
||||
conflictingModule,
|
||||
exportInfo.name
|
||||
);
|
||||
const conflictingTarget = conflictingExportInfo.getTerminalBinding(
|
||||
moduleGraph
|
||||
);
|
||||
if (!conflictingTarget) continue;
|
||||
if (target === conflictingTarget) continue;
|
||||
const list = conflicts.get(conflictingDependency.request);
|
||||
if (list === undefined) {
|
||||
conflicts.set(conflictingDependency.request, [exportInfo.name]);
|
||||
} else {
|
||||
list.push(exportInfo.name);
|
||||
}
|
||||
}
|
||||
for (const [request, exports] of conflicts) {
|
||||
if (!errors) errors = [];
|
||||
errors.push(
|
||||
new HarmonyLinkingError(
|
||||
`The requested module '${
|
||||
this.request
|
||||
}' contains conflicting star exports for the ${
|
||||
exports.length > 1 ? "names" : "name"
|
||||
} ${exports
|
||||
.map(e => `'${e}'`)
|
||||
.join(", ")} with the previous requested module '${request}'`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,7 @@ class HarmonyExportSpecifierDependency extends NullDependency {
|
|||
getExports(moduleGraph) {
|
||||
return {
|
||||
exports: [this.name],
|
||||
terminalBinding: true,
|
||||
dependencies: undefined
|
||||
};
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ class HarmonyImportDependency extends ModuleDependency {
|
|||
constructor(request, sourceOrder) {
|
||||
super(request);
|
||||
this.sourceOrder = sourceOrder;
|
||||
this.await = false;
|
||||
}
|
||||
|
||||
get category() {
|
||||
|
@ -212,20 +211,17 @@ class HarmonyImportDependency extends ModuleDependency {
|
|||
if (chunkGraph.moduleGraph.isAsync(importedModule)) hash.update("async");
|
||||
}
|
||||
hash.update(`${this.sourceOrder}`);
|
||||
if (this.await) hash.update("await");
|
||||
}
|
||||
|
||||
serialize(context) {
|
||||
const { write } = context;
|
||||
write(this.sourceOrder);
|
||||
write(this.await);
|
||||
super.serialize(context);
|
||||
}
|
||||
|
||||
deserialize(context) {
|
||||
const { read } = context;
|
||||
this.sourceOrder = read();
|
||||
this.await = read();
|
||||
super.deserialize(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
const { module: moduleOptions } = options;
|
||||
this.strictExportPresence = moduleOptions.strictExportPresence;
|
||||
this.strictThisContextOnImports = moduleOptions.strictThisContextOnImports;
|
||||
this.importAwait = options.importAwait;
|
||||
}
|
||||
|
||||
apply(parser) {
|
||||
|
@ -51,13 +50,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
parser.state.lastHarmonyImportOrder
|
||||
);
|
||||
sideEffectDep.loc = statement.loc;
|
||||
sideEffectDep.await = statement.await;
|
||||
parser.state.module.addDependency(sideEffectDep);
|
||||
if (statement.await && !this.importAwait) {
|
||||
throw new Error(
|
||||
"Used 'import await' but import-await experiment is not enabled (set experiments.importAwait: true to enable it)"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -69,8 +62,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
name,
|
||||
source,
|
||||
ids,
|
||||
sourceOrder: parser.state.lastHarmonyImportOrder,
|
||||
await: statement.await
|
||||
sourceOrder: parser.state.lastHarmonyImportOrder
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -90,7 +82,6 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
dep.shorthand = parser.scope.inShorthand;
|
||||
dep.directImport = true;
|
||||
dep.asiSafe = !parser.isAsiPosition(expr.range[0]);
|
||||
dep.await = settings.await;
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
|
||||
|
@ -109,7 +100,6 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
expr.range,
|
||||
this.strictExportPresence
|
||||
);
|
||||
dep.await = settings.await;
|
||||
dep.asiSafe = !parser.isAsiPosition(expr.range[0]);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
|
@ -132,7 +122,6 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
this.strictExportPresence
|
||||
);
|
||||
dep.directImport = members.length === 0;
|
||||
dep.await = settings.await;
|
||||
dep.call = true;
|
||||
dep.asiSafe = !parser.isAsiPosition(expr.range[0]);
|
||||
// only in case when we strictly follow the spec we need a special case here
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = class RequireContextDependencyParserPlugin {
|
|||
expr.range
|
||||
);
|
||||
dep.loc = expr.loc;
|
||||
dep.optional = parser.scope.inTry;
|
||||
dep.optional = !!parser.scope.inTry;
|
||||
parser.state.current.addDependency(dep);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -405,6 +405,7 @@ class BasicEvaluatedExpression {
|
|||
setTruthy() {
|
||||
this.falsy = false;
|
||||
this.truthy = true;
|
||||
this.nullish = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ const { tryRunOrWebpackError } = require("../HookWebpackError");
|
|||
const HotUpdateChunk = require("../HotUpdateChunk");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const StringXor = require("../util/StringXor");
|
||||
const { compareModulesByIdentifier } = require("../util/comparators");
|
||||
const createHash = require("../util/createHash");
|
||||
const JavascriptGenerator = require("./JavascriptGenerator");
|
||||
|
@ -328,25 +329,27 @@ class JavascriptModulesPlugin {
|
|||
moduleGraph,
|
||||
runtimeTemplate
|
||||
});
|
||||
const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
||||
const modules = chunkGraph.getChunkModulesIterableBySourceType(
|
||||
chunk,
|
||||
"javascript",
|
||||
compareModulesByIdentifier
|
||||
"javascript"
|
||||
);
|
||||
if (modules) {
|
||||
const xor = new StringXor();
|
||||
for (const m of modules) {
|
||||
hash.update(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
}
|
||||
xor.updateHash(hash);
|
||||
}
|
||||
const runtimeModules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
||||
const runtimeModules = chunkGraph.getChunkModulesIterableBySourceType(
|
||||
chunk,
|
||||
"runtime",
|
||||
compareModulesByIdentifier
|
||||
"runtime"
|
||||
);
|
||||
if (runtimeModules) {
|
||||
const xor = new StringXor();
|
||||
for (const m of runtimeModules) {
|
||||
hash.update(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
xor.add(chunkGraph.getModuleHash(m, chunk.runtime));
|
||||
}
|
||||
xor.updateHash(hash);
|
||||
}
|
||||
if (hotUpdateChunk) {
|
||||
hash.update(JSON.stringify(hotUpdateChunk.removedModules));
|
||||
|
|
|
@ -29,6 +29,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|||
/** @typedef {import("estree").LabeledStatement} LabeledStatementNode */
|
||||
/** @typedef {import("estree").Literal} LiteralNode */
|
||||
/** @typedef {import("estree").LogicalExpression} LogicalExpressionNode */
|
||||
/** @typedef {import("estree").ChainExpression} ChainExpressionNode */
|
||||
/** @typedef {import("estree").MemberExpression} MemberExpressionNode */
|
||||
/** @typedef {import("estree").MetaProperty} MetaPropertyNode */
|
||||
/** @typedef {import("estree").MethodDefinition} MethodDefinitionNode */
|
||||
|
@ -52,7 +53,7 @@ const EMPTY_ARRAY = [];
|
|||
|
||||
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
||||
|
||||
const parser = AcornParser.extend(require("../parsing/importAwaitAcornPlugin"));
|
||||
const parser = AcornParser;
|
||||
|
||||
class VariableInfo {
|
||||
/**
|
||||
|
@ -135,7 +136,7 @@ const EMPTY_COMMENT_OPTIONS = {
|
|||
|
||||
class JavascriptParser extends Parser {
|
||||
/**
|
||||
* @param {TODO} options options
|
||||
* @param {{[k: string]: any}} options options
|
||||
* @param {"module" | "script" | "auto"} sourceType default source type
|
||||
*/
|
||||
constructor(options, sourceType = "auto") {
|
||||
|
@ -260,6 +261,8 @@ class JavascriptParser extends Parser {
|
|||
"members"
|
||||
])
|
||||
),
|
||||
/** @type {SyncBailHook<[ChainExpressionNode], boolean | void>} */
|
||||
optionalChaining: new SyncBailHook(["optionalChaining"]),
|
||||
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
|
||||
new: new HookMap(() => new SyncBailHook(["expression"])),
|
||||
/** @type {SyncBailHook<[MetaPropertyNode], boolean | void>} */
|
||||
|
@ -755,6 +758,15 @@ class JavascriptParser extends Parser {
|
|||
if (res !== undefined) return res;
|
||||
break;
|
||||
}
|
||||
case "ChainExpression": {
|
||||
const res = this.callHooksForExpression(
|
||||
this.hooks.evaluateTypeof,
|
||||
expr.argument.expression,
|
||||
expr
|
||||
);
|
||||
if (res !== undefined) return res;
|
||||
break;
|
||||
}
|
||||
case "FunctionExpression": {
|
||||
return new BasicEvaluatedExpression()
|
||||
.setString("function")
|
||||
|
@ -1223,6 +1235,48 @@ class JavascriptParser extends Parser {
|
|||
.setItems(items)
|
||||
.setRange(expr.range);
|
||||
});
|
||||
this.hooks.evaluate
|
||||
.for("ChainExpression")
|
||||
.tap("JavascriptParser", _expr => {
|
||||
const expr = /** @type {ChainExpressionNode} */ (_expr);
|
||||
/** @type {ExpressionNode[]} */
|
||||
const optionalExpressionsStack = [];
|
||||
/** @type {ExpressionNode|SuperNode} */
|
||||
let next = expr.expression;
|
||||
|
||||
while (
|
||||
next.type === "MemberExpression" ||
|
||||
next.type === "CallExpression"
|
||||
) {
|
||||
if (next.type === "MemberExpression") {
|
||||
if (next.optional) {
|
||||
// SuperNode can not be optional
|
||||
optionalExpressionsStack.push(
|
||||
/** @type {ExpressionNode} */ (next.object)
|
||||
);
|
||||
}
|
||||
next = next.object;
|
||||
} else {
|
||||
if (next.optional) {
|
||||
// SuperNode can not be optional
|
||||
optionalExpressionsStack.push(
|
||||
/** @type {ExpressionNode} */ (next.callee)
|
||||
);
|
||||
}
|
||||
next = next.callee;
|
||||
}
|
||||
}
|
||||
|
||||
while (optionalExpressionsStack.length > 0) {
|
||||
const expression = optionalExpressionsStack.pop();
|
||||
const evaluated = this.evaluateExpression(expression);
|
||||
|
||||
if (evaluated && evaluated.asNullish()) {
|
||||
return evaluated.setRange(_expr.range);
|
||||
}
|
||||
}
|
||||
return this.evaluateExpression(expr.expression);
|
||||
});
|
||||
}
|
||||
|
||||
getRenameIdentifier(expr) {
|
||||
|
@ -1922,14 +1976,36 @@ class JavascriptParser extends Parser {
|
|||
}
|
||||
|
||||
walkSwitchCases(switchCases) {
|
||||
for (let index = 0, len = switchCases.length; index < len; index++) {
|
||||
const switchCase = switchCases[index];
|
||||
this.inBlockScope(() => {
|
||||
const len = switchCases.length;
|
||||
|
||||
if (switchCase.test) {
|
||||
this.walkExpression(switchCase.test);
|
||||
// we need to pre walk all statements first since we can have invalid code
|
||||
// import A from "module";
|
||||
// switch(1) {
|
||||
// case 1:
|
||||
// console.log(A); // should fail at runtime
|
||||
// case 2:
|
||||
// const A = 1;
|
||||
// }
|
||||
for (let index = 0; index < len; index++) {
|
||||
const switchCase = switchCases[index];
|
||||
|
||||
if (switchCase.consequent.length > 0) {
|
||||
this.blockPreWalkStatements(switchCase.consequent);
|
||||
}
|
||||
}
|
||||
this.walkStatements(switchCase.consequent);
|
||||
}
|
||||
|
||||
for (let index = 0; index < len; index++) {
|
||||
const switchCase = switchCases[index];
|
||||
|
||||
if (switchCase.test) {
|
||||
this.walkExpression(switchCase.test);
|
||||
}
|
||||
if (switchCase.consequent.length > 0) {
|
||||
this.walkStatements(switchCase.consequent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
preWalkCatchClause(catchClause) {
|
||||
|
@ -2024,6 +2100,9 @@ class JavascriptParser extends Parser {
|
|||
case "CallExpression":
|
||||
this.walkCallExpression(expression);
|
||||
break;
|
||||
case "ChainExpression":
|
||||
this.walkChainExpression(expression);
|
||||
break;
|
||||
case "ClassExpression":
|
||||
this.walkClassExpression(expression);
|
||||
break;
|
||||
|
@ -2182,6 +2261,14 @@ class JavascriptParser extends Parser {
|
|||
expression
|
||||
);
|
||||
if (result === true) return;
|
||||
if (expression.argument.type === "ChainExpression") {
|
||||
const result = this.callHooksForExpression(
|
||||
this.hooks.typeof,
|
||||
expression.argument.expression,
|
||||
expression
|
||||
);
|
||||
if (result === true) return;
|
||||
}
|
||||
}
|
||||
this.walkExpression(expression.argument);
|
||||
}
|
||||
|
@ -2326,6 +2413,21 @@ class JavascriptParser extends Parser {
|
|||
this.walkClass(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChainExpressionNode} expression expression
|
||||
*/
|
||||
walkChainExpression(expression) {
|
||||
const result = this.hooks.optionalChaining.call(expression);
|
||||
|
||||
if (result === undefined) {
|
||||
if (expression.expression.type === "CallExpression") {
|
||||
this.walkCallExpression(expression.expression);
|
||||
} else {
|
||||
this.walkMemberExpression(expression.expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_walkIIFE(functionExpression, options, currentThis) {
|
||||
const getVarInfo = argOrThis => {
|
||||
const renameIdentifier = this.getRenameIdentifier(argOrThis);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
const Watchpack = require("watchpack");
|
||||
|
||||
/** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
|
||||
/** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
|
||||
/** @typedef {import("../util/fs").WatchFileSystem} WatchFileSystem */
|
||||
/** @typedef {import("../util/fs").WatchMethod} WatchMethod */
|
||||
|
@ -26,7 +27,7 @@ class NodeWatchFileSystem {
|
|||
* @param {Iterable<string>} directories watched directories
|
||||
* @param {Iterable<string>} missing watched exitance entries
|
||||
* @param {number} startTime timestamp of start time
|
||||
* @param {TODO} options options object
|
||||
* @param {WatchOptions} options options object
|
||||
* @param {function(Error=, Map<string, FileSystemInfoEntry>, Map<string, FileSystemInfoEntry>, Set<string>, Set<string>): void} callback aggregated callback
|
||||
* @param {function(string, number): void} callbackUndelayed callback when the first change was detected
|
||||
* @returns {Watcher} a watcher
|
||||
|
|
|
@ -24,6 +24,7 @@ const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency
|
|||
const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency");
|
||||
const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
|
||||
const JavascriptParser = require("../javascript/JavascriptParser");
|
||||
const { equals } = require("../util/ArrayHelpers");
|
||||
const LazySet = require("../util/LazySet");
|
||||
const { concatComparators, keepOriginalOrder } = require("../util/comparators");
|
||||
const createHash = require("../util/createHash");
|
||||
|
@ -31,6 +32,7 @@ const contextify = require("../util/identifier").contextify;
|
|||
const makeSerializable = require("../util/makeSerializable");
|
||||
const propertyAccess = require("../util/propertyAccess");
|
||||
|
||||
/** @typedef {import("eslint-scope").Scope} Scope */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
|
@ -77,8 +79,8 @@ const propertyAccess = require("../util/propertyAccess");
|
|||
* @property {Source} internalSource
|
||||
* @property {ReplaceSource} source
|
||||
* @property {Iterable<string>} runtimeRequirements
|
||||
* @property {TODO} globalScope
|
||||
* @property {TODO} moduleScope
|
||||
* @property {Scope} globalScope
|
||||
* @property {Scope} moduleScope
|
||||
* @property {Map<string, string>} internalNames
|
||||
* @property {Map<string, string>} exportMap
|
||||
* @property {Map<string, ReexportInfo>} reexportMap
|
||||
|
@ -168,14 +170,6 @@ const joinIterableWithComma = iterable => {
|
|||
return str;
|
||||
};
|
||||
|
||||
const arrayEquals = (a, b) => {
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConcatenationEntry
|
||||
* @property {"concatenated" | "external"} type
|
||||
|
@ -314,7 +308,7 @@ const getExternalImport = (
|
|||
exportName.length === 0 ||
|
||||
moduleGraph.getExportsInfo(importedModule).getUsedName(exportName, runtime);
|
||||
if (!used) return "/* unused export */undefined";
|
||||
const comment = arrayEquals(used, exportName)
|
||||
const comment = equals(used, exportName)
|
||||
? ""
|
||||
: Template.toNormalComment(`${exportName.join(".")}`);
|
||||
const reference = `${exprStart}${comment}${propertyAccess(used)}`;
|
||||
|
@ -1060,11 +1054,17 @@ class ConcatenatedModule extends Module {
|
|||
// renaming to work correctly
|
||||
for (const childScope of info.moduleScope.childScopes) {
|
||||
if (childScope.type !== "class") continue;
|
||||
if (!childScope.block.superClass) continue;
|
||||
superClassExpressions.push({
|
||||
range: childScope.block.superClass.range,
|
||||
variables: childScope.variables
|
||||
});
|
||||
const block = childScope.block;
|
||||
if (
|
||||
(block.type === "ClassDeclaration" ||
|
||||
block.type === "ClassExpression") &&
|
||||
block.superClass
|
||||
) {
|
||||
superClassExpressions.push({
|
||||
range: block.superClass.range,
|
||||
variables: childScope.variables
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,80 +48,6 @@ const globToRegexp = (glob, cache) => {
|
|||
return regexp;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ReexportInfo} info info object
|
||||
* @param {string} exportName name of export
|
||||
* @returns {ExportInModule | undefined} static export
|
||||
*/
|
||||
const getMappingFromInfo = (info, exportName) => {
|
||||
const staticMappings = info.static.get(exportName);
|
||||
if (staticMappings !== undefined) {
|
||||
if (staticMappings.length === 1) return staticMappings[0];
|
||||
return undefined;
|
||||
}
|
||||
const dynamicMappings = Array.from(info.dynamic).filter(
|
||||
([_, ignored]) => !ignored.has(exportName)
|
||||
);
|
||||
if (dynamicMappings.length === 1) {
|
||||
return {
|
||||
module: dynamicMappings[0][0],
|
||||
exportName,
|
||||
checked: true
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ReexportInfo} info info object
|
||||
* @param {string} exportName name of export of source module
|
||||
* @param {Module} module the target module
|
||||
* @param {string} innerExportName name of export of target module
|
||||
* @param {boolean} checked true, if existence of target module is checked
|
||||
*/
|
||||
const addStaticReexport = (
|
||||
info,
|
||||
exportName,
|
||||
module,
|
||||
innerExportName,
|
||||
checked
|
||||
) => {
|
||||
let mappings = info.static.get(exportName);
|
||||
if (mappings !== undefined) {
|
||||
for (const mapping of mappings) {
|
||||
if (mapping.module === module && mapping.exportName === innerExportName) {
|
||||
mapping.checked = mapping.checked && checked;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mappings = [];
|
||||
info.static.set(exportName, mappings);
|
||||
}
|
||||
mappings.push({
|
||||
module,
|
||||
exportName: innerExportName,
|
||||
checked
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ReexportInfo} info info object
|
||||
* @param {Module} module the reexport module
|
||||
* @param {Set<string>} ignored ignore list
|
||||
* @returns {void}
|
||||
*/
|
||||
const addDynamicReexport = (info, module, ignored) => {
|
||||
const existingList = info.dynamic.get(module);
|
||||
if (existingList !== undefined) {
|
||||
for (const key of existingList) {
|
||||
if (!ignored.has(key)) existingList.delete(key);
|
||||
}
|
||||
} else {
|
||||
info.dynamic.set(module, new Set(ignored));
|
||||
}
|
||||
};
|
||||
|
||||
class SideEffectsFlagPlugin {
|
||||
/**
|
||||
* Apply the plugin
|
||||
|
@ -182,178 +108,51 @@ class SideEffectsFlagPlugin {
|
|||
modules => {
|
||||
const logger = compilation.getLogger("webpack.SideEffectsFlagPlugin");
|
||||
|
||||
/** @type {Map<Module, ReexportInfo>} */
|
||||
const reexportMaps = new Map();
|
||||
|
||||
// Capture reexports of sideEffectFree modules
|
||||
logger.time("capture reexports from modules");
|
||||
logger.time("update dependencies");
|
||||
for (const module of modules) {
|
||||
if (
|
||||
module.factoryMeta !== undefined &&
|
||||
module.factoryMeta.sideEffectFree
|
||||
) {
|
||||
for (const dep of module.dependencies) {
|
||||
if (dep instanceof HarmonyExportImportedSpecifierDependency) {
|
||||
const mode = dep.getMode(moduleGraph, undefined);
|
||||
if (
|
||||
mode.type === "normal-reexport" ||
|
||||
mode.type === "dynamic-reexport" ||
|
||||
mode.type === "reexport-dynamic-default" ||
|
||||
mode.type === "reexport-named-default"
|
||||
) {
|
||||
let info = reexportMaps.get(module);
|
||||
if (!info) {
|
||||
reexportMaps.set(
|
||||
module,
|
||||
(info = {
|
||||
static: new Map(),
|
||||
dynamic: new Map()
|
||||
})
|
||||
);
|
||||
}
|
||||
const targetModule = moduleGraph.getModule(dep);
|
||||
switch (mode.type) {
|
||||
case "normal-reexport":
|
||||
for (const { name, ids, checked } of mode.items) {
|
||||
// TODO Support reexporting namespace object
|
||||
if (ids.length > 0) {
|
||||
addStaticReexport(
|
||||
info,
|
||||
name,
|
||||
targetModule,
|
||||
ids[0],
|
||||
checked
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "dynamic-reexport":
|
||||
addDynamicReexport(info, targetModule, mode.ignored);
|
||||
break;
|
||||
case "reexport-dynamic-default":
|
||||
case "reexport-named-default":
|
||||
addStaticReexport(
|
||||
info,
|
||||
mode.name,
|
||||
targetModule,
|
||||
"default",
|
||||
false
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.timeEnd("capture reexports from modules");
|
||||
const exportsInfo = moduleGraph.getExportsInfo(module);
|
||||
for (const connection of moduleGraph.getIncomingConnections(
|
||||
module
|
||||
)) {
|
||||
const dep = connection.dependency;
|
||||
if (
|
||||
dep instanceof HarmonyExportImportedSpecifierDependency ||
|
||||
(dep instanceof HarmonyImportSpecifierDependency &&
|
||||
!dep.namespaceObjectAsContext)
|
||||
) {
|
||||
// TODO improve for nested imports
|
||||
const ids = dep.getIds(moduleGraph);
|
||||
if (ids.length > 0) {
|
||||
const exportInfo = exportsInfo.getExportInfo(ids[0]);
|
||||
const target = exportInfo.getTarget(
|
||||
moduleGraph,
|
||||
({ module }) =>
|
||||
module.factoryMeta !== undefined &&
|
||||
module.factoryMeta.sideEffectFree
|
||||
);
|
||||
if (!target) continue;
|
||||
|
||||
// Flatten reexports
|
||||
logger.time("flatten dynamic reexports");
|
||||
for (const info of reexportMaps.values()) {
|
||||
const dynamicReexports = info.dynamic;
|
||||
info.dynamic = new Map();
|
||||
for (const reexport of dynamicReexports) {
|
||||
let [targetModule, ignored] = reexport;
|
||||
for (;;) {
|
||||
const innerInfo = reexportMaps.get(targetModule);
|
||||
if (!innerInfo) break;
|
||||
|
||||
for (const [key, reexports] of innerInfo.static) {
|
||||
if (ignored.has(key)) continue;
|
||||
for (const { module, exportName, checked } of reexports) {
|
||||
addStaticReexport(info, key, module, exportName, checked);
|
||||
}
|
||||
}
|
||||
|
||||
// Follow dynamic reexport if there is only one
|
||||
if (innerInfo.dynamic.size !== 1) {
|
||||
// When there are more then one, we don't know which one
|
||||
break;
|
||||
}
|
||||
|
||||
ignored = new Set(ignored);
|
||||
for (const [innerModule, innerIgnored] of innerInfo.dynamic) {
|
||||
for (const key of innerIgnored) {
|
||||
if (ignored.has(key)) continue;
|
||||
// This reexports ends here
|
||||
addStaticReexport(info, key, targetModule, key, true);
|
||||
ignored.add(key);
|
||||
}
|
||||
targetModule = innerModule;
|
||||
}
|
||||
}
|
||||
|
||||
// Update reexport as all other cases has been handled
|
||||
addDynamicReexport(info, targetModule, ignored);
|
||||
}
|
||||
}
|
||||
logger.timeEnd("flatten dynamic reexports");
|
||||
|
||||
logger.time("flatten static reexports");
|
||||
for (const info of reexportMaps.values()) {
|
||||
const staticReexports = info.static;
|
||||
info.static = new Map();
|
||||
for (const [key, reexports] of staticReexports) {
|
||||
for (let mapping of reexports) {
|
||||
for (;;) {
|
||||
const innerInfo = reexportMaps.get(mapping.module);
|
||||
if (!innerInfo) break;
|
||||
|
||||
const newMapping = getMappingFromInfo(
|
||||
innerInfo,
|
||||
mapping.exportName
|
||||
);
|
||||
if (!newMapping) break;
|
||||
mapping = newMapping;
|
||||
}
|
||||
addStaticReexport(
|
||||
info,
|
||||
key,
|
||||
mapping.module,
|
||||
mapping.exportName,
|
||||
mapping.checked
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.timeEnd("flatten static reexports");
|
||||
|
||||
// Update imports along the reexports from sideEffectFree modules
|
||||
logger.time("update imports");
|
||||
for (const [module, info] of reexportMaps) {
|
||||
for (const connection of moduleGraph.getIncomingConnections(
|
||||
module
|
||||
)) {
|
||||
const dep = connection.dependency;
|
||||
if (
|
||||
dep instanceof HarmonyExportImportedSpecifierDependency ||
|
||||
(dep instanceof HarmonyImportSpecifierDependency &&
|
||||
!dep.namespaceObjectAsContext)
|
||||
) {
|
||||
// TODO improve for nested imports
|
||||
const ids = dep.getIds(moduleGraph);
|
||||
if (ids.length > 0) {
|
||||
const mapping = getMappingFromInfo(info, ids[0]);
|
||||
if (mapping) {
|
||||
moduleGraph.updateModule(dep, mapping.module);
|
||||
moduleGraph.updateModule(dep, target.module);
|
||||
moduleGraph.addExplanation(
|
||||
dep,
|
||||
"(skipped side-effect-free modules)"
|
||||
);
|
||||
dep.setIds(
|
||||
moduleGraph,
|
||||
mapping.exportName
|
||||
? [mapping.exportName, ...ids.slice(1)]
|
||||
target.export
|
||||
? [...target.export, ...ids.slice(1)]
|
||||
: ids.slice(1)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.timeEnd("update imports");
|
||||
logger.timeEnd("update dependencies");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const Chunk = require("../Chunk");
|
||||
const { STAGE_ADVANCED } = require("../OptimizationStages");
|
||||
const WebpackError = require("../WebpackError");
|
||||
const { requestToId } = require("../ids/IdHelpers");
|
||||
|
@ -155,7 +156,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {Record<string, number>} sizes
|
||||
* @property {Set<Chunk>} chunks
|
||||
* @property {Set<Chunk>} reuseableChunks
|
||||
* @property {Set<bigint>} chunksKeys
|
||||
* @property {Set<bigint | Chunk>} chunksKeys
|
||||
*/
|
||||
|
||||
const defaultGetName = /** @type {GetName} */ (() => {});
|
||||
|
@ -706,31 +707,44 @@ module.exports = class SplitChunksPlugin {
|
|||
}
|
||||
/**
|
||||
* @param {Iterable<Chunk>} chunks list of chunks
|
||||
* @returns {bigint} key of the chunks
|
||||
* @returns {bigint | Chunk} key of the chunks
|
||||
*/
|
||||
const getKey = chunks => {
|
||||
let key = ZERO;
|
||||
for (const c of chunks) {
|
||||
key = key | chunkIndexMap.get(c);
|
||||
const iterator = chunks[Symbol.iterator]();
|
||||
let result = iterator.next();
|
||||
if (result.done) return ZERO;
|
||||
const first = result.value;
|
||||
result = iterator.next();
|
||||
if (result.done) return first;
|
||||
let key =
|
||||
chunkIndexMap.get(first) | chunkIndexMap.get(result.value);
|
||||
while (!(result = iterator.next()).done) {
|
||||
key = key | chunkIndexMap.get(result.value);
|
||||
}
|
||||
return key;
|
||||
};
|
||||
const keyToString = key => {
|
||||
if (typeof key === "bigint") return key.toString(16);
|
||||
return chunkIndexMap.get(key).toString(16);
|
||||
};
|
||||
|
||||
const getChunkSetsInGraph = memorize(() => {
|
||||
/** @type {Map<bigint, Set<Chunk>>} */
|
||||
const chunkSetsInGraph = new Map();
|
||||
/** @type {Set<Chunk>} */
|
||||
const singleChunkSets = new Set();
|
||||
for (const module of compilation.modules) {
|
||||
const chunksKey = getKey(
|
||||
chunkGraph.getModuleChunksIterable(module)
|
||||
);
|
||||
if (!chunkSetsInGraph.has(chunksKey)) {
|
||||
chunkSetsInGraph.set(
|
||||
chunksKey,
|
||||
new Set(chunkGraph.getModuleChunksIterable(module))
|
||||
);
|
||||
const chunks = chunkGraph.getModuleChunksIterable(module);
|
||||
const chunksKey = getKey(chunks);
|
||||
if (typeof chunksKey === "bigint") {
|
||||
if (!chunkSetsInGraph.has(chunksKey)) {
|
||||
chunkSetsInGraph.set(chunksKey, new Set(chunks));
|
||||
}
|
||||
} else {
|
||||
singleChunkSets.add(chunksKey);
|
||||
}
|
||||
}
|
||||
return chunkSetsInGraph;
|
||||
return { chunkSetsInGraph, singleChunkSets };
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -758,17 +772,23 @@ module.exports = class SplitChunksPlugin {
|
|||
const getExportsChunkSetsInGraph = memorize(() => {
|
||||
/** @type {Map<bigint, Set<Chunk>>} */
|
||||
const chunkSetsInGraph = new Map();
|
||||
/** @type {Set<Chunk>} */
|
||||
const singleChunkSets = new Set();
|
||||
for (const module of compilation.modules) {
|
||||
const groupedChunks = Array.from(groupChunksByExports(module));
|
||||
groupedByExportsMap.set(module, groupedChunks);
|
||||
for (const chunks of groupedChunks) {
|
||||
const chunksKey = getKey(chunks);
|
||||
if (!chunkSetsInGraph.has(chunksKey)) {
|
||||
chunkSetsInGraph.set(chunksKey, new Set(chunks));
|
||||
if (chunks.length === 1) {
|
||||
singleChunkSets.add(chunks[0]);
|
||||
} else {
|
||||
const chunksKey = /** @type {bigint} */ (getKey(chunks));
|
||||
if (!chunkSetsInGraph.has(chunksKey)) {
|
||||
chunkSetsInGraph.set(chunksKey, new Set(chunks));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunkSetsInGraph;
|
||||
return { chunkSetsInGraph, singleChunkSets };
|
||||
});
|
||||
|
||||
// group these set of chunks by count
|
||||
|
@ -789,67 +809,93 @@ module.exports = class SplitChunksPlugin {
|
|||
return chunkSetsByCount;
|
||||
};
|
||||
const getChunkSetsByCount = memorize(() =>
|
||||
groupChunkSetsByCount(getChunkSetsInGraph().values())
|
||||
groupChunkSetsByCount(
|
||||
getChunkSetsInGraph().chunkSetsInGraph.values()
|
||||
)
|
||||
);
|
||||
const getExportsChunkSetsByCount = memorize(() =>
|
||||
groupChunkSetsByCount(getExportsChunkSetsInGraph().values())
|
||||
groupChunkSetsByCount(
|
||||
getExportsChunkSetsInGraph().chunkSetsInGraph.values()
|
||||
)
|
||||
);
|
||||
|
||||
// Create a list of possible combinations
|
||||
const createGetCombinations = (chunkSets, chunkSetsByCount) => {
|
||||
/** @type {Map<bigint, Set<Chunk>[]>} */
|
||||
const createGetCombinations = (
|
||||
chunkSets,
|
||||
singleChunkSets,
|
||||
chunkSetsByCount
|
||||
) => {
|
||||
/** @type {Map<bigint | Chunk, (Set<Chunk> | Chunk)[]>} */
|
||||
const combinationsCache = new Map();
|
||||
|
||||
return key => {
|
||||
const cacheEntry = combinationsCache.get(key);
|
||||
if (cacheEntry !== undefined) return cacheEntry;
|
||||
if (key instanceof Chunk) {
|
||||
const result = [key];
|
||||
combinationsCache.set(key, result);
|
||||
return result;
|
||||
}
|
||||
const chunksSet = chunkSets.get(key);
|
||||
/** @type {Set<Chunk>[]} */
|
||||
var array = [chunksSet];
|
||||
if (chunksSet.size > 1) {
|
||||
for (const [count, setArray] of chunkSetsByCount) {
|
||||
// "equal" is not needed because they would have been merge in the first step
|
||||
if (count < chunksSet.size) {
|
||||
for (const set of setArray) {
|
||||
if (isSubset(chunksSet, set)) {
|
||||
array.push(set);
|
||||
}
|
||||
/** @type {(Set<Chunk> | Chunk)[]} */
|
||||
const array = [chunksSet];
|
||||
for (const [count, setArray] of chunkSetsByCount) {
|
||||
// "equal" is not needed because they would have been merge in the first step
|
||||
if (count < chunksSet.size) {
|
||||
for (const set of setArray) {
|
||||
if (isSubset(chunksSet, set)) {
|
||||
array.push(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const chunk of singleChunkSets) {
|
||||
if (chunksSet.has(chunk)) {
|
||||
array.push(chunk);
|
||||
}
|
||||
}
|
||||
combinationsCache.set(key, array);
|
||||
return array;
|
||||
};
|
||||
};
|
||||
|
||||
const getCombinationsFactory = memorize(() =>
|
||||
createGetCombinations(getChunkSetsInGraph(), getChunkSetsByCount())
|
||||
);
|
||||
const getCombinationsFactory = memorize(() => {
|
||||
const { chunkSetsInGraph, singleChunkSets } = getChunkSetsInGraph();
|
||||
return createGetCombinations(
|
||||
chunkSetsInGraph,
|
||||
singleChunkSets,
|
||||
getChunkSetsByCount()
|
||||
);
|
||||
});
|
||||
const getCombinations = key => getCombinationsFactory()(key);
|
||||
|
||||
const getExportsCombinationsFactory = memorize(() =>
|
||||
createGetCombinations(
|
||||
getExportsChunkSetsInGraph(),
|
||||
const getExportsCombinationsFactory = memorize(() => {
|
||||
const {
|
||||
chunkSetsInGraph,
|
||||
singleChunkSets
|
||||
} = getExportsChunkSetsInGraph();
|
||||
return createGetCombinations(
|
||||
chunkSetsInGraph,
|
||||
singleChunkSets,
|
||||
getExportsChunkSetsByCount()
|
||||
)
|
||||
);
|
||||
);
|
||||
});
|
||||
const getExportsCombinations = key =>
|
||||
getExportsCombinationsFactory()(key);
|
||||
|
||||
/**
|
||||
* @typedef {Object} SelectedChunksResult
|
||||
* @property {Chunk[]} chunks the list of chunks
|
||||
* @property {bigint} key a key of the list
|
||||
* @property {bigint | Chunk} key a key of the list
|
||||
*/
|
||||
|
||||
/** @type {WeakMap<Set<Chunk>, WeakMap<ChunkFilterFunction, SelectedChunksResult>>} */
|
||||
/** @type {WeakMap<Set<Chunk> | Chunk, WeakMap<ChunkFilterFunction, SelectedChunksResult>>} */
|
||||
const selectedChunksCacheByChunksSet = new WeakMap();
|
||||
|
||||
/**
|
||||
* get list and key by applying the filter function to the list
|
||||
* It is cached for performance reasons
|
||||
* @param {Set<Chunk>} chunks list of chunks
|
||||
* @param {Set<Chunk> | Chunk} chunks list of chunks
|
||||
* @param {ChunkFilterFunction} chunkFilter filter function for chunks
|
||||
* @returns {SelectedChunksResult} list and key
|
||||
*/
|
||||
|
@ -864,8 +910,12 @@ module.exports = class SplitChunksPlugin {
|
|||
if (entry2 === undefined) {
|
||||
/** @type {Chunk[]} */
|
||||
const selectedChunks = [];
|
||||
for (const chunk of chunks) {
|
||||
if (chunkFilter(chunk)) selectedChunks.push(chunk);
|
||||
if (chunks instanceof Chunk) {
|
||||
if (chunkFilter(chunks)) selectedChunks.push(chunks);
|
||||
} else {
|
||||
for (const chunk of chunks) {
|
||||
if (chunkFilter(chunk)) selectedChunks.push(chunk);
|
||||
}
|
||||
}
|
||||
entry2 = {
|
||||
chunks: selectedChunks,
|
||||
|
@ -888,7 +938,7 @@ module.exports = class SplitChunksPlugin {
|
|||
* @param {CacheGroup} cacheGroup the current cache group
|
||||
* @param {number} cacheGroupIndex the index of the cache group of ordering
|
||||
* @param {Chunk[]} selectedChunks chunks selected for this module
|
||||
* @param {bigint} selectedChunksKey a key of selectedChunks
|
||||
* @param {bigint | Chunk} selectedChunksKey a key of selectedChunks
|
||||
* @param {Module} module the current module
|
||||
* @returns {void}
|
||||
*/
|
||||
|
@ -933,7 +983,9 @@ module.exports = class SplitChunksPlugin {
|
|||
// This automatically merges equal names
|
||||
const key =
|
||||
cacheGroup.key +
|
||||
(name ? ` name:${name}` : ` chunks:${selectedChunksKey}`);
|
||||
(name
|
||||
? ` name:${name}`
|
||||
: ` chunks:${keyToString(selectedChunksKey)}`);
|
||||
// Add module to maps
|
||||
let info = chunksInfoMap.get(key);
|
||||
if (info === undefined) {
|
||||
|
@ -994,7 +1046,7 @@ module.exports = class SplitChunksPlugin {
|
|||
const getCombsByUsedExports = memorize(() => {
|
||||
// fill the groupedByExportsMap
|
||||
getExportsChunkSetsInGraph();
|
||||
/** @type {Set<Set<Chunk>>} */
|
||||
/** @type {Set<Set<Chunk> | Chunk>} */
|
||||
const set = new Set();
|
||||
const groupedByUsedExports = groupedByExportsMap.get(module);
|
||||
for (const chunks of groupedByUsedExports) {
|
||||
|
@ -1015,7 +1067,9 @@ module.exports = class SplitChunksPlugin {
|
|||
// For all combination of chunk selection
|
||||
for (const chunkCombination of combs) {
|
||||
// Break if minimum number of chunks is not reached
|
||||
if (chunkCombination.size < cacheGroup.minChunks) continue;
|
||||
const count =
|
||||
chunkCombination instanceof Chunk ? 1 : chunkCombination.size;
|
||||
if (count < cacheGroup.minChunks) continue;
|
||||
// Select chunks by configuration
|
||||
const {
|
||||
chunks: selectedChunks,
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { tokTypes: tt } = require("acorn");
|
||||
|
||||
/** @typedef {typeof import("acorn").Parser} Parser */
|
||||
|
||||
/**
|
||||
* @param {Parser} P the acorn parser
|
||||
* @returns {Parser} new acorn parser
|
||||
*/
|
||||
module.exports = P => {
|
||||
const Base = /** @type {any} */ (P);
|
||||
const NewParser = /** @type {unknown} */ (class extends Base {
|
||||
parseImport(node) {
|
||||
this.next();
|
||||
// import await '...'
|
||||
if (this.type === tt.name && this.value === "await") {
|
||||
node.await = true;
|
||||
} else {
|
||||
node.await = false;
|
||||
this.pos = this.start;
|
||||
}
|
||||
return super.parseImport(node);
|
||||
}
|
||||
parseExport(node) {
|
||||
this.next();
|
||||
// export await '...'
|
||||
if (this.type === tt.name && this.value === "await") {
|
||||
node.await = true;
|
||||
} else {
|
||||
node.await = false;
|
||||
this.pos = this.start;
|
||||
}
|
||||
const result = super.parseExport(node);
|
||||
if (node.await && !node.source) {
|
||||
this.raiseRecoverable(
|
||||
node.start,
|
||||
"Missing from source in export await"
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return /** @type {Parser} */ (NewParser);
|
||||
};
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const ModuleDependency = require("../dependencies/ModuleDependency");
|
||||
const formatLocation = require("../formatLocation");
|
||||
const { LogType } = require("../logging/Logger");
|
||||
const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
|
||||
|
@ -810,7 +811,9 @@ const SIMPLE_EXTRACTORS = {
|
|||
},
|
||||
moduleReason: {
|
||||
_: (object, reason, { runtime }, { requestShortener }) => {
|
||||
const depAsAny = /** @type {TODO} */ (reason.dependency);
|
||||
const dep = reason.dependency;
|
||||
const moduleDep =
|
||||
dep && dep instanceof ModuleDependency ? dep : undefined;
|
||||
Object.assign(object, {
|
||||
moduleIdentifier: reason.originModule
|
||||
? reason.originModule.identifier()
|
||||
|
@ -830,8 +833,7 @@ const SIMPLE_EXTRACTORS = {
|
|||
type: reason.dependency ? reason.dependency.type : null,
|
||||
active: reason.isActive(runtime),
|
||||
explanation: reason.explanation,
|
||||
userRequest:
|
||||
depAsAny && "userRequest" in depAsAny ? depAsAny.userRequest : null
|
||||
userRequest: (moduleDep && moduleDep.userRequest) || null
|
||||
});
|
||||
if (reason.dependency) {
|
||||
const locInfo = formatLocation(reason.dependency.loc);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
exports.equals = (a, b) => {
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class StringXor {
|
||||
constructor() {
|
||||
this._value = undefined;
|
||||
this._buffer = undefined;
|
||||
}
|
||||
|
||||
add(str) {
|
||||
let buf = this._buffer;
|
||||
let value;
|
||||
if (buf === undefined) {
|
||||
buf = this._buffer = Buffer.from(str, "latin1");
|
||||
this._value = Buffer.from(buf);
|
||||
return;
|
||||
} else if (buf.length !== str.length) {
|
||||
value = this._value;
|
||||
buf = this._buffer = Buffer.from(str, "latin1");
|
||||
if (value.length < buf.length) {
|
||||
this._value = Buffer.allocUnsafe(buf.length);
|
||||
value.copy(this._value);
|
||||
this._value.fill(0, value.length);
|
||||
value = this._value;
|
||||
}
|
||||
} else {
|
||||
value = this._value;
|
||||
buf.write(str, "latin1");
|
||||
}
|
||||
const len = buf.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
value[i] = value[i] ^ buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this._value === undefined ? "" : this._value.toString("latin1");
|
||||
}
|
||||
|
||||
updateHash(hash) {
|
||||
if (this._value !== undefined) hash.update(this._value);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringXor;
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Sam Chen @chenxsan
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @param {string} urlAndGlobal the script request
|
||||
* @returns {string[]} script url and its global variable
|
||||
*/
|
||||
module.exports = function extractUrlAndGlobal(urlAndGlobal) {
|
||||
const index = urlAndGlobal.indexOf("@");
|
||||
return [urlAndGlobal.substring(index + 1), urlAndGlobal.substring(0, index)];
|
||||
};
|
|
@ -8,6 +8,7 @@
|
|||
const path = require("path");
|
||||
|
||||
/** @typedef {import("fs").Stats} NodeFsStats */
|
||||
/** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
|
||||
/** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
|
||||
|
||||
/** @typedef {function(NodeJS.ErrnoException=): void} Callback */
|
||||
|
@ -32,7 +33,7 @@ const path = require("path");
|
|||
* @param {Iterable<string>} directories watched directories
|
||||
* @param {Iterable<string>} missing watched exitance entries
|
||||
* @param {number} startTime timestamp of start time
|
||||
* @param {TODO} options options object
|
||||
* @param {WatchOptions} options options object
|
||||
* @param {function(Error=, Map<string, FileSystemInfoEntry>, Map<string, FileSystemInfoEntry>, Set<string>, Set<string>): void} callback aggregated callback
|
||||
* @param {function(string, number): void} callbackUndelayed callback when the first change was detected
|
||||
* @returns {Watcher} a watcher
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
|
||||
/** @typedef {(string|number|undefined|[])[]} SemVerRange */
|
||||
|
||||
const splitAndConvert = str => {
|
||||
return str.split(".").map(item => (`${+item}` === item ? +item : item));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} str version string
|
||||
* @returns {(string|number|undefined|[])[]} parsed version
|
||||
*/
|
||||
const parseVersion = str => {
|
||||
var splitAndConvert = function (str) {
|
||||
return str.split(".").map(function (item) {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
return +item == item ? +item : item;
|
||||
});
|
||||
};
|
||||
var match = /^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(str);
|
||||
/** @type {(string|number|undefined|[])[]} */
|
||||
var ver = match[1] ? splitAndConvert(match[1]) : [];
|
||||
|
@ -31,21 +33,6 @@ const parseVersion = str => {
|
|||
};
|
||||
exports.parseVersion = parseVersion;
|
||||
|
||||
// must be a minimized version of above
|
||||
exports.parseVersionRuntimeCode = runtimeTemplate =>
|
||||
`var parseVersion = ${runtimeTemplate.basicFunction("str", [
|
||||
`var convertNumber = ${runtimeTemplate.returningFunction(
|
||||
"+str == str ? +str : str;",
|
||||
"str"
|
||||
)};`,
|
||||
`var splitAndConvert = ${runtimeTemplate.returningFunction(
|
||||
'str.split(".").map(convertNumber);',
|
||||
"str"
|
||||
)};`,
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
"var n=/^([^-+]+)?(?:-([^+]+))?(?:\\+(.+))?$/.exec(str),p=n[1]?splitAndConvert(n[1]):[];return n[2]&&(p.length++,p.push.apply(p,splitAndConvert(n[2]))),n[3]&&(p.push([]),p.push.apply(p,splitAndConvert(n[3]))),p"
|
||||
])}`;
|
||||
|
||||
/* eslint-disable eqeqeq */
|
||||
/**
|
||||
* @param {string} a version
|
||||
|
@ -96,18 +83,14 @@ const versionLt = (a, b) => {
|
|||
/* eslint-enable eqeqeq */
|
||||
exports.versionLt = versionLt;
|
||||
|
||||
// must be a minimized version of above
|
||||
exports.versionLtRuntimeCode = runtimeTemplate =>
|
||||
`var versionLt = ${runtimeTemplate.basicFunction("a, b", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var t=a[r],e=(typeof t)[0];if(r>=b.length)return"u"==e;var n=b[r],f=(typeof n)[0];if(e!=f)return"o"==e&&"n"==f||("s"==f||"u"==e);if("o"!=e&&"u"!=e&&t!=n)return t<n;r++}'
|
||||
])}`;
|
||||
|
||||
/**
|
||||
* @param {string} str range string
|
||||
* @returns {SemVerRange} parsed range
|
||||
*/
|
||||
exports.parseRange = str => {
|
||||
const splitAndConvert = str => {
|
||||
return str.split(".").map(item => (`${+item}` === item ? +item : item));
|
||||
};
|
||||
// see https://docs.npmjs.com/misc/semver#range-grammar for grammar
|
||||
const parsePartial = str => {
|
||||
const match = /^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(str);
|
||||
|
@ -288,13 +271,6 @@ const rangeToString = range => {
|
|||
/* eslint-enable eqeqeq */
|
||||
exports.rangeToString = rangeToString;
|
||||
|
||||
// must be a minimized version of above
|
||||
exports.rangeToStringRuntimeCode = runtimeTemplate =>
|
||||
`var rangeToString = ${runtimeTemplate.basicFunction("range", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'if(1===range.length)return"*";if(0 in range){var r="",n=range[0];r+=0==n?">=":-1==n?"<":1==n?"^":2==n?"~":n>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,r+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return r}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^\\((.+)\\)$/,"$1")}'
|
||||
])}`;
|
||||
|
||||
/* eslint-disable eqeqeq */
|
||||
/**
|
||||
* @param {SemVerRange} range version range
|
||||
|
@ -443,13 +419,6 @@ const satisfy = (range, version) => {
|
|||
/* eslint-enable eqeqeq */
|
||||
exports.satisfy = satisfy;
|
||||
|
||||
// must be a minimized version of above
|
||||
exports.satisfyRuntimeCode = runtimeTemplate =>
|
||||
`var satisfy = ${runtimeTemplate.basicFunction("range, version", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,f=!0;;i++,n++){var a,s,t=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(a=version[n]))[0]))return!f||("u"==t?i>e&&!r:""==t!=r);if("u"==s){if(!f||"u"!=t)return!1}else if(f)if(t==s)if(i<=e){if(a!=range[i])return!1}else{if(r?a>range[i]:a<range[i])return!1;a!=range[i]&&(f=!1)}else if("s"!=t&&"n"!=t){if(r||i<=e)return!1;f=!1,i--}else{if(i<=e||s<t!=r)return!1;f=!1}else"s"!=t&&"n"!=t&&(f=!1,i--)}}var g=[],o=g.pop.bind(g);for(n=1;n<range.length;n++){var u=range[n];g.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o()'
|
||||
])}`;
|
||||
|
||||
exports.stringifyHoley = json => {
|
||||
switch (typeof json) {
|
||||
case "undefined":
|
||||
|
@ -470,3 +439,39 @@ exports.stringifyHoley = json => {
|
|||
return JSON.stringify(json);
|
||||
}
|
||||
};
|
||||
|
||||
//#region runtime code: parseVersion
|
||||
exports.parseVersionRuntimeCode = runtimeTemplate =>
|
||||
`var parseVersion = ${runtimeTemplate.basicFunction("str", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
`var p=${
|
||||
runtimeTemplate.supportsArrowFunction() ? "p=>" : "function(p)"
|
||||
}{return p.split(".").map((${
|
||||
runtimeTemplate.supportsArrowFunction() ? "p=>" : "function(p)"
|
||||
}{return+p==p?+p:p}))},n=/^([^-+]+)?(?:-([^+]+))?(?:\\+(.+))?$/.exec(str),r=n[1]?p(n[1]):[];return n[2]&&(r.length++,r.push.apply(r,p(n[2]))),n[3]&&(r.push([]),r.push.apply(r,p(n[3]))),r;`
|
||||
])}`;
|
||||
//#endregion
|
||||
|
||||
//#region runtime code: versionLt
|
||||
exports.versionLtRuntimeCode = runtimeTemplate =>
|
||||
`var versionLt = ${runtimeTemplate.basicFunction("a, b", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'a=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++}'
|
||||
])}`;
|
||||
//#endregion
|
||||
|
||||
//#region runtime code: rangeToString
|
||||
exports.rangeToStringRuntimeCode = runtimeTemplate =>
|
||||
`var rangeToString = ${runtimeTemplate.basicFunction("range", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'if(1===range.length)return"*";if(0 in range){var r="",n=range[0];r+=0==n?">=":-1==n?"<":1==n?"^":2==n?"~":n>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,r+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return r}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^\\((.+)\\)$/,"$1")}'
|
||||
])}`;
|
||||
//#endregion
|
||||
|
||||
//#region runtime code: satisfy
|
||||
exports.satisfyRuntimeCode = runtimeTemplate =>
|
||||
`var satisfy = ${runtimeTemplate.basicFunction("range, version", [
|
||||
"// see webpack/lib/util/semver.js for original code",
|
||||
'if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o();'
|
||||
])}`;
|
||||
//#endregion
|
||||
|
|
|
@ -40,7 +40,7 @@ const validateSchema = (schema, options) => {
|
|||
validate(schema, options, {
|
||||
name: "Webpack",
|
||||
postFormatter: (formattedError, error) => {
|
||||
const children = /** @type {TODO} */ (error).children;
|
||||
const children = error.children;
|
||||
if (
|
||||
children &&
|
||||
children.some(
|
||||
|
|
|
@ -58,7 +58,6 @@ class WasmFinalizeExportsPlugin {
|
|||
)
|
||||
) {
|
||||
// 4. error
|
||||
/** @type {TODO} */
|
||||
const error = new UnsupportedWebAssemblyFeatureError(
|
||||
`Export "${name}" with ${jsIncompatibleExports[name]} can only be used for direct wasm to wasm dependencies\n` +
|
||||
`It's used from ${connection.originModule.readableIdentifier(
|
||||
|
|
|
@ -11,10 +11,12 @@ const Generator = require("../Generator");
|
|||
const InitFragment = require("../InitFragment");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const ModuleDependency = require("../dependencies/ModuleDependency");
|
||||
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
|
||||
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
|
||||
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
||||
/** @typedef {import("../NormalModule")} NormalModule */
|
||||
|
@ -63,7 +65,8 @@ class WebAssemblyJavascriptGenerator extends Generator {
|
|||
const initParams = [];
|
||||
let index = 0;
|
||||
for (const dep of module.dependencies) {
|
||||
const depAsAny = /** @type {TODO} */ (dep);
|
||||
const moduleDep =
|
||||
dep && dep instanceof ModuleDependency ? dep : undefined;
|
||||
if (moduleGraph.getModule(dep)) {
|
||||
let importData = importedModules.get(moduleGraph.getModule(dep));
|
||||
if (importData === undefined) {
|
||||
|
@ -72,8 +75,7 @@ class WebAssemblyJavascriptGenerator extends Generator {
|
|||
(importData = {
|
||||
importVar: `m${index}`,
|
||||
index,
|
||||
request:
|
||||
"userRequest" in depAsAny ? depAsAny.userRequest : undefined,
|
||||
request: (moduleDep && moduleDep.userRequest) || undefined,
|
||||
names: new Set(),
|
||||
reexports: []
|
||||
})
|
||||
|
|
|
@ -41,7 +41,7 @@ exports.getEntryInfo = (chunkGraph, chunk, chunkFilter) => {
|
|||
).map(([module, chunkGroup]) => {
|
||||
const arr = [chunkGraph.getModuleId(module)];
|
||||
for (const c of getAllChunks(chunkGroup)) {
|
||||
if (!chunkFilter(c)) continue;
|
||||
if (!chunkFilter(c) && !c.hasRuntime()) continue;
|
||||
const id = c.id;
|
||||
if (id === chunk.id) continue;
|
||||
arr.push(id);
|
||||
|
|
113
package.json
113
package.json
|
@ -1,31 +1,33 @@
|
|||
{
|
||||
"name": "webpack",
|
||||
"version": "5.0.0-beta.23",
|
||||
"version": "5.0.0-beta.26",
|
||||
"author": "Tobias Koppers @sokra",
|
||||
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.0",
|
||||
"@types/estree": "^0.0.45",
|
||||
"@webassemblyjs/ast": "1.9.0",
|
||||
"@webassemblyjs/helper-module-context": "1.9.0",
|
||||
"@webassemblyjs/wasm-edit": "1.9.0",
|
||||
"@webassemblyjs/wasm-parser": "1.9.0",
|
||||
"acorn": "^7.3.0",
|
||||
"acorn": "^7.4.0",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"core-js": "^3.6.5",
|
||||
"enhanced-resolve": "5.0.0-beta.10",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"events": "^3.0.0",
|
||||
"eslint-scope": "^5.1.0",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.15",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^4.0.0",
|
||||
"mime-types": "^2.1.26",
|
||||
"neo-async": "^2.6.1",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"pkg-dir": "^4.2.0",
|
||||
"schema-utils": "^2.5.0",
|
||||
"tapable": "^2.0.0-beta.10",
|
||||
"schema-utils": "^2.7.0",
|
||||
"tapable": "^2.0.0-beta.11",
|
||||
"terser-webpack-plugin": "^3.0.2",
|
||||
"watchpack": "2.0.0-beta.13",
|
||||
"watchpack": "2.0.0-beta.14",
|
||||
"webpack-sources": "2.0.0-beta.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
|
@ -34,69 +36,70 @@
|
|||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.2",
|
||||
"@babel/preset-react": "^7.10.1",
|
||||
"@types/jest": "^25.1.5",
|
||||
"@types/node": "^12.6.9",
|
||||
"babel-loader": "^8.0.6",
|
||||
"benchmark": "^2.1.1",
|
||||
"bundle-loader": "~0.5.0",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@types/jest": "^25.2.3",
|
||||
"@types/node": "^13.13.15",
|
||||
"babel-loader": "^8.1.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"bundle-loader": "^0.5.6",
|
||||
"coffee-loader": "^1.0.0",
|
||||
"coffeescript": "^2.3.2",
|
||||
"coveralls": "^3.0.2",
|
||||
"cspell": "^4.0.55",
|
||||
"css-loader": "^3.2.0",
|
||||
"date-fns": "^2.12.0",
|
||||
"es6-promise-polyfill": "^1.1.1",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-plugin-jest": "^23.8.1",
|
||||
"coffeescript": "^2.5.1",
|
||||
"coveralls": "^3.1.0",
|
||||
"cspell": "^4.0.63",
|
||||
"css-loader": "^3.6.0",
|
||||
"date-fns": "^2.15.0",
|
||||
"es6-promise-polyfill": "^1.2.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-jest": "^23.20.0",
|
||||
"eslint-plugin-jsdoc": "^22.0.0",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"file-loader": "^6.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "^1.5.0",
|
||||
"husky": "^4.2.3",
|
||||
"husky": "^4.2.5",
|
||||
"is-ci": "^2.0.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"jest": "^25.1.0",
|
||||
"jest-diff": "^25.1.0",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jest-junit": "^11.1.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"json5": "^2.1.1",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^6.1.0",
|
||||
"lint-staged": "^10.0.8",
|
||||
"json5": "^2.1.3",
|
||||
"less": "^3.12.2",
|
||||
"less-loader": "^6.2.0",
|
||||
"lint-staged": "^10.2.11",
|
||||
"loader-utils": "^2.0.0",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash": "^4.17.19",
|
||||
"lodash-es": "^4.17.15",
|
||||
"memfs": "^3.1.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"mini-svg-data-uri": "^1.1.3",
|
||||
"open-cli": "^5.0.0",
|
||||
"prettier": "2",
|
||||
"pretty-format": "^25.1.0",
|
||||
"pug": "^2.0.4",
|
||||
"memfs": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.10.0",
|
||||
"mini-svg-data-uri": "^1.2.3",
|
||||
"open-cli": "^6.0.1",
|
||||
"prettier": "^2.0.5",
|
||||
"pretty-format": "^26.3.0",
|
||||
"pug": "^3.0.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"raw-loader": "^4.0.1",
|
||||
"react": "^16.8.0",
|
||||
"react-dom": "^16.8.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"script-loader": "~0.7.0",
|
||||
"simple-git": "^1.65.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"script-loader": "^0.7.2",
|
||||
"simple-git": "^2.17.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"style-loader": "^1.1.4",
|
||||
"terser": "^4.8.0",
|
||||
"toml": "^3.0.0",
|
||||
"tooling": "webpack/tooling#v1.8.0",
|
||||
"ts-loader": "^6.0.4",
|
||||
"typescript": "^3.9.2",
|
||||
"ts-loader": "^8.0.2",
|
||||
"typescript": "^3.9.7",
|
||||
"url-loader": "^4.1.0",
|
||||
"wast-loader": "^1.5.5",
|
||||
"wast-loader": "^1.9.0",
|
||||
"webassembly-feature": "1.3.0",
|
||||
"worker-loader": "^2.0.0",
|
||||
"xxhashjs": "^0.2.1",
|
||||
"worker-loader": "^3.0.1",
|
||||
"xxhashjs": "^0.2.2",
|
||||
"yamljs": "^0.3.0",
|
||||
"yarn-deduplicate": "^2.0.0"
|
||||
"yarn-deduplicate": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
|
@ -144,8 +147,8 @@
|
|||
"type-lint": "tsc",
|
||||
"typings-lint": "tsc -p tsconfig.test.json",
|
||||
"spellcheck": "cspell \"{.github,benchmark,bin,examples,hot,lib,schemas,setup,tooling}/**/*.{md,yml,yaml,js,json}\" \"*.md\"",
|
||||
"special-lint": "node node_modules/tooling/lockfile-lint && node node_modules/tooling/schemas-lint && node node_modules/tooling/inherit-types && node node_modules/tooling/format-schemas && node node_modules/tooling/format-file-header && node node_modules/tooling/compile-to-definitions && node node_modules/tooling/generate-types",
|
||||
"special-lint-fix": "node node_modules/tooling/inherit-types --write && node node_modules/tooling/format-schemas --write && node node_modules/tooling/format-file-header --write && node node_modules/tooling/compile-to-definitions --write && node node_modules/tooling/generate-types --write",
|
||||
"special-lint": "node node_modules/tooling/lockfile-lint && node node_modules/tooling/schemas-lint && node node_modules/tooling/inherit-types && node node_modules/tooling/format-schemas && node tooling/generate-runtime-code.js && node node_modules/tooling/format-file-header && node node_modules/tooling/compile-to-definitions && node node_modules/tooling/generate-types",
|
||||
"special-lint-fix": "node node_modules/tooling/inherit-types --write && node node_modules/tooling/format-schemas --write && node tooling/generate-runtime-code.js --write && node node_modules/tooling/format-file-header --write && node node_modules/tooling/compile-to-definitions --write && node node_modules/tooling/generate-types --write",
|
||||
"fix": "yarn code-lint --fix && yarn special-lint-fix && yarn pretty-lint-fix",
|
||||
"pretty-lint-base": "prettier \"*.{ts,json,yml,yaml,md}\" \"{setup,lib,bin,hot,benchmark,tooling,schemas}/**/*.json\" \"examples/*.md\"",
|
||||
"pretty-lint-base-all": "yarn pretty-lint-base \"*.js\" \"{setup,lib,bin,hot,benchmark,tooling,schemas}/**/*.js\" \"test/*.js\" \"test/helpers/*.js\" \"test/{configCases,watchCases,statsCases,hotCases,benchmarkCases}/**/webpack.config.js\" \"examples/**/webpack.config.js\"",
|
||||
|
|
|
@ -373,14 +373,6 @@
|
|||
"description": "Support WebAssembly as asynchronous EcmaScript Module.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"importAsync": {
|
||||
"description": "Allow 'import/export' syntax to import async modules.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"importAwait": {
|
||||
"description": "Allow 'import/export await' syntax to import async modules.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"mjs": {
|
||||
"description": "Support .mjs files as way to define strict ESM file (node.js).",
|
||||
"type": "boolean"
|
||||
|
|
|
@ -91,8 +91,6 @@ describe("Defaults", () => {
|
|||
"experiments": Object {
|
||||
"asset": false,
|
||||
"asyncWebAssembly": false,
|
||||
"importAsync": false,
|
||||
"importAwait": false,
|
||||
"mjs": false,
|
||||
"outputModule": false,
|
||||
"syncWebAssembly": false,
|
||||
|
@ -208,7 +206,7 @@ describe("Defaults", () => {
|
|||
"usedExports": false,
|
||||
},
|
||||
"output": Object {
|
||||
"assetModuleFilename": "[hash][ext]",
|
||||
"assetModuleFilename": "[hash][ext][query]",
|
||||
"baseURI": undefined,
|
||||
"chunkCallbackName": "webpackChunkwebpack",
|
||||
"chunkFilename": "[name].js",
|
||||
|
@ -716,9 +714,8 @@ describe("Defaults", () => {
|
|||
|
||||
@@ ... @@
|
||||
- "asyncWebAssembly": false,
|
||||
+ "asyncWebAssembly": true,
|
||||
@@ ... @@
|
||||
- "mjs": false,
|
||||
+ "asyncWebAssembly": true,
|
||||
+ "mjs": true,
|
||||
@@ ... @@
|
||||
+ },
|
||||
|
|
|
@ -2,60 +2,66 @@
|
|||
|
||||
const {
|
||||
parseVersion,
|
||||
parseVersionRuntimeCode,
|
||||
versionLt,
|
||||
versionLtRuntimeCode,
|
||||
parseRange,
|
||||
rangeToString,
|
||||
satisfy
|
||||
rangeToStringRuntimeCode,
|
||||
satisfy,
|
||||
satisfyRuntimeCode
|
||||
} = require("../lib/util/semver");
|
||||
|
||||
describe("SemVer", () => {
|
||||
it("should parseVersion correctly", () => {
|
||||
expect(parseVersion("1")).toEqual([1]);
|
||||
expect(parseVersion("1.2.3")).toEqual([1, 2, 3]);
|
||||
expect(parseVersion("1.2.3.4.999")).toEqual([1, 2, 3, 4, 999]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(parseVersion("1.2.3-beta")).toEqual([1, 2, 3, , "beta"]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(parseVersion("1.2.3-beta.1.2")).toEqual([1, 2, 3, , "beta", 1, 2]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(parseVersion("1.2.3-alpha.beta-42")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
,
|
||||
"alpha",
|
||||
"beta-42"
|
||||
]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(parseVersion("1.2.3-beta.1.alpha.0+5343")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
,
|
||||
"beta",
|
||||
1,
|
||||
"alpha",
|
||||
0,
|
||||
[],
|
||||
5343
|
||||
]);
|
||||
expect(parseVersion("1.2.3+5343.beta+1")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
[],
|
||||
5343,
|
||||
"beta+1"
|
||||
]);
|
||||
expect(parseVersion("1.2.3+5343.beta+1")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
[],
|
||||
5343,
|
||||
"beta+1"
|
||||
]);
|
||||
});
|
||||
const createRuntimeFunction = runtimeCodeFunction => {
|
||||
const runtimeFunction = runtimeCodeFunction({
|
||||
basicFunction: (args, body) => `(${args}) => {\n${body.join("\n")}\n}`,
|
||||
supportsArrowFunction: () => true
|
||||
});
|
||||
const functionName = runtimeFunction.match(/^var (\w+)/)[1];
|
||||
return eval(
|
||||
`(function (...args) { ${runtimeFunction}; return ${functionName}(...args); })`
|
||||
);
|
||||
};
|
||||
|
||||
for (const [name, fn] of [
|
||||
["normal", parseVersion],
|
||||
["runtime", createRuntimeFunction(parseVersionRuntimeCode)]
|
||||
]) {
|
||||
it(`should parseVersion correctly (${name})`, () => {
|
||||
expect(fn("1")).toEqual([1]);
|
||||
expect(fn("1.2.3")).toEqual([1, 2, 3]);
|
||||
expect(fn("1.2.3.4.999")).toEqual([1, 2, 3, 4, 999]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(fn("1.2.3-beta")).toEqual([1, 2, 3, , "beta"]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(fn("1.2.3-beta.1.2")).toEqual([1, 2, 3, , "beta", 1, 2]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(fn("1.2.3-alpha.beta-42")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
,
|
||||
"alpha",
|
||||
"beta-42"
|
||||
]);
|
||||
// eslint-disable-next-line no-sparse-arrays
|
||||
expect(fn("1.2.3-beta.1.alpha.0+5343")).toEqual([
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
,
|
||||
"beta",
|
||||
1,
|
||||
"alpha",
|
||||
0,
|
||||
[],
|
||||
5343
|
||||
]);
|
||||
expect(fn("1.2.3+5343.beta+1")).toEqual([1, 2, 3, [], 5343, "beta+1"]);
|
||||
expect(fn("1.2.3+5343.beta+1")).toEqual([1, 2, 3, [], 5343, "beta+1"]);
|
||||
});
|
||||
}
|
||||
|
||||
describe("versionLt", () => {
|
||||
const cases = [
|
||||
|
@ -103,15 +109,21 @@ describe("SemVer", () => {
|
|||
"2.alpha < 2.beta.1"
|
||||
];
|
||||
for (const c of cases) {
|
||||
it(c, () => {
|
||||
const parts = c.split(" < ");
|
||||
const a = parts[0];
|
||||
const b = parts[1];
|
||||
expect(versionLt(a, a)).toBe(false);
|
||||
expect(versionLt(b, b)).toBe(false);
|
||||
expect(versionLt(a, b)).toBe(true);
|
||||
expect(versionLt(b, a)).toBe(false);
|
||||
});
|
||||
const parts = c.split(" < ");
|
||||
const a = parts[0];
|
||||
const b = parts[1];
|
||||
|
||||
for (const [name, fn] of [
|
||||
["normal", versionLt],
|
||||
["runtime", createRuntimeFunction(versionLtRuntimeCode)]
|
||||
]) {
|
||||
it(`${c} (${name})`, () => {
|
||||
expect(fn(a, a)).toBe(false);
|
||||
expect(fn(b, b)).toBe(false);
|
||||
expect(fn(a, b)).toBe(true);
|
||||
expect(fn(b, a)).toBe(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -163,11 +175,18 @@ describe("SemVer", () => {
|
|||
"1.2.3 - 3.2.1 || >3 <=4 || 1":
|
||||
">=1.2.3 (<3.2.1 || =3.2.1) || >=3 not(^3) (<4 || ^4) || ^1"
|
||||
};
|
||||
|
||||
for (const key of Object.keys(cases)) {
|
||||
const expected = cases[key];
|
||||
it(`should ${key} stringify to ${expected}`, () => {
|
||||
expect(rangeToString(parseRange(key))).toEqual(expected);
|
||||
});
|
||||
|
||||
for (const [name, fn] of [
|
||||
["normal", rangeToString],
|
||||
["runtime", createRuntimeFunction(rangeToStringRuntimeCode)]
|
||||
]) {
|
||||
it(`should ${key} stringify to ${expected} (${name})`, () => {
|
||||
expect(fn(parseRange(key))).toEqual(expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -500,20 +519,28 @@ describe("SemVer", () => {
|
|||
"1.0.0+55"
|
||||
]
|
||||
};
|
||||
for (const name of Object.keys(cases)) {
|
||||
describe(name, () => {
|
||||
it(`should be able to parse ${name}`, () => {
|
||||
parseRange(name);
|
||||
|
||||
for (const range of Object.keys(cases)) {
|
||||
describe(range, () => {
|
||||
it(`should be able to parse ${range}`, () => {
|
||||
parseRange(range);
|
||||
});
|
||||
for (const item of cases[name]) {
|
||||
if (item.startsWith("!")) {
|
||||
it(`should not be satisfied by ${item.slice(1)}`, () => {
|
||||
expect(satisfy(parseRange(name), item.slice(1))).toBe(false);
|
||||
});
|
||||
} else {
|
||||
it(`should be satisfied by ${item}`, () => {
|
||||
expect(satisfy(parseRange(name), item)).toBe(true);
|
||||
});
|
||||
for (const item of cases[range]) {
|
||||
for (const [name, fn] of [
|
||||
["normal", satisfy],
|
||||
["runtime", createRuntimeFunction(satisfyRuntimeCode)]
|
||||
]) {
|
||||
if (item.startsWith("!")) {
|
||||
it(`should not be satisfied by ${item.slice(
|
||||
1
|
||||
)} (${name})`, () => {
|
||||
expect(fn(parseRange(range), item.slice(1))).toBe(false);
|
||||
});
|
||||
} else {
|
||||
it(`should be satisfied by ${item} (${name})`, () => {
|
||||
expect(fn(parseRange(range), item)).toBe(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -188,6 +188,7 @@ describe("Stats", () => {
|
|||
"emitted": true,
|
||||
"filteredRelated": undefined,
|
||||
"info": Object {
|
||||
"minimized": true,
|
||||
"size": 111,
|
||||
},
|
||||
"name": "chunkB.js",
|
||||
|
@ -205,6 +206,7 @@ describe("Stats", () => {
|
|||
"emitted": true,
|
||||
"filteredRelated": undefined,
|
||||
"info": Object {
|
||||
"minimized": true,
|
||||
"size": 182,
|
||||
},
|
||||
"name": "entryA.js",
|
||||
|
@ -222,6 +224,7 @@ describe("Stats", () => {
|
|||
"emitted": true,
|
||||
"filteredRelated": undefined,
|
||||
"info": Object {
|
||||
"minimized": true,
|
||||
"size": 2219,
|
||||
},
|
||||
"name": "entryB.js",
|
||||
|
|
|
@ -179,9 +179,7 @@ const describeCases = config => {
|
|||
experiments: {
|
||||
mjs: true,
|
||||
asyncWebAssembly: true,
|
||||
topLevelAwait: true,
|
||||
importAwait: true,
|
||||
importAsync: true
|
||||
topLevelAwait: true
|
||||
}
|
||||
};
|
||||
beforeAll(done => {
|
||||
|
|
|
@ -11,10 +11,6 @@ describe("TestCases", () => {
|
|||
moduleIds: "named",
|
||||
chunkIds: "named"
|
||||
},
|
||||
plugins: [new webpack.HotModuleReplacementPlugin()],
|
||||
deprecations: [
|
||||
// TODO update terser-webpack-plugin to use getCache()
|
||||
expect.objectContaining({ code: "DEP_WEBPACK_COMPILATION_CACHE" })
|
||||
]
|
||||
plugins: [new webpack.HotModuleReplacementPlugin()]
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,10 +7,6 @@ describe("TestCases", () => {
|
|||
minimize: true,
|
||||
optimization: {
|
||||
moduleIds: "hashed"
|
||||
},
|
||||
deprecations: [
|
||||
// TODO update terser-webpack-plugin to use getCache()
|
||||
expect.objectContaining({ code: "DEP_WEBPACK_COMPILATION_CACHE" })
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,10 +5,6 @@ describe("TestCases", () => {
|
|||
name: "minimized-source-map",
|
||||
mode: "production",
|
||||
devtool: "eval-cheap-module-source-map",
|
||||
minimize: true,
|
||||
deprecations: [
|
||||
// TODO update terser-webpack-plugin to use getCache()
|
||||
expect.objectContaining({ code: "DEP_WEBPACK_COMPILATION_CACHE" })
|
||||
]
|
||||
minimize: true
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,9 +4,6 @@ describe("TestCases", () => {
|
|||
describeCases({
|
||||
name: "production",
|
||||
mode: "production",
|
||||
deprecations: [
|
||||
// TODO update terser-webpack-plugin to use getCache()
|
||||
expect.objectContaining({ code: "DEP_WEBPACK_COMPILATION_CACHE" })
|
||||
]
|
||||
minimize: true
|
||||
});
|
||||
});
|
||||
|
|
|
@ -354,32 +354,6 @@ Object {
|
|||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"experiments-import-async": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Allow 'import/export' syntax to import async modules.",
|
||||
"multiple": false,
|
||||
"path": "experiments.importAsync",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Allow 'import/export' syntax to import async modules.",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"experiments-import-await": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Allow 'import/export await' syntax to import async modules.",
|
||||
"multiple": false,
|
||||
"path": "experiments.importAwait",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Allow 'import/export await' syntax to import async modules.",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"experiments-mjs": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +0,0 @@
|
|||
it("should allow to use import await", () => {
|
||||
return import("./reexport").then(({ default: value, other }) => {
|
||||
expect(value).toBe(42);
|
||||
expect(other).toBe(42);
|
||||
});
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
export default 42;
|
|
@ -1,4 +0,0 @@
|
|||
export await { default } from "./module";
|
||||
import await value from "./module";
|
||||
|
||||
export const other = value;
|
|
@ -1,6 +0,0 @@
|
|||
it("should allow to use import await", () => {
|
||||
return import("./reexport").then(({ default: value, other }) => {
|
||||
expect(value).toBe(42);
|
||||
expect(other).toBe(42);
|
||||
});
|
||||
});
|
|
@ -1,3 +0,0 @@
|
|||
await new Promise(r => setTimeout(r, 100));
|
||||
|
||||
export default 42;
|
|
@ -1,4 +0,0 @@
|
|||
export { default } from "./module";
|
||||
import value from "./module";
|
||||
|
||||
export const other = value;
|
|
@ -1,4 +1,4 @@
|
|||
it("should allow to use import await", () => {
|
||||
it("should allow to use top-level-await", () => {
|
||||
return import("./reexport").then(({ default: value, other }) => {
|
||||
expect(value).toBe(42);
|
||||
expect(other).toBe(42);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue