chrome: migrate Chrome extension to Manifest V3 with service worker support
Changes
Manifest V3 Migration (src/manifest.json)
- Updated
manifest_versionfrom 2 to 3 - Changed
browser_actiontoaction - Migrated
background.scriptstobackground.service_worker - Added
host_permissionsarray for required permissions - Updated
web_accessible_resourcesto MV3 object format
Service Worker Compatibility (src/background.ts)
- Replaced
window.cryptowithglobalThis.cryptofor service worker compatibility - Changed all
windowreferences toglobalThisto work in service worker context - Updated
browser.browserAction.setIcon()tobrowser.action.setIcon()for MV3 API
Browser Detection Fix (src/utils/utils.ts)
- Fixed "window is not defined" error in service workers by making browser detection lazy
- Added service worker fallback using
browser.runtime.getBrowserInfoinstead ofwindow.location - Previously top-level code accessed
window.locationat module load time, breaking service workers
Icon Generation Dual-Path (src/utils/utils.ts)
- Service workers use
OffscreenCanvaswith PNG sincecreateImageBitmap()doesn't support SVG - DOM contexts continue using regular canvas with SVG (unchanged)
- Runtime detection via
typeof window === 'undefined' || typeof document === 'undefined'
Canvas Performance Optimization (src/utils/utils.ts, src/renderer.ts)
- Added
{ willReadFrequently: true }to all canvas context creation to fix Chrome performance warnings
Webpack Configuration (webpack.config.js)
- Chrome builds use
service_workerfor background - Firefox builds explicitly override to use
scripts: ["background.js"](Firefox MV3 still supports background scripts) - Updated Firefox minimum version to 109.0
- Fixed CSP format for MV3 testing builds
Why This Approach
Firefox Compatibility: Firefox MV3 background scripts retain window/document access, so webpack explicitly configures Firefox to use scripts mode. The runtime detection ensures the existing SVG code path is taken.
Chrome Service Workers: Chrome MV3 requires true service workers without DOM access, so we use OffscreenCanvas with a pre-generated PNG for icon generation.
closes #1674
Hi, thanks for taking the time to open an MR. Someone already did this (also with AI!) here: https://github.com/glacambre/firenvim/pull/1692 , I just haven't taken the time to properly review it. Your MR seems to do a lot less than theirs, do you know why?
Hi!
Yes, I can explain the scope difference:
The key architectural difference:
-
My approach (#1700): Keeps the existing preloaded Neovim instance and
funcName-based RPC system. I focused on making minimal changes to get Chrome working with MV3 service workers by usingglobalThisinstead ofwindow, adding lazy browser detection, and creating a dual-path for icon generation (OffscreenCanvas for service workers, DOM for regular contexts). -
#1692 approach: Removes the preloaded instance entirely (creating Neovim on-demand), refactors the entire message passing system with a typed MessageType enum, migrates all state to
browser.storage.sessionAPI, and brings both Chrome AND Firefox to MV3. It's a much more comprehensive migration.
Why I took the simpler approach:
When I read your earlier comment about how "Manifest v3 disallows long-lived processes, so a lot of refactoring may have to happen," I wanted to first see if we could get Chrome working without that major refactor. In my testing, the preloaded instance actually works fine in Chrome's service worker environment.
Potential path forward:
My thinking was this could serve as an intermediate solution to unblock Chrome users quickly while you have time to properly review and test the more comprehensive refactor. Chrome support has been broken for a while, so getting something working sooner might be valuable to users—even if it's not the final architecture.
The other approach is definitely more thorough and addresses the architectural concerns more completely. It's really a question of whether you'd prefer:
- Ship mine quickly as a stopgap → users have working Chrome extension → later review/merge the comprehensive refactor at your pace
- Take time to properly review the comprehensive approach → merge that directly → Chrome users wait longer but get the better architecture
Either way is fine with me! I'm just trying to help unblock the situation.
In the meantime I will continue using my fork until the situation is resolved :)