diff --git a/runtime/src/esm_http_test.rs b/runtime/src/esm_http_test.rs index 5fd9ac8..4580d1c 100644 --- a/runtime/src/esm_http_test.rs +++ b/runtime/src/esm_http_test.rs @@ -248,6 +248,24 @@ fn http_import_failures_reject_with_the_cause() { assert_eq!(invalid, "TypeError"); } +#[test] +fn worker_entry_served_over_http() { + let server = TestServer::start(); + let o = server.origin.clone(); + server.route("/ns/m/echo.worker.js", "text/javascript", "import { add } from './add.js';\nself.onmessage = (event) => self.postMessage(add(event.data));"); + server.route("/ns/m/add.js", "text/javascript", "export const add = (n) => n + 1;"); + let mut runtime = Runtime::new("."); + runtime.register_delegate_isolate_ptr(); + let run = |path: &str| { + format!( + "new Promise((resolve, reject) => {{ const worker = new Worker(new URL('{o}{path}')); worker.onmessage = (event) => {{ worker.terminate(); event.type === 'messageerror' ? reject(event.error) : resolve(event.data); }}; worker.postMessage(41); }})" + ) + }; + assert_eq!(await_js(&mut runtime, &run("/ns/m/echo.worker.js")), "ok:42"); + let missing = await_js(&mut runtime, &run("/ns/m/missing.worker.js")); + assert!(missing.starts_with("err:") && missing.contains("status=404"), "{missing}"); +} + #[test] fn native_websocket_round_trip() { let server = TestServer::start(); diff --git a/runtime/src/worker_support.rs b/runtime/src/worker_support.rs index da678d1..21065e0 100644 --- a/runtime/src/worker_support.rs +++ b/runtime/src/worker_support.rs @@ -26,6 +26,12 @@ pub fn install_worker_runtime(scope: &mut ContextScope) { return { source: input, filename: '[worker:eval]' }; } + // A dev server's URL (`new URL('./x.worker.ts', import.meta.url)` under HMR) isn't a + // file: the worker's thread imports it, so its own imports resolve against the URL. + if (/^https?:\/\//.test(input)) { + return { source: '', filename: input }; + } + if (typeof globalThis.__nsResolveModulePath !== 'function' || typeof globalThis.__nsReadTextFile !== 'function') { throw new Error('Worker file loading is unavailable: missing runtime host hooks'); } @@ -90,6 +96,10 @@ pub fn install_worker_runtime(scope: &mut ContextScope) { typeof globalThis.__nsWorkerPollMessagesBlocking === 'function' && typeof globalThis.__nsWorkerTerminate === 'function'; + if (!canUseThreadedHost && /^https?:\/\//.test(resolved.filename)) { + throw new Error('Loading a Worker from a URL needs the threaded worker host: ' + resolved.filename); + } + var channel = new MessageChannel(); var mainPort = channel.port1; var workerPort = channel.port2; diff --git a/runtime/src/worker_threads.rs b/runtime/src/worker_threads.rs index 8b536bc..ae28770 100644 --- a/runtime/src/worker_threads.rs +++ b/runtime/src/worker_threads.rs @@ -173,7 +173,11 @@ fn worker_bootstrap_script(source: &str, filename: &str) -> Result