new Worker() support
add support for async anonymous entrypoints from inside the codebase add worker example move entry options into Entrypoint and receive them from there
This commit is contained in:
parent
3f12b0fa27
commit
ed06a7f83a
|
@ -179,6 +179,7 @@
|
|||
"analysing",
|
||||
"etags",
|
||||
"destructure",
|
||||
"onconnect",
|
||||
|
||||
"webassemblyjs",
|
||||
"fsevents",
|
||||
|
|
|
@ -1759,6 +1759,10 @@ export interface Output {
|
|||
* The filename of WebAssembly modules as relative path inside the `output.path` directory.
|
||||
*/
|
||||
webassemblyModuleFilename?: WebassemblyModuleFilename;
|
||||
/**
|
||||
* The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).
|
||||
*/
|
||||
workerChunkLoading?: ChunkLoading;
|
||||
}
|
||||
/**
|
||||
* Configuration object for web performance recommendations.
|
||||
|
@ -2361,6 +2365,10 @@ export interface OutputNormalized {
|
|||
* The filename of WebAssembly modules as relative path inside the `output.path` directory.
|
||||
*/
|
||||
webassemblyModuleFilename?: WebassemblyModuleFilename;
|
||||
/**
|
||||
* The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).
|
||||
*/
|
||||
workerChunkLoading?: ChunkLoading;
|
||||
}
|
||||
/**
|
||||
* Normalized webpack options object.
|
||||
|
|
|
@ -14,9 +14,7 @@ function lessStrict(regExpStr) {
|
|||
}
|
||||
|
||||
const runtimeModulesRegexp = /(\/\*{72}\/\n(?:\/(?:\*{6}|\*{72})\/.*\n)*\/\*{72}\/\n)/g;
|
||||
const timeRegexp = /\s*Time: \d+ ms/g;
|
||||
const buildAtRegexp = /\s*Built at: .+/mg;
|
||||
const hashRegexp = /Hash: [a-f0-9]+/g;
|
||||
const timeRegexp = / in \d+ ms/g;
|
||||
const dataUrlRegexp = /("data:[^"]+")/g;
|
||||
|
||||
exports.replaceBase = (template) => {
|
||||
|
@ -40,8 +38,6 @@ exports.replaceBase = (template) => {
|
|||
.replace(webpack, "(webpack)")
|
||||
.replace(webpackParent, "(webpack)/~")
|
||||
.replace(timeRegexp, "")
|
||||
.replace(buildAtRegexp, "")
|
||||
.replace(hashRegexp, "Hash: 0a1b2c3d4e5f6a7b8c9d")
|
||||
.replace(dataUrlRegexp, function(match) {
|
||||
if(match.length < 100) return match;
|
||||
return match.slice(0, 50) + "..." + match.slice(-10);
|
||||
|
|
|
@ -0,0 +1,809 @@
|
|||
# example.js
|
||||
|
||||
```javascript
|
||||
document.body.innerHTML = `
|
||||
<pre id="history"></pre>
|
||||
<form>
|
||||
<input id="message" type="text">
|
||||
<button id="send">Send Message</button>
|
||||
</form>
|
||||
<p>Computing fibonacci without worker:</p>
|
||||
<input id="fib1" type="number">
|
||||
<pre id="output1"></pre>
|
||||
<p>Computing fibonacci with worker:</p>
|
||||
<input id="fib2" type="number">
|
||||
<pre id="output2"></pre>
|
||||
`;
|
||||
|
||||
const history = document.getElementById("history");
|
||||
const message = document.getElementById("message");
|
||||
const send = document.getElementById("send");
|
||||
const fib1 = document.getElementById("fib1");
|
||||
const output1 = document.getElementById("output1");
|
||||
const fib2 = document.getElementById("fib2");
|
||||
const output2 = document.getElementById("output2");
|
||||
|
||||
/// CHAT with shared worker ///
|
||||
|
||||
const chatWorker = new SharedWorker(
|
||||
new URL("./chat-worker.js", import.meta.url),
|
||||
{
|
||||
name: "chat"
|
||||
}
|
||||
);
|
||||
|
||||
let historyTimeout;
|
||||
const scheduleUpdateHistory = () => {
|
||||
clearTimeout(historyTimeout);
|
||||
historyTimeout = setTimeout(() => {
|
||||
chatWorker.port.postMessage({ type: "history" });
|
||||
}, 1000);
|
||||
};
|
||||
scheduleUpdateHistory();
|
||||
|
||||
const from = `User ${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
send.addEventListener("click", e => {
|
||||
chatWorker.port.postMessage({
|
||||
type: "message",
|
||||
content: message.value,
|
||||
from
|
||||
});
|
||||
message.value = "";
|
||||
message.focus();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
chatWorker.port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "history":
|
||||
history.innerText = msg.history.join("\n");
|
||||
scheduleUpdateHistory();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/// FIBONACCI without worker ///
|
||||
|
||||
fib1.addEventListener("change", async () => {
|
||||
try {
|
||||
const value = parseInt(fib1.value, 10);
|
||||
const { fibonacci } = await import("./fibonacci");
|
||||
const result = fibonacci(value);
|
||||
output1.innerText = `fib(${value}) = ${result}`;
|
||||
} catch (e) {
|
||||
output1.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
/// FIBONACCI with worker ///
|
||||
|
||||
const fibWorker = new Worker(new URL("./fib-worker.js", import.meta.url), {
|
||||
name: "fibonacci"
|
||||
/* webpackEntryOptions: { filename: "workers/[name].js" } */
|
||||
});
|
||||
|
||||
fib2.addEventListener("change", () => {
|
||||
try {
|
||||
const value = parseInt(fib2.value, 10);
|
||||
fibWorker.postMessage(`${value}`);
|
||||
} catch (e) {
|
||||
output2.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
fibWorker.onmessage = event => {
|
||||
output2.innerText = event.data;
|
||||
};
|
||||
```
|
||||
|
||||
# fib-worker.js
|
||||
|
||||
```javascript
|
||||
onmessage = async event => {
|
||||
const { fibonacci } = await import("./fibonacci");
|
||||
const value = JSON.parse(event.data);
|
||||
postMessage(`fib(${value}) = ${fibonacci(value)}`);
|
||||
};
|
||||
```
|
||||
|
||||
# fibonacci.js
|
||||
|
||||
```javascript
|
||||
export function fibonacci(n) {
|
||||
return n < 1 ? 0 : n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
||||
```
|
||||
|
||||
# chat-worker.js
|
||||
|
||||
```javascript
|
||||
import { history, add } from "./chat-module";
|
||||
|
||||
onconnect = function (e) {
|
||||
for (const port of e.ports) {
|
||||
port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "message":
|
||||
add(msg.content, msg.from);
|
||||
// fallthrough
|
||||
case "history":
|
||||
port.postMessage({
|
||||
type: "history",
|
||||
history
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
# chat-module.js
|
||||
|
||||
```javascript
|
||||
export const history = [];
|
||||
|
||||
export const add = (content, from) => {
|
||||
if (history.length > 10) history.shift();
|
||||
history.push(`${from}: ${content}`);
|
||||
};
|
||||
```
|
||||
|
||||
# dist/main.js
|
||||
|
||||
```javascript
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ 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
|
||||
/******/ if(__webpack_module_cache__[moduleId]) {
|
||||
/******/ return __webpack_module_cache__[moduleId].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 not based on template
|
||||
/******/ if (chunkId === 631) return "workers/fibonacci.js";
|
||||
/******/ // return url for filenames based on template
|
||||
/******/ return "" + (chunkId === 348 ? "chat" : chunkId) + ".js";
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/load script */
|
||||
/******/ (() => {
|
||||
/******/ var inProgress = {};
|
||||
/******/ // data-webpack is not used as build has no uniqueName
|
||||
/******/ // loadScript function to load a script via script tag
|
||||
/******/ __webpack_require__.l = (url, done, key) => {
|
||||
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
|
||||
/******/ var script, needAttach;
|
||||
/******/ if(key !== undefined) {
|
||||
/******/ var scripts = document.getElementsByTagName("script");
|
||||
/******/ for(var i = 0; i < scripts.length; i++) {
|
||||
/******/ var s = scripts[i];
|
||||
/******/ if(s.getAttribute("src") == url) { script = s; break; }
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(!script) {
|
||||
/******/ needAttach = true;
|
||||
/******/ script = document.createElement('script');
|
||||
/******/
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.timeout = 120;
|
||||
/******/ if (__webpack_require__.nc) {
|
||||
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ script.src = url;
|
||||
/******/ }
|
||||
/******/ inProgress[url] = [done];
|
||||
/******/ var onScriptComplete = (prev, event) => {
|
||||
/******/ // avoid mem leaks in IE.
|
||||
/******/ script.onerror = script.onload = null;
|
||||
/******/ clearTimeout(timeout);
|
||||
/******/ var doneFns = inProgress[url];
|
||||
/******/ delete inProgress[url];
|
||||
/******/ script.parentNode && script.parentNode.removeChild(script);
|
||||
/******/ doneFns && doneFns.forEach((fn) => fn(event));
|
||||
/******/ if(prev) return prev(event);
|
||||
/******/ }
|
||||
/******/ ;
|
||||
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
|
||||
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
|
||||
/******/ script.onload = onScriptComplete.bind(null, script.onload);
|
||||
/******/ needAttach && document.head.appendChild(script);
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/publicPath */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.p = "dist/";
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/jsonp chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.b = document.baseURI || self.location.href;
|
||||
/******/
|
||||
/******/ // object to store loaded and loading chunks
|
||||
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||||
/******/ // Promise = chunk loading, 0 = chunk loaded
|
||||
/******/ var installedChunks = {
|
||||
/******/ 179: 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[2]);
|
||||
/******/ } else {
|
||||
/******/ if(true) { // all chunks have JS
|
||||
/******/ // setup Promise in chunk cache
|
||||
/******/ var promise = new Promise((resolve, reject) => {
|
||||
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
|
||||
/******/ });
|
||||
/******/ promises.push(installedChunkData[2] = promise);
|
||||
/******/
|
||||
/******/ // start chunk loading
|
||||
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
|
||||
/******/ // create error before stack unwound to get useful stacktrace later
|
||||
/******/ var error = new Error();
|
||||
/******/ var loadingEnded = (event) => {
|
||||
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
|
||||
/******/ installedChunkData = installedChunks[chunkId];
|
||||
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
|
||||
/******/ if(installedChunkData) {
|
||||
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||
/******/ var realSrc = event && event.target && event.target.src;
|
||||
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||
/******/ error.name = 'ChunkLoadError';
|
||||
/******/ error.type = errorType;
|
||||
/******/ error.request = realSrc;
|
||||
/******/ installedChunkData[1](error);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId);
|
||||
/******/ } else installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // no prefetching
|
||||
/******/
|
||||
/******/ // no preloaded
|
||||
/******/
|
||||
/******/ // no HMR
|
||||
/******/
|
||||
/******/ // no HMR manifest
|
||||
/******/
|
||||
/******/ // no deferred startup
|
||||
/******/
|
||||
/******/ // install a JSONP callback for chunk loading
|
||||
/******/ var webpackJsonpCallback = (data) => {
|
||||
/******/ var [chunkIds, moreModules, runtime] = data;
|
||||
/******/ // add "moreModules" to the modules object,
|
||||
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||||
/******/ var moduleId, chunkId, i = 0, resolves = [];
|
||||
/******/ for(;i < chunkIds.length; i++) {
|
||||
/******/ chunkId = chunkIds[i];
|
||||
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||||
/******/ resolves.push(installedChunks[chunkId][0]);
|
||||
/******/ }
|
||||
/******/ installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ for(moduleId in moreModules) {
|
||||
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
||||
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(runtime) runtime(__webpack_require__);
|
||||
/******/ parentChunkLoadingFunction(data);
|
||||
/******/ while(resolves.length) {
|
||||
/******/ resolves.shift()();
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
|
||||
/******/ var parentChunkLoadingFunction = chunkLoadingGlobal.push.bind(chunkLoadingGlobal);
|
||||
/******/ chunkLoadingGlobal.push = webpackJsonpCallback;
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
``` js
|
||||
/*!********************!*\
|
||||
!*** ./example.js ***!
|
||||
\********************/
|
||||
/*! unknown exports (runtime-defined) */
|
||||
/*! runtime requirements: __webpack_require__.p, __webpack_require__.b, __webpack_require__.u, __webpack_require__.e, __webpack_require__, __webpack_require__.* */
|
||||
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
|
||||
document.body.innerHTML = `
|
||||
<pre id="history"></pre>
|
||||
<form>
|
||||
<input id="message" type="text">
|
||||
<button id="send">Send Message</button>
|
||||
</form>
|
||||
<p>Computing fibonacci without worker:</p>
|
||||
<input id="fib1" type="number">
|
||||
<pre id="output1"></pre>
|
||||
<p>Computing fibonacci with worker:</p>
|
||||
<input id="fib2" type="number">
|
||||
<pre id="output2"></pre>
|
||||
`;
|
||||
|
||||
const history = document.getElementById("history");
|
||||
const message = document.getElementById("message");
|
||||
const send = document.getElementById("send");
|
||||
const fib1 = document.getElementById("fib1");
|
||||
const output1 = document.getElementById("output1");
|
||||
const fib2 = document.getElementById("fib2");
|
||||
const output2 = document.getElementById("output2");
|
||||
|
||||
/// CHAT with shared worker ///
|
||||
|
||||
const chatWorker = new SharedWorker(
|
||||
new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u(348), __webpack_require__.b),
|
||||
{
|
||||
name: "chat"
|
||||
}
|
||||
);
|
||||
|
||||
let historyTimeout;
|
||||
const scheduleUpdateHistory = () => {
|
||||
clearTimeout(historyTimeout);
|
||||
historyTimeout = setTimeout(() => {
|
||||
chatWorker.port.postMessage({ type: "history" });
|
||||
}, 1000);
|
||||
};
|
||||
scheduleUpdateHistory();
|
||||
|
||||
const from = `User ${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
send.addEventListener("click", e => {
|
||||
chatWorker.port.postMessage({
|
||||
type: "message",
|
||||
content: message.value,
|
||||
from
|
||||
});
|
||||
message.value = "";
|
||||
message.focus();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
chatWorker.port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "history":
|
||||
history.innerText = msg.history.join("\n");
|
||||
scheduleUpdateHistory();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/// FIBONACCI without worker ///
|
||||
|
||||
fib1.addEventListener("change", async () => {
|
||||
try {
|
||||
const value = parseInt(fib1.value, 10);
|
||||
const { fibonacci } = await __webpack_require__.e(/*! import() */ 129).then(__webpack_require__.bind(__webpack_require__, /*! ./fibonacci */ 2));
|
||||
const result = fibonacci(value);
|
||||
output1.innerText = `fib(${value}) = ${result}`;
|
||||
} catch (e) {
|
||||
output1.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
/// FIBONACCI with worker ///
|
||||
|
||||
const fibWorker = new Worker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u(631), __webpack_require__.b), {
|
||||
name: "fibonacci"
|
||||
/* webpackEntryOptions: { filename: "workers/[name].js" } */
|
||||
});
|
||||
|
||||
fib2.addEventListener("change", () => {
|
||||
try {
|
||||
const value = parseInt(fib2.value, 10);
|
||||
fibWorker.postMessage(`${value}`);
|
||||
} catch (e) {
|
||||
output2.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
fibWorker.onmessage = event => {
|
||||
output2.innerText = event.data;
|
||||
};
|
||||
|
||||
/******/ })()
|
||||
;
|
||||
```
|
||||
|
||||
# dist/chat.js
|
||||
|
||||
```javascript
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/*!************************************!*\
|
||||
!*** ./chat-worker.js + 1 modules ***!
|
||||
\************************************/
|
||||
/*! namespace exports */
|
||||
/*! runtime requirements: */
|
||||
|
||||
// CONCATENATED MODULE: ./chat-module.js
|
||||
const chat_module_history = [];
|
||||
|
||||
const add = (content, from) => {
|
||||
if (chat_module_history.length > 10) chat_module_history.shift();
|
||||
chat_module_history.push(`${from}: ${content}`);
|
||||
};
|
||||
|
||||
// CONCATENATED MODULE: ./chat-worker.js
|
||||
|
||||
|
||||
onconnect = function (e) {
|
||||
for (const port of e.ports) {
|
||||
port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "message":
|
||||
add(msg.content, msg.from);
|
||||
// fallthrough
|
||||
case "history":
|
||||
port.postMessage({
|
||||
type: "history",
|
||||
history: chat_module_history
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/******/ })()
|
||||
;
|
||||
```
|
||||
|
||||
```javascript
|
||||
(()=>{"use strict";const s=[];onconnect=function(t){for(const o of t.ports)o.onmessage=t=>{const e=t.data;switch(e.type){case"message":n=e.content,c=e.from,s.length>10&&s.shift(),s.push(`${c}: ${n}`);case"history":o.postMessage({type:"history",history:s})}var n,c}}})();
|
||||
```
|
||||
|
||||
# dist/workers/fibonacci.js
|
||||
|
||||
```javascript
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ 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
|
||||
/******/ if(__webpack_module_cache__[moduleId]) {
|
||||
/******/ return __webpack_module_cache__[moduleId].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 + ".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/publicPath */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.p = "dist/";
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/importScripts chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ // no baseURI
|
||||
/******/
|
||||
/******/ // object to store loaded chunks
|
||||
/******/ // "1" means "already loaded"
|
||||
/******/ var installedChunks = {
|
||||
/******/ 631: 1
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // importScripts chunk loading
|
||||
/******/ var chunkLoadingCallback = (data) => {
|
||||
/******/ var [chunkIds, moreModules, runtime] = data;
|
||||
/******/ for(var moduleId in moreModules) {
|
||||
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
||||
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(runtime) runtime(__webpack_require__);
|
||||
/******/ while(chunkIds.length)
|
||||
/******/ installedChunks[chunkIds.pop()] = 1;
|
||||
/******/ parentChunkLoadingFunction(data);
|
||||
/******/ };
|
||||
/******/ __webpack_require__.f.i = (chunkId, promises) => {
|
||||
/******/ // "1" is the signal for "already loaded"
|
||||
/******/ if(!installedChunks[chunkId]) {
|
||||
/******/ importScripts("../" + __webpack_require__.u(chunkId));
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
|
||||
/******/ var parentChunkLoadingFunction = chunkLoadingGlobal.push.bind(chunkLoadingGlobal);
|
||||
/******/ chunkLoadingGlobal.push = chunkLoadingCallback;
|
||||
/******/
|
||||
/******/ // no HMR
|
||||
/******/
|
||||
/******/ // no HMR manifest
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
``` js
|
||||
/*!***********************!*\
|
||||
!*** ./fib-worker.js ***!
|
||||
\***********************/
|
||||
/*! unknown exports (runtime-defined) */
|
||||
/*! runtime requirements: __webpack_require__.e, __webpack_require__, __webpack_require__.* */
|
||||
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
|
||||
onmessage = async event => {
|
||||
const { fibonacci } = await __webpack_require__.e(/*! import() */ 129).then(__webpack_require__.bind(__webpack_require__, /*! ./fibonacci */ 2));
|
||||
const value = JSON.parse(event.data);
|
||||
postMessage(`fib(${value}) = ${fibonacci(value)}`);
|
||||
};
|
||||
|
||||
/******/ })()
|
||||
;
|
||||
```
|
||||
|
||||
```javascript
|
||||
(()=>{var e={},r={};function o(t){if(r[t])return r[t].exports;var a=r[t]={exports:{}};return e[t](a,a.exports,o),a.exports}o.m=e,o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((r,t)=>(o.f[t](e,r),r),[])),o.u=e=>e+".js",o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.p="dist/",(()=>{var e={631:1};o.f.i=(r,t)=>{e[r]||importScripts("../"+o.u(r))};var r=self.webpackChunk=self.webpackChunk||[],t=r.push.bind(r);r.push=r=>{var[a,n,s]=r;for(var p in n)o.o(n,p)&&(o.m[p]=n[p]);for(s&&s(o);a.length;)e[a.pop()]=1;t(r)}})(),onmessage=async e=>{const{fibonacci:r}=await o.e(129).then(o.bind(o,129)),t=JSON.parse(e.data);postMessage(`fib(${t}) = ${r(t)}`)}})();
|
||||
```
|
||||
|
||||
# dist/129.js
|
||||
|
||||
```javascript
|
||||
(self["webpackChunk"] = self["webpackChunk"] || []).push([[129],{
|
||||
|
||||
/***/ 2:
|
||||
/*!**********************!*\
|
||||
!*** ./fibonacci.js ***!
|
||||
\**********************/
|
||||
/*! namespace exports */
|
||||
/*! export fibonacci [provided] [maybe used in main, fibonacci (runtime-defined)] [usage prevents renaming] */
|
||||
/*! other exports [not provided] [maybe used in main, fibonacci (runtime-defined)] */
|
||||
/*! runtime requirements: __webpack_require__.r, __webpack_exports__, __webpack_require__.d, __webpack_require__.* */
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ "fibonacci": () => /* binding */ fibonacci
|
||||
/* harmony export */ });
|
||||
function fibonacci(n) {
|
||||
return n < 1 ? 0 : n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
}]);
|
||||
```
|
||||
|
||||
# Info
|
||||
|
||||
## Unoptimized
|
||||
|
||||
```
|
||||
asset 129.js 907 bytes [emitted]
|
||||
asset chat.js 879 bytes [emitted] (name: chat)
|
||||
asset main.js 12.2 KiB [emitted] (name: main)
|
||||
asset workers/fibonacci.js 5.3 KiB [emitted] (name: fibonacci)
|
||||
chunk (runtime: fibonacci, main) 129.js 103 bytes [rendered]
|
||||
> ./fibonacci ./example.js 69:30-51
|
||||
> ./fibonacci ./fib-worker.js 2:29-50
|
||||
./fibonacci.js 103 bytes [built] [code generated]
|
||||
[exports: fibonacci]
|
||||
import() ./fibonacci ./example.js 69:30-51
|
||||
import() ./fibonacci ./fib-worker.js 2:29-50
|
||||
chunk (runtime: main) main.js (main) 2.22 KiB (javascript) 5.59 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
runtime modules 5.59 KiB 8 modules
|
||||
./example.js 2.22 KiB [built] [code generated]
|
||||
[no exports used]
|
||||
entry ./example.js main
|
||||
chunk (runtime: chat) chat.js (chat) 527 bytes [entry] [rendered]
|
||||
> ./example.js 25:19-30:1
|
||||
./chat-worker.js + 1 modules 527 bytes [built] [code generated]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
new Worker() ./chat-worker.js ./example.js 25:19-30:1
|
||||
chunk (runtime: fibonacci) workers/fibonacci.js (fibonacci) 176 bytes (javascript) 2.1 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js 79:18-82:2
|
||||
runtime modules 2.1 KiB 7 modules
|
||||
./fib-worker.js 176 bytes [built] [code generated]
|
||||
[no exports used]
|
||||
new Worker() ./fib-worker.js ./example.js 79:18-82:2
|
||||
webpack 5.0.0-beta.29 compiled successfully
|
||||
```
|
||||
|
||||
## Production mode
|
||||
|
||||
```
|
||||
asset 129.js 166 bytes [emitted] [minimized]
|
||||
asset chat.js 270 bytes [emitted] [minimized] (name: chat)
|
||||
asset main.js 3.37 KiB [emitted] [minimized] (name: main)
|
||||
asset workers/fibonacci.js 930 bytes [emitted] [minimized] (name: fibonacci)
|
||||
chunk (runtime: fibonacci, main) 129.js 103 bytes [rendered]
|
||||
> ./fibonacci ./example.js 69:30-51
|
||||
> ./fibonacci ./fib-worker.js 2:29-50
|
||||
./fibonacci.js 103 bytes [built] [code generated]
|
||||
[exports: fibonacci]
|
||||
import() ./fibonacci ./example.js 69:30-51
|
||||
import() ./fibonacci ./fib-worker.js 2:29-50
|
||||
chunk (runtime: main) main.js (main) 2.22 KiB (javascript) 5.59 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js main
|
||||
runtime modules 5.59 KiB 8 modules
|
||||
./example.js 2.22 KiB [built] [code generated]
|
||||
[no exports used]
|
||||
entry ./example.js main
|
||||
chunk (runtime: chat) chat.js (chat) 527 bytes [entry] [rendered]
|
||||
> ./example.js 25:19-30:1
|
||||
./chat-worker.js + 1 modules 527 bytes [built] [code generated]
|
||||
[no exports]
|
||||
[no exports used]
|
||||
new Worker() ./chat-worker.js ./example.js 25:19-30:1
|
||||
chunk (runtime: fibonacci) workers/fibonacci.js (fibonacci) 176 bytes (javascript) 2.1 KiB (runtime) [entry] [rendered]
|
||||
> ./example.js 79:18-82:2
|
||||
runtime modules 2.1 KiB 7 modules
|
||||
./fib-worker.js 176 bytes [built] [code generated]
|
||||
[no exports used]
|
||||
new Worker() ./fib-worker.js ./example.js 79:18-82:2
|
||||
webpack 5.0.0-beta.29 compiled successfully
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
global.NO_TARGET_ARGS = true;
|
||||
require("../build-common");
|
|
@ -0,0 +1,6 @@
|
|||
export const history = [];
|
||||
|
||||
export const add = (content, from) => {
|
||||
if (history.length > 10) history.shift();
|
||||
history.push(`${from}: ${content}`);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import { history, add } from "./chat-module";
|
||||
|
||||
onconnect = function (e) {
|
||||
for (const port of e.ports) {
|
||||
port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "message":
|
||||
add(msg.content, msg.from);
|
||||
// fallthrough
|
||||
case "history":
|
||||
port.postMessage({
|
||||
type: "history",
|
||||
history
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
document.body.innerHTML = `
|
||||
<pre id="history"></pre>
|
||||
<form>
|
||||
<input id="message" type="text">
|
||||
<button id="send">Send Message</button>
|
||||
</form>
|
||||
<p>Computing fibonacci without worker:</p>
|
||||
<input id="fib1" type="number">
|
||||
<pre id="output1"></pre>
|
||||
<p>Computing fibonacci with worker:</p>
|
||||
<input id="fib2" type="number">
|
||||
<pre id="output2"></pre>
|
||||
`;
|
||||
|
||||
const history = document.getElementById("history");
|
||||
const message = document.getElementById("message");
|
||||
const send = document.getElementById("send");
|
||||
const fib1 = document.getElementById("fib1");
|
||||
const output1 = document.getElementById("output1");
|
||||
const fib2 = document.getElementById("fib2");
|
||||
const output2 = document.getElementById("output2");
|
||||
|
||||
/// CHAT with shared worker ///
|
||||
|
||||
const chatWorker = new SharedWorker(
|
||||
new URL("./chat-worker.js", import.meta.url),
|
||||
{
|
||||
name: "chat"
|
||||
}
|
||||
);
|
||||
|
||||
let historyTimeout;
|
||||
const scheduleUpdateHistory = () => {
|
||||
clearTimeout(historyTimeout);
|
||||
historyTimeout = setTimeout(() => {
|
||||
chatWorker.port.postMessage({ type: "history" });
|
||||
}, 1000);
|
||||
};
|
||||
scheduleUpdateHistory();
|
||||
|
||||
const from = `User ${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
send.addEventListener("click", e => {
|
||||
chatWorker.port.postMessage({
|
||||
type: "message",
|
||||
content: message.value,
|
||||
from
|
||||
});
|
||||
message.value = "";
|
||||
message.focus();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
chatWorker.port.onmessage = event => {
|
||||
const msg = event.data;
|
||||
switch (msg.type) {
|
||||
case "history":
|
||||
history.innerText = msg.history.join("\n");
|
||||
scheduleUpdateHistory();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/// FIBONACCI without worker ///
|
||||
|
||||
fib1.addEventListener("change", async () => {
|
||||
try {
|
||||
const value = parseInt(fib1.value, 10);
|
||||
const { fibonacci } = await import("./fibonacci");
|
||||
const result = fibonacci(value);
|
||||
output1.innerText = `fib(${value}) = ${result}`;
|
||||
} catch (e) {
|
||||
output1.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
/// FIBONACCI with worker ///
|
||||
|
||||
const fibWorker = new Worker(new URL("./fib-worker.js", import.meta.url), {
|
||||
name: "fibonacci"
|
||||
/* webpackEntryOptions: { filename: "workers/[name].js" } */
|
||||
});
|
||||
|
||||
fib2.addEventListener("change", () => {
|
||||
try {
|
||||
const value = parseInt(fib2.value, 10);
|
||||
fibWorker.postMessage(`${value}`);
|
||||
} catch (e) {
|
||||
output2.innerText = e.message;
|
||||
}
|
||||
});
|
||||
|
||||
fibWorker.onmessage = event => {
|
||||
output2.innerText = event.data;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
onmessage = async event => {
|
||||
const { fibonacci } = await import("./fibonacci");
|
||||
const value = JSON.parse(event.data);
|
||||
postMessage(`fib(${value}) = ${fibonacci(value)}`);
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
export function fibonacci(n) {
|
||||
return n < 1 ? 0 : n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Worker example</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./dist/main.js" async></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,75 @@
|
|||
# example.js
|
||||
|
||||
```javascript
|
||||
_{{example.js}}_
|
||||
```
|
||||
|
||||
# fib-worker.js
|
||||
|
||||
```javascript
|
||||
_{{fib-worker.js}}_
|
||||
```
|
||||
|
||||
# fibonacci.js
|
||||
|
||||
```javascript
|
||||
_{{fibonacci.js}}_
|
||||
```
|
||||
|
||||
# chat-worker.js
|
||||
|
||||
```javascript
|
||||
_{{chat-worker.js}}_
|
||||
```
|
||||
|
||||
# chat-module.js
|
||||
|
||||
```javascript
|
||||
_{{chat-module.js}}_
|
||||
```
|
||||
|
||||
# dist/main.js
|
||||
|
||||
```javascript
|
||||
_{{dist/main.js}}_
|
||||
```
|
||||
|
||||
# dist/chat.js
|
||||
|
||||
```javascript
|
||||
_{{dist/chat.js}}_
|
||||
```
|
||||
|
||||
```javascript
|
||||
_{{production:dist/chat.js}}_
|
||||
```
|
||||
|
||||
# dist/workers/fibonacci.js
|
||||
|
||||
```javascript
|
||||
_{{dist/workers/fibonacci.js}}_
|
||||
```
|
||||
|
||||
```javascript
|
||||
_{{production:dist/workers/fibonacci.js}}_
|
||||
```
|
||||
|
||||
# dist/129.js
|
||||
|
||||
```javascript
|
||||
_{{dist/129.js}}_
|
||||
```
|
||||
|
||||
# Info
|
||||
|
||||
## Unoptimized
|
||||
|
||||
```
|
||||
_{{stdout}}_
|
||||
```
|
||||
|
||||
## Production mode
|
||||
|
||||
```
|
||||
_{{production:stdout}}_
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
var path = require("path");
|
||||
|
||||
module.exports = {
|
||||
entry: "./example.js",
|
||||
output: {
|
||||
path: path.join(__dirname, "dist"),
|
||||
filename: "[name].js",
|
||||
chunkFilename: "[name].js",
|
||||
publicPath: "/dist/"
|
||||
},
|
||||
optimization: {
|
||||
concatenateModules: true,
|
||||
usedExports: true,
|
||||
providedExports: true,
|
||||
chunkIds: "deterministic" // To keep filename consistent between different modes (for example building only)
|
||||
}
|
||||
};
|
|
@ -13,12 +13,13 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
/** @typedef {import("./ChunkGroup").ChunkGroupOptions} ChunkGroupOptions */
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
|
||||
/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./util/Hash")} Hash */
|
||||
|
||||
class AsyncDependenciesBlock extends DependenciesBlock {
|
||||
/**
|
||||
* @param {ChunkGroupOptions} groupOptions options for the group
|
||||
* @param {ChunkGroupOptions & { entryOptions?: EntryOptions }} groupOptions options for the group
|
||||
* @param {DependencyLocation=} loc the line of code
|
||||
* @param {string=} request the request
|
||||
*/
|
||||
|
@ -64,14 +65,6 @@ class AsyncDependenciesBlock extends DependenciesBlock {
|
|||
super.updateHash(hash, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGroup} parentChunkGroup the parent chunk group
|
||||
* @returns {boolean} true when this dependencies block should be loaded async
|
||||
*/
|
||||
isAsync(parentChunkGroup) {
|
||||
return true;
|
||||
}
|
||||
|
||||
serialize(context) {
|
||||
const { write } = context;
|
||||
write(this.groupOptions);
|
||||
|
|
33
lib/Chunk.js
33
lib/Chunk.js
|
@ -26,6 +26,7 @@ const { mergeRuntime } = require("./util/runtime");
|
|||
/** @typedef {import("./Compilation")} Compilation */
|
||||
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
|
||||
/** @typedef {import("./Compilation").PathData} PathData */
|
||||
/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("./util/Hash")} Hash */
|
||||
|
@ -427,7 +428,6 @@ class Chunk {
|
|||
hasRuntime() {
|
||||
for (const chunkGroup of this._groups) {
|
||||
if (
|
||||
chunkGroup.isInitial() &&
|
||||
chunkGroup instanceof Entrypoint &&
|
||||
chunkGroup.getRuntimeChunk() === this
|
||||
) {
|
||||
|
@ -458,6 +458,18 @@ class Chunk {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {EntryOptions | undefined} the entry options for this chunk
|
||||
*/
|
||||
getEntryOptions() {
|
||||
for (const chunkGroup of this._groups) {
|
||||
if (chunkGroup instanceof Entrypoint) {
|
||||
return chunkGroup.options;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being added
|
||||
* @returns {void}
|
||||
|
@ -602,6 +614,25 @@ class Chunk {
|
|||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Set<Entrypoint>} a set of all the referenced entrypoints
|
||||
*/
|
||||
getAllReferencedAsyncEntrypoints() {
|
||||
const queue = new Set(this.groupsIterable);
|
||||
const entrypoints = new Set();
|
||||
|
||||
for (const chunkGroup of queue) {
|
||||
for (const entrypoint of chunkGroup.asyncEntrypointsIterable) {
|
||||
entrypoints.add(entrypoint);
|
||||
}
|
||||
for (const child of chunkGroup.childrenIterable) {
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return entrypoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} true, if the chunk references async chunks
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,7 @@ const {
|
|||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Entrypoint")} Entrypoint */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
|
||||
|
@ -81,7 +82,10 @@ class ChunkGroup {
|
|||
this.options = options;
|
||||
/** @type {SortableSet<ChunkGroup>} */
|
||||
this._children = new SortableSet(undefined, sortById);
|
||||
/** @type {SortableSet<ChunkGroup>} */
|
||||
this._parents = new SortableSet(undefined, sortById);
|
||||
/** @type {SortableSet<ChunkGroup>} */
|
||||
this._asyncEntrypoints = new SortableSet(undefined, sortById);
|
||||
this._blocks = new SortableSet();
|
||||
/** @type {Chunk[]} */
|
||||
this.chunks = [];
|
||||
|
@ -241,20 +245,21 @@ class ChunkGroup {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} true, when this chunk group will be loaded on initial page load
|
||||
*/
|
||||
isInitial() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGroup} group chunk ground to add
|
||||
* @returns {boolean} returns true if chunk ground was added
|
||||
* @param {ChunkGroup} group chunk group to add
|
||||
* @returns {boolean} returns true if chunk group was added
|
||||
*/
|
||||
addChild(group) {
|
||||
if (this._children.has(group)) {
|
||||
return false;
|
||||
}
|
||||
const size = this._children.size;
|
||||
this._children.add(group);
|
||||
return true;
|
||||
return size !== this._children.size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -333,6 +338,20 @@ class ChunkGroup {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Entrypoint} entrypoint entrypoint to add
|
||||
* @returns {boolean} returns true if entrypoint was added
|
||||
*/
|
||||
addAsyncEntrypoint(entrypoint) {
|
||||
const size = this._asyncEntrypoints.size;
|
||||
this._asyncEntrypoints.add(entrypoint);
|
||||
return size !== this._asyncEntrypoints.size;
|
||||
}
|
||||
|
||||
get asyncEntrypointsIterable() {
|
||||
return this._asyncEntrypoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Array} an array containing the blocks
|
||||
*/
|
||||
|
|
|
@ -85,6 +85,7 @@ const { getRuntimeKey } = require("./util/runtime");
|
|||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */
|
||||
/** @typedef {import("./DependencyTemplate")} DependencyTemplate */
|
||||
/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
|
||||
/** @typedef {import("./ModuleFactory")} ModuleFactory */
|
||||
|
@ -155,8 +156,6 @@ const { getRuntimeKey } = require("./util/runtime");
|
|||
* @property {ChunkGraph} chunkGraph the chunk graph
|
||||
*/
|
||||
|
||||
/** @typedef {{ name: string } & Omit<EntryDescription, "import">} EntryOptions */
|
||||
|
||||
/**
|
||||
* @typedef {Object} EntryData
|
||||
* @property {Dependency[]} dependencies dependencies of the entrypoint that should be evaluated at startup
|
||||
|
@ -716,6 +715,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|||
};
|
||||
/** @type {Map<string, Entrypoint>} */
|
||||
this.entrypoints = new Map();
|
||||
/** @type {Entrypoint[]} */
|
||||
this.asyncEntrypoints = [];
|
||||
/** @type {Set<Chunk>} */
|
||||
this.chunks = new Set();
|
||||
arrayToSetDeprecation(this.chunks, "Compilation.chunks");
|
||||
|
@ -1751,11 +1752,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|||
for (const [name, { dependencies, includeDependencies, options }] of this
|
||||
.entries) {
|
||||
const chunk = this.addChunk(name);
|
||||
chunk.name = name;
|
||||
if (options.filename) {
|
||||
chunk.filenameTemplate = options.filename;
|
||||
}
|
||||
const entrypoint = new Entrypoint(name);
|
||||
const entrypoint = new Entrypoint(options);
|
||||
if (!options.dependOn && !options.runtime) {
|
||||
entrypoint.setRuntimeChunk(chunk);
|
||||
}
|
||||
|
@ -1951,7 +1951,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
|
||||
this.logger.time("runtime requirements");
|
||||
this.hooks.beforeRuntimeRequirements.call();
|
||||
this.processRuntimeRequirements(this.entrypoints.values());
|
||||
this.processRuntimeRequirements();
|
||||
this.hooks.afterRuntimeRequirements.call();
|
||||
this.logger.timeEnd("runtime requirements");
|
||||
|
||||
|
@ -2177,10 +2177,9 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Iterable<Entrypoint>} entrypoints the entrypoints
|
||||
* @returns {void}
|
||||
*/
|
||||
processRuntimeRequirements(entrypoints) {
|
||||
processRuntimeRequirements() {
|
||||
const { chunkGraph } = this;
|
||||
|
||||
const additionalModuleRuntimeRequirements = this.hooks
|
||||
|
@ -2232,7 +2231,11 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
|
||||
/** @type {Set<Chunk>} */
|
||||
const treeEntries = new Set();
|
||||
for (const ep of entrypoints) {
|
||||
for (const ep of this.entrypoints.values()) {
|
||||
const chunk = ep.getRuntimeChunk();
|
||||
if (chunk) treeEntries.add(chunk);
|
||||
}
|
||||
for (const ep of this.asyncEntrypoints) {
|
||||
const chunk = ep.getRuntimeChunk();
|
||||
if (chunk) treeEntries.add(chunk);
|
||||
}
|
||||
|
@ -2305,7 +2308,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {string|ChunkGroupOptions} groupOptions options for the chunk group
|
||||
* @param {string | ChunkGroupOptions} groupOptions options for the chunk group
|
||||
* @param {Module} module the module the references the chunk group
|
||||
* @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
|
||||
* @param {string} request the request from which the the chunk group is referenced
|
||||
|
@ -2316,6 +2319,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
groupOptions = { name: groupOptions };
|
||||
}
|
||||
const name = groupOptions.name;
|
||||
|
||||
if (name) {
|
||||
const chunkGroup = this.namedChunkGroups.get(name);
|
||||
if (chunkGroup !== undefined) {
|
||||
|
@ -2339,6 +2343,49 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
return chunkGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {EntryOptions} options options for the entrypoint
|
||||
* @param {Module} module the module the references the chunk group
|
||||
* @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
|
||||
* @param {string} request the request from which the the chunk group is referenced
|
||||
* @returns {Entrypoint} the new or existing entrypoint
|
||||
*/
|
||||
addAsyncEntrypoint(options, module, loc, request) {
|
||||
const name = options.name;
|
||||
if (name) {
|
||||
const entrypoint = this.namedChunkGroups.get(name);
|
||||
if (entrypoint instanceof Entrypoint) {
|
||||
if (entrypoint !== undefined) {
|
||||
if (module) {
|
||||
entrypoint.addOrigin(module, loc, request);
|
||||
}
|
||||
return entrypoint;
|
||||
}
|
||||
} else if (entrypoint) {
|
||||
throw new Error(
|
||||
`Cannot add an async entrypoint with the name '${name}', because there is already an chunk group with this name`
|
||||
);
|
||||
}
|
||||
}
|
||||
const chunk = this.addChunk(name);
|
||||
if (options.filename) {
|
||||
chunk.filenameTemplate = options.filename;
|
||||
}
|
||||
const entrypoint = new Entrypoint(options, false);
|
||||
entrypoint.setRuntimeChunk(chunk);
|
||||
entrypoint.setEntrypointChunk(chunk);
|
||||
if (name) {
|
||||
this.namedChunkGroups.set(name, entrypoint);
|
||||
}
|
||||
this.chunkGroups.push(entrypoint);
|
||||
this.asyncEntrypoints.push(entrypoint);
|
||||
connectChunkGroupAndChunk(entrypoint, chunk);
|
||||
if (module) {
|
||||
entrypoint.addOrigin(module, loc, request);
|
||||
}
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method first looks to see if a name is provided for a new chunk,
|
||||
* and first looks to see if any named chunks already exist and reuse that chunk instead.
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
"use strict";
|
||||
|
||||
/** @typedef {import("../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescription */
|
||||
/** @typedef {import("./Compilation").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
|
||||
|
||||
class EntryOptionPlugin {
|
||||
/**
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
const EntryDependency = require("./dependencies/EntryDependency");
|
||||
|
||||
/** @typedef {import("./Compilation").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./Entrypoint").EntryOptions} EntryOptions */
|
||||
|
||||
class EntryPlugin {
|
||||
/**
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
const ChunkGroup = require("./ChunkGroup");
|
||||
|
||||
/** @typedef {import("../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescription */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
|
||||
/** @typedef {{ name?: string } & Omit<EntryDescription, "import">} EntryOptions */
|
||||
|
||||
/**
|
||||
* Entrypoint serves as an encapsulation primitive for chunks that are
|
||||
* a part of a single ChunkGroup. They represent all bundles that need to be loaded for a
|
||||
|
@ -18,22 +21,30 @@ const ChunkGroup = require("./ChunkGroup");
|
|||
class Entrypoint extends ChunkGroup {
|
||||
/**
|
||||
* Creates an instance of Entrypoint.
|
||||
* @param {string} name the name of the entrypoint
|
||||
* @param {EntryOptions | string} entryOptions the options for the entrypoint (or name)
|
||||
* @param {boolean=} initial false, when the entrypoint is not initial loaded
|
||||
*/
|
||||
constructor(name) {
|
||||
super(name);
|
||||
constructor(entryOptions, initial = true) {
|
||||
if (typeof entryOptions === "string") {
|
||||
entryOptions = { name: entryOptions };
|
||||
}
|
||||
super({
|
||||
name: entryOptions.name
|
||||
});
|
||||
this.options = entryOptions;
|
||||
/** @type {Chunk=} */
|
||||
this._runtimeChunk = undefined;
|
||||
/** @type {Chunk=} */
|
||||
this._entrypointChunk = undefined;
|
||||
/** @type {boolean} */
|
||||
this._initial = initial;
|
||||
}
|
||||
|
||||
/**
|
||||
* isInitial will always return true for Entrypoint ChunkGroup.
|
||||
* @returns {true} returns true as all entrypoints are initial ChunkGroups
|
||||
* @returns {boolean} true, when this chunk group will be loaded on initial page load
|
||||
*/
|
||||
isInitial() {
|
||||
return true;
|
||||
return this._initial;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -154,7 +154,7 @@ class FlagDependencyUsagePlugin {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {DependenciesBlock} module the module
|
||||
* @param {RuntimeSpec} runtime part of which runtime
|
||||
* @returns {void}
|
||||
*/
|
||||
|
@ -166,7 +166,11 @@ class FlagDependencyUsagePlugin {
|
|||
const queue = [module];
|
||||
for (const block of queue) {
|
||||
for (const b of block.blocks) {
|
||||
queue.push(b);
|
||||
if (b.groupOptions && b.groupOptions.entryOptions) {
|
||||
processModule(b, b.groupOptions.entryOptions.runtime);
|
||||
} else {
|
||||
queue.push(b);
|
||||
}
|
||||
}
|
||||
for (const dep of block.dependencies) {
|
||||
const connection = moduleGraph.getConnection(dep);
|
||||
|
@ -303,14 +307,23 @@ class FlagDependencyUsagePlugin {
|
|||
);
|
||||
if (!this.global) {
|
||||
compilation.hooks.afterChunks.tap("FlagDependencyUsagePlugin", () => {
|
||||
/** @type {Set<Chunk>} */
|
||||
const runtimeChunks = new Set();
|
||||
/** @type {Map<Chunk, string>} */
|
||||
const runtimeChunks = new Map();
|
||||
for (const entrypoint of compilation.entrypoints.values()) {
|
||||
runtimeChunks.add(entrypoint.getRuntimeChunk());
|
||||
runtimeChunks.set(
|
||||
entrypoint.getRuntimeChunk(),
|
||||
entrypoint.options.runtime
|
||||
);
|
||||
}
|
||||
for (const entrypoint of compilation.asyncEntrypoints) {
|
||||
runtimeChunks.set(
|
||||
entrypoint.getRuntimeChunk(),
|
||||
entrypoint.options.runtime
|
||||
);
|
||||
}
|
||||
|
||||
for (const runtimeChunk of runtimeChunks) {
|
||||
const runtime = runtimeChunk.name;
|
||||
for (const [runtimeChunk, runtimeName] of runtimeChunks) {
|
||||
const runtime = runtimeName || runtimeChunk.name;
|
||||
for (const chunk of runtimeChunk.getAllReferencedChunks()) {
|
||||
chunk.runtime = mergeRuntime(chunk.runtime, runtime);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ class LibManifestPlugin {
|
|||
asyncLib.forEach(
|
||||
Array.from(compilation.chunks),
|
||||
(chunk, callback) => {
|
||||
if (!chunk.isOnlyInitial()) {
|
||||
if (!chunk.canBeInitial()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ class RuntimePlugin {
|
|||
RuntimeGlobals.getChunkScriptFilename,
|
||||
chunk =>
|
||||
chunk.filenameTemplate ||
|
||||
(chunk.isOnlyInitial()
|
||||
(chunk.canBeInitial()
|
||||
? compilation.outputOptions.filename
|
||||
: compilation.outputOptions.chunkFilename),
|
||||
false
|
||||
|
|
|
@ -28,7 +28,6 @@ const TemplatedPathPlugin = require("./TemplatedPathPlugin");
|
|||
const UseStrictPlugin = require("./UseStrictPlugin");
|
||||
const WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");
|
||||
|
||||
const URLPlugin = require("./dependencies/URLPlugin");
|
||||
const DataUriPlugin = require("./schemes/DataUriPlugin");
|
||||
const FileUriPlugin = require("./schemes/FileUriPlugin");
|
||||
|
||||
|
@ -43,6 +42,7 @@ const RequireContextPlugin = require("./dependencies/RequireContextPlugin");
|
|||
const RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
|
||||
const RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");
|
||||
const SystemPlugin = require("./dependencies/SystemPlugin");
|
||||
const URLPlugin = require("./dependencies/URLPlugin");
|
||||
|
||||
const InferAsyncModulesPlugin = require("./async-modules/InferAsyncModulesPlugin");
|
||||
|
||||
|
@ -276,7 +276,6 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
|
||||
new InferAsyncModulesPlugin().apply(compiler);
|
||||
|
||||
new URLPlugin().apply(compiler);
|
||||
new DataUriPlugin().apply(compiler);
|
||||
new FileUriPlugin().apply(compiler);
|
||||
|
||||
|
@ -307,6 +306,12 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
new ImportPlugin(options.module).apply(compiler);
|
||||
new SystemPlugin(options.module).apply(compiler);
|
||||
new ImportMetaPlugin().apply(compiler);
|
||||
new URLPlugin().apply(compiler);
|
||||
|
||||
if (options.output.workerChunkLoading) {
|
||||
const WorkerPlugin = require("./dependencies/WorkerPlugin");
|
||||
new WorkerPlugin(options.output.workerChunkLoading).apply(compiler);
|
||||
}
|
||||
|
||||
new DefaultStatsFactoryPlugin().apply(compiler);
|
||||
new DefaultStatsPresetPlugin().apply(compiler);
|
||||
|
|
|
@ -178,10 +178,15 @@ const visitModules = (
|
|||
/** @type {Map<string, ChunkGroupInfo>} */
|
||||
const namedChunkGroups = new Map();
|
||||
|
||||
const ADD_AND_ENTER_MODULE = 0;
|
||||
const ENTER_MODULE = 1;
|
||||
const PROCESS_BLOCK = 2;
|
||||
const LEAVE_MODULE = 3;
|
||||
/** @type {Map<string, ChunkGroupInfo>} */
|
||||
const namedAsyncEntrypoints = new Map();
|
||||
|
||||
const ADD_AND_ENTER_ENTRY_MODULE = 0;
|
||||
const ADD_AND_ENTER_MODULE = 1;
|
||||
const ENTER_MODULE = 2;
|
||||
const PROCESS_BLOCK = 3;
|
||||
const PROCESS_ENTRY_BLOCK = 4;
|
||||
const LEAVE_MODULE = 5;
|
||||
|
||||
/** @type {QueueItem[]} */
|
||||
let queue = [];
|
||||
|
@ -293,77 +298,135 @@ const visitModules = (
|
|||
let cgi = blockChunkGroups.get(b);
|
||||
/** @type {ChunkGroup} */
|
||||
let c;
|
||||
/** @type {Entrypoint} */
|
||||
let entrypoint;
|
||||
const entryOptions = b.groupOptions && b.groupOptions.entryOptions;
|
||||
if (cgi === undefined) {
|
||||
const chunkName = (b.groupOptions && b.groupOptions.name) || b.chunkName;
|
||||
cgi = namedChunkGroups.get(chunkName);
|
||||
if (!cgi) {
|
||||
c = compilation.addChunkInGroup(
|
||||
b.groupOptions || b.chunkName,
|
||||
module,
|
||||
b.loc,
|
||||
b.request
|
||||
);
|
||||
c.index = nextChunkGroupIndex++;
|
||||
cgi = {
|
||||
chunkGroup: c,
|
||||
minAvailableModules: undefined,
|
||||
minAvailableModulesOwned: undefined,
|
||||
availableModulesToBeMerged: [],
|
||||
skippedItems: undefined,
|
||||
resultingAvailableModules: undefined,
|
||||
children: undefined,
|
||||
availableSources: undefined,
|
||||
availableChildren: undefined,
|
||||
preOrderIndex: 0,
|
||||
postOrderIndex: 0
|
||||
};
|
||||
allCreatedChunkGroups.add(c);
|
||||
chunkGroupInfoMap.set(c, cgi);
|
||||
if (chunkName) {
|
||||
namedChunkGroups.set(chunkName, cgi);
|
||||
}
|
||||
} else {
|
||||
c = cgi.chunkGroup;
|
||||
if (c.isInitial()) {
|
||||
compilation.errors.push(
|
||||
new AsyncDependencyToInitialChunkError(chunkName, module, b.loc)
|
||||
if (entryOptions) {
|
||||
cgi = namedAsyncEntrypoints.get(chunkName);
|
||||
if (!cgi) {
|
||||
entrypoint = compilation.addAsyncEntrypoint(
|
||||
entryOptions,
|
||||
module,
|
||||
b.loc,
|
||||
b.request
|
||||
);
|
||||
c = chunkGroup;
|
||||
entrypoint.index = nextChunkGroupIndex++;
|
||||
cgi = {
|
||||
chunkGroup: entrypoint,
|
||||
minAvailableModules: EMPTY_SET,
|
||||
minAvailableModulesOwned: false,
|
||||
availableModulesToBeMerged: [],
|
||||
skippedItems: undefined,
|
||||
resultingAvailableModules: undefined,
|
||||
children: undefined,
|
||||
availableSources: undefined,
|
||||
availableChildren: undefined,
|
||||
preOrderIndex: 0,
|
||||
postOrderIndex: 0
|
||||
};
|
||||
chunkGroupInfoMap.set(entrypoint, cgi);
|
||||
|
||||
chunkGraph.connectBlockAndChunkGroup(b, entrypoint);
|
||||
if (chunkName) {
|
||||
namedAsyncEntrypoints.set(chunkName, cgi);
|
||||
}
|
||||
} else {
|
||||
entrypoint = /** @type {Entrypoint} */ (cgi.chunkGroup);
|
||||
// TODO merge entryOptions
|
||||
entrypoint.addOrigin(module, b.loc, b.request);
|
||||
chunkGraph.connectBlockAndChunkGroup(b, entrypoint);
|
||||
}
|
||||
|
||||
// 2. We enqueue the DependenciesBlock for traversal
|
||||
queueDelayed.push({
|
||||
action: PROCESS_ENTRY_BLOCK,
|
||||
block: b,
|
||||
module: module,
|
||||
chunk: entrypoint.chunks[0],
|
||||
chunkGroup: entrypoint,
|
||||
chunkGroupInfo: cgi
|
||||
});
|
||||
} else {
|
||||
cgi = namedChunkGroups.get(chunkName);
|
||||
if (!cgi) {
|
||||
c = compilation.addChunkInGroup(
|
||||
b.groupOptions || b.chunkName,
|
||||
module,
|
||||
b.loc,
|
||||
b.request
|
||||
);
|
||||
c.index = nextChunkGroupIndex++;
|
||||
cgi = {
|
||||
chunkGroup: c,
|
||||
minAvailableModules: undefined,
|
||||
minAvailableModulesOwned: undefined,
|
||||
availableModulesToBeMerged: [],
|
||||
skippedItems: undefined,
|
||||
resultingAvailableModules: undefined,
|
||||
children: undefined,
|
||||
availableSources: undefined,
|
||||
availableChildren: undefined,
|
||||
preOrderIndex: 0,
|
||||
postOrderIndex: 0
|
||||
};
|
||||
allCreatedChunkGroups.add(c);
|
||||
chunkGroupInfoMap.set(c, cgi);
|
||||
if (chunkName) {
|
||||
namedChunkGroups.set(chunkName, cgi);
|
||||
}
|
||||
} else {
|
||||
c = cgi.chunkGroup;
|
||||
if (c.isInitial()) {
|
||||
compilation.errors.push(
|
||||
new AsyncDependencyToInitialChunkError(chunkName, module, b.loc)
|
||||
);
|
||||
c = chunkGroup;
|
||||
}
|
||||
c.addOptions(b.groupOptions);
|
||||
c.addOrigin(module, b.loc, b.request);
|
||||
}
|
||||
c.addOptions(b.groupOptions);
|
||||
c.addOrigin(module, b.loc, b.request);
|
||||
}
|
||||
blockChunkGroups.set(b, cgi);
|
||||
} else if (entryOptions) {
|
||||
entrypoint = /** @type {Entrypoint} */ (cgi.chunkGroup);
|
||||
} else {
|
||||
c = cgi.chunkGroup;
|
||||
}
|
||||
|
||||
// 2. We store the Block + Chunk Group mapping as dependency
|
||||
// for the chunk group which is set in processQueue
|
||||
let deps = chunkGroupDependencies.get(chunkGroup);
|
||||
if (!deps) chunkGroupDependencies.set(chunkGroup, (deps = []));
|
||||
deps.push({
|
||||
block: b,
|
||||
chunkGroup: c
|
||||
});
|
||||
if (c !== undefined) {
|
||||
// 2. We store the Block + Chunk Group mapping as dependency
|
||||
// for the chunk group which is set in processQueue
|
||||
let deps = chunkGroupDependencies.get(chunkGroup);
|
||||
if (!deps) chunkGroupDependencies.set(chunkGroup, (deps = []));
|
||||
deps.push({
|
||||
block: b,
|
||||
chunkGroup: c
|
||||
});
|
||||
|
||||
// 3. We enqueue the chunk group info creation/updating
|
||||
let connectList = queueConnect.get(chunkGroupInfo);
|
||||
if (connectList === undefined) {
|
||||
connectList = new Set();
|
||||
queueConnect.set(chunkGroupInfo, connectList);
|
||||
// 3. We enqueue the chunk group info creation/updating
|
||||
let connectList = queueConnect.get(chunkGroupInfo);
|
||||
if (connectList === undefined) {
|
||||
connectList = new Set();
|
||||
queueConnect.set(chunkGroupInfo, connectList);
|
||||
}
|
||||
connectList.add(cgi);
|
||||
|
||||
// TODO check if this really need to be done for each traversal
|
||||
// or if it is enough when it's queued when created
|
||||
// 4. We enqueue the DependenciesBlock for traversal
|
||||
queueDelayed.push({
|
||||
action: PROCESS_BLOCK,
|
||||
block: b,
|
||||
module: module,
|
||||
chunk: c.chunks[0],
|
||||
chunkGroup: c,
|
||||
chunkGroupInfo: cgi
|
||||
});
|
||||
} else {
|
||||
chunkGroupInfo.chunkGroup.addAsyncEntrypoint(entrypoint);
|
||||
}
|
||||
connectList.add(cgi);
|
||||
|
||||
// 4. We enqueue the DependenciesBlock for traversal
|
||||
queueDelayed.push({
|
||||
action: PROCESS_BLOCK,
|
||||
block: b,
|
||||
module: module,
|
||||
chunk: c.chunks[0],
|
||||
chunkGroup: c,
|
||||
chunkGroupInfo: cgi
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -424,11 +487,49 @@ const visitModules = (
|
|||
|
||||
// Traverse all Blocks
|
||||
for (const b of block.blocks) {
|
||||
if (b.isAsync(chunkGroup)) {
|
||||
iteratorBlock(b);
|
||||
} else {
|
||||
processBlock(b);
|
||||
iteratorBlock(b);
|
||||
}
|
||||
|
||||
if (block.blocks.length > 0 && module !== block) {
|
||||
blocksWithNestedBlocks.add(block);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {DependenciesBlock} block the block
|
||||
* @returns {void}
|
||||
*/
|
||||
const processEntryBlock = block => {
|
||||
statProcessedBlocks++;
|
||||
// get prepared block info
|
||||
const blockModules = blockModulesMap.get(block);
|
||||
|
||||
if (blockModules !== undefined) {
|
||||
// Traverse all referenced modules
|
||||
for (const refModule of blockModules) {
|
||||
// enqueue, then add and enter to be in the correct order
|
||||
// this is relevant with circular dependencies
|
||||
queueBuffer.push({
|
||||
action: ADD_AND_ENTER_ENTRY_MODULE,
|
||||
block: refModule,
|
||||
module: refModule,
|
||||
chunk,
|
||||
chunkGroup,
|
||||
chunkGroupInfo
|
||||
});
|
||||
}
|
||||
// Add buffered items in reverse order
|
||||
if (queueBuffer.length > 0) {
|
||||
for (let i = queueBuffer.length - 1; i >= 0; i--) {
|
||||
queue.push(queueBuffer[i]);
|
||||
}
|
||||
queueBuffer.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all Blocks
|
||||
for (const b of block.blocks) {
|
||||
iteratorBlock(b);
|
||||
}
|
||||
|
||||
if (block.blocks.length > 0 && module !== block) {
|
||||
|
@ -447,6 +548,13 @@ const visitModules = (
|
|||
chunkGroupInfo = queueItem.chunkGroupInfo;
|
||||
|
||||
switch (queueItem.action) {
|
||||
case ADD_AND_ENTER_ENTRY_MODULE:
|
||||
chunkGraph.connectChunkAndEntryModule(
|
||||
chunk,
|
||||
module,
|
||||
/** @type {Entrypoint} */ (chunkGroup)
|
||||
);
|
||||
// fallthrough
|
||||
case ADD_AND_ENTER_MODULE: {
|
||||
if (chunkGraph.isModuleInChunk(module, chunk)) {
|
||||
// already connected, skip it
|
||||
|
@ -483,6 +591,10 @@ const visitModules = (
|
|||
processBlock(block);
|
||||
break;
|
||||
}
|
||||
case PROCESS_ENTRY_BLOCK: {
|
||||
processEntryBlock(block);
|
||||
break;
|
||||
}
|
||||
case LEAVE_MODULE: {
|
||||
const index = chunkGroup.getModulePostOrderIndex(module);
|
||||
if (index === undefined) {
|
||||
|
|
|
@ -188,6 +188,9 @@ const applyWebpackOptionsDefaults = options => {
|
|||
if (options.output.chunkLoading) {
|
||||
enabledChunkLoadingTypes.push(options.output.chunkLoading);
|
||||
}
|
||||
if (options.output.workerChunkLoading) {
|
||||
enabledChunkLoadingTypes.push(options.output.workerChunkLoading);
|
||||
}
|
||||
for (const name of Object.keys(options.entry)) {
|
||||
const desc = options.entry[name];
|
||||
if (desc.chunkLoading) {
|
||||
|
@ -646,6 +649,18 @@ const applyOutputDefaults = (
|
|||
return false;
|
||||
}
|
||||
});
|
||||
F(output, "workerChunkLoading", () => {
|
||||
switch (output.chunkLoading) {
|
||||
case "jsonp":
|
||||
return "import-scripts";
|
||||
case "require":
|
||||
return "require";
|
||||
case "async-node":
|
||||
return "async-node";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
F(output, "devtoolNamespace", () => output.uniqueName);
|
||||
F(output, "libraryTarget", () => (output.module ? "module" : "var"));
|
||||
F(output, "path", () => path.join(process.cwd(), "dist"));
|
||||
|
|
|
@ -219,6 +219,7 @@ const getNormalizedWebpackOptions = config => {
|
|||
chunkFilename: output.chunkFilename,
|
||||
chunkFormat: output.chunkFormat,
|
||||
chunkLoading: output.chunkLoading,
|
||||
workerChunkLoading: output.workerChunkLoading,
|
||||
chunkLoadingGlobal: output.chunkLoadingGlobal,
|
||||
chunkLoadTimeout: output.chunkLoadTimeout,
|
||||
compareBeforeEmit: output.compareBeforeEmit,
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Ivan Kopeykin @vankop
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const Dependency = require("../Dependency");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const makeSerializable = require("../util/makeSerializable");
|
||||
const ModuleDependency = require("./ModuleDependency");
|
||||
|
||||
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
|
||||
/** @typedef {import("../AsyncDependenciesBlock")} AsyncDependenciesBlock */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
|
||||
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
|
||||
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
|
||||
/** @typedef {import("../Entrypoint")} Entrypoint */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("../util/Hash")} Hash */
|
||||
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
|
||||
|
||||
class WorkerDependency extends ModuleDependency {
|
||||
/**
|
||||
* @param {string} request request
|
||||
* @param {[number, number]} range range
|
||||
*/
|
||||
constructor(request, range) {
|
||||
super(request);
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of exports referenced by this dependency
|
||||
* @param {ModuleGraph} moduleGraph module graph
|
||||
* @param {RuntimeSpec} runtime the runtime for which the module is analysed
|
||||
* @returns {(string[] | ReferencedExport)[]} referenced exports
|
||||
*/
|
||||
getReferencedExports(moduleGraph, runtime) {
|
||||
return Dependency.NO_EXPORTS_REFERENCED;
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "new Worker()";
|
||||
}
|
||||
|
||||
get category() {
|
||||
return "esm";
|
||||
}
|
||||
}
|
||||
|
||||
WorkerDependency.Template = class WorkerDependencyTemplate extends ModuleDependency.Template {
|
||||
/**
|
||||
* @param {Dependency} dependency the dependency for which the template should be applied
|
||||
* @param {ReplaceSource} source the current replace source which can be modified
|
||||
* @param {DependencyTemplateContext} templateContext the context object
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(dependency, source, templateContext) {
|
||||
const { chunkGraph, moduleGraph, runtimeRequirements } = templateContext;
|
||||
const dep = /** @type {WorkerDependency} */ (dependency);
|
||||
const block = /** @type {AsyncDependenciesBlock} */ (moduleGraph.getParentBlock(
|
||||
dependency
|
||||
));
|
||||
const entrypoint = /** @type {Entrypoint} */ (chunkGraph.getBlockChunkGroup(
|
||||
block
|
||||
));
|
||||
const chunk = entrypoint.getEntrypointChunk();
|
||||
|
||||
runtimeRequirements.add(RuntimeGlobals.publicPath);
|
||||
runtimeRequirements.add(RuntimeGlobals.baseURI);
|
||||
runtimeRequirements.add(RuntimeGlobals.getChunkScriptFilename);
|
||||
|
||||
source.replace(
|
||||
dep.range[0],
|
||||
dep.range[1] - 1,
|
||||
`/* worker import */ ${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(${JSON.stringify(chunk.id)}), ${RuntimeGlobals.baseURI}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
makeSerializable(WorkerDependency, "webpack/lib/dependencies/WorkerDependency");
|
||||
|
||||
module.exports = WorkerDependency;
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { pathToFileURL } = require("url");
|
||||
const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
|
||||
const CommentCompilationWarning = require("../CommentCompilationWarning");
|
||||
const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
|
||||
const formatLocation = require("../formatLocation");
|
||||
const EnableChunkLoadingPlugin = require("../javascript/EnableChunkLoadingPlugin");
|
||||
const {
|
||||
harmonySpecifierTag
|
||||
} = require("./HarmonyImportDependencyParserPlugin");
|
||||
const WorkerDependency = require("./WorkerDependency");
|
||||
|
||||
/** @typedef {import("estree").Expression} Expression */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Entrypoint").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
|
||||
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
|
||||
/** @typedef {import("./HarmonyImportDependencyParserPlugin").HarmonySettings} HarmonySettings */
|
||||
|
||||
const getUrl = module => {
|
||||
return pathToFileURL(module.resource).toString();
|
||||
};
|
||||
|
||||
class WorkerPlugin {
|
||||
constructor(chunkLoading) {
|
||||
this._chunkLoading = chunkLoading;
|
||||
}
|
||||
/**
|
||||
* Apply the plugin
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
if (this._chunkLoading) {
|
||||
new EnableChunkLoadingPlugin(this._chunkLoading).apply(compiler);
|
||||
}
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
"WorkerPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
compilation.dependencyFactories.set(
|
||||
WorkerDependency,
|
||||
normalModuleFactory
|
||||
);
|
||||
compilation.dependencyTemplates.set(
|
||||
WorkerDependency,
|
||||
new WorkerDependency.Template()
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {JavascriptParser} parser the parser
|
||||
* @param {Expression} expr expression
|
||||
* @returns {[BasicEvaluatedExpression, [number, number]]} parsed
|
||||
*/
|
||||
const parseModuleUrl = (parser, expr) => {
|
||||
if (
|
||||
expr.type !== "NewExpression" ||
|
||||
expr.callee.type === "Super" ||
|
||||
expr.arguments.length !== 2
|
||||
)
|
||||
return;
|
||||
const [arg1, arg2] = expr.arguments;
|
||||
if (arg1.type === "SpreadElement") return;
|
||||
if (arg2.type === "SpreadElement") return;
|
||||
const callee = parser.evaluateExpression(expr.callee);
|
||||
if (!callee.isIdentifier() || callee.identifier !== "URL") return;
|
||||
const arg2Value = parser.evaluateExpression(arg2);
|
||||
if (
|
||||
!arg2Value.isString() ||
|
||||
!arg2Value.string.startsWith("file://") ||
|
||||
arg2Value.string !== getUrl(parser.state.module)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const arg1Value = parser.evaluateExpression(arg1);
|
||||
return [arg1Value, [arg1.range[0], arg2.range[1]]];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {JavascriptParser} parser the parser
|
||||
* @param {Expression} expr expression
|
||||
* @returns {object | undefined} parsed object
|
||||
*/
|
||||
const parseObjectLiteral = (parser, expr) => {
|
||||
if (expr.type !== "ObjectExpression") return;
|
||||
const obj = {};
|
||||
for (const prop of expr.properties) {
|
||||
if (prop.type === "Property") {
|
||||
if (
|
||||
!prop.method &&
|
||||
!prop.computed &&
|
||||
!prop.shorthand &&
|
||||
prop.key.type === "Identifier" &&
|
||||
!prop.value.type.endsWith("Pattern")
|
||||
) {
|
||||
const value = parser.evaluateExpression(
|
||||
/** @type {Expression} */ (prop.value)
|
||||
);
|
||||
if (value.isCompileTimeValue())
|
||||
obj[prop.key.name] = value.asCompileTimeValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {JavascriptParser} parser the parser
|
||||
* @param {object} parserOptions options
|
||||
*/
|
||||
const parserPlugin = (parser, parserOptions) => {
|
||||
if (parserOptions.worker === false) return;
|
||||
const handleNewWorker = expr => {
|
||||
if (expr.arguments.length === 0 || expr.arguments.length > 2)
|
||||
return;
|
||||
const [arg1, arg2] = expr.arguments;
|
||||
if (arg1.type === "SpreadElement") return;
|
||||
if (arg2 && arg2.type === "SpreadElement") return;
|
||||
const parsedUrl = parseModuleUrl(parser, arg1);
|
||||
if (!parsedUrl) return;
|
||||
const [url, range] = parsedUrl;
|
||||
if (url.isString()) {
|
||||
const options = arg2 && parseObjectLiteral(parser, arg2);
|
||||
const {
|
||||
options: importOptions,
|
||||
errors: commentErrors
|
||||
} = parser.parseCommentOptions(expr.range);
|
||||
|
||||
if (commentErrors) {
|
||||
for (const e of commentErrors) {
|
||||
const { comment } = e;
|
||||
parser.state.module.addWarning(
|
||||
new CommentCompilationWarning(
|
||||
`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
|
||||
comment.loc
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {EntryOptions} */
|
||||
let entryOptions = {};
|
||||
|
||||
if (importOptions) {
|
||||
if (importOptions.webpackIgnore !== undefined) {
|
||||
if (typeof importOptions.webpackIgnore !== "boolean") {
|
||||
parser.state.module.addWarning(
|
||||
new UnsupportedFeatureWarning(
|
||||
`\`webpackIgnore\` expected a boolean, but received: ${importOptions.webpackIgnore}.`,
|
||||
expr.loc
|
||||
)
|
||||
);
|
||||
} else {
|
||||
if (importOptions.webpackIgnore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (importOptions.webpackEntryOptions !== undefined) {
|
||||
if (
|
||||
typeof importOptions.webpackEntryOptions !== "object" ||
|
||||
importOptions.webpackEntryOptions === null
|
||||
) {
|
||||
parser.state.module.addWarning(
|
||||
new UnsupportedFeatureWarning(
|
||||
`\`webpackEntryOptions\` expected a object, but received: ${importOptions.webpackEntryOptions}.`,
|
||||
expr.loc
|
||||
)
|
||||
);
|
||||
} else {
|
||||
Object.assign(
|
||||
entryOptions,
|
||||
importOptions.webpackEntryOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
if (importOptions.webpackChunkName !== undefined) {
|
||||
if (typeof importOptions.webpackChunkName !== "string") {
|
||||
parser.state.module.addWarning(
|
||||
new UnsupportedFeatureWarning(
|
||||
`\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`,
|
||||
expr.loc
|
||||
)
|
||||
);
|
||||
} else {
|
||||
entryOptions.name = importOptions.webpackChunkName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(entryOptions, "name") &&
|
||||
options &&
|
||||
options.name
|
||||
) {
|
||||
entryOptions.name = options.name;
|
||||
}
|
||||
|
||||
if (!entryOptions.runtime) {
|
||||
entryOptions.runtime = `${parser.state.module.identifier()}|${formatLocation(
|
||||
expr.loc
|
||||
)}`;
|
||||
}
|
||||
|
||||
const block = new AsyncDependenciesBlock({
|
||||
name: entryOptions.name,
|
||||
entryOptions: {
|
||||
chunkLoading: this._chunkLoading,
|
||||
...entryOptions
|
||||
}
|
||||
});
|
||||
block.loc = expr.loc;
|
||||
const dep = new WorkerDependency(url.string, range);
|
||||
dep.loc = expr.loc;
|
||||
block.addDependency(dep);
|
||||
parser.state.module.addBlock(block);
|
||||
parser.walkExpression(expr.callee);
|
||||
if (arg2) parser.walkExpression(arg2);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
parser.hooks.new.for("Worker").tap("WorkerPlugin", handleNewWorker);
|
||||
parser.hooks.new
|
||||
.for("SharedWorker")
|
||||
.tap("WorkerPlugin", handleNewWorker);
|
||||
parser.hooks.call
|
||||
.for("navigator.serviceWorker.register")
|
||||
.tap("WorkerPlugin", handleNewWorker);
|
||||
parser.hooks.new
|
||||
.for(harmonySpecifierTag)
|
||||
.tap("WorkerPlugin", expr => {
|
||||
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
|
||||
if (
|
||||
!settings ||
|
||||
settings.source !== "worker_threads" ||
|
||||
settings.ids.length !== 1 ||
|
||||
settings.ids[0] !== "Worker"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return handleNewWorker(expr);
|
||||
});
|
||||
};
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/auto")
|
||||
.tap("WorkerPlugin", parserPlugin);
|
||||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/esm")
|
||||
.tap("WorkerPlugin", parserPlugin);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = WorkerPlugin;
|
|
@ -21,6 +21,7 @@ const Template = require("../Template");
|
|||
const StringXor = require("../util/StringXor");
|
||||
const { compareModulesByIdentifier } = require("../util/comparators");
|
||||
const createHash = require("../util/createHash");
|
||||
const { intersectRuntime } = require("../util/runtime");
|
||||
const JavascriptGenerator = require("./JavascriptGenerator");
|
||||
const JavascriptParser = require("./JavascriptParser");
|
||||
|
||||
|
@ -367,7 +368,7 @@ class JavascriptModulesPlugin {
|
|||
return chunk.filenameTemplate;
|
||||
} else if (chunk instanceof HotUpdateChunk) {
|
||||
return outputOptions.hotUpdateChunkFilename;
|
||||
} else if (chunk.hasRuntime() || chunk.isOnlyInitial()) {
|
||||
} else if (chunk.canBeInitial()) {
|
||||
return outputOptions.filename;
|
||||
} else {
|
||||
return outputOptions.chunkFilename;
|
||||
|
@ -813,7 +814,14 @@ class JavascriptModulesPlugin {
|
|||
result.allowInlineStartup &&
|
||||
someInIterable(
|
||||
moduleGraph.getIncomingConnections(entryModule),
|
||||
c => c.originModule && c.isActive(chunk.runtime)
|
||||
c =>
|
||||
c.originModule &&
|
||||
c.isActive(chunk.runtime) &&
|
||||
someInIterable(
|
||||
chunkGraph.getModuleRuntimes(c.originModule),
|
||||
runtime =>
|
||||
intersectRuntime(runtime, chunk.runtime) !== undefined
|
||||
)
|
||||
)
|
||||
) {
|
||||
buf2.push(
|
||||
|
|
|
@ -267,7 +267,7 @@ class JavascriptParser extends Parser {
|
|||
),
|
||||
/** @type {SyncBailHook<[ChainExpressionNode], boolean | void>} */
|
||||
optionalChaining: new SyncBailHook(["optionalChaining"]),
|
||||
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
|
||||
/** @type {HookMap<SyncBailHook<[NewExpressionNode], boolean | void>>} */
|
||||
new: new HookMap(() => new SyncBailHook(["expression"])),
|
||||
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
|
||||
expression: new HookMap(() => new SyncBailHook(["expression"])),
|
||||
|
@ -2747,19 +2747,13 @@ class JavascriptParser extends Parser {
|
|||
}
|
||||
|
||||
callHooksForExpression(hookMap, expr, ...args) {
|
||||
const exprName = this.getMemberExpressionInfo(
|
||||
return this.callHooksForExpressionWithFallback(
|
||||
hookMap,
|
||||
expr,
|
||||
ALLOWED_MEMBER_TYPES_EXPRESSION
|
||||
undefined,
|
||||
undefined,
|
||||
...args
|
||||
);
|
||||
if (exprName !== undefined) {
|
||||
return this.callHooksForInfoWithFallback(
|
||||
hookMap,
|
||||
exprName.name,
|
||||
undefined,
|
||||
undefined,
|
||||
...args
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2784,9 +2778,10 @@ class JavascriptParser extends Parser {
|
|||
ALLOWED_MEMBER_TYPES_EXPRESSION
|
||||
);
|
||||
if (exprName !== undefined) {
|
||||
const members = exprName.getMembers();
|
||||
return this.callHooksForInfoWithFallback(
|
||||
hookMap,
|
||||
exprName.name,
|
||||
members.length === 0 ? exprName.rootInfo : exprName.name,
|
||||
fallback &&
|
||||
(name => fallback(name, exprName.rootInfo, exprName.getMembers)),
|
||||
defined && (() => defined(exprName.name)),
|
||||
|
|
|
@ -75,8 +75,8 @@ class AbstractLibraryPlugin {
|
|||
const getOptionsForChunk = chunk => {
|
||||
if (compilation.chunkGraph.getNumberOfEntryModules(chunk) === 0)
|
||||
return false;
|
||||
const entry = compilation.entries.get(chunk.name);
|
||||
const library = entry && entry.options.library;
|
||||
const options = chunk.getEntryOptions();
|
||||
const library = options && options.library;
|
||||
return this._parseOptionsCached(
|
||||
library !== undefined ? library : compilation.outputOptions.library
|
||||
);
|
||||
|
|
|
@ -29,6 +29,7 @@ class CommonJsChunkLoadingPlugin {
|
|||
? "async-node"
|
||||
: "require";
|
||||
new StartupChunkDependenciesPlugin({
|
||||
chunkLoading: chunkLoadingValue,
|
||||
asyncChunkLoading: this._asyncChunkLoading
|
||||
}).apply(compiler);
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
|
@ -36,9 +37,9 @@ class CommonJsChunkLoadingPlugin {
|
|||
compilation => {
|
||||
const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
||||
const isEnabledForChunk = chunk => {
|
||||
const entry = compilation.entries.get(chunk.name);
|
||||
const options = chunk.getEntryOptions();
|
||||
const chunkLoading =
|
||||
(entry && entry.options.chunkLoading) || globalChunkLoading;
|
||||
(options && options.chunkLoading) || globalChunkLoading;
|
||||
return chunkLoading === chunkLoadingValue;
|
||||
};
|
||||
const onceForChunkSet = new WeakSet();
|
||||
|
|
|
@ -30,6 +30,13 @@ class RemoveParentModulesPlugin {
|
|||
queue.enqueue(child);
|
||||
}
|
||||
}
|
||||
for (const chunkGroup of compilation.asyncEntrypoints) {
|
||||
// initialize available modules for chunks without parents
|
||||
availableModulesMap.set(chunkGroup, new Set());
|
||||
for (const child of chunkGroup.childrenIterable) {
|
||||
queue.enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue.length > 0) {
|
||||
const chunkGroup = queue.dequeue();
|
||||
|
|
|
@ -101,6 +101,9 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (const entrypoint of chunk.getAllReferencedAsyncEntrypoints()) {
|
||||
addChunk(entrypoint.chunks[entrypoint.chunks.length - 1]);
|
||||
}
|
||||
|
||||
/** @type {Map<string, Set<string | number>>} */
|
||||
const staticUrls = new Map();
|
||||
|
|
|
@ -12,8 +12,9 @@ const StartupEntrypointRuntimeModule = require("./StartupEntrypointRuntimeModule
|
|||
|
||||
class StartupChunkDependenciesPlugin {
|
||||
constructor(options) {
|
||||
this.chunkLoading = options.chunkLoading;
|
||||
this.asyncChunkLoading =
|
||||
options && typeof options.asyncChunkLoading === "boolean"
|
||||
typeof options.asyncChunkLoading === "boolean"
|
||||
? options.asyncChunkLoading
|
||||
: true;
|
||||
}
|
||||
|
@ -27,9 +28,17 @@ class StartupChunkDependenciesPlugin {
|
|||
compiler.hooks.thisCompilation.tap(
|
||||
"StartupChunkDependenciesPlugin",
|
||||
compilation => {
|
||||
const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
||||
const isEnabledForChunk = chunk => {
|
||||
const options = chunk.getEntryOptions();
|
||||
const chunkLoading =
|
||||
(options && options.chunkLoading) || globalChunkLoading;
|
||||
return chunkLoading === this.chunkLoading;
|
||||
};
|
||||
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
||||
"StartupChunkDependenciesPlugin",
|
||||
(chunk, set) => {
|
||||
if (!isEnabledForChunk(chunk)) return;
|
||||
if (compilation.chunkGraph.hasChunkEntryDependentChunks(chunk)) {
|
||||
set.add(RuntimeGlobals.startup);
|
||||
set.add(RuntimeGlobals.ensureChunk);
|
||||
|
@ -46,6 +55,7 @@ class StartupChunkDependenciesPlugin {
|
|||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.startupEntrypoint)
|
||||
.tap("StartupChunkDependenciesPlugin", (chunk, set) => {
|
||||
if (!isEnabledForChunk(chunk)) return;
|
||||
set.add(RuntimeGlobals.ensureChunk);
|
||||
set.add(RuntimeGlobals.ensureChunkIncludeEntries);
|
||||
compilation.addRuntimeModule(
|
||||
|
|
|
@ -46,6 +46,7 @@ const { makePathsRelative, parseResource } = require("../util/identifier");
|
|||
/**
|
||||
* @typedef {Object} UsualContext
|
||||
* @property {string} type
|
||||
* @property {function(string): string} makePathsRelative
|
||||
* @property {Compilation} compilation
|
||||
* @property {Set<Module>} rootModules
|
||||
* @property {Map<string,Chunk[]>} compilationFileToChunks
|
||||
|
@ -247,7 +248,11 @@ const EXTRACT_ERROR = {
|
|||
/** @type {SimpleExtractors} */
|
||||
const SIMPLE_EXTRACTORS = {
|
||||
compilation: {
|
||||
_: (object, compilation) => {
|
||||
_: (object, compilation, context) => {
|
||||
context.makePathsRelative = makePathsRelative.bindContextCache(
|
||||
compilation.compiler.context,
|
||||
compilation.compiler.root
|
||||
);
|
||||
if (compilation.name) {
|
||||
object.name = compilation.name;
|
||||
}
|
||||
|
@ -975,7 +980,7 @@ const SIMPLE_EXTRACTORS = {
|
|||
}
|
||||
},
|
||||
chunk: {
|
||||
_: (object, chunk, { compilation: { chunkGraph } }) => {
|
||||
_: (object, chunk, { makePathsRelative, compilation: { chunkGraph } }) => {
|
||||
const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph);
|
||||
|
||||
Object.assign(object, {
|
||||
|
@ -992,8 +997,8 @@ const SIMPLE_EXTRACTORS = {
|
|||
chunk.runtime === undefined
|
||||
? undefined
|
||||
: typeof chunk.runtime === "string"
|
||||
? [chunk.runtime]
|
||||
: Array.from(chunk.runtime.sort()),
|
||||
? [makePathsRelative(chunk.runtime)]
|
||||
: Array.from(chunk.runtime.sort(), makePathsRelative),
|
||||
files: Array.from(chunk.files),
|
||||
auxiliaryFiles: Array.from(chunk.auxiliaryFiles).sort(compareIds),
|
||||
hash: chunk.renderedHash,
|
||||
|
|
|
@ -150,6 +150,8 @@ module.exports = {
|
|||
require("../dependencies/WebAssemblyExportImportedDependency"),
|
||||
"dependencies/WebAssemblyImportDependency": () =>
|
||||
require("../dependencies/WebAssemblyImportDependency"),
|
||||
"dependencies/WorkerDependency": () =>
|
||||
require("../dependencies/WorkerDependency"),
|
||||
"optimize/ConcatenatedModule": () =>
|
||||
require("../optimize/ConcatenatedModule"),
|
||||
DelegatedModule: () => require("../DelegatedModule"),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const SortableSet = require("./SortableSet");
|
||||
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
/** @typedef {import("../Compilation").EntryOptions} EntryOptions */
|
||||
/** @typedef {import("../Entrypoint").EntryOptions} EntryOptions */
|
||||
|
||||
/** @typedef {string | SortableSet<string> | undefined} RuntimeSpec */
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@ class JsonpChunkLoadingPlugin {
|
|||
compilation => {
|
||||
const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
||||
const isEnabledForChunk = chunk => {
|
||||
const entry = compilation.entries.get(chunk.name);
|
||||
const options = chunk.getEntryOptions();
|
||||
const chunkLoading =
|
||||
(entry && entry.options.chunkLoading) || globalChunkLoading;
|
||||
(options && options.chunkLoading) || globalChunkLoading;
|
||||
return chunkLoading === "jsonp";
|
||||
};
|
||||
const onceForChunkSet = new WeakSet();
|
||||
|
@ -90,10 +90,8 @@ class JsonpChunkLoadingPlugin {
|
|||
if (withDefer) {
|
||||
set.add(RuntimeGlobals.startup);
|
||||
set.add(RuntimeGlobals.startupNoDefault);
|
||||
handler(chunk, set);
|
||||
}
|
||||
if (withDefer) {
|
||||
set.add(RuntimeGlobals.require);
|
||||
handler(chunk, set);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"use strict";
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {(string|number)[]} EntryItem */
|
||||
|
@ -52,10 +53,22 @@ exports.getEntryInfo = (chunkGraph, chunk, chunkFilter) => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {boolean} true, when other chunks have this chunk as runtime chunk
|
||||
*/
|
||||
exports.needEntryDeferringCode = (compilation, chunk) => {
|
||||
for (const entrypoint of compilation.entrypoints.values()) {
|
||||
if (entrypoint.getRuntimeChunk() === chunk) {
|
||||
if (entrypoint.chunks.some(c => c !== chunk)) return true;
|
||||
if (entrypoint.chunks.length > 1 || entrypoint.chunks[0] !== chunk)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const entrypoint of compilation.asyncEntrypoints) {
|
||||
if (entrypoint.getRuntimeChunk() === chunk) {
|
||||
if (entrypoint.chunks.length > 1 || entrypoint.chunks[0] !== chunk)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -19,6 +19,7 @@ class ImportScriptsChunkLoadingPlugin {
|
|||
*/
|
||||
apply(compiler) {
|
||||
new StartupChunkDependenciesPlugin({
|
||||
chunkLoading: "import-scripts",
|
||||
asyncChunkLoading: true
|
||||
}).apply(compiler);
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
|
@ -26,9 +27,9 @@ class ImportScriptsChunkLoadingPlugin {
|
|||
compilation => {
|
||||
const globalChunkLoading = compilation.outputOptions.chunkLoading;
|
||||
const isEnabledForChunk = chunk => {
|
||||
const entry = compilation.entries.get(chunk.name);
|
||||
const options = chunk.getEntryOptions();
|
||||
const chunkLoading =
|
||||
(entry && entry.options.chunkLoading) || globalChunkLoading;
|
||||
(options && options.chunkLoading) || globalChunkLoading;
|
||||
return chunkLoading === "import-scripts";
|
||||
};
|
||||
const onceForChunkSet = new WeakSet();
|
||||
|
|
|
@ -1862,6 +1862,9 @@
|
|||
},
|
||||
"webassemblyModuleFilename": {
|
||||
"$ref": "#/definitions/WebassemblyModuleFilename"
|
||||
},
|
||||
"workerChunkLoading": {
|
||||
"$ref": "#/definitions/ChunkLoading"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1984,6 +1987,9 @@
|
|||
},
|
||||
"webassemblyModuleFilename": {
|
||||
"$ref": "#/definitions/WebassemblyModuleFilename"
|
||||
},
|
||||
"workerChunkLoading": {
|
||||
"$ref": "#/definitions/ChunkLoading"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -296,6 +296,54 @@ const describeCases = config => {
|
|||
moduleScope.window = globalContext;
|
||||
moduleScope.self = globalContext;
|
||||
moduleScope.URL = URL;
|
||||
moduleScope.Worker = class Worker {
|
||||
constructor(url, options) {
|
||||
expect(url).toBeInstanceOf(URL);
|
||||
expect(url.origin).toBe("https://test.cases");
|
||||
expect(url.pathname.startsWith("/path/")).toBe(
|
||||
true
|
||||
);
|
||||
const file = url.pathname.slice(6);
|
||||
const workerBootstrap = `
|
||||
const { parentPort } = require("worker_threads");
|
||||
const { URL } = require("url");
|
||||
const path = require("path");
|
||||
global.self = global;
|
||||
self.URL = URL;
|
||||
self.importScripts = url => {
|
||||
require(path.resolve(${JSON.stringify(outputDirectory)}, \`./\${url}\`));
|
||||
};
|
||||
parentPort.on("message", data => {
|
||||
if(self.onmessage) self.onmessage({
|
||||
data
|
||||
});
|
||||
});
|
||||
self.postMessage = data => {
|
||||
parentPort.postMessage(data);
|
||||
};
|
||||
require(${JSON.stringify(path.resolve(outputDirectory, file))});
|
||||
`;
|
||||
// eslint-disable-next-line node/no-unsupported-features/node-builtins
|
||||
this.worker = new (require("worker_threads").Worker)(
|
||||
workerBootstrap,
|
||||
{
|
||||
eval: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
set onmessage(value) {
|
||||
this.worker.on("message", data => {
|
||||
value({
|
||||
data
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
postMessage(data) {
|
||||
this.worker.postMessage(data);
|
||||
}
|
||||
};
|
||||
runInNewContext = true;
|
||||
}
|
||||
if (testConfig.moduleScope) {
|
||||
|
|
|
@ -225,6 +225,7 @@ describe("Defaults", () => {
|
|||
"ecmaVersion": 6,
|
||||
"enabledChunkLoadingTypes": Array [
|
||||
"jsonp",
|
||||
"import-scripts",
|
||||
],
|
||||
"enabledLibraryTypes": Array [],
|
||||
"filename": "[name].js",
|
||||
|
@ -250,6 +251,7 @@ describe("Defaults", () => {
|
|||
"strictModuleExceptionHandling": false,
|
||||
"uniqueName": "webpack",
|
||||
"webassemblyModuleFilename": "[hash].module.wasm",
|
||||
"workerChunkLoading": "import-scripts",
|
||||
},
|
||||
"parallelism": 100,
|
||||
"performance": false,
|
||||
|
@ -983,11 +985,16 @@ describe("Defaults", () => {
|
|||
+ "chunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "jsonp",
|
||||
- "import-scripts",
|
||||
+ "require",
|
||||
+ "require",
|
||||
@@ ... @@
|
||||
- "globalObject": "self",
|
||||
+ "globalObject": "global",
|
||||
@@ ... @@
|
||||
- "workerChunkLoading": "import-scripts",
|
||||
+ "workerChunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "aliasFields": Array [
|
||||
- "browser",
|
||||
- ],
|
||||
|
@ -1067,7 +1074,9 @@ describe("Defaults", () => {
|
|||
+ "chunkLoading": "import-scripts",
|
||||
@@ ... @@
|
||||
- "jsonp",
|
||||
+ "import-scripts",
|
||||
@@ ... @@
|
||||
- "workerChunkLoading": "import-scripts",
|
||||
+ "workerChunkLoading": false,
|
||||
@@ ... @@
|
||||
+ "worker",
|
||||
@@ ... @@
|
||||
|
@ -1095,11 +1104,16 @@ describe("Defaults", () => {
|
|||
+ "chunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "jsonp",
|
||||
- "import-scripts",
|
||||
+ "require",
|
||||
+ "require",
|
||||
@@ ... @@
|
||||
- "globalObject": "self",
|
||||
+ "globalObject": "global",
|
||||
@@ ... @@
|
||||
- "workerChunkLoading": "import-scripts",
|
||||
+ "workerChunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "aliasFields": Array [
|
||||
- "browser",
|
||||
- ],
|
||||
|
@ -1183,11 +1197,16 @@ describe("Defaults", () => {
|
|||
+ "chunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "jsonp",
|
||||
- "import-scripts",
|
||||
+ "require",
|
||||
+ "require",
|
||||
@@ ... @@
|
||||
- "globalObject": "self",
|
||||
+ "globalObject": "global",
|
||||
@@ ... @@
|
||||
- "workerChunkLoading": "import-scripts",
|
||||
+ "workerChunkLoading": "require",
|
||||
@@ ... @@
|
||||
- "aliasFields": Array [
|
||||
- "browser",
|
||||
- ],
|
||||
|
|
|
@ -72,10 +72,12 @@ describe("Stats", () => {
|
|||
expect(
|
||||
stats.toJson({
|
||||
all: false,
|
||||
errorsCount: true,
|
||||
chunkGroups: true
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"errorsCount": 0,
|
||||
"namedChunkGroups": Object {
|
||||
"entryA": Object {
|
||||
"assets": Array [
|
||||
|
@ -126,10 +128,12 @@ describe("Stats", () => {
|
|||
expect(
|
||||
stats.toJson({
|
||||
all: false,
|
||||
errorsCount: true,
|
||||
chunkGroups: true
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"errorsCount": 0,
|
||||
"namedChunkGroups": Object {
|
||||
"chunkB": Object {
|
||||
"assets": Array [
|
||||
|
@ -197,6 +201,7 @@ describe("Stats", () => {
|
|||
expect(
|
||||
stats.toJson({
|
||||
all: false,
|
||||
errorsCount: true,
|
||||
assets: true
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
|
@ -271,6 +276,7 @@ describe("Stats", () => {
|
|||
"entryB.js",
|
||||
],
|
||||
},
|
||||
"errorsCount": 0,
|
||||
"filteredAssets": undefined,
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -2678,6 +2678,40 @@ Object {
|
|||
"multiple": false,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"output-worker-chunk-loading": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).",
|
||||
"multiple": false,
|
||||
"path": "output.workerChunkLoading",
|
||||
"type": "enum",
|
||||
"values": Array [
|
||||
false,
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"description": "The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).",
|
||||
"multiple": false,
|
||||
"path": "output.workerChunkLoading",
|
||||
"type": "enum",
|
||||
"values": Array [
|
||||
"jsonp",
|
||||
"import-scripts",
|
||||
"require",
|
||||
"async-node",
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"description": "The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).",
|
||||
"multiple": false,
|
||||
"path": "output.workerChunkLoading",
|
||||
"type": "string",
|
||||
},
|
||||
],
|
||||
"description": "The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).",
|
||||
"multiple": false,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"parallelism": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
|
|
@ -2987,9 +2987,9 @@ webpack x.x.x compiled successfully in X ms"
|
|||
exports[`StatsTestCases should print correct stats for split-chunks 1`] = `
|
||||
"default:
|
||||
Entrypoint main 9.93 KiB = default/main.js
|
||||
Entrypoint a 10.5 KiB = default/a.js
|
||||
Entrypoint b 2.26 KiB = default/b.js
|
||||
Entrypoint c 2.26 KiB = default/c.js
|
||||
Entrypoint a 10.2 KiB = default/a.js
|
||||
Entrypoint b 1.98 KiB = default/b.js
|
||||
Entrypoint c 1.98 KiB = default/c.js
|
||||
chunk (runtime: b) default/b.js (b) 152 bytes [entry] [rendered]
|
||||
> ./b b
|
||||
dependent modules 80 bytes [dependent] 4 modules
|
||||
|
@ -3259,7 +3259,7 @@ name-too-long:
|
|||
|
||||
custom-chunks-filter:
|
||||
Entrypoint main 9.94 KiB = custom-chunks-filter/main.js
|
||||
Entrypoint a 10.5 KiB = custom-chunks-filter/a.js
|
||||
Entrypoint a 10.2 KiB = custom-chunks-filter/a.js
|
||||
Entrypoint b 6.47 KiB = custom-chunks-filter/282.js 204 bytes custom-chunks-filter/954.js 204 bytes custom-chunks-filter/568.js 204 bytes custom-chunks-filter/767.js 204 bytes custom-chunks-filter/b.js 5.68 KiB
|
||||
Entrypoint c 6.47 KiB = custom-chunks-filter/282.js 204 bytes custom-chunks-filter/769.js 204 bytes custom-chunks-filter/568.js 204 bytes custom-chunks-filter/767.js 204 bytes custom-chunks-filter/c.js 5.68 KiB
|
||||
chunk (runtime: b) custom-chunks-filter/b.js (b) 72 bytes (javascript) 2.6 KiB (runtime) ={282}= ={568}= ={767}= ={954}= [entry] [rendered]
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { Worker } from "worker_threads";
|
||||
|
||||
it("should allow to create a WebWorker", async () => {
|
||||
const worker = new Worker(new URL("./worker.js", import.meta.url), {
|
||||
name: "MyWorker"
|
||||
});
|
||||
worker.postMessage("ok");
|
||||
const result = await new Promise(resolve => {
|
||||
worker.on("message", data => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
expect(result).toBe("data: OK, thanks");
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
it("should allow to create another WebWorker", async () => {
|
||||
const worker = new Worker(new URL("./worker.js", import.meta.url), {
|
||||
name: "MyWorker"
|
||||
});
|
||||
worker.postMessage("ok");
|
||||
const result = await new Promise(resolve => {
|
||||
worker.on("message", data => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
expect(result).toBe("data: OK, thanks");
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
it("should allow to share chunks", async () => {
|
||||
const { upper } = await import("./module");
|
||||
expect(upper("ok")).toBe("OK");
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export function upper(str) {
|
||||
return str.toUpperCase();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function(i, options) {
|
||||
return ["main.js"];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
}
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
import { parentPort } from "worker_threads";
|
||||
|
||||
parentPort.on("message", async data => {
|
||||
const { upper } = await import("./module");
|
||||
parentPort.postMessage(`data: ${upper(data)}, thanks`);
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import { Worker } from "worker_threads";
|
||||
|
||||
it("should allow to create a WebWorker", async () => {
|
||||
const worker = new Worker(new URL("./worker.js", import.meta.url));
|
||||
worker.postMessage("ok");
|
||||
const result = await new Promise(resolve => {
|
||||
worker.on("message", data => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
expect(result).toBe("data: OK, thanks");
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
it("should allow to share chunks", async () => {
|
||||
const { upper } = await import("./module");
|
||||
expect(upper("ok")).toBe("OK");
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export function upper(str) {
|
||||
return str.toUpperCase();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function(i, options) {
|
||||
return ["main.js"];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
}
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
import { parentPort } from "worker_threads";
|
||||
|
||||
parentPort.on("message", async data => {
|
||||
const { upper } = await import("./module");
|
||||
parentPort.postMessage(`data: ${upper(data)}, thanks`);
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
it("should allow to create a WebWorker", async () => {
|
||||
const worker = new Worker(new URL("./worker.js", import.meta.url), {
|
||||
type: "module"
|
||||
});
|
||||
worker.postMessage("ok");
|
||||
const result = await new Promise(resolve => {
|
||||
worker.onmessage = event => {
|
||||
resolve(event.data);
|
||||
};
|
||||
});
|
||||
expect(result).toBe("data: OK, thanks");
|
||||
});
|
||||
|
||||
it("should allow to share chunks", async () => {
|
||||
const promise = import("./module");
|
||||
const script = document.head._children[0];
|
||||
const src = script.src;
|
||||
const file = src.slice(src.lastIndexOf("/"));
|
||||
__non_webpack_require__(`./${file}`);
|
||||
script.onload();
|
||||
const { upper } = await promise;
|
||||
expect(upper("ok")).toBe("OK");
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export function upper(str) {
|
||||
return str.toUpperCase();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function(i, options) {
|
||||
return ["main.js"];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
},
|
||||
target: "web"
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
onmessage = async event => {
|
||||
const { upper } = await import("./module");
|
||||
postMessage(`data: ${upper(event.data)}, thanks`);
|
||||
};
|
|
@ -262,12 +262,15 @@ declare abstract class AsyncDependenciesBlock extends DependenciesBlock {
|
|||
preloadOrder?: number;
|
||||
prefetchOrder?: number;
|
||||
name?: string;
|
||||
entryOptions?: { name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>;
|
||||
};
|
||||
loc: SyntheticDependencyLocation | RealDependencyLocation;
|
||||
request: string;
|
||||
parent: DependenciesBlock;
|
||||
chunkName: string;
|
||||
isAsync(parentChunkGroup: ChunkGroup): boolean;
|
||||
module: any;
|
||||
}
|
||||
declare abstract class AsyncQueue<T, K, R> {
|
||||
|
@ -617,6 +620,10 @@ declare class Chunk {
|
|||
hasRuntime(): boolean;
|
||||
canBeInitial(): boolean;
|
||||
isOnlyInitial(): boolean;
|
||||
getEntryOptions(): { name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>;
|
||||
addGroup(chunkGroup: ChunkGroup): void;
|
||||
removeGroup(chunkGroup: ChunkGroup): void;
|
||||
isInGroup(chunkGroup: ChunkGroup): boolean;
|
||||
|
@ -628,6 +635,7 @@ declare class Chunk {
|
|||
getAllAsyncChunks(): Set<Chunk>;
|
||||
getAllInitialChunks(): Set<Chunk>;
|
||||
getAllReferencedChunks(): Set<Chunk>;
|
||||
getAllReferencedAsyncEntrypoints(): Set<Entrypoint>;
|
||||
hasAsyncChunks(): boolean;
|
||||
getChildIdsByOrders(
|
||||
chunkGraph: ChunkGraph,
|
||||
|
@ -848,6 +856,8 @@ declare abstract class ChunkGroup {
|
|||
hasParent(parent: ChunkGroup): boolean;
|
||||
readonly parentsIterable: SortableSet<ChunkGroup>;
|
||||
removeParent(chunkGroup: ChunkGroup): boolean;
|
||||
addAsyncEntrypoint(entrypoint: Entrypoint): boolean;
|
||||
readonly asyncEntrypointsIterable: SortableSet<ChunkGroup>;
|
||||
getBlocks(): any[];
|
||||
getNumberOfBlocks(): number;
|
||||
hasBlock(block?: any): boolean;
|
||||
|
@ -1049,7 +1059,7 @@ declare class Compilation {
|
|||
addEntry: SyncHook<
|
||||
[
|
||||
Dependency,
|
||||
{ name: string } & Pick<
|
||||
{ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>
|
||||
|
@ -1059,7 +1069,7 @@ declare class Compilation {
|
|||
failedEntry: SyncHook<
|
||||
[
|
||||
Dependency,
|
||||
{ name: string } & Pick<
|
||||
{ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>,
|
||||
|
@ -1070,7 +1080,7 @@ declare class Compilation {
|
|||
succeedEntry: SyncHook<
|
||||
[
|
||||
Dependency,
|
||||
{ name: string } & Pick<
|
||||
{ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>,
|
||||
|
@ -1227,6 +1237,7 @@ declare class Compilation {
|
|||
entries: Map<string, EntryData>;
|
||||
globalEntry: EntryData;
|
||||
entrypoints: Map<string, Entrypoint>;
|
||||
asyncEntrypoints: Entrypoint[];
|
||||
chunks: Set<Chunk>;
|
||||
chunkGroups: ChunkGroup[];
|
||||
namedChunkGroups: Map<string, ChunkGroup>;
|
||||
|
@ -1306,7 +1317,7 @@ declare class Compilation {
|
|||
entry: Dependency,
|
||||
optionsOrName:
|
||||
| string
|
||||
| ({ name: string } & Pick<
|
||||
| ({ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>),
|
||||
|
@ -1315,7 +1326,7 @@ declare class Compilation {
|
|||
addInclude(
|
||||
context: string,
|
||||
dependency: Dependency,
|
||||
options: { name: string } & Pick<
|
||||
options: { name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>,
|
||||
|
@ -1333,7 +1344,7 @@ declare class Compilation {
|
|||
blocks: DependenciesBlock[]
|
||||
): void;
|
||||
codeGeneration(callback?: any): void;
|
||||
processRuntimeRequirements(entrypoints: Iterable<Entrypoint>): void;
|
||||
processRuntimeRequirements(): void;
|
||||
addRuntimeModule(chunk: Chunk, module: RuntimeModule): void;
|
||||
addChunkInGroup(
|
||||
groupOptions:
|
||||
|
@ -1343,6 +1354,15 @@ declare class Compilation {
|
|||
loc: SyntheticDependencyLocation | RealDependencyLocation,
|
||||
request: string
|
||||
): ChunkGroup;
|
||||
addAsyncEntrypoint(
|
||||
options: { name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>,
|
||||
module: Module,
|
||||
loc: SyntheticDependencyLocation | RealDependencyLocation,
|
||||
request: string
|
||||
): Entrypoint;
|
||||
|
||||
/**
|
||||
* This method first looks to see if a name is provided for a new chunk,
|
||||
|
@ -2416,7 +2436,7 @@ declare interface EntryData {
|
|||
/**
|
||||
* options of the entrypoint
|
||||
*/
|
||||
options: { name: string } & Pick<
|
||||
options: { name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>;
|
||||
|
@ -2513,7 +2533,7 @@ declare class EntryPlugin {
|
|||
entry: string,
|
||||
options:
|
||||
| string
|
||||
| ({ name: string } & Pick<
|
||||
| ({ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>)
|
||||
|
@ -2522,7 +2542,7 @@ declare class EntryPlugin {
|
|||
entry: string;
|
||||
options:
|
||||
| string
|
||||
| ({ name: string } & Pick<
|
||||
| ({ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>);
|
||||
|
@ -2535,7 +2555,7 @@ declare class EntryPlugin {
|
|||
entry: string,
|
||||
options:
|
||||
| string
|
||||
| ({ name: string } & Pick<
|
||||
| ({ name?: string } & Pick<
|
||||
EntryDescriptionNormalized,
|
||||
"filename" | "chunkLoading" | "dependOn" | "library" | "runtime"
|
||||
>)
|
||||
|
@ -3624,7 +3644,7 @@ declare class JavascriptParser extends Parser {
|
|||
>
|
||||
>;
|
||||
optionalChaining: SyncBailHook<[ChainExpression], boolean | void>;
|
||||
new: HookMap<SyncBailHook<[Expression], boolean | void>>;
|
||||
new: HookMap<SyncBailHook<[NewExpression], boolean | void>>;
|
||||
expression: HookMap<SyncBailHook<[Expression], boolean | void>>;
|
||||
expressionMemberChain: HookMap<
|
||||
SyncBailHook<[Expression, string[]], boolean | void>
|
||||
|
@ -5781,6 +5801,11 @@ declare interface Output {
|
|||
* The filename of WebAssembly modules as relative path inside the `output.path` directory.
|
||||
*/
|
||||
webassemblyModuleFilename?: string;
|
||||
|
||||
/**
|
||||
* The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).
|
||||
*/
|
||||
workerChunkLoading?: DevTool;
|
||||
}
|
||||
declare interface OutputFileSystem {
|
||||
writeFile: (
|
||||
|
@ -5990,6 +6015,11 @@ declare interface OutputNormalized {
|
|||
* The filename of WebAssembly modules as relative path inside the `output.path` directory.
|
||||
*/
|
||||
webassemblyModuleFilename?: string;
|
||||
|
||||
/**
|
||||
* The method of loading chunks (methods included by default are 'jsonp' (web), 'importScripts' (WebWorker), 'require' (sync node.js), 'async-node' (async node.js), but others might be added by plugins).
|
||||
*/
|
||||
workerChunkLoading?: DevTool;
|
||||
}
|
||||
declare interface ParsedIdentifier {
|
||||
request: string;
|
||||
|
|
Loading…
Reference in New Issue