mirror of https://github.com/webpack/webpack.git
add `module` library support, test and example
add test cases for `experiments.outputModule`
This commit is contained in:
parent
c3af61fe2a
commit
4da99d8254
|
@ -0,0 +1,274 @@
|
||||||
|
# example.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { resetCounter, print } from "./methods";
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
const counter = await import("./counter");
|
||||||
|
print(counter.value);
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
print(counter.value);
|
||||||
|
await resetCounter();
|
||||||
|
print(counter.value);
|
||||||
|
}, 100);
|
||||||
|
```
|
||||||
|
|
||||||
|
# methods.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const resetCounter = async () => {
|
||||||
|
(await import("./counter")).reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const print = value => console.log(value);
|
||||||
|
```
|
||||||
|
|
||||||
|
# counter.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export let value = 0;
|
||||||
|
export function increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
export function decrement() {
|
||||||
|
value--;
|
||||||
|
}
|
||||||
|
export function reset() {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/******/ "use strict";
|
||||||
|
/******/ var __webpack_modules__ = ({});
|
||||||
|
```
|
||||||
|
|
||||||
|
<details><summary><code>/* webpack runtime code */</code></summary>
|
||||||
|
|
||||||
|
``` js
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var __webpack_module_cache__ = {};
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||||
|
/******/ if (cachedModule !== undefined) {
|
||||||
|
/******/ return cachedModule.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||||
|
/******/ // no module.id needed
|
||||||
|
/******/ // no module.loaded needed
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = __webpack_modules__;
|
||||||
|
/******/
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ /* webpack/runtime/define property getters */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ // define getter functions for harmony exports
|
||||||
|
/******/ __webpack_require__.d = (exports, definition) => {
|
||||||
|
/******/ for(var key in definition) {
|
||||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/ensure chunk */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ __webpack_require__.f = {};
|
||||||
|
/******/ // This file contains only the entry chunk.
|
||||||
|
/******/ // The chunk loading function for additional chunks
|
||||||
|
/******/ __webpack_require__.e = (chunkId) => {
|
||||||
|
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
|
||||||
|
/******/ __webpack_require__.f[key](chunkId, promises);
|
||||||
|
/******/ return promises;
|
||||||
|
/******/ }, []));
|
||||||
|
/******/ };
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/get javascript chunk filename */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ // This function allow to reference async chunks
|
||||||
|
/******/ __webpack_require__.u = (chunkId) => {
|
||||||
|
/******/ // return url for filenames based on template
|
||||||
|
/******/ return "" + chunkId + ".output.js";
|
||||||
|
/******/ };
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ __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/import chunk loading */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ // no baseURI
|
||||||
|
/******/
|
||||||
|
/******/ // object to store loaded and loading chunks
|
||||||
|
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||||||
|
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
|
||||||
|
/******/ var installedChunks = {
|
||||||
|
/******/ 0: 0
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ __webpack_require__.f.j = (chunkId, promises) => {
|
||||||
|
/******/ // JSONP chunk loading for javascript
|
||||||
|
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
|
||||||
|
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
|
||||||
|
/******/
|
||||||
|
/******/ // a Promise means "currently loading".
|
||||||
|
/******/ if(installedChunkData) {
|
||||||
|
/******/ promises.push(installedChunkData[1]);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ if(true) { // all chunks have JS
|
||||||
|
/******/ // setup Promise in chunk cache
|
||||||
|
/******/ var promise = import("./" + __webpack_require__.u(chunkId)).then((data) => {
|
||||||
|
/******/ var {ids, modules, runtime} = data;
|
||||||
|
/******/ // add "modules" to the modules object,
|
||||||
|
/******/ // then flag all "ids" as loaded and fire callback
|
||||||
|
/******/ var moduleId, chunkId, i = 0;
|
||||||
|
/******/ for(moduleId in modules) {
|
||||||
|
/******/ if(__webpack_require__.o(modules, moduleId)) {
|
||||||
|
/******/ __webpack_require__.m[moduleId] = modules[moduleId];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ if(runtime) runtime(__webpack_require__);
|
||||||
|
/******/ for(;i < ids.length; i++) {
|
||||||
|
/******/ chunkId = ids[i];
|
||||||
|
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||||||
|
/******/ installedChunks[chunkId][0]();
|
||||||
|
/******/ }
|
||||||
|
/******/ installedChunks[ids[i]] = 0;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ }, (e) => {
|
||||||
|
/******/ if(installedChunks[chunkId] !== 0) installedChunks[chunkId] = undefined;
|
||||||
|
/******/ throw e;
|
||||||
|
/******/ });
|
||||||
|
/******/ var promise = Promise.race([promise, new Promise((resolve) => (installedChunkData = installedChunks[chunkId] = [resolve]))])
|
||||||
|
/******/ promises.push(installedChunkData[1] = promise);
|
||||||
|
/******/ } else installedChunks[chunkId] = 0;
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // no on chunks loaded
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/************************************************************************/
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var __webpack_exports__ = {};
|
||||||
|
/*!********************************!*\
|
||||||
|
!*** ./example.js + 1 modules ***!
|
||||||
|
\********************************/
|
||||||
|
/*! namespace exports */
|
||||||
|
/*! runtime requirements: __webpack_require__.e, __webpack_require__, __webpack_require__.* */
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./methods.js
|
||||||
|
const resetCounter = async () => {
|
||||||
|
(await __webpack_require__.e(/*! import() */ 1).then(__webpack_require__.bind(__webpack_require__, /*! ./counter */ 1))).reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const print = value => console.log(value);
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./example.js
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
const counter = await __webpack_require__.e(/*! import() */ 1).then(__webpack_require__.bind(__webpack_require__, /*! ./counter */ 1));
|
||||||
|
print(counter.value);
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
print(counter.value);
|
||||||
|
await resetCounter();
|
||||||
|
print(counter.value);
|
||||||
|
}, 100);
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js (production)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var e,o={},t={};function r(e){var n=t[e];if(void 0!==n)return n.exports;var i=t[e]={exports:{}};return o[e](i,i.exports,r),i.exports}r.m=o,r.d=(e,o)=>{for(var t in o)r.o(o,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((o,t)=>(r.f[t](e,o),o)),[])),r.u=e=>e+".output.js",r.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e={179:0},r.f.j=(o,t)=>{var n=r.o(e,o)?e[o]:void 0;if(0!==n)if(n)t.push(n[1]);else{var i=import("./"+r.u(o)).then((o=>{var t,n,{ids:i,modules:a,runtime:s}=o,u=0;for(t in a)r.o(a,t)&&(r.m[t]=a[t]);for(s&&s(r);u<i.length;u++)n=i[u],r.o(e,n)&&e[n]&&e[n][0](),e[i[u]]=0}),(t=>{throw 0!==e[o]&&(e[o]=void 0),t}));i=Promise.race([i,new Promise((t=>n=e[o]=[t]))]),t.push(n[1]=i)}};const n=e=>console.log(e);setTimeout((async()=>{const e=await r.e(946).then(r.bind(r,946));n(e.value),e.increment(),e.increment(),e.increment(),n(e.value),await(async()=>{(await r.e(946).then(r.bind(r,946))).reset()})(),n(e.value)}),100);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Info
|
||||||
|
|
||||||
|
## Unoptimized
|
||||||
|
|
||||||
|
```
|
||||||
|
asset output.js 6.35 KiB [emitted] [javascript module] (name: main)
|
||||||
|
asset 1.output.js 1.36 KiB [emitted] [javascript module]
|
||||||
|
chunk (runtime: main) output.js (main) 420 bytes (javascript) 2.89 KiB (runtime) [entry] [rendered]
|
||||||
|
> ./example.js main
|
||||||
|
runtime modules 2.89 KiB 6 modules
|
||||||
|
./example.js + 1 modules 420 bytes [built] [code generated]
|
||||||
|
[no exports]
|
||||||
|
[no exports used]
|
||||||
|
entry ./example.js main
|
||||||
|
used as library export
|
||||||
|
chunk (runtime: main) 1.output.js 146 bytes [rendered]
|
||||||
|
> ./counter ./methods.js 2:8-27
|
||||||
|
> ./counter ./example.js 4:23-42
|
||||||
|
./counter.js 146 bytes [built] [code generated]
|
||||||
|
[exports: decrement, increment, reset, value]
|
||||||
|
import() ./counter ./example.js + 1 modules ./example.js 4:23-42
|
||||||
|
import() ./counter ./example.js + 1 modules ./methods.js 2:8-27
|
||||||
|
webpack 5.40.0 compiled successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production mode
|
||||||
|
|
||||||
|
```
|
||||||
|
asset output.js 1.15 KiB [emitted] [javascript module] [minimized] (name: main)
|
||||||
|
asset 946.output.js 213 bytes [emitted] [javascript module] [minimized]
|
||||||
|
chunk (runtime: main) output.js (main) 420 bytes (javascript) 2.89 KiB (runtime) [entry] [rendered]
|
||||||
|
> ./example.js main
|
||||||
|
runtime modules 2.89 KiB 6 modules
|
||||||
|
./example.js + 1 modules 420 bytes [built] [code generated]
|
||||||
|
[no exports]
|
||||||
|
[no exports used]
|
||||||
|
entry ./example.js main
|
||||||
|
used as library export
|
||||||
|
chunk (runtime: main) 946.output.js 146 bytes [rendered]
|
||||||
|
> ./counter ./methods.js 2:8-27
|
||||||
|
> ./counter ./example.js 4:23-42
|
||||||
|
./counter.js 146 bytes [built] [code generated]
|
||||||
|
[exports: decrement, increment, reset, value]
|
||||||
|
import() ./counter ./example.js + 1 modules ./example.js 4:23-42
|
||||||
|
import() ./counter ./example.js + 1 modules ./methods.js 2:8-27
|
||||||
|
webpack 5.40.0 compiled successfully
|
||||||
|
```
|
|
@ -0,0 +1 @@
|
||||||
|
require("../build-common");
|
|
@ -0,0 +1,10 @@
|
||||||
|
export let value = 0;
|
||||||
|
export function increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
export function decrement() {
|
||||||
|
value--;
|
||||||
|
}
|
||||||
|
export function reset() {
|
||||||
|
value = 0;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { resetCounter, print } from "./methods";
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
const counter = await import("./counter");
|
||||||
|
print(counter.value);
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
counter.increment();
|
||||||
|
print(counter.value);
|
||||||
|
await resetCounter();
|
||||||
|
print(counter.value);
|
||||||
|
}, 100);
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Worker example</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="./dist/main.mjs" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const resetCounter = async () => {
|
||||||
|
(await import("./counter")).reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const print = value => console.log(value);
|
|
@ -0,0 +1,43 @@
|
||||||
|
# example.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{example.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# methods.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{methods.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# counter.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{counter.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{dist/output.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js (production)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{production:dist/output.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# Info
|
||||||
|
|
||||||
|
## Unoptimized
|
||||||
|
|
||||||
|
```
|
||||||
|
_{{stdout}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production mode
|
||||||
|
|
||||||
|
```
|
||||||
|
_{{production:stdout}}_
|
||||||
|
```
|
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = {
|
||||||
|
output: {
|
||||||
|
module: true,
|
||||||
|
library: {
|
||||||
|
type: "module"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
usedExports: true,
|
||||||
|
concatenateModules: true
|
||||||
|
},
|
||||||
|
target: "browserslist: last 2 chrome versions",
|
||||||
|
experiments: {
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,170 @@
|
||||||
|
# example.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export * from "./counter";
|
||||||
|
export * from "./methods";
|
||||||
|
```
|
||||||
|
|
||||||
|
# methods.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export { reset as resetCounter } from "./counter";
|
||||||
|
|
||||||
|
export const print = value => console.log(value);
|
||||||
|
```
|
||||||
|
|
||||||
|
# counter.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export let value = 0;
|
||||||
|
export function increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
export function decrement() {
|
||||||
|
value--;
|
||||||
|
}
|
||||||
|
export function reset() {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/******/ "use strict";
|
||||||
|
/******/ // The require scope
|
||||||
|
/******/ var __webpack_require__ = {};
|
||||||
|
/******/
|
||||||
|
```
|
||||||
|
|
||||||
|
<details><summary><code>/* webpack runtime code */</code></summary>
|
||||||
|
|
||||||
|
``` js
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ /* webpack/runtime/define property getters */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ // define getter functions for harmony exports
|
||||||
|
/******/ __webpack_require__.d = (exports, definition) => {
|
||||||
|
/******/ for(var key in definition) {
|
||||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||||
|
/******/ (() => {
|
||||||
|
/******/ __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 });
|
||||||
|
/******/ };
|
||||||
|
/******/ })();
|
||||||
|
/******/
|
||||||
|
/************************************************************************/
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var __webpack_exports__ = {};
|
||||||
|
/*!********************************!*\
|
||||||
|
!*** ./example.js + 2 modules ***!
|
||||||
|
\********************************/
|
||||||
|
/*! namespace exports */
|
||||||
|
/*! export decrement [provided] [used in main] [missing usage info prevents renaming] -> ./counter.js .decrement */
|
||||||
|
/*! export increment [provided] [used in main] [missing usage info prevents renaming] -> ./counter.js .increment */
|
||||||
|
/*! export print [provided] [used in main] [missing usage info prevents renaming] -> ./methods.js .print */
|
||||||
|
/*! export reset [provided] [used in main] [missing usage info prevents renaming] -> ./counter.js .reset */
|
||||||
|
/*! export resetCounter [provided] [used in main] [missing usage info prevents renaming] -> ./counter.js .reset */
|
||||||
|
/*! export value [provided] [used in main] [missing usage info prevents renaming] -> ./counter.js .value */
|
||||||
|
/*! other exports [not provided] [no usage info] */
|
||||||
|
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||||
|
// ESM COMPAT FLAG
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
|
||||||
|
// EXPORTS
|
||||||
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
|
"decrement": () => (/* reexport */ decrement),
|
||||||
|
"increment": () => (/* reexport */ increment),
|
||||||
|
"print": () => (/* reexport */ print),
|
||||||
|
"reset": () => (/* reexport */ counter_reset),
|
||||||
|
"resetCounter": () => (/* reexport */ counter_reset),
|
||||||
|
"value": () => (/* reexport */ value)
|
||||||
|
});
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./counter.js
|
||||||
|
let value = 0;
|
||||||
|
function increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
function decrement() {
|
||||||
|
value--;
|
||||||
|
}
|
||||||
|
function counter_reset() {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./methods.js
|
||||||
|
|
||||||
|
|
||||||
|
const print = value => console.log(value);
|
||||||
|
|
||||||
|
;// CONCATENATED MODULE: ./example.js
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var __webpack_exports__decrement = __webpack_exports__.decrement;
|
||||||
|
var __webpack_exports__increment = __webpack_exports__.increment;
|
||||||
|
var __webpack_exports__print = __webpack_exports__.print;
|
||||||
|
var __webpack_exports__reset = __webpack_exports__.reset;
|
||||||
|
var __webpack_exports__resetCounter = __webpack_exports__.resetCounter;
|
||||||
|
var __webpack_exports__value = __webpack_exports__.value;
|
||||||
|
export { __webpack_exports__decrement as decrement, __webpack_exports__increment as increment, __webpack_exports__print as print, __webpack_exports__reset as reset, __webpack_exports__resetCounter as resetCounter, __webpack_exports__value as value };
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js (production)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var e={d:(n,t)=>{for(var o in t)e.o(t,o)&&!e.o(n,o)&&Object.defineProperty(n,o,{enumerable:!0,get:t[o]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{Mj:()=>r,nP:()=>o,S0:()=>c,mc:()=>a,Uh:()=>a,S3:()=>t});let t=0;function o(){t++}function r(){t--}function a(){t=0}const c=e=>console.log(e);var s=n.Mj,i=n.nP,l=n.S0,p=n.mc,u=n.Uh,f=n.S3;export{s as decrement,i as increment,l as print,p as reset,u as resetCounter,f as value};
|
||||||
|
```
|
||||||
|
|
||||||
|
# Info
|
||||||
|
|
||||||
|
## Unoptimized
|
||||||
|
|
||||||
|
```
|
||||||
|
asset output.js 3.63 KiB [emitted] [javascript module] (name: main)
|
||||||
|
chunk (runtime: main) output.js (main) 302 bytes (javascript) 670 bytes (runtime) [entry] [rendered]
|
||||||
|
> ./example.js main
|
||||||
|
runtime modules 670 bytes 3 modules
|
||||||
|
./example.js + 2 modules 302 bytes [built] [code generated]
|
||||||
|
[exports: decrement, increment, print, reset, resetCounter, value]
|
||||||
|
[used exports unknown]
|
||||||
|
entry ./example.js main
|
||||||
|
used as library export
|
||||||
|
webpack 5.40.0 compiled successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production mode
|
||||||
|
|
||||||
|
```
|
||||||
|
asset output.js 446 bytes [emitted] [javascript module] [minimized] (name: main)
|
||||||
|
chunk (runtime: main) output.js (main) 302 bytes (javascript) 396 bytes (runtime) [entry] [rendered]
|
||||||
|
> ./example.js main
|
||||||
|
runtime modules 396 bytes 2 modules
|
||||||
|
./example.js + 2 modules 302 bytes [built] [code generated]
|
||||||
|
[exports: decrement, increment, print, reset, resetCounter, value]
|
||||||
|
[all exports used]
|
||||||
|
entry ./example.js main
|
||||||
|
used as library export
|
||||||
|
webpack 5.40.0 compiled successfully
|
||||||
|
```
|
|
@ -0,0 +1 @@
|
||||||
|
require("../build-common");
|
|
@ -0,0 +1,10 @@
|
||||||
|
export let value = 0;
|
||||||
|
export function increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
export function decrement() {
|
||||||
|
value--;
|
||||||
|
}
|
||||||
|
export function reset() {
|
||||||
|
value = 0;
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./counter";
|
||||||
|
export * from "./methods";
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { reset as resetCounter } from "./counter";
|
||||||
|
|
||||||
|
export const print = value => console.log(value);
|
|
@ -0,0 +1,43 @@
|
||||||
|
# example.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{example.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# methods.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{methods.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# counter.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{counter.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{dist/output.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# dist/output.js (production)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
_{{production:dist/output.js}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
# Info
|
||||||
|
|
||||||
|
## Unoptimized
|
||||||
|
|
||||||
|
```
|
||||||
|
_{{stdout}}_
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production mode
|
||||||
|
|
||||||
|
```
|
||||||
|
_{{production:stdout}}_
|
||||||
|
```
|
|
@ -0,0 +1,14 @@
|
||||||
|
module.exports = {
|
||||||
|
output: {
|
||||||
|
module: true,
|
||||||
|
library: {
|
||||||
|
type: "module"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
concatenateModules: true
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
|
};
|
|
@ -133,6 +133,14 @@ class RuntimeTemplate {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destructureObject(items, value) {
|
||||||
|
return this.supportsDestructuring()
|
||||||
|
? `var {${items.join(", ")}} = ${value};`
|
||||||
|
: Template.asString(
|
||||||
|
items.map(item => `var ${item} = ${value}${propertyAccess([item])};`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
iife(args, body) {
|
iife(args, body) {
|
||||||
return `(${this.basicFunction(args, body)})()`;
|
return `(${this.basicFunction(args, body)})()`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,10 +139,11 @@ class WebpackOptionsApply extends OptionsApply {
|
||||||
new CommonJsChunkFormatPlugin().apply(compiler);
|
new CommonJsChunkFormatPlugin().apply(compiler);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "module":
|
case "module": {
|
||||||
throw new Error(
|
const ModuleChunkFormatPlugin = require("./esm/ModuleChunkFormatPlugin");
|
||||||
"EcmaScript Module Chunk Format is not implemented yet"
|
new ModuleChunkFormatPlugin().apply(compiler);
|
||||||
);
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Unsupported chunk format '" + options.output.chunkFormat + "'."
|
"Unsupported chunk format '" + options.output.chunkFormat + "'."
|
||||||
|
|
|
@ -182,6 +182,11 @@ const applyWebpackOptionsDefaults = options => {
|
||||||
applyOutputDefaults(options.output, {
|
applyOutputDefaults(options.output, {
|
||||||
context: options.context,
|
context: options.context,
|
||||||
targetProperties,
|
targetProperties,
|
||||||
|
isAffectedByBrowserslist:
|
||||||
|
target === undefined ||
|
||||||
|
(typeof target === "string" && target.startsWith("browserslist")) ||
|
||||||
|
(Array.isArray(target) &&
|
||||||
|
target.some(target => target.startsWith("browserslist"))),
|
||||||
outputModule: options.experiments.outputModule,
|
outputModule: options.experiments.outputModule,
|
||||||
development,
|
development,
|
||||||
entry: options.entry,
|
entry: options.entry,
|
||||||
|
@ -543,6 +548,7 @@ const applyModuleDefaults = (
|
||||||
* @param {Object} options options
|
* @param {Object} options options
|
||||||
* @param {string} options.context context
|
* @param {string} options.context context
|
||||||
* @param {TargetProperties | false} options.targetProperties target properties
|
* @param {TargetProperties | false} options.targetProperties target properties
|
||||||
|
* @param {boolean} options.isAffectedByBrowserslist is affected by browserslist
|
||||||
* @param {boolean} options.outputModule is outputModule experiment enabled
|
* @param {boolean} options.outputModule is outputModule experiment enabled
|
||||||
* @param {boolean} options.development is development mode
|
* @param {boolean} options.development is development mode
|
||||||
* @param {Entry} options.entry entry option
|
* @param {Entry} options.entry entry option
|
||||||
|
@ -551,7 +557,15 @@ const applyModuleDefaults = (
|
||||||
*/
|
*/
|
||||||
const applyOutputDefaults = (
|
const applyOutputDefaults = (
|
||||||
output,
|
output,
|
||||||
{ context, targetProperties: tp, outputModule, development, entry, module }
|
{
|
||||||
|
context,
|
||||||
|
targetProperties: tp,
|
||||||
|
isAffectedByBrowserslist,
|
||||||
|
outputModule,
|
||||||
|
development,
|
||||||
|
entry,
|
||||||
|
module
|
||||||
|
}
|
||||||
) => {
|
) => {
|
||||||
/**
|
/**
|
||||||
* @param {Library=} library the library option
|
* @param {Library=} library the library option
|
||||||
|
@ -591,8 +605,8 @@ const applyOutputDefaults = (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
D(output, "filename", "[name].js");
|
|
||||||
F(output, "module", () => !!outputModule);
|
F(output, "module", () => !!outputModule);
|
||||||
|
D(output, "filename", output.module ? "[name].mjs" : "[name].js");
|
||||||
F(output, "iife", () => !output.module);
|
F(output, "iife", () => !output.module);
|
||||||
D(output, "importFunctionName", "import");
|
D(output, "importFunctionName", "import");
|
||||||
D(output, "importMetaName", "import.meta");
|
D(output, "importMetaName", "import.meta");
|
||||||
|
@ -608,7 +622,7 @@ const applyOutputDefaults = (
|
||||||
// Otherwise prefix "[id]." in front of the basename to make it changing
|
// Otherwise prefix "[id]." in front of the basename to make it changing
|
||||||
return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
|
return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
|
||||||
}
|
}
|
||||||
return "[id].js";
|
return output.module ? "[id].mjs" : "[id].js";
|
||||||
});
|
});
|
||||||
D(output, "assetModuleFilename", "[hash][ext][query]");
|
D(output, "assetModuleFilename", "[hash][ext][query]");
|
||||||
D(output, "webassemblyModuleFilename", "[hash].module.wasm");
|
D(output, "webassemblyModuleFilename", "[hash].module.wasm");
|
||||||
|
@ -633,13 +647,34 @@ const applyOutputDefaults = (
|
||||||
});
|
});
|
||||||
F(output, "chunkFormat", () => {
|
F(output, "chunkFormat", () => {
|
||||||
if (tp) {
|
if (tp) {
|
||||||
|
const helpMessage = isAffectedByBrowserslist
|
||||||
|
? "Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly."
|
||||||
|
: "Select an appropriate 'target' to allow selecting one by default, or specify the 'output.chunkFormat' directly.";
|
||||||
|
if (output.module) {
|
||||||
|
if (tp.dynamicImport) return "module";
|
||||||
|
if (tp.document) return "array-push";
|
||||||
|
throw new Error(
|
||||||
|
"For the selected environment is no default ESM chunk format available:\n" +
|
||||||
|
"ESM exports can be chosen when 'import()' is available.\n" +
|
||||||
|
"JSONP Array push can be chosen when 'document' is available.\n" +
|
||||||
|
helpMessage
|
||||||
|
);
|
||||||
|
} else {
|
||||||
if (tp.document) return "array-push";
|
if (tp.document) return "array-push";
|
||||||
if (tp.require) return "commonjs";
|
if (tp.require) return "commonjs";
|
||||||
if (tp.nodeBuiltins) return "commonjs";
|
if (tp.nodeBuiltins) return "commonjs";
|
||||||
if (tp.importScripts) return "array-push";
|
if (tp.importScripts) return "array-push";
|
||||||
if (tp.dynamicImport && output.module) return "module";
|
throw new Error(
|
||||||
|
"For the selected environment is no default script chunk format available:\n" +
|
||||||
|
"JSONP Array push can be chosen when 'document' or 'importScripts' is available.\n" +
|
||||||
|
"CommonJs exports can be chosen when 'require' or node builtins are available.\n" +
|
||||||
|
helpMessage
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
throw new Error(
|
||||||
|
"Chunk format can't be selected by default when no target is specified"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
F(output, "chunkLoading", () => {
|
F(output, "chunkLoading", () => {
|
||||||
if (tp) {
|
if (tp) {
|
||||||
|
@ -709,7 +744,11 @@ const applyOutputDefaults = (
|
||||||
F(output, "path", () => path.join(process.cwd(), "dist"));
|
F(output, "path", () => path.join(process.cwd(), "dist"));
|
||||||
F(output, "pathinfo", () => development);
|
F(output, "pathinfo", () => development);
|
||||||
D(output, "sourceMapFilename", "[file].map[query]");
|
D(output, "sourceMapFilename", "[file].map[query]");
|
||||||
D(output, "hotUpdateChunkFilename", "[id].[fullhash].hot-update.js");
|
D(
|
||||||
|
output,
|
||||||
|
"hotUpdateChunkFilename",
|
||||||
|
`[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}`
|
||||||
|
);
|
||||||
D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json");
|
D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json");
|
||||||
D(output, "crossOriginLoading", false);
|
D(output, "crossOriginLoading", false);
|
||||||
F(output, "scriptType", () => (output.module ? "module" : false));
|
F(output, "scriptType", () => (output.module ? "module" : false));
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
Author Tobias Koppers @sokra
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { ConcatSource } = require("webpack-sources");
|
||||||
|
const { RuntimeGlobals } = require("..");
|
||||||
|
const HotUpdateChunk = require("../HotUpdateChunk");
|
||||||
|
const Template = require("../Template");
|
||||||
|
const {
|
||||||
|
getCompilationHooks
|
||||||
|
} = require("../javascript/JavascriptModulesPlugin");
|
||||||
|
|
||||||
|
/** @typedef {import("../Compiler")} Compiler */
|
||||||
|
|
||||||
|
class ModuleChunkFormatPlugin {
|
||||||
|
/**
|
||||||
|
* Apply the plugin
|
||||||
|
* @param {Compiler} compiler the compiler instance
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.thisCompilation.tap(
|
||||||
|
"ModuleChunkFormatPlugin",
|
||||||
|
compilation => {
|
||||||
|
compilation.hooks.additionalChunkRuntimeRequirements.tap(
|
||||||
|
"ModuleChunkFormatPlugin",
|
||||||
|
(chunk, set) => {
|
||||||
|
if (chunk.hasRuntime()) return;
|
||||||
|
if (compilation.chunkGraph.getNumberOfEntryModules(chunk) > 0) {
|
||||||
|
set.add(RuntimeGlobals.onChunksLoaded);
|
||||||
|
set.add(RuntimeGlobals.require);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const hooks = getCompilationHooks(compilation);
|
||||||
|
hooks.renderChunk.tap(
|
||||||
|
"ModuleChunkFormatPlugin",
|
||||||
|
(modules, renderContext) => {
|
||||||
|
const { chunk, chunkGraph } = renderContext;
|
||||||
|
const hotUpdateChunk =
|
||||||
|
chunk instanceof HotUpdateChunk ? chunk : null;
|
||||||
|
const source = new ConcatSource();
|
||||||
|
if (hotUpdateChunk) {
|
||||||
|
throw new Error(
|
||||||
|
"HMR is not implemented for module chunk format yet"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
source.add(`export const id = ${JSON.stringify(chunk.id)};\n`);
|
||||||
|
source.add(`export const ids = ${JSON.stringify(chunk.ids)};\n`);
|
||||||
|
source.add(`export const modules = `);
|
||||||
|
source.add(modules);
|
||||||
|
source.add(`;\n`);
|
||||||
|
const runtimeModules =
|
||||||
|
chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
||||||
|
if (runtimeModules.length > 0) {
|
||||||
|
source.add("export const runtime =\n");
|
||||||
|
source.add(
|
||||||
|
Template.renderChunkRuntimeModules(
|
||||||
|
runtimeModules,
|
||||||
|
renderContext
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const entries = Array.from(
|
||||||
|
chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||||
|
);
|
||||||
|
if (entries.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
"Entry modules in chunk is not implemented for module chunk format yet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
hooks.chunkHash.tap(
|
||||||
|
"ModuleChunkFormatPlugin",
|
||||||
|
(chunk, hash, { chunkGraph, runtimeTemplate }) => {
|
||||||
|
if (chunk.hasRuntime()) return;
|
||||||
|
hash.update("ModuleChunkFormatPlugin");
|
||||||
|
hash.update("1");
|
||||||
|
// TODO
|
||||||
|
// const entries = Array.from(
|
||||||
|
// chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||||
|
// );
|
||||||
|
// updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ModuleChunkFormatPlugin;
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
Author Tobias Koppers @sokra
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
|
const ModuleChunkLoadingRuntimeModule = require("./ModuleChunkLoadingRuntimeModule");
|
||||||
|
|
||||||
|
/** @typedef {import("../Compiler")} Compiler */
|
||||||
|
|
||||||
|
class ModuleChunkLoadingPlugin {
|
||||||
|
/**
|
||||||
|
* Apply the plugin
|
||||||
|
* @param {Compiler} compiler the compiler instance
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.thisCompilation.tap(
|
||||||
|
"ModuleChunkLoadingPlugin",
|
||||||
|
compilation => {
|
||||||
|
const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
||||||
|
const isEnabledForChunk = chunk => {
|
||||||
|
const options = chunk.getEntryOptions();
|
||||||
|
const chunkLoading =
|
||||||
|
(options && options.chunkLoading) || globalChunkLoading;
|
||||||
|
return chunkLoading === "import";
|
||||||
|
};
|
||||||
|
const onceForChunkSet = new WeakSet();
|
||||||
|
const handler = (chunk, set) => {
|
||||||
|
if (onceForChunkSet.has(chunk)) return;
|
||||||
|
onceForChunkSet.add(chunk);
|
||||||
|
if (!isEnabledForChunk(chunk)) return;
|
||||||
|
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
|
||||||
|
set.add(RuntimeGlobals.hasOwnProperty);
|
||||||
|
compilation.addRuntimeModule(
|
||||||
|
chunk,
|
||||||
|
new ModuleChunkLoadingRuntimeModule(set)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||||
|
.tap("ModuleChunkLoadingPlugin", handler);
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.baseURI)
|
||||||
|
.tap("ModuleChunkLoadingPlugin", handler);
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.onChunksLoaded)
|
||||||
|
.tap("ModuleChunkLoadingPlugin", handler);
|
||||||
|
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||||
|
.tap("ModuleChunkLoadingPlugin", (chunk, set) => {
|
||||||
|
if (!isEnabledForChunk(chunk)) return;
|
||||||
|
set.add(RuntimeGlobals.getChunkScriptFilename);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ModuleChunkLoadingPlugin;
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { SyncWaterfallHook } = require("tapable");
|
||||||
|
const Compilation = require("../Compilation");
|
||||||
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
|
const RuntimeModule = require("../RuntimeModule");
|
||||||
|
const Template = require("../Template");
|
||||||
|
const {
|
||||||
|
getChunkFilenameTemplate,
|
||||||
|
chunkHasJs
|
||||||
|
} = require("../javascript/JavascriptModulesPlugin");
|
||||||
|
const { getInitialChunkIds } = require("../javascript/StartupHelpers");
|
||||||
|
const compileBooleanMatcher = require("../util/compileBooleanMatcher");
|
||||||
|
const { getUndoPath } = require("../util/identifier");
|
||||||
|
|
||||||
|
/** @typedef {import("../Chunk")} Chunk */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} JsonpCompilationPluginHooks
|
||||||
|
* @property {SyncWaterfallHook<[string, Chunk]>} linkPreload
|
||||||
|
* @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {WeakMap<Compilation, JsonpCompilationPluginHooks>} */
|
||||||
|
const compilationHooksMap = new WeakMap();
|
||||||
|
|
||||||
|
class ModuleChunkLoadingRuntimeModule extends RuntimeModule {
|
||||||
|
/**
|
||||||
|
* @param {Compilation} compilation the compilation
|
||||||
|
* @returns {JsonpCompilationPluginHooks} hooks
|
||||||
|
*/
|
||||||
|
static getCompilationHooks(compilation) {
|
||||||
|
if (!(compilation instanceof Compilation)) {
|
||||||
|
throw new TypeError(
|
||||||
|
"The 'compilation' argument must be an instance of Compilation"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let hooks = compilationHooksMap.get(compilation);
|
||||||
|
if (hooks === undefined) {
|
||||||
|
hooks = {
|
||||||
|
linkPreload: new SyncWaterfallHook(["source", "chunk"]),
|
||||||
|
linkPrefetch: new SyncWaterfallHook(["source", "chunk"])
|
||||||
|
};
|
||||||
|
compilationHooksMap.set(compilation, hooks);
|
||||||
|
}
|
||||||
|
return hooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(runtimeRequirements) {
|
||||||
|
super("import chunk loading", RuntimeModule.STAGE_ATTACH);
|
||||||
|
this._runtimeRequirements = runtimeRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} runtime code
|
||||||
|
*/
|
||||||
|
generate() {
|
||||||
|
const { compilation, chunk } = this;
|
||||||
|
const {
|
||||||
|
runtimeTemplate,
|
||||||
|
chunkGraph,
|
||||||
|
outputOptions: { importFunctionName, importMetaName }
|
||||||
|
} = compilation;
|
||||||
|
const fn = RuntimeGlobals.ensureChunkHandlers;
|
||||||
|
const withBaseURI = this._runtimeRequirements.has(RuntimeGlobals.baseURI);
|
||||||
|
const withLoading = this._runtimeRequirements.has(
|
||||||
|
RuntimeGlobals.ensureChunkHandlers
|
||||||
|
);
|
||||||
|
const withOnChunkLoad = this._runtimeRequirements.has(
|
||||||
|
RuntimeGlobals.onChunksLoaded
|
||||||
|
);
|
||||||
|
const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasJs);
|
||||||
|
const hasJsMatcher = compileBooleanMatcher(conditionMap);
|
||||||
|
const initialChunkIds = getInitialChunkIds(chunk, chunkGraph);
|
||||||
|
|
||||||
|
const outputName = this.compilation.getPath(
|
||||||
|
getChunkFilenameTemplate(chunk, this.compilation.outputOptions),
|
||||||
|
{
|
||||||
|
chunk,
|
||||||
|
contentHashType: "javascript"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const rootOutputDir = getUndoPath(
|
||||||
|
outputName,
|
||||||
|
this.compilation.outputOptions.path,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
return Template.asString([
|
||||||
|
withBaseURI
|
||||||
|
? Template.asString([
|
||||||
|
`${RuntimeGlobals.baseURI} = new URL(${JSON.stringify(
|
||||||
|
rootOutputDir
|
||||||
|
)}, ${importMetaName}.url);`
|
||||||
|
])
|
||||||
|
: "// no baseURI",
|
||||||
|
"",
|
||||||
|
"// object to store loaded and loading chunks",
|
||||||
|
"// undefined = chunk not loaded, null = chunk preloaded/prefetched",
|
||||||
|
"// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded",
|
||||||
|
"var installedChunks = {",
|
||||||
|
Template.indent(
|
||||||
|
Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 0`).join(
|
||||||
|
",\n"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"};",
|
||||||
|
"",
|
||||||
|
withLoading
|
||||||
|
? Template.asString([
|
||||||
|
`${fn}.j = ${runtimeTemplate.basicFunction(
|
||||||
|
"chunkId, promises",
|
||||||
|
hasJsMatcher !== false
|
||||||
|
? Template.indent([
|
||||||
|
"// JSONP chunk loading for javascript",
|
||||||
|
`var installedChunkData = ${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;`,
|
||||||
|
'if(installedChunkData !== 0) { // 0 means "already installed".',
|
||||||
|
Template.indent([
|
||||||
|
"",
|
||||||
|
'// a Promise means "currently loading".',
|
||||||
|
"if(installedChunkData) {",
|
||||||
|
Template.indent([
|
||||||
|
"promises.push(installedChunkData[1]);"
|
||||||
|
]),
|
||||||
|
"} else {",
|
||||||
|
Template.indent([
|
||||||
|
hasJsMatcher === true
|
||||||
|
? "if(true) { // all chunks have JS"
|
||||||
|
: `if(${hasJsMatcher("chunkId")}) {`,
|
||||||
|
Template.indent([
|
||||||
|
"// setup Promise in chunk cache",
|
||||||
|
`var promise = ${importFunctionName}(${JSON.stringify(
|
||||||
|
rootOutputDir
|
||||||
|
)} + ${
|
||||||
|
RuntimeGlobals.getChunkScriptFilename
|
||||||
|
}(chunkId)).then(${runtimeTemplate.basicFunction(
|
||||||
|
"data",
|
||||||
|
[
|
||||||
|
runtimeTemplate.destructureObject(
|
||||||
|
["ids", "modules", "runtime"],
|
||||||
|
"data"
|
||||||
|
),
|
||||||
|
'// add "modules" to the modules object,',
|
||||||
|
'// then flag all "ids" as loaded and fire callback',
|
||||||
|
"var moduleId, chunkId, i = 0;",
|
||||||
|
"for(moduleId in modules) {",
|
||||||
|
Template.indent([
|
||||||
|
`if(${RuntimeGlobals.hasOwnProperty}(modules, moduleId)) {`,
|
||||||
|
Template.indent(
|
||||||
|
`${RuntimeGlobals.moduleFactories}[moduleId] = modules[moduleId];`
|
||||||
|
),
|
||||||
|
"}"
|
||||||
|
]),
|
||||||
|
"}",
|
||||||
|
"if(runtime) runtime(__webpack_require__);",
|
||||||
|
"for(;i < ids.length; i++) {",
|
||||||
|
Template.indent([
|
||||||
|
"chunkId = ids[i];",
|
||||||
|
`if(${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) && installedChunks[chunkId]) {`,
|
||||||
|
Template.indent(
|
||||||
|
"installedChunks[chunkId][0]();"
|
||||||
|
),
|
||||||
|
"}",
|
||||||
|
"installedChunks[ids[i]] = 0;"
|
||||||
|
]),
|
||||||
|
"}",
|
||||||
|
withOnChunkLoad
|
||||||
|
? `${RuntimeGlobals.onChunksLoaded}();`
|
||||||
|
: ""
|
||||||
|
]
|
||||||
|
)}, ${runtimeTemplate.basicFunction("e", [
|
||||||
|
"if(installedChunks[chunkId] !== 0) installedChunks[chunkId] = undefined;",
|
||||||
|
"throw e;"
|
||||||
|
])});`,
|
||||||
|
`var promise = Promise.race([promise, new Promise(${runtimeTemplate.expressionFunction(
|
||||||
|
`installedChunkData = installedChunks[chunkId] = [resolve]`,
|
||||||
|
"resolve"
|
||||||
|
)})])`,
|
||||||
|
`promises.push(installedChunkData[1] = promise);`
|
||||||
|
]),
|
||||||
|
"} else installedChunks[chunkId] = 0;"
|
||||||
|
]),
|
||||||
|
"}"
|
||||||
|
]),
|
||||||
|
"}"
|
||||||
|
])
|
||||||
|
: Template.indent(["installedChunks[chunkId] = 0;"])
|
||||||
|
)};`
|
||||||
|
])
|
||||||
|
: "// no chunk on demand loading",
|
||||||
|
"",
|
||||||
|
withOnChunkLoad
|
||||||
|
? `${
|
||||||
|
RuntimeGlobals.onChunksLoaded
|
||||||
|
}.j = ${runtimeTemplate.returningFunction(
|
||||||
|
"installedChunks[chunkId] === 0",
|
||||||
|
"chunkId"
|
||||||
|
)};`
|
||||||
|
: "// no on chunks loaded"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ModuleChunkLoadingRuntimeModule;
|
|
@ -96,9 +96,11 @@ class EnableChunkLoadingPlugin {
|
||||||
}).apply(compiler);
|
}).apply(compiler);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "import":
|
case "import": {
|
||||||
// TODO implement import chunk loading
|
const ModuleChunkLoadingPlugin = require("../esm/ModuleChunkLoadingPlugin");
|
||||||
throw new Error("Chunk Loading via import() is not implemented yet");
|
new ModuleChunkLoadingPlugin().apply(compiler);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "universal":
|
case "universal":
|
||||||
// TODO implement universal chunk loading
|
// TODO implement universal chunk loading
|
||||||
throw new Error("Universal Chunk Loading is not implemented yet");
|
throw new Error("Universal Chunk Loading is not implemented yet");
|
||||||
|
|
18
package.json
18
package.json
|
@ -131,11 +131,11 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"setup": "node ./setup/setup.js",
|
"setup": "node ./setup/setup.js",
|
||||||
"test": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest",
|
"test": "node --max-old-space-size=4096 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest",
|
||||||
"test:update-snapshots": "yarn jest -u",
|
"test:update-snapshots": "yarn jest -u",
|
||||||
"test:integration": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.js\"",
|
"test:integration": "node --max-old-space-size=4096 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.js\"",
|
||||||
"test:basic": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/te{st/TestCasesNormal,st/StatsTestCases,st/ConfigTestCases}.test.js\"",
|
"test:basic": "node --max-old-space-size=4096 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/te{st/TestCasesNormal,st/StatsTestCases,st/ConfigTestCases}.test.js\"",
|
||||||
"test:unit": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\"",
|
"test:unit": "node --max-old-space-size=4096 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\"",
|
||||||
"travis:integration": "yarn cover:integration --ci $JEST",
|
"travis:integration": "yarn cover:integration --ci $JEST",
|
||||||
"travis:basic": "yarn cover:basic --ci $JEST",
|
"travis:basic": "yarn cover:basic --ci $JEST",
|
||||||
"travis:lintunit": "yarn lint && yarn cover:unit --ci $JEST",
|
"travis:lintunit": "yarn lint && yarn cover:unit --ci $JEST",
|
||||||
|
@ -162,13 +162,13 @@
|
||||||
"pretty-lint": "yarn pretty-lint-base --check",
|
"pretty-lint": "yarn pretty-lint-base --check",
|
||||||
"yarn-lint": "yarn-deduplicate --fail --list -s highest yarn.lock",
|
"yarn-lint": "yarn-deduplicate --fail --list -s highest yarn.lock",
|
||||||
"yarn-lint-fix": "yarn-deduplicate -s highest yarn.lock",
|
"yarn-lint-fix": "yarn-deduplicate -s highest yarn.lock",
|
||||||
"benchmark": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.benchmark.js\" --runInBand",
|
"benchmark": "node --max-old-space-size=4096 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.benchmark.js\" --runInBand",
|
||||||
"cover": "yarn cover:all && yarn cover:report",
|
"cover": "yarn cover:all && yarn cover:report",
|
||||||
"cover:clean": "rimraf .nyc_output coverage",
|
"cover:clean": "rimraf .nyc_output coverage",
|
||||||
"cover:all": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --coverage",
|
"cover:all": "node --max-old-space-size=4096 --experimental-vm-modules node_modules/jest-cli/bin/jest --coverage",
|
||||||
"cover:basic": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/te{st/TestCasesNormal,st/StatsTestCases,st/ConfigTestCases}.test.js\" --coverage",
|
"cover:basic": "node --max-old-space-size=4096 --experimental-vm-modules node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/te{st/TestCasesNormal,st/StatsTestCases,st/ConfigTestCases}.test.js\" --coverage",
|
||||||
"cover:integration": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.js\" --coverage",
|
"cover:integration": "node --max-old-space-size=4096 --experimental-vm-modules node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.js\" --coverage",
|
||||||
"cover:unit": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\" --coverage",
|
"cover:unit": "node --max-old-space-size=4096 --experimental-vm-modules node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\" --coverage",
|
||||||
"cover:types": "node node_modules/tooling/type-coverage",
|
"cover:types": "node node_modules/tooling/type-coverage",
|
||||||
"cover:merge": "nyc merge .nyc_output coverage/coverage-nyc.json && rimraf .nyc_output",
|
"cover:merge": "nyc merge .nyc_output coverage/coverage-nyc.json && rimraf .nyc_output",
|
||||||
"cover:report": "nyc report -t coverage"
|
"cover:report": "nyc report -t coverage"
|
||||||
|
|
|
@ -84,7 +84,12 @@ const describeCases = config => {
|
||||||
if (typeof options.output.pathinfo === "undefined")
|
if (typeof options.output.pathinfo === "undefined")
|
||||||
options.output.pathinfo = true;
|
options.output.pathinfo = true;
|
||||||
if (!options.output.filename)
|
if (!options.output.filename)
|
||||||
options.output.filename = "bundle" + idx + ".js";
|
options.output.filename =
|
||||||
|
"bundle" +
|
||||||
|
idx +
|
||||||
|
(options.experiments && options.experiments.outputModule
|
||||||
|
? ".mjs"
|
||||||
|
: ".js");
|
||||||
if (config.cache) {
|
if (config.cache) {
|
||||||
options.cache = {
|
options.cache = {
|
||||||
cacheDirectory,
|
cacheDirectory,
|
||||||
|
@ -295,7 +300,12 @@ const describeCases = config => {
|
||||||
|
|
||||||
const requireCache = Object.create(null);
|
const requireCache = Object.create(null);
|
||||||
// eslint-disable-next-line no-loop-func
|
// eslint-disable-next-line no-loop-func
|
||||||
const _require = (currentDirectory, options, module) => {
|
const _require = (
|
||||||
|
currentDirectory,
|
||||||
|
options,
|
||||||
|
module,
|
||||||
|
esmModule
|
||||||
|
) => {
|
||||||
if (Array.isArray(module) || /^\.\.?\//.test(module)) {
|
if (Array.isArray(module) || /^\.\.?\//.test(module)) {
|
||||||
let content;
|
let content;
|
||||||
let p;
|
let p;
|
||||||
|
@ -339,10 +349,27 @@ const describeCases = config => {
|
||||||
};
|
};
|
||||||
requireCache[p] = m;
|
requireCache[p] = m;
|
||||||
let runInNewContext = false;
|
let runInNewContext = false;
|
||||||
let oldCurrentScript = document.currentScript;
|
|
||||||
document.currentScript = new CurrentScript(subPath);
|
|
||||||
|
|
||||||
const moduleScope = {
|
const moduleScope = {
|
||||||
|
it: _it,
|
||||||
|
beforeEach: _beforeEach,
|
||||||
|
afterEach: _afterEach,
|
||||||
|
expect,
|
||||||
|
jest,
|
||||||
|
__STATS__: jsonStats,
|
||||||
|
nsObj: m => {
|
||||||
|
Object.defineProperty(m, Symbol.toStringTag, {
|
||||||
|
value: "Module"
|
||||||
|
});
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const isModule =
|
||||||
|
p.endsWith(".mjs") &&
|
||||||
|
options.experiments &&
|
||||||
|
options.experiments.outputModule;
|
||||||
|
if (!isModule) {
|
||||||
|
Object.assign(moduleScope, {
|
||||||
require: _require.bind(
|
require: _require.bind(
|
||||||
null,
|
null,
|
||||||
path.dirname(p),
|
path.dirname(p),
|
||||||
|
@ -355,27 +382,18 @@ const describeCases = config => {
|
||||||
_require(
|
_require(
|
||||||
outputDirectory,
|
outputDirectory,
|
||||||
options,
|
options,
|
||||||
`.${url.slice("https://test.cases/path".length)}`
|
`.${url.slice(
|
||||||
|
"https://test.cases/path".length
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
module: m,
|
module: m,
|
||||||
exports: m.exports,
|
exports: m.exports,
|
||||||
__dirname: path.dirname(p),
|
__dirname: path.dirname(p),
|
||||||
__filename: p,
|
__filename: p,
|
||||||
it: _it,
|
_globalAssign: { expect }
|
||||||
beforeEach: _beforeEach,
|
|
||||||
afterEach: _afterEach,
|
|
||||||
expect,
|
|
||||||
jest,
|
|
||||||
_globalAssign: { expect },
|
|
||||||
__STATS__: jsonStats,
|
|
||||||
nsObj: m => {
|
|
||||||
Object.defineProperty(m, Symbol.toStringTag, {
|
|
||||||
value: "Module"
|
|
||||||
});
|
});
|
||||||
return m;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if (
|
if (
|
||||||
options.target === "web" ||
|
options.target === "web" ||
|
||||||
options.target === "webworker"
|
options.target === "webworker"
|
||||||
|
@ -392,21 +410,88 @@ const describeCases = config => {
|
||||||
if (testConfig.moduleScope) {
|
if (testConfig.moduleScope) {
|
||||||
testConfig.moduleScope(moduleScope);
|
testConfig.moduleScope(moduleScope);
|
||||||
}
|
}
|
||||||
const args = Object.keys(moduleScope);
|
if (isModule) {
|
||||||
const argValues = args.map(arg => moduleScope[arg]);
|
if (!vm.SourceTextModule)
|
||||||
|
throw new Error(
|
||||||
|
"Running this test requires '--experimental-vm-modules'.\nRun with 'node --experimental-vm-modules node_modules/jest-cli/bin/jest'."
|
||||||
|
);
|
||||||
|
const esm = new vm.SourceTextModule(content, {
|
||||||
|
identifier: p,
|
||||||
|
context: vm.createContext(moduleScope, {
|
||||||
|
name: `context for ${p}`
|
||||||
|
}),
|
||||||
|
importModuleDynamically: async (
|
||||||
|
specifier,
|
||||||
|
module
|
||||||
|
) => {
|
||||||
|
const result = await _require(
|
||||||
|
path.dirname(p),
|
||||||
|
options,
|
||||||
|
specifier,
|
||||||
|
"evaluated"
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
result instanceof
|
||||||
|
(vm.Module ||
|
||||||
|
/* node.js 10 */ vm.SourceTextModule)
|
||||||
|
) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (!vm.SyntheticModule) return result;
|
||||||
|
return new vm.SyntheticModule(
|
||||||
|
[
|
||||||
|
...new Set([
|
||||||
|
"default",
|
||||||
|
...Object.keys(result)
|
||||||
|
])
|
||||||
|
],
|
||||||
|
function () {
|
||||||
|
for (const key in result) {
|
||||||
|
this.setExport(key, result[key]);
|
||||||
|
}
|
||||||
|
this.setExport("default", result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (esmModule === "unlinked") return esm;
|
||||||
|
return (async () => {
|
||||||
|
await esm.link(
|
||||||
|
async (specifier, referencingModule) => {
|
||||||
|
return _require(
|
||||||
|
path.dirname(referencingModule.identfier),
|
||||||
|
options,
|
||||||
|
specifier,
|
||||||
|
"unlinked"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// node.js 10 needs instantiate
|
||||||
|
if (esm.instantiate) esm.instantiate();
|
||||||
|
await esm.evaluate();
|
||||||
|
if (esmModule === "evaluated") return esm;
|
||||||
|
const ns = esm.namespace;
|
||||||
|
return ns.default && ns.default instanceof Promise
|
||||||
|
? ns.default
|
||||||
|
: ns;
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
if (!runInNewContext)
|
if (!runInNewContext)
|
||||||
content = `Object.assign(global, _globalAssign); ${content}`;
|
content = `Object.assign(global, _globalAssign); ${content}`;
|
||||||
|
const args = Object.keys(moduleScope);
|
||||||
|
const argValues = args.map(arg => moduleScope[arg]);
|
||||||
const code = `(function(${args.join(
|
const code = `(function(${args.join(
|
||||||
", "
|
", "
|
||||||
)}) {${content}\n})`;
|
)}) {${content}\n})`;
|
||||||
|
|
||||||
|
let oldCurrentScript = document.currentScript;
|
||||||
|
document.currentScript = new CurrentScript(subPath);
|
||||||
const fn = runInNewContext
|
const fn = runInNewContext
|
||||||
? vm.runInNewContext(code, globalContext, p)
|
? vm.runInNewContext(code, globalContext, p)
|
||||||
: vm.runInThisContext(code, p);
|
: vm.runInThisContext(code, p);
|
||||||
fn.call(m.exports, ...argValues);
|
fn.call(m.exports, ...argValues);
|
||||||
|
|
||||||
//restore state
|
|
||||||
document.currentScript = oldCurrentScript;
|
document.currentScript = oldCurrentScript;
|
||||||
|
}
|
||||||
return m.exports;
|
return m.exports;
|
||||||
} else if (
|
} else if (
|
||||||
testConfig.modules &&
|
testConfig.modules &&
|
||||||
|
|
|
@ -861,6 +861,15 @@ describe("Defaults", () => {
|
||||||
- "externalsType": "var",
|
- "externalsType": "var",
|
||||||
+ "externalsType": "module",
|
+ "externalsType": "module",
|
||||||
@@ ... @@
|
@@ ... @@
|
||||||
|
- "chunkFilename": "[name].js",
|
||||||
|
+ "chunkFilename": "[name].mjs",
|
||||||
|
@@ ... @@
|
||||||
|
- "filename": "[name].js",
|
||||||
|
+ "filename": "[name].mjs",
|
||||||
|
@@ ... @@
|
||||||
|
- "hotUpdateChunkFilename": "[id].[fullhash].hot-update.js",
|
||||||
|
+ "hotUpdateChunkFilename": "[id].[fullhash].hot-update.mjs",
|
||||||
|
@@ ... @@
|
||||||
- "iife": true,
|
- "iife": true,
|
||||||
+ "iife": false,
|
+ "iife": false,
|
||||||
@@ ... @@
|
@@ ... @@
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("graceful-fs");
|
const fs = require("graceful-fs");
|
||||||
const vm = require("vm");
|
const vm = require("vm");
|
||||||
|
const { pathToFileURL } = require("url");
|
||||||
const rimraf = require("rimraf");
|
const rimraf = require("rimraf");
|
||||||
const webpack = require("..");
|
const webpack = require("..");
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
@ -122,7 +123,7 @@ const describeCases = config => {
|
||||||
output: {
|
output: {
|
||||||
pathinfo: true,
|
pathinfo: true,
|
||||||
path: outputDirectory,
|
path: outputDirectory,
|
||||||
filename: "bundle.js"
|
filename: config.module ? "bundle.mjs" : "bundle.js"
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: ["web_modules", "node_modules"],
|
modules: ["web_modules", "node_modules"],
|
||||||
|
@ -186,7 +187,8 @@ const describeCases = config => {
|
||||||
}),
|
}),
|
||||||
experiments: {
|
experiments: {
|
||||||
asyncWebAssembly: true,
|
asyncWebAssembly: true,
|
||||||
topLevelAwait: true
|
topLevelAwait: true,
|
||||||
|
...(config.module ? { outputModule: true } : {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
beforeAll(done => {
|
beforeAll(done => {
|
||||||
|
@ -309,6 +311,38 @@ const describeCases = config => {
|
||||||
function _require(module) {
|
function _require(module) {
|
||||||
if (module.substr(0, 2) === "./") {
|
if (module.substr(0, 2) === "./") {
|
||||||
const p = path.join(outputDirectory, module);
|
const p = path.join(outputDirectory, module);
|
||||||
|
if (p.endsWith(".mjs")) {
|
||||||
|
const module = new vm.SourceTextModule(
|
||||||
|
`import { it, expect } from "TEST_ENV";
|
||||||
|
function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }
|
||||||
|
${fs.readFileSync(p, "utf-8")}`,
|
||||||
|
{
|
||||||
|
identifier: p,
|
||||||
|
lineOffset: 1,
|
||||||
|
initializeImportMeta: (meta, module) => {
|
||||||
|
meta.url = pathToFileURL(p);
|
||||||
|
},
|
||||||
|
importModuleDynamically: (specifier, module) => {
|
||||||
|
return _require(specifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return module
|
||||||
|
.link((specifier, module) => {
|
||||||
|
if (specifier === "TEST_ENV") {
|
||||||
|
const m = new vm.SyntheticModule(
|
||||||
|
["it", "expect"],
|
||||||
|
function () {
|
||||||
|
this.setExport("it", _it);
|
||||||
|
this.setExport("expect", expect);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => module.evaluate())
|
||||||
|
.then(() => module.namespace);
|
||||||
|
} else {
|
||||||
const fn = vm.runInThisContext(
|
const fn = vm.runInThisContext(
|
||||||
"(function(require, module, exports, __dirname, __filename, it, expect) {" +
|
"(function(require, module, exports, __dirname, __filename, it, expect) {" +
|
||||||
"global.expect = expect;" +
|
"global.expect = expect;" +
|
||||||
|
@ -332,13 +366,18 @@ const describeCases = config => {
|
||||||
expect
|
expect
|
||||||
);
|
);
|
||||||
return m.exports;
|
return m.exports;
|
||||||
|
}
|
||||||
} else return require(module);
|
} else return require(module);
|
||||||
}
|
}
|
||||||
_require.webpackTestSuiteRequire = true;
|
_require.webpackTestSuiteRequire = true;
|
||||||
_require("./bundle.js");
|
const promise = _require("./" + options.output.filename);
|
||||||
|
if (promise && promise.then) promise.then(finish);
|
||||||
|
else finish();
|
||||||
|
function finish() {
|
||||||
if (getNumberOfTests() === 0)
|
if (getNumberOfTests() === 0)
|
||||||
return done(new Error("No tests exported by test case"));
|
return done(new Error("No tests exported by test case"));
|
||||||
done();
|
done();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
10000
|
10000
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
const { describeCases } = require("./TestCases.template");
|
||||||
|
const vm = require("vm");
|
||||||
|
|
||||||
|
describe("TestCases", () => {
|
||||||
|
if (!vm.SourceTextModule) {
|
||||||
|
it("module can't run without --experimental-vm-modules");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
describeCases({
|
||||||
|
name: "module",
|
||||||
|
module: true
|
||||||
|
});
|
||||||
|
});
|
|
@ -1673,8 +1673,8 @@ webpack x.x.x compiled successfully in X ms"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`StatsTestCases should print correct stats for output-module 1`] = `
|
exports[`StatsTestCases should print correct stats for output-module 1`] = `
|
||||||
"asset main.js 9.95 KiB [emitted] [javascript module] (name: main)
|
"asset main.mjs 9.95 KiB [emitted] [javascript module] (name: main)
|
||||||
asset 52.js 417 bytes [emitted] [javascript module]
|
asset 52.mjs 417 bytes [emitted] [javascript module]
|
||||||
runtime modules 6.01 KiB 8 modules
|
runtime modules 6.01 KiB 8 modules
|
||||||
orphan modules 38 bytes [orphan] 1 module
|
orphan modules 38 bytes [orphan] 1 module
|
||||||
cacheable modules 263 bytes
|
cacheable modules 263 bytes
|
||||||
|
|
|
@ -2,6 +2,21 @@ const path = require("path");
|
||||||
const webpack = require("../../../../");
|
const webpack = require("../../../../");
|
||||||
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
||||||
module.exports = (env, { testPath }) => [
|
module.exports = (env, { testPath }) => [
|
||||||
|
{
|
||||||
|
output: {
|
||||||
|
filename: "esm.js",
|
||||||
|
libraryTarget: "module"
|
||||||
|
},
|
||||||
|
target: "node14",
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
external: "./non-external"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
output: {
|
output: {
|
||||||
filename: "commonjs.js",
|
filename: "commonjs.js",
|
||||||
|
|
|
@ -2,6 +2,18 @@ var webpack = require("../../../../");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
||||||
module.exports = (env, { testPath }) => [
|
module.exports = (env, { testPath }) => [
|
||||||
|
{
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
library: path.resolve(testPath, "../0-create-library/esm.js")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
NAME: JSON.stringify("esm")
|
||||||
|
})
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export default 42;
|
|
@ -0,0 +1,12 @@
|
||||||
|
it("should execute as module", () => {
|
||||||
|
expect(
|
||||||
|
(function () {
|
||||||
|
return !this;
|
||||||
|
})()
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be able to load a chunk", async () => {
|
||||||
|
const module = await import("./chunk");
|
||||||
|
expect(module.default).toBe(42);
|
||||||
|
});
|
|
@ -0,0 +1,7 @@
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
experiments: {
|
||||||
|
outputModule: true
|
||||||
|
},
|
||||||
|
target: "node14"
|
||||||
|
};
|
|
@ -9671,6 +9671,7 @@ declare abstract class RuntimeTemplate {
|
||||||
expressionFunction(expression?: any, args?: string): string;
|
expressionFunction(expression?: any, args?: string): string;
|
||||||
emptyFunction(): "x => {}" | "function() {}";
|
emptyFunction(): "x => {}" | "function() {}";
|
||||||
destructureArray(items?: any, value?: any): string;
|
destructureArray(items?: any, value?: any): string;
|
||||||
|
destructureObject(items?: any, value?: any): string;
|
||||||
iife(args?: any, body?: any): string;
|
iife(args?: any, body?: any): string;
|
||||||
forEach(variable?: any, array?: any, body?: any): string;
|
forEach(variable?: any, array?: any, body?: any): string;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue