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) {
|
||||
return `(${this.basicFunction(args, body)})()`;
|
||||
}
|
||||
|
|
|
@ -139,10 +139,11 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
new CommonJsChunkFormatPlugin().apply(compiler);
|
||||
break;
|
||||
}
|
||||
case "module":
|
||||
throw new Error(
|
||||
"EcmaScript Module Chunk Format is not implemented yet"
|
||||
);
|
||||
case "module": {
|
||||
const ModuleChunkFormatPlugin = require("./esm/ModuleChunkFormatPlugin");
|
||||
new ModuleChunkFormatPlugin().apply(compiler);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(
|
||||
"Unsupported chunk format '" + options.output.chunkFormat + "'."
|
||||
|
|
|
@ -182,6 +182,11 @@ const applyWebpackOptionsDefaults = options => {
|
|||
applyOutputDefaults(options.output, {
|
||||
context: options.context,
|
||||
targetProperties,
|
||||
isAffectedByBrowserslist:
|
||||
target === undefined ||
|
||||
(typeof target === "string" && target.startsWith("browserslist")) ||
|
||||
(Array.isArray(target) &&
|
||||
target.some(target => target.startsWith("browserslist"))),
|
||||
outputModule: options.experiments.outputModule,
|
||||
development,
|
||||
entry: options.entry,
|
||||
|
@ -543,6 +548,7 @@ const applyModuleDefaults = (
|
|||
* @param {Object} options options
|
||||
* @param {string} options.context context
|
||||
* @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.development is development mode
|
||||
* @param {Entry} options.entry entry option
|
||||
|
@ -551,7 +557,15 @@ const applyModuleDefaults = (
|
|||
*/
|
||||
const applyOutputDefaults = (
|
||||
output,
|
||||
{ context, targetProperties: tp, outputModule, development, entry, module }
|
||||
{
|
||||
context,
|
||||
targetProperties: tp,
|
||||
isAffectedByBrowserslist,
|
||||
outputModule,
|
||||
development,
|
||||
entry,
|
||||
module
|
||||
}
|
||||
) => {
|
||||
/**
|
||||
* @param {Library=} library the library option
|
||||
|
@ -591,8 +605,8 @@ const applyOutputDefaults = (
|
|||
}
|
||||
});
|
||||
|
||||
D(output, "filename", "[name].js");
|
||||
F(output, "module", () => !!outputModule);
|
||||
D(output, "filename", output.module ? "[name].mjs" : "[name].js");
|
||||
F(output, "iife", () => !output.module);
|
||||
D(output, "importFunctionName", "import");
|
||||
D(output, "importMetaName", "import.meta");
|
||||
|
@ -608,7 +622,7 @@ const applyOutputDefaults = (
|
|||
// Otherwise prefix "[id]." in front of the basename to make it changing
|
||||
return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2");
|
||||
}
|
||||
return "[id].js";
|
||||
return output.module ? "[id].mjs" : "[id].js";
|
||||
});
|
||||
D(output, "assetModuleFilename", "[hash][ext][query]");
|
||||
D(output, "webassemblyModuleFilename", "[hash].module.wasm");
|
||||
|
@ -633,13 +647,34 @@ const applyOutputDefaults = (
|
|||
});
|
||||
F(output, "chunkFormat", () => {
|
||||
if (tp) {
|
||||
if (tp.document) return "array-push";
|
||||
if (tp.require) return "commonjs";
|
||||
if (tp.nodeBuiltins) return "commonjs";
|
||||
if (tp.importScripts) return "array-push";
|
||||
if (tp.dynamicImport && output.module) return "module";
|
||||
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.require) return "commonjs";
|
||||
if (tp.nodeBuiltins) return "commonjs";
|
||||
if (tp.importScripts) return "array-push";
|
||||
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", () => {
|
||||
if (tp) {
|
||||
|
@ -709,7 +744,11 @@ const applyOutputDefaults = (
|
|||
F(output, "path", () => path.join(process.cwd(), "dist"));
|
||||
F(output, "pathinfo", () => development);
|
||||
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, "crossOriginLoading", 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);
|
||||
break;
|
||||
}
|
||||
case "import":
|
||||
// TODO implement import chunk loading
|
||||
throw new Error("Chunk Loading via import() is not implemented yet");
|
||||
case "import": {
|
||||
const ModuleChunkLoadingPlugin = require("../esm/ModuleChunkLoadingPlugin");
|
||||
new ModuleChunkLoadingPlugin().apply(compiler);
|
||||
break;
|
||||
}
|
||||
case "universal":
|
||||
// TODO implement universal chunk loading
|
||||
throw new Error("Universal Chunk Loading is not implemented yet");
|
||||
|
|
18
package.json
18
package.json
|
@ -131,11 +131,11 @@
|
|||
],
|
||||
"scripts": {
|
||||
"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:integration": "node --max-old-space-size=4096 --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:unit": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.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 --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 --experimental-vm-modules --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\"",
|
||||
"travis:integration": "yarn cover:integration --ci $JEST",
|
||||
"travis:basic": "yarn cover:basic --ci $JEST",
|
||||
"travis:lintunit": "yarn lint && yarn cover:unit --ci $JEST",
|
||||
|
@ -162,13 +162,13 @@
|
|||
"pretty-lint": "yarn pretty-lint-base --check",
|
||||
"yarn-lint": "yarn-deduplicate --fail --list -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:clean": "rimraf .nyc_output coverage",
|
||||
"cover:all": "node --max-old-space-size=4096 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:integration": "node --max-old-space-size=4096 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: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 --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 --experimental-vm-modules node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.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:merge": "nyc merge .nyc_output coverage/coverage-nyc.json && rimraf .nyc_output",
|
||||
"cover:report": "nyc report -t coverage"
|
||||
|
|
|
@ -84,7 +84,12 @@ const describeCases = config => {
|
|||
if (typeof options.output.pathinfo === "undefined")
|
||||
options.output.pathinfo = true;
|
||||
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) {
|
||||
options.cache = {
|
||||
cacheDirectory,
|
||||
|
@ -295,7 +300,12 @@ const describeCases = config => {
|
|||
|
||||
const requireCache = Object.create(null);
|
||||
// eslint-disable-next-line no-loop-func
|
||||
const _require = (currentDirectory, options, module) => {
|
||||
const _require = (
|
||||
currentDirectory,
|
||||
options,
|
||||
module,
|
||||
esmModule
|
||||
) => {
|
||||
if (Array.isArray(module) || /^\.\.?\//.test(module)) {
|
||||
let content;
|
||||
let p;
|
||||
|
@ -339,35 +349,13 @@ const describeCases = config => {
|
|||
};
|
||||
requireCache[p] = m;
|
||||
let runInNewContext = false;
|
||||
let oldCurrentScript = document.currentScript;
|
||||
document.currentScript = new CurrentScript(subPath);
|
||||
|
||||
const moduleScope = {
|
||||
require: _require.bind(
|
||||
null,
|
||||
path.dirname(p),
|
||||
options
|
||||
),
|
||||
importScripts: url => {
|
||||
expect(url).toMatch(
|
||||
/^https:\/\/test\.cases\/path\//
|
||||
);
|
||||
_require(
|
||||
outputDirectory,
|
||||
options,
|
||||
`.${url.slice("https://test.cases/path".length)}`
|
||||
);
|
||||
},
|
||||
module: m,
|
||||
exports: m.exports,
|
||||
__dirname: path.dirname(p),
|
||||
__filename: p,
|
||||
it: _it,
|
||||
beforeEach: _beforeEach,
|
||||
afterEach: _afterEach,
|
||||
expect,
|
||||
jest,
|
||||
_globalAssign: { expect },
|
||||
__STATS__: jsonStats,
|
||||
nsObj: m => {
|
||||
Object.defineProperty(m, Symbol.toStringTag, {
|
||||
|
@ -376,6 +364,36 @@ const describeCases = config => {
|
|||
return m;
|
||||
}
|
||||
};
|
||||
const isModule =
|
||||
p.endsWith(".mjs") &&
|
||||
options.experiments &&
|
||||
options.experiments.outputModule;
|
||||
if (!isModule) {
|
||||
Object.assign(moduleScope, {
|
||||
require: _require.bind(
|
||||
null,
|
||||
path.dirname(p),
|
||||
options
|
||||
),
|
||||
importScripts: url => {
|
||||
expect(url).toMatch(
|
||||
/^https:\/\/test\.cases\/path\//
|
||||
);
|
||||
_require(
|
||||
outputDirectory,
|
||||
options,
|
||||
`.${url.slice(
|
||||
"https://test.cases/path".length
|
||||
)}`
|
||||
);
|
||||
},
|
||||
module: m,
|
||||
exports: m.exports,
|
||||
__dirname: path.dirname(p),
|
||||
__filename: p,
|
||||
_globalAssign: { expect }
|
||||
});
|
||||
}
|
||||
if (
|
||||
options.target === "web" ||
|
||||
options.target === "webworker"
|
||||
|
@ -392,21 +410,88 @@ const describeCases = config => {
|
|||
if (testConfig.moduleScope) {
|
||||
testConfig.moduleScope(moduleScope);
|
||||
}
|
||||
const args = Object.keys(moduleScope);
|
||||
const argValues = args.map(arg => moduleScope[arg]);
|
||||
if (!runInNewContext)
|
||||
content = `Object.assign(global, _globalAssign); ${content}`;
|
||||
const code = `(function(${args.join(
|
||||
", "
|
||||
)}) {${content}\n})`;
|
||||
const fn = runInNewContext
|
||||
? vm.runInNewContext(code, globalContext, p)
|
||||
: vm.runInThisContext(code, p);
|
||||
fn.call(m.exports, ...argValues);
|
||||
|
||||
//restore state
|
||||
document.currentScript = oldCurrentScript;
|
||||
if (isModule) {
|
||||
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)
|
||||
content = `Object.assign(global, _globalAssign); ${content}`;
|
||||
const args = Object.keys(moduleScope);
|
||||
const argValues = args.map(arg => moduleScope[arg]);
|
||||
const code = `(function(${args.join(
|
||||
", "
|
||||
)}) {${content}\n})`;
|
||||
|
||||
let oldCurrentScript = document.currentScript;
|
||||
document.currentScript = new CurrentScript(subPath);
|
||||
const fn = runInNewContext
|
||||
? vm.runInNewContext(code, globalContext, p)
|
||||
: vm.runInThisContext(code, p);
|
||||
fn.call(m.exports, ...argValues);
|
||||
document.currentScript = oldCurrentScript;
|
||||
}
|
||||
return m.exports;
|
||||
} else if (
|
||||
testConfig.modules &&
|
||||
|
|
|
@ -861,6 +861,15 @@ describe("Defaults", () => {
|
|||
- "externalsType": "var",
|
||||
+ "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": false,
|
||||
@@ ... @@
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
const path = require("path");
|
||||
const fs = require("graceful-fs");
|
||||
const vm = require("vm");
|
||||
const { pathToFileURL } = require("url");
|
||||
const rimraf = require("rimraf");
|
||||
const webpack = require("..");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
|
@ -122,7 +123,7 @@ const describeCases = config => {
|
|||
output: {
|
||||
pathinfo: true,
|
||||
path: outputDirectory,
|
||||
filename: "bundle.js"
|
||||
filename: config.module ? "bundle.mjs" : "bundle.js"
|
||||
},
|
||||
resolve: {
|
||||
modules: ["web_modules", "node_modules"],
|
||||
|
@ -186,7 +187,8 @@ const describeCases = config => {
|
|||
}),
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
topLevelAwait: true
|
||||
topLevelAwait: true,
|
||||
...(config.module ? { outputModule: true } : {})
|
||||
}
|
||||
};
|
||||
beforeAll(done => {
|
||||
|
@ -309,36 +311,73 @@ const describeCases = config => {
|
|||
function _require(module) {
|
||||
if (module.substr(0, 2) === "./") {
|
||||
const p = path.join(outputDirectory, module);
|
||||
const fn = vm.runInThisContext(
|
||||
"(function(require, module, exports, __dirname, __filename, it, expect) {" +
|
||||
"global.expect = expect;" +
|
||||
'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' +
|
||||
fs.readFileSync(p, "utf-8") +
|
||||
"\n})",
|
||||
p
|
||||
);
|
||||
const m = {
|
||||
exports: {},
|
||||
webpackTestSuiteModule: true
|
||||
};
|
||||
fn.call(
|
||||
m.exports,
|
||||
_require,
|
||||
m,
|
||||
m.exports,
|
||||
outputDirectory,
|
||||
p,
|
||||
_it,
|
||||
expect
|
||||
);
|
||||
return m.exports;
|
||||
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(
|
||||
"(function(require, module, exports, __dirname, __filename, it, expect) {" +
|
||||
"global.expect = expect;" +
|
||||
'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' +
|
||||
fs.readFileSync(p, "utf-8") +
|
||||
"\n})",
|
||||
p
|
||||
);
|
||||
const m = {
|
||||
exports: {},
|
||||
webpackTestSuiteModule: true
|
||||
};
|
||||
fn.call(
|
||||
m.exports,
|
||||
_require,
|
||||
m,
|
||||
m.exports,
|
||||
outputDirectory,
|
||||
p,
|
||||
_it,
|
||||
expect
|
||||
);
|
||||
return m.exports;
|
||||
}
|
||||
} else return require(module);
|
||||
}
|
||||
_require.webpackTestSuiteRequire = true;
|
||||
_require("./bundle.js");
|
||||
if (getNumberOfTests() === 0)
|
||||
return done(new Error("No tests exported by test case"));
|
||||
done();
|
||||
const promise = _require("./" + options.output.filename);
|
||||
if (promise && promise.then) promise.then(finish);
|
||||
else finish();
|
||||
function finish() {
|
||||
if (getNumberOfTests() === 0)
|
||||
return done(new Error("No tests exported by test case"));
|
||||
done();
|
||||
}
|
||||
},
|
||||
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`] = `
|
||||
"asset main.js 9.95 KiB [emitted] [javascript module] (name: main)
|
||||
asset 52.js 417 bytes [emitted] [javascript module]
|
||||
"asset main.mjs 9.95 KiB [emitted] [javascript module] (name: main)
|
||||
asset 52.mjs 417 bytes [emitted] [javascript module]
|
||||
runtime modules 6.01 KiB 8 modules
|
||||
orphan modules 38 bytes [orphan] 1 module
|
||||
cacheable modules 263 bytes
|
||||
|
|
|
@ -2,6 +2,21 @@ const path = require("path");
|
|||
const webpack = require("../../../../");
|
||||
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
||||
module.exports = (env, { testPath }) => [
|
||||
{
|
||||
output: {
|
||||
filename: "esm.js",
|
||||
libraryTarget: "module"
|
||||
},
|
||||
target: "node14",
|
||||
resolve: {
|
||||
alias: {
|
||||
external: "./non-external"
|
||||
}
|
||||
},
|
||||
experiments: {
|
||||
outputModule: true
|
||||
}
|
||||
},
|
||||
{
|
||||
output: {
|
||||
filename: "commonjs.js",
|
||||
|
|
|
@ -2,6 +2,18 @@ var webpack = require("../../../../");
|
|||
var path = require("path");
|
||||
/** @type {function(any, any): import("../../../../").Configuration[]} */
|
||||
module.exports = (env, { testPath }) => [
|
||||
{
|
||||
resolve: {
|
||||
alias: {
|
||||
library: path.resolve(testPath, "../0-create-library/esm.js")
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
NAME: JSON.stringify("esm")
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
resolve: {
|
||||
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;
|
||||
emptyFunction(): "x => {}" | "function() {}";
|
||||
destructureArray(items?: any, value?: any): string;
|
||||
destructureObject(items?: any, value?: any): string;
|
||||
iife(args?: any, body?: any): string;
|
||||
forEach(variable?: any, array?: any, body?: any): string;
|
||||
|
||||
|
|
Loading…
Reference in New Issue