So like during this time of trying to move work off the main thread of runpkg there was a question about performance. How much time does it take to spin up, spin down, posting and receiving messages. Fortunately James Milner has a really great post documenting this information. TL:DR is that as long as you're not sending lots of information via postMessage it seems to run sub millisecond (< 1000 keys). That's great news, so let's move onto implementation.
So with the above information, we refactored our recursiveDependencyFetchWorker
to just hammer the React event listener with messages, so that the data storage was handled by the event listener. The issue we found is that when hitting that eventListener and dispatching multiple dispatch
callbacks (~600 for lodash-es), then you ruin the performance of your app. So time for batching.
So we ended up using the following strategy where we dispatch a buffer every second for a regular update of our cache.
react.useEffect(() => {
let buffer = {};
if (worker.current) {
worker.current.addEventListener("message", e => {
if (e.data.url === "https://unpkg.com/" + request.path) {
dispatch({
type: "setCache",
payload: { [e.data.url]: e.data }
});
} else {
buffer = { ...buffer, [e.data.url]: e.data };
}
});
setInterval(() => {
if (Object.keys(buffer).length > 0) {
dispatch({
type: "setCache",
payload: buffer
});
buffer = {};
}
}, 1000);
}
return () => cleanup;
}, [...dependencies]);
Overall this got our first meaningful paint to 0.8s and a useful codepane for lodash-es renders in around 2s with an empty cache. This is down from about 6 seconds with the original runpkg with lodash-es!!! With the service worker this work is even faster with lodash-es rendering in 1.8s!*
I feel really happy with all the work we've done to increase the performance of runpkg!
Finally we had to add functionality to kill the webworker in case a user switched paths. This required adding a terminate in the instantiator of the worker:
if (worker.current) {
worker.current.terminate();
}
worker.current = new Worker("./utils/recursiveDependencyFetchWorker.js");
* These are all sorta a fudge of chrome performance dev tools and lighthouse auditing with no cpu or network slowdown so YMMV.