one
Version:
One is a new React Framework that makes Vite serve both native and web.
178 lines • 5.19 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
value: true
}), mod);
var workerPool_exports = {};
__export(workerPool_exports, {
BuildWorkerPool: () => BuildWorkerPool,
getWorkerPool: () => getWorkerPool,
terminateWorkerPool: () => terminateWorkerPool
});
module.exports = __toCommonJS(workerPool_exports);
var import_node_worker_threads = require("node:worker_threads");
var import_node_os = require("node:os");
var import_node_url = require("node:url");
var import_node_path = require("node:path");
const import_meta = {};
const __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
const __dirname = (0, import_node_path.dirname)(__filename);
class BuildWorkerPool {
workers = [];
available = [];
taskQueue = [];
pendingById = /* @__PURE__ */new Map();
nextId = 0;
readyCount = 0;
initCount = 0;
_ready;
_resolveReady;
_initialized;
_resolveInitialized;
_terminated = false;
constructor(size = Math.max(1, (0, import_node_os.cpus)().length - 1)) {
this._ready = new Promise(resolve => {
this._resolveReady = resolve;
});
this._initialized = new Promise(resolve => {
this._resolveInitialized = resolve;
});
const workerPath = (0, import_node_path.join)(__dirname, "buildPageWorker.mjs");
for (let i = 0; i < size; i++) {
const worker = new import_node_worker_threads.Worker(workerPath);
worker.on("message", msg => {
if (msg.type === "ready") {
this.readyCount++;
this.available.push(worker);
if (this.readyCount === size) {
this._resolveReady();
}
} else if (msg.type === "init-done") {
this.initCount++;
if (this.initCount === size) {
this._resolveInitialized();
}
this.dispatch();
} else if (msg.type === "done" || msg.type === "error") {
const pending = this.pendingById.get(msg.id);
if (pending) {
this.pendingById.delete(msg.id);
if (msg.type === "done") {
pending.resolve(msg.result);
} else {
pending.reject(new Error(msg.error));
}
}
this.available.push(worker);
this.dispatch();
}
});
worker.on("error", err => {
console.error("[BuildWorkerPool] Worker error:", err);
});
this.workers.push(worker);
}
}
get size() {
return this.workers.length;
}
// initialize all workers with pre-loaded config from main thread
async initialize(oneOptions) {
await this._ready;
for (const worker of this.workers) {
worker.postMessage({
type: "init",
id: this.nextId++,
oneOptions
});
}
await this._initialized;
}
dispatch() {
while (this.available.length > 0 && this.taskQueue.length > 0) {
const worker = this.available.shift();
const {
msg,
pending
} = this.taskQueue.shift();
this.pendingById.set(pending.id, pending);
worker.postMessage(msg);
}
}
async buildPage(args) {
if (this._terminated) {
throw new Error("Worker pool has been terminated");
}
const serializedRoute = {
type: args.foundRoute.type,
file: args.foundRoute.file,
// only keep serializable layout data
layouts: args.foundRoute.layouts?.map(layout => ({
contextKey: layout.contextKey,
loaderServerPath: layout.loaderServerPath,
layoutRenderMode: layout.layoutRenderMode
})),
// only keep contextKey from middlewares
middlewares: args.foundRoute.middlewares?.map(mw => ({
contextKey: mw.contextKey
}))
};
const id = this.nextId++;
const msg = {
type: "build",
id,
args: {
...args,
foundRoute: serializedRoute
}
};
return new Promise((resolve, reject) => {
const pending = {
id,
resolve,
reject
};
this.taskQueue.push({
msg,
pending
});
this.dispatch();
});
}
async terminate() {
this._terminated = true;
await Promise.all(this.workers.map(w => w.terminate()));
this.workers = [];
this.available = [];
}
}
let pool = null;
function getWorkerPool(size) {
if (!pool) {
pool = new BuildWorkerPool(size);
}
return pool;
}
async function terminateWorkerPool() {
if (pool) {
await pool.terminate();
pool = null;
}
}