@@ -31,16 +31,32 @@ function createClonedMessageEvent(
3131 debug ( 'clone worker message %o' , data )
3232 const origin = typeof location === 'undefined' ? undefined : location . origin
3333 const ports = transfer ?. filter ( ( t ) : t is MessagePort => t instanceof MessagePort )
34- const transferWithoutPorts = transfer ?. filter ( // `ports` must be excluded from the `transfer` option passed to `structuredClone` to keep the MessagePort objects working correctly in the same thread.
35- t => ! ( t instanceof MessagePort ) ,
36- )
3734
3835 if ( typeof structuredClone === 'function' && clone === 'native' ) {
3936 debug ( 'create message event, using native structured clone' )
37+ // A real Worker serializes `data` across realms and exposes the
38+ // MessagePorts from `transfer` as `event.ports` on the receiving side.
39+ // @vitest /web-worker runs both sides in a single realm, so we use
40+ // `structuredClone` to emulate that transfer boundary.
41+ //
42+ // `MessageEvent.ports` must be the *cloned* ports returned by
43+ // `structuredClone`, not the originals from `transfer`: once transferred,
44+ // the originals are detached and can no longer communicate — e.g.
45+ // `port1.postMessage(...)` on the caller side would not trigger
46+ // `port2.onmessage` on a detached `port2`.
47+ //
48+ // `data` and `ports` must also be cloned in the *same* `structuredClone`
49+ // call. A transferred object is detached immediately, so we cannot clone
50+ // `data` first and then clone `ports` (or vice versa) — the second call
51+ // would see already-detached ports. Passing them together as a single
52+ // input also makes `structuredClone` deduplicate by identity, so a port
53+ // referenced from inside `data` and from `transfer` resolves to the same
54+ // transferred instance in the cloned graph.
55+ const { data : clonedData , ports : clonedPorts } = structuredClone ( { data, ports } , { transfer } )
4056 return new MessageEvent ( 'message' , {
41- data : structuredClone ( data , { transfer : transferWithoutPorts } ) ,
57+ data : clonedData ,
4258 origin,
43- ports,
59+ ports : clonedPorts ,
4460 } )
4561 }
4662 if ( clone !== 'none' ) {
0 commit comments