webpack/test/helpers/createFakeWorker.js

123 lines
2.7 KiB
JavaScript

"use strict";
const path = require("path");
module.exports = ({ outputDirectory }) =>
class Worker {
constructor(resource, options = {}) {
const isFileURL = /^file:/i.test(resource);
const isBlobURL = /^blob:/i.test(resource);
if (!isFileURL && !isBlobURL) {
expect(resource.origin).toBe("https://test.cases");
expect(resource.pathname.startsWith("/path/")).toBe(true);
}
this.url = resource;
const file = isFileURL
? resource
: path.resolve(
outputDirectory,
isBlobURL
? options.originalURL.pathname.slice(6)
: resource.pathname.slice(6)
);
const workerBootstrap = `
const { parentPort } = require("worker_threads");
const { URL, fileURLToPath } = require("url");
const path = require("path");
const fs = require("fs");
global.self = global;
self.URL = URL;
self.location = new URL(${JSON.stringify(
isBlobURL
? resource.toString().replace("nodedata:", "https://test.cases/path/")
: resource.toString()
)});
const urlToPath = url => {
if (/^file:/i.test(url)) return fileURLToPath(url);
if (url.startsWith("https://test.cases/path/")) url = url.slice(24);
return path.resolve(${JSON.stringify(outputDirectory)}, \`./\${url}\`);
};
self.importScripts = url => {
${
options.type === "module"
? 'throw new Error("importScripts is not supported in module workers")'
: "require(urlToPath(url))"
};
};
self.fetch = async url => {
try {
const buffer = await new Promise((resolve, reject) =>
fs.readFile(urlToPath(url), (err, b) =>
err ? reject(err) : resolve(b)
)
);
return {
headers: { get(name) { } },
status: 200,
ok: true,
arrayBuffer() { return buffer; },
json: async () => JSON.parse(buffer.toString("utf-8"))
};
} catch(err) {
if(err.code === "ENOENT") {
return {
status: 404,
ok: false
};
}
throw err;
}
};
self.postMessage = data => {
parentPort.postMessage(data);
};
if (${options.type === "module"}) {
import(${JSON.stringify(file)}).then(() => {
parentPort.on("message", data => {
if(self.onmessage) self.onmessage({
data
});
});
});
} else {
parentPort.on("message", data => {
if(self.onmessage) self.onmessage({
data
});
});
require(${JSON.stringify(file)});
}
`;
this.worker = new (require("worker_threads").Worker)(workerBootstrap, {
eval: true
});
this._onmessage = undefined;
}
// eslint-disable-next-line accessor-pairs
set onmessage(value) {
if (this._onmessage) this.worker.off("message", this._onmessage);
this.worker.on(
"message",
(this._onmessage = (data) => {
value({
data
});
})
);
}
postMessage(data) {
this.worker.postMessage(data);
}
terminate() {
return this.worker.terminate();
}
};