How do you draw the line between a Web Worker and the main thread without a message spaghetti mess?

What’s up everyone? I’m trying to move some heavier work (filtering/sorting a big dataset plus a little formatting) into a Web Worker so the UI stays snappy, but I keep tripping over where state should live and how chatty the message passing should be.

If you’ve done this in a real app, what’s your rule of thumb for deciding what data gets shipped to the worker vs kept on the main thread, especially when the failure mode is either copying huge payloads (slow/memory) or building a brittle mini-protocol of messages (hard to evolve)?