Skip to content

Commit a8a5d89

Browse files
committed
fix: one worker for each bundling request
1 parent 8db8d06 commit a8a5d89

4 files changed

Lines changed: 65 additions & 61 deletions

File tree

src/lib/bundle/core.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ import { RSPACK_CONFIG } from "@/store/common";
66
import { DependenciesPlugin } from "./dependency";
77

88
type RspackBrowserAPI = typeof import("@rspack/browser");
9+
type RspackStats = {
10+
toJson: (options: { all: false; errors: true; warnings: false }) => {
11+
errors?: Array<{ message: string }>;
12+
warnings?: Array<{ message: string }>;
13+
};
14+
};
15+
type RspackCompiler = {
16+
run: (callback: (error: Error | null, stats?: RspackStats) => void) => void;
17+
};
918
interface RspackBrowserPackageManifest {
1019
dependencies?: Record<string, string>;
1120
}
@@ -375,7 +384,8 @@ export async function bundle(files: SourceFile[], version: string): Promise<Bund
375384

376385
const startTime = performance.now();
377386
return new Promise((resolve) => {
378-
rspack(options, async (err, stats) => {
387+
const compiler = rspack(options) as RspackCompiler;
388+
compiler.run(async (err, stats) => {
379389
if (err) {
380390
const endTime = performance.now();
381391
resolve(createBundleFailure([err.message], endTime - startTime));

src/lib/bundle/index.ts

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,67 @@
11
import type { BundleResult, SourceFile } from "@/store/bundler";
22
import type { BundleWorkerRequest, BundleWorkerResponse } from "./protocol";
33

4-
let nextRequestId = 0;
5-
let bundleWorker: Worker | null = null;
4+
let currentBundle: {
5+
worker: Worker;
6+
reject: (error: Error) => void;
7+
} | null = null;
68

7-
const pendingRequests = new Map<
8-
number,
9-
{
10-
resolve: (result: BundleResult) => void;
11-
reject: (error: Error) => void;
9+
function stopCurrentBundle(error: Error) {
10+
if (!currentBundle) {
11+
return;
1212
}
13-
>();
1413

15-
function rejectPendingRequests(error: Error) {
16-
for (const { reject } of pendingRequests.values()) {
17-
reject(error);
18-
}
19-
pendingRequests.clear();
14+
const { worker, reject } = currentBundle;
15+
currentBundle = null;
16+
worker.terminate();
17+
reject(error);
2018
}
2119

22-
function ensureWorker() {
23-
if (bundleWorker) {
24-
return bundleWorker;
25-
}
20+
export async function bundle(files: SourceFile[], version: string): Promise<BundleResult> {
21+
stopCurrentBundle(new Error("Bundle request superseded"));
2622

27-
bundleWorker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module" });
23+
const worker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module" });
24+
const request: BundleWorkerRequest = {
25+
files,
26+
version,
27+
};
2828

29-
bundleWorker.onmessage = (event: MessageEvent<BundleWorkerResponse>) => {
30-
const response = event.data;
31-
const pending = pendingRequests.get(response.id);
32-
if (!pending) {
33-
return;
34-
}
29+
return new Promise((resolve, reject) => {
30+
const bundleState = { worker, reject };
31+
currentBundle = bundleState;
3532

36-
pendingRequests.delete(response.id);
37-
if (response.ok) {
38-
pending.resolve(response.result);
39-
return;
40-
}
33+
const clearCurrentBundle = () => {
34+
if (currentBundle === bundleState) {
35+
currentBundle = null;
36+
}
37+
};
4138

42-
pending.reject(new Error(response.error));
43-
};
39+
worker.onmessage = (event: MessageEvent<BundleWorkerResponse>) => {
40+
if (currentBundle !== bundleState) {
41+
return;
42+
}
4443

45-
bundleWorker.onerror = (event) => {
46-
const error = new Error(event.message || "Rspack worker crashed");
47-
rejectPendingRequests(error);
48-
bundleWorker?.terminate();
49-
bundleWorker = null;
50-
};
44+
clearCurrentBundle();
5145

52-
return bundleWorker;
53-
}
46+
const response = event.data;
47+
if (response.ok) {
48+
resolve(response.result);
49+
return;
50+
}
5451

55-
export async function bundle(files: SourceFile[], version: string): Promise<BundleResult> {
56-
const worker = ensureWorker();
57-
const id = nextRequestId++;
52+
reject(new Error(response.error));
53+
};
5854

59-
const request: BundleWorkerRequest = {
60-
id,
61-
files,
62-
version,
63-
};
55+
worker.onerror = (event) => {
56+
if (currentBundle !== bundleState) {
57+
return;
58+
}
59+
60+
clearCurrentBundle();
61+
worker.terminate();
62+
reject(new Error(event.message || "Rspack worker crashed"));
63+
};
6464

65-
return new Promise((resolve, reject) => {
66-
pendingRequests.set(id, {
67-
resolve,
68-
reject,
69-
});
7065
worker.postMessage(request);
7166
});
7267
}

src/lib/bundle/protocol.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import type { BundleResult, SourceFile } from "@/store/bundler";
22

33
export interface BundleWorkerRequest {
4-
id: number;
54
files: SourceFile[];
65
version: string;
76
}
87

98
export interface BundleWorkerSuccessResponse {
10-
id: number;
119
ok: true;
1210
result: BundleResult;
1311
}
1412

1513
export interface BundleWorkerErrorResponse {
16-
id: number;
1714
ok: false;
1815
error: string;
1916
}

src/lib/bundle/worker.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
import { bundle } from "./core";
22
import type { BundleWorkerRequest, BundleWorkerResponse } from "./protocol";
33

4-
self.onmessage = async (event: MessageEvent<BundleWorkerRequest>) => {
5-
const { id, files, version } = event.data;
4+
async function handleBundleRequest(event: MessageEvent<BundleWorkerRequest>) {
5+
const { files, version } = event.data;
66

77
try {
88
const result = await bundle(files, version);
99
const response: BundleWorkerResponse = {
10-
id,
1110
ok: true,
1211
result,
1312
};
1413
self.postMessage(response);
1514
} catch (error) {
1615
const response: BundleWorkerResponse = {
17-
id,
1816
ok: false,
1917
error: error instanceof Error ? error.message : "Failed to bundle with rspack",
2018
};
2119
self.postMessage(response);
20+
} finally {
21+
self.close();
2222
}
23-
};
23+
}
24+
25+
self.addEventListener("message", handleBundleRequest, { once: true });

0 commit comments

Comments
 (0)