Skip to content

Commit

Permalink
[search] Add a direct inline worker instantiation fallback.
Browse files Browse the repository at this point in the history
This works around parcel-bundler/parcel#9051, which makes it impossible for us to recover from instantiation errors using the more portable `new URL(…, import.meta.url)` strategy.
  • Loading branch information
lgarron committed May 29, 2023
1 parent d91053e commit 44d3917
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 8 deletions.
70 changes: 62 additions & 8 deletions src/cubing/search/instantiator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import { insideAPI, type WorkerInsideAPI } from "./inside/api";
import { searchOutsideDebugGlobals } from "./outside";
import {
instantiateSearchWorkerURLNewURLImportMetaURL,
searchWorkerURLEsbuildWorkaround,
searchWorkerURLImportMetaResolve,
searchWorkerURLNewURLImportMetaURL,
Expand Down Expand Up @@ -81,6 +82,43 @@ export async function instantiateModuleWorker(
});
}

// Maybe some day if we work really hard, this code path can work:
// - in `node` ()
// - for CDNs (using `BlankWorker`)
export async function instantiateModuleWorkerDirectlyForBrowser(): Promise<InsideOutsideAPI> {
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO
return new Promise<InsideOutsideAPI>(async (resolve, reject) => {
try {
const worker = instantiateSearchWorkerURLNewURLImportMetaURL();

const onError = (e: ErrorEvent) => {
reject(e);
};

// TODO: Remove this once we can remove the workarounds for lack of `import.meta.resolve(…)` support.
const onFirstMessage = (messageData: string) => {
if (messageData === "comlink-exposed") {
// We need to clear the timeout so that we don't prevent `node` from exiting in the meantime.
resolve(wrapWithTerminate(worker));
} else {
reject(
new Error(`wrong module instantiation message ${messageData}`),
);
}
};

worker.addEventListener("error", onError, {
once: true,
});
worker.addEventListener("message", (e) => onFirstMessage(e.data), {
once: true,
});
} catch (e) {
reject(e);
}
});
}

function wrapWithTerminate(worker: Worker): InsideOutsideAPI {
const insideAPI = wrap<WorkerInsideAPI>(worker);
const terminate = worker.terminate.bind(worker);
Expand Down Expand Up @@ -119,25 +157,41 @@ async function instantiateWorkerImplementation(): Promise<InsideOutsideAPI> {
}

const fallbackOrder: [
fn: () => string | URL | Promise<string>,
fn: () => Promise<InsideOutsideAPI>,
description: string,
warnOnSuccess: boolean,
warnOnSuccess: null | string,
][] = [
[searchWorkerURLImportMetaResolve, "using `import.meta.resolve(…)", false],
[
searchWorkerURLNewURLImportMetaURL,
async () =>
instantiateModuleWorker(await searchWorkerURLImportMetaResolve()),
"using `import.meta.resolve(…)",
null,
],
// TODO: This fallback should be lower (because it's less portable), but we need to try it earlier to work around https://github.com/parcel-bundler/parcel/issues/9051
[
instantiateModuleWorkerDirectlyForBrowser,
"using inline `new URL(…, import.meta.url)`",
"may",
],
[
async () => instantiateModuleWorker(searchWorkerURLNewURLImportMetaURL()),
"using `new URL(…, import.meta.url)`",
true,
"will",
],
[
async () =>
instantiateModuleWorker(await searchWorkerURLEsbuildWorkaround()),
"using the `esbuild` workaround",
"will",
],
[searchWorkerURLEsbuildWorkaround, "using the `esbuild` workaround", true],
];

for (const [fn, description, warnOnSuccess] of fallbackOrder) {
try {
const worker = await instantiateModuleWorker(await fn());
const worker = await fn();
if (warnOnSuccess) {
console.warn(
`Module worker instantiation required ${description}. \`cubing.js\` will not support this fallback in the future.`,
`Module worker instantiation required ${description}. \`cubing.js\` ${warnOnSuccess} not support this fallback in the future.`,
);
}
return worker;
Expand Down
10 changes: 10 additions & 0 deletions src/cubing/search/worker-workarounds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,13 @@ export async function searchWorkerURLEsbuildWorkaround(): Promise<string> {
exposeAPI.expose = false;
return (await import("./search-worker-entry")).WORKER_ENTRY_FILE_URL;
}

export function instantiateSearchWorkerURLNewURLImportMetaURL(): Worker {
return new Worker(
new URL(
"./search/worker-workarounds/search-worker-entry.js",
import.meta.url,
),
{ type: "module" },
);
}

0 comments on commit 44d3917

Please sign in to comment.