fix: support umd web workers loading

This commit is contained in:
Alexander Akait 2025-09-19 01:25:38 +03:00 committed by GitHub
parent 7fc28f1e53
commit 3ac31e24e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 216 additions and 72 deletions

View File

@ -69,7 +69,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
if (options && options.baseUri) { if (options && options.baseUri) {
return `${RuntimeGlobals.baseURI} = ${JSON.stringify(options.baseUri)};`; return `${RuntimeGlobals.baseURI} = ${JSON.stringify(options.baseUri)};`;
} }
return `${RuntimeGlobals.baseURI} = document.baseURI || self.location.href;`; return `${RuntimeGlobals.baseURI} = (document && document.baseURI) || self.location.href;`;
} }
/** /**

View File

@ -3,14 +3,21 @@ import * as styles from "./style.modules.css";
it("should work", done => { it("should work", done => {
expect(pureStyle).toEqual({}); expect(pureStyle).toEqual({});
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("background")).toBe(" red"); if (typeof document !== "undefined") {
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("background")).toBe(" red");
}
expect(styles.foo).toBe('_style_modules_css-foo'); expect(styles.foo).toBe('_style_modules_css-foo');
import(/* webpackPrefetch: true */ "./style2.css").then(x => { import(/* webpackPrefetch: true */ "./style2.css").then(x => {
expect(x).toEqual({}); expect(x).toEqual({});
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("color")).toBe(" blue"); if (typeof document !== "undefined") {
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("color")).toBe(" blue");
}
import(/* webpackPrefetch: true */ "./style2.modules.css").then(x => { import(/* webpackPrefetch: true */ "./style2.modules.css").then(x => {
expect(x.bar).toBe("_style2_modules_css-bar"); expect(x.bar).toBe("_style2_modules_css-bar");

View File

@ -1,10 +1,16 @@
"use strict"; "use strict";
module.exports = { module.exports = {
moduleScope(scope) { moduleScope(scope, options) {
const link = scope.window.document.createElement("link"); if (options.name.includes("node")) {
link.rel = "stylesheet"; delete scope.window;
link.href = "bundle0.css"; delete scope.document;
scope.window.document.head.appendChild(link); delete scope.self;
} else {
const link = scope.window.document.createElement("link");
link.rel = "stylesheet";
link.href = "bundle0.css";
scope.window.document.head.appendChild(link);
}
} }
}; };

View File

@ -1,11 +1,25 @@
"use strict"; "use strict";
/** @type {import("../../../../").Configuration} */ /** @type {import("../../../../").Configuration[]} */
module.exports = { module.exports = [
target: ["web", "node"], {
mode: "development", name: "web",
experiments: { target: ["web", "node"],
css: true, devtool: false,
outputModule: true mode: "development",
experiments: {
css: true,
outputModule: true
}
},
{
name: "node",
target: ["web", "node"],
devtool: false,
mode: "development",
experiments: {
css: true,
outputModule: true
}
} }
}; ];

View File

@ -1,6 +1,13 @@
"use strict"; "use strict";
module.exports = { module.exports = {
moduleScope(scope, options) {
if (options.name.includes("node")) {
delete scope.window;
delete scope.document;
delete scope.self;
}
},
findBundle() { findBundle() {
return ["./runtime.mjs", "./separate.mjs", "./main.mjs"]; return ["./runtime.mjs", "./separate.mjs", "./main.mjs"];
} }

View File

@ -1,32 +1,65 @@
"use strict"; "use strict";
/** @type {import("../../../../").Configuration} */ /** @type {import("../../../../").Configuration[]} */
module.exports = { module.exports = [
output: { {
filename: "[name].mjs", name: "web",
library: { output: {
type: "module" filename: "[name].mjs",
} library: {
}, type: "module"
target: ["web", "node"], }
experiments: { },
outputModule: true target: ["web", "node"],
}, experiments: {
optimization: { outputModule: true
minimize: true, },
runtimeChunk: "single", optimization: {
splitChunks: { minimize: true,
cacheGroups: { runtimeChunk: "single",
separate: { splitChunks: {
test: /separate/, cacheGroups: {
chunks: "all", separate: {
filename: "separate.mjs", test: /separate/,
enforce: true chunks: "all",
filename: "separate.mjs",
enforce: true
}
} }
} }
},
externals: {
"external-self": "./main.mjs"
} }
}, },
externals: { {
"external-self": "./main.mjs" name: "node",
output: {
filename: "[name].mjs",
library: {
type: "module"
}
},
target: ["web", "node"],
experiments: {
outputModule: true
},
optimization: {
minimize: true,
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
separate: {
test: /separate/,
chunks: "all",
filename: "separate.mjs",
enforce: true
}
}
}
},
externals: {
"external-self": "./main.mjs"
}
} }
}; ];

View File

@ -1,27 +1,7 @@
"use strict"; "use strict";
/** @type {import("../../../../").Configuration} */ /** @type {import("../../../../").Configuration[]} */
module.exports = [ module.exports = [
{
name: "node",
target: ["web", "node"],
module: {
rules: [
{
test: /\.wat$/,
loader: "wast-loader",
type: "webassembly/async"
}
]
},
output: {
webassemblyModuleFilename: "[id].[hash].wasm"
},
experiments: {
outputModule: true,
asyncWebAssembly: true
}
},
{ {
name: "web", name: "web",
target: ["web", "node"], target: ["web", "node"],
@ -41,5 +21,25 @@ module.exports = [
outputModule: true, outputModule: true,
asyncWebAssembly: true asyncWebAssembly: true
} }
},
{
name: "node",
target: ["web", "node"],
module: {
rules: [
{
test: /\.wat$/,
loader: "wast-loader",
type: "webassembly/async"
}
]
},
output: {
webassemblyModuleFilename: "[id].[hash].wasm"
},
experiments: {
outputModule: true,
asyncWebAssembly: true
}
} }
]; ];

View File

@ -0,0 +1,5 @@
import * as lib from "library";
it("should work", () => {
expect(lib.value).toBe("data: OK, thanks")
});

View File

@ -0,0 +1,18 @@
let value;
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 => {
value = event.data;
resolve(event.data);
};
});
expect(result).toBe("data: OK, thanks");
await worker.terminate();
});
export { value }

View File

@ -0,0 +1,3 @@
export function upper(str) {
return str.toUpperCase();
}

View File

@ -0,0 +1,7 @@
"use strict";
module.exports = {
moduleScope(scope) {
delete scope.document.baseURI;
}
};

View File

@ -0,0 +1,5 @@
"use strict";
const supportsWorker = require("../../../helpers/supportsWorker");
module.exports = () => supportsWorker();

View File

@ -0,0 +1,29 @@
"use strict";
const path = require("path");
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{
name: "library",
entry: "./library.js",
target: "web",
output: {
library: {
name: "library",
type: "umd"
}
}
},
{
name: "build",
dependencies: ["library"],
entry: "./index.js",
target: "web",
resolve: {
alias: {
library: path.resolve(testPath, "./bundle0.js")
}
}
}
];

View File

@ -0,0 +1,7 @@
export function upper(str) {
return str.toUpperCase();
}
self.onmessage = async event => {
postMessage(`data: ${upper(event.data)}, thanks`);
};

View File

@ -3,10 +3,9 @@
module.exports = { module.exports = {
moduleScope(scope, options) { moduleScope(scope, options) {
if (options.name.includes("node")) { if (options.name.includes("node")) {
delete scope.Worker; delete scope.window;
delete scope.document;
delete scope.self;
} }
},
findBundle() {
return ["web-main.mjs"];
} }
}; };

View File

@ -1,13 +1,17 @@
"use strict"; "use strict";
/** @type {import("../../../../").Configuration} */ /** @type {import("../../../../").Configuration[]} */
module.exports = [ module.exports = [
{ {
name: "web", name: "web",
target: ["web", "node"], target: ["web", "node"],
output: { experiments: {
filename: "web-[name].mjs" outputModule: true
}, }
},
{
name: "node",
target: ["web", "node"],
experiments: { experiments: {
outputModule: true outputModule: true
} }