























So one day a client came to me and said: “we want a Chrome extension.” Simple enough, right?
First thing to know: the client didn’t want to build a real extension from scratch with its own codebase and logic. They wanted a wrapper, essentially their existing Rails app, dressed up and living inside a Chrome extension panel.
Same features, same views, same assets. Just… accessible from the browser bar.
That sounds simpler than building from scratch. But, was it?
Now, when it comes to Chrome extensions, there are a few main UI patterns:
The trigger can be a button injected into the page (via content_scripts,
positioned with CSS), or the native Chrome extension icon in the browser bar.
We explored a few options before eventually landing on a reference to model
it after.
We ended up going with an iframe approach: a wrapper around the main Rails app, rendering its views and assets inside the extension panel.
Here’s where it gets fun. The code for the extension, the page with the trigger, the button, the iframe, all of it, lived inside the same Rails app that hosted the main product. Why? Because it needed to render views and serve assets from that app, and stay in sync if the main content changed.
But running two things from one Rails app (the main UI + the extension wrapper)
is… not a great time. Locally, we ran into endless Rack-CORS errors.
Trial and error sessions that felt like a personal war.
In hindsight, the much cleaner solution would have been to spin up a separate lightweight app just for the extension code, pointed at the main app as an API. Staying in one repo is a common and totally understandable constraint: less duplication, easier to keep things in sync. The tradeoff is exactly what we ran into: CORS complexity and two contexts fighting each other locally. Worth knowing before you commit to that architecture.
Okay, if CORS was annoying, auth was brutal.
The main app used Devise with cookie-based sessions. Totally normal for a Rails app only. Totally terrible when you’re trying to embed it inside a Chrome extension where there’s now another session in a different context.
Cookies + iframes + different origins = CHAOS. The sessions would conflict, auth state got confused between the main UI and the extension view, and debugging it felt like a nightmare.
The core issue: the extension iframe was loading the app from the same origin as the main app, so cookies were being shared, but in ways that weren’t predictable or clean. Having the extension live in a separate app/repo with its own auth flow would have made this much more manageable.
Once auth was (mostly) sorted, the assets decided to have a turn.
Icons and images weren’t rendering inside the iframe. The Rails asset pipeline had opinions about how assets were served, and those opinions didn’t align with being loaded in a sandboxed Chrome extension context. Some path adjustments and pipeline config tweaks later, it was working, but it was one of those things where you fix it and never want to look at it again.
Here’s the practical stuff that I wish was better documented:
You need a Chrome Developer account: a Google account registered as a Chrome Extension developer.
The client owned this account, which made sense since they’d be the publisher. But the Chrome Extension developer account didn’t support collaborators. So deployments of staging versions had to go through the client’s access. That’s a workflow you want to sort out early, when you are a developer on a client project: nothing worse than needing to push a fix and waiting for someone else to log in or test changes for you. And make debugging an extra hard task.
Anyhow, in practice, this is the flow:
sandbox/unpublished modeChrome extensions are powerful and actually not that hard in isolation. The complexity explodes when you’re wrapping an existing app with existing auth and trying to share code. Clean separation of concerns is your friend. CORS is your nemesis. And always ask the client if they have a reference they want to take inspiration from.
Building a Chrome extension and not sure where to start? Now we know exactly how to. Let’s chat.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。