Made a thing because reloading Chrome extensions manually was driving me insane
So I've been building a few Chrome extensions in the last months and the dev workflow is painful.
Every single change... go to chrome://extensions, remove, load unpacked, click around, test. Over and over.
I know Plasmo and WXT exist but I didn't want to restructure my whole project around a framework just to get hot reload. I just wanted something that watches my files and reloads the extension.
Couldn't find anything lightweight so I built one myself:
npx livepak ./my-extension
That's it. It launches Chrome, loads your extension, pins it to the toolbar, and watches for changes. Edit a file, extension reloads automatically.
Some things that surprised me while building this:
--load-extensionflag doesn't work on normal Chrome. It literally says "not allowed" and ignores it. You need Chrome for Testing (a separate binary Google provides for automation). So livepak downloads and caches that automatically.- There's no API to pin an extension to the toolbar. None. I had to navigate a tab to chrome://extensions via the DevTools Protocol and call an internal Chrome API (
developerPrivate). Took way too long to figure out. - WebSocket frames from client to server must be "masked" (random XOR). Chrome's DevTools Protocol just silently drops unmasked frames with zero error message. Lost hours on that one.
The whole thing has zero npm dependencies. Raw WebSocket server, native fs.watch, talks CDP directly. About 600 lines of code total.
Works with MV2 and MV3, supports multiple extensions at once, and if you kill the process without Ctrl+C it cleans up the injected files on next run.
https://github.com/jeanpierrecarvalho/livepak
Let me know if I messed something up.