As the server is in full control of the HTML, JS and CSS it sends, this approach has the benefits of:
- dynamic layout and content
- dynamic css
- dynamic js
I’ve built a small notes taking app as a browser extension popup to demonstrate the full implementation, and here I’d like to highlight a few aspects that make it all possible:
Extension starter template
Although an extension could be as simple as a
package.json with one
js and one
html file, if you want to go production level, you’re likely to need a a proper build system as well to serve the extension in development mode, to compile it for production, and all that ideally working accross different browsers. I’ve had a good deal of research done looking and indeed I’ve managed to find a great starter template from @abhijithvijayan - https://github.com/abhijithvijayan/web-extension-starter. Thank you @abhijithvijayan!
As mentioned early in the documentation - for simple no-framework JS, use the master branch.
Fetch all js and css from the server
I went all the way, so that even my JS and CSS come from the server. That allows me to:
- not have to publish a new version of the extension every time I make a change
- reduce iteration cycles day to seconds
This is pretty big as you have much much greater control and flexibility over what your users see at any point in time. A deploy of your code is immediately reflected on the extensions.
To achieve that, we’d just query a dynamic endpoint (
http://localhost:3000/scripts/popup), which would return the latest link to the JS file ➡️
http://localhost:3000/assets/application-[hash].js. We’d then render that inline. CSS is bundled in with the JS together.
Executing remote code like this is not enabled by default for protection. To enable it, add your url to the
See the full extension manifest.json for details.
Render index page from server
We basically replace the body of our popup with whatever html came from the server. Once the html on the page is updated, the main stimulus controller and a few web components elements from Material Design kick in to provide the interactivity.
Any further interactivity is via a small Stimulus controller.
Updates to the page are fetched via websockets with the help of Stimulus Reflex. In the default case - the main listing of snippets are re-rendered on the server and morphed back to the document.body element.
When iterating over the popup, clicking the extension browser action in the top right corner of the browser can get quite frustrating. It’s very easy to setup our own mock implementation of the popup window.
Create a rails layout file with the exact same html as the original popup window. Within a separate JS pack, require the original
popup.js which is rendered by the browser when opening the browser extension.
The only caveat is that any browser extension specific functionalities won’t work. It’s easy to mock them. In this case I’ve replaced the whole
webextension-polyfill module with my own dev shim: