Bitwarden

This used to be instantaneous. Then one day it took 5 seconds. Infuriating!

I use Bitwarden for password management. As is inevitably the case with these pieces of software, they start out quite speedy and nice and then, unfortunately for us, the software engineers working on them upgrade to the latest Apple M-series laptop. They inevitably have a ceiling of experienced latency that they're unwilling to cross and consequently, these upgrades to developer laptops cause a collapse in performance for users who haven't joined them in the upgrade cycle.

Nowadays, we have fairly advanced LLMs, however, and one can diagnose the problem easily, even if one can't fix it trivially. Claude walked me through the console in developer tools on the service worker.

Diagnosing

[edit | edit source]
  1. Click the extension box
  2. Wait 5 s for it to load
  3. Right click anywhere and click "Inspect"
  4. You'll be dropped into Chrome Developer Tools for that window

From here on you can see what you want. You can also get to these by going to the extensions page, selecting the extension, and clicking Inspect Service Worker.

Native App Messaging

[edit | edit source]

I used to have the Bitwarden native app installed but it's also not very good, so I stopped using it. Unfortunately, at some point the Bitwarden Chrome extension learned of its presence and decided that it must attempt to contact it repeatedly and eagerly. Even though I had this feature turned off, it kept trying to reach it, so I uninstalled the native app entirely. This didn't help either.

[Native Messaging IPC] Connecting to Bitwarden Desktop app...
NativeMessaging port disconnected because of error: Specified native messaging host not found.
Noise handshake with DesktopRenderer timed out after 2 seconds
[IPC] Failed to handshake with Bitwarden Desktop App RequestError: Failed to send message: SendError("Timeout")

The extension would attempt this connection in the hot path and fail. As usual Claude had a solution:

chrome.permissions.remove({ permissions: ["nativeMessaging"] }, r => console.log("removed:", r, chrome.runtime.lastError));

This removed some 2 seconds from the click to window time, but it still sucked. To be clear, the original extension was instantaneous on this very same hardware. Having to wait was alien to me. And the M1 Max is a very capable processor. You can do a hell of a lot of computation on it in the 5 seconds it was taking.

Performance Profiling

[edit | edit source]

Listening to my whispering earring, I measured what was actually taking time.

  const n = performance.getEntriesByType('navigation')[0];
  console.log('domContentLoaded', Math.round(n.domContentLoadedEventEnd), 'load', Math.round(n.loadEventEnd));
  console.table(performance.getEntriesByType('resource').map(r => ({file: r.name.split('/').pop(), ms: Math.round(r.duration), kb: Math.round(r.transferSize/1024)})).sort((a,b)=>b.ms-a.ms).slice(0,10));

That told us that the whole thing took 1.26 s for domContentLoaded and 1.33 s for load, though oddly when you reloaded the chrome tab for the extension it was blazing fast. Bizarrely, when I popped out the Bitwarden UI, then the icon popup was again pretty quick. If you've written any software you instantly recognize this as some cold-start problem where something is either loading something every time, or downloading something every time, or compiling something every time. Claude had some ideas that might have related to the migration to Chrome Manifest V3 (which removed persistent background pages), but in the end the trick that worked was to just keep the popped open thing in the background.

Conclusion

[edit | edit source]
  1. Turn off the native integration - more trouble than it's worth
  2. Pop out the Bitwarden window and keep it persistent

It's ugly. I don't like it. But honestly despite the fact that this must imply some bogus code in there, I trust myself even less to write a decent Chrome extension that won't leak credentials. Defence is a lot harder than features and it's very easy to make mistakes. So I'm going to stick with this (admittedly ridiculous) workaround.

Epilogue

[edit | edit source]

Not a day later, it seemed that the issue had reappeared and by now my patience was thing. The Bitwarden clients are here so you can just go there and ask Fable to build you a better version. It literally opens in milliseconds now, and is fully compatible.