serversideup / webext-bridge

💬 Messaging in Web Extensions made easy. Batteries included.
https://serversideup.net/open-source/webext-bridge
MIT License
518 stars 48 forks source link

Bundling issues #27

Open gurupras opened 2 years ago

gurupras commented 2 years ago

This is probably not an issue with the library itself, but maybe the issues described below can be solved at the library layer?

I currently use webext-bridge through vitesse-webext and I ran into some issues that took a few hours to get to the bottom of.

At its core, the issue is that I have a manifest that looks like this:

{
  "content_scripts": [
    {
      "all_frames": true,
      "matches": [
        "http://*/*",
        "https://*/*"
      ],
      "js": [
        "./dist/contentScripts/index.global.js",
        "./dist/contentScripts/amazon-video/index.js"
      ]
    },
    {
      "all_frames": true,
      "run_at": "document_start",
      "matches": [
        "*://*.twoseven.xyz/**"
      ],
      "js": [
        "./dist/contentScripts/twoseven/index.js"
      ]
    },
    {
      "all_frames": true,
      "matches": [
        "http://*.netflix.com/**",
        "https://*.netflix.com/**"
      ],
      "run_at": "document_end",
      "js": [
        "./dist/contentScripts/netflix/index.js"
      ]
    }
  ]
}

All JS files mentioned above make use of webext-bridge and because I have a) a global bundle and b) per-website bundles, this causes webext-bridge to be present in two separate bundles. As a result, I was observing that I was running into scenarios where messages that were being sent by the background script would make it to the wrong bundle, which had no open transactions and thus led to the messages being dropped.

Any elegant way to solve this at the library level? Or do I have to come up with some different bundling strategies to solve this?

zikaari commented 2 years ago

I can imagine what's happening. Because each "bundle" per frame has it's own import of webext-bridge, it's creating 2 isolated closures for the webext-bridge code, even though both closures are running in just 1 isolated content script world.

So this must also mean that each closure per frame is establishing a port connection with the background page under the same portId, thus one overriding the another, depending on their order of execution?!

Before we look for a solution, can you confirm the latter thesis?

gurupras commented 2 years ago

Sorry, I ended up fixing this for myself by creating a separate bundle of only webext-bridge and injecting this bundle into each website. I will set up a new environment later today or tomorrow to debug this further

vsromanc commented 2 years ago

I got the same issue here, also ended up fixing it by creating a separate bundle (as usual webpack entry point).

And I think it should work only this way, no reason to include the library twice (or more).

zikaari commented 2 years ago

Just out of curiosity can you try installing 6.0.0-rc2 and see if this just works out of the box with this scenario?

vinceprofeta commented 1 year ago

I am experiencing this issue as well? @zikaari can you help me understand what a good solution might be?

zikaari commented 1 year ago

Hi vince, did you try 6.0.0-rc4?

vinceprofeta commented 1 year ago

@zikaari I did. I have a content script that gets injected from the manifest, which messages back to the bkg context to inject another content script. I see both ports connect in the logs of the bkg context but i still get the error:

registered in 'content-script' to accept messages with id 'initial-message'

If I do not inject the second script it works fine.

It seems that once I inject the second content-scripts any reference or message to the original content-script breaks. I cannot message to it from the background context or other content scripts.

It does still work if i message to itself.

zikaari commented 1 year ago

That is not a bundling issue. The reason you're seeing this error is that the second content script overrides the port registration with the background page, removing the bindings established by the previously loaded content script, which it appears does contain a listener for initial-message.

Unfortunately, I did not account for this scenario when I was designing the library, if you have ideas please feel free to share.

vinceprofeta commented 1 year ago

@zikaari i'd have to dig into the internals of how ports get established and how it knows if a listener is on the other side. Potentially having a map of connected ports, and doing a check when sending & replying from messages? Just spit balling. Let me know if you have any thoughts and maybe we can figure something out.

gurupras commented 9 months ago

I finally updated my entire extension to use webext-bridge@6.0.1, and the problem is not solved. Yes, there are two separate closures that are being created, one per bundle.