Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firefox support? Got POC working #48

Open
jhholm opened this issue Jan 11, 2023 · 22 comments
Open

Firefox support? Got POC working #48

jhholm opened this issue Jan 11, 2023 · 22 comments
Labels
enhancement New feature or request

Comments

@jhholm
Copy link

jhholm commented Jan 11, 2023

I was able to get the extension somehow working in Firefox with a few changes

chrome.devtools.panels.create("SharePoint", null, "index.html", null);

That needs to changed to

chrome.devtools.panels.create("SharePoint", "", "index.html");

The bigger refactor was for the definition file loads for monaco-editor. Firefox does not support the following API that is used.

chrome.runtime.getPackageDirectoryEntry

Thus I created a bit hacky workaround: creating a gulp task, that creates dependency.ts file with all the definitions as an JSON array that can be created on build time.

After that I was able to load the extension successfully in Firefox. I think Firefox 109 finally supports officially manifest v3.

I can share my hack, but I guess gulp is a bit deprecated. But I recommend the library definitions would be loaded on buildtime, instead of runtime.

@jhholm jhholm changed the title Firefox-support? Firefox support? Got POC working Jan 11, 2023
@jhholm
Copy link
Author

jhholm commented Jan 12, 2023

It seems that I got PnP JS Console successfully working in Firefox 108 with my hacky changes, but other functionalities seem to have small issues.

@tavikukko
Copy link
Collaborator

tavikukko commented Jan 19, 2023

Hi @jhholm !
This is very interesting and would love to see support for Firefox too, great work! So please, keep working and do not hesitate to contact if facing any issue! And yeah, share the hack (PR/repo), very interested on your work!

@tavikukko tavikukko added the enhancement New feature or request label Feb 7, 2023
@jhholm
Copy link
Author

jhholm commented Feb 12, 2023

Small update. Got 6.6.0 popup working with Firefox. I had to change chrome.runtime.executeScript to use world: 'ISOLATED' instead of 'MAIN' as 'MAIN' is not yet supported in Firefox. The change also worked in Edge, though I had to wrap the subsequent fetch calls to chrome.runtime.executeScripts as well, cause in Firefox I would be otherwise running the fetches in the popup context (without auth).

The current issue that I'm facing is with any action from devtools that expects to get a message back from an eval. See below:

  1. Action is triggered from devtools, e.g. spshooter GET call, uses chrome.runtime.onMessage.addListener to start a listener for messages
  2. Action sends code with chrome.devtools.inspectedWindow.eval(<script here>)
  3. Evaluated code does its business and eventuallly triggers window.postMessage()
  4. content_script content.js gets the message and triggers chrome.runtime.sendMessage()
  5. Devtools addListener should catch the message, but doesn't do that on Firefox (there is an actual error that no listeners exist)

The documentation is a bit lacking on this subject, but I could find this stackoverflow. I guess I would start by creating a smaller sample and play around how to get the messaging working back to devtools. Would it be possible to use chrome.runtime.executeScript instead?

@tavikukko
Copy link
Collaborator

Nice work @jhholm!

  • MAIN/ISOLATED: maybe we can check if env if FF, we can conditionally switch to ISOLATED
  • subsequent calls: we can also use executeScript for subsequent calls if that makes it work also in FF
  • messaging: When creating the popup, I studied the execueScript and realised it could be used for all communications, so my plan is to replace the current communication logic to use that. Have not tested or started conversion yet, but should not be that hard.

I will test how the executeScript could work for dev_tools messaging part and will post the results here.

@jhholm
Copy link
Author

jhholm commented Feb 13, 2023

  • ISOLATED seems to work in both browsers, I did play around with a isFirefox approach initially
  • executeScript({ world: "main"... }).then((result) => fetch()) seems to work for some reason in Edge/Chrome, even though fetches to SharePoint API's in then should not contain auth headers IMO. Wrapping fetches to executeScript solved this in Firefox and had proper auth headers.

I guess if executeScript approach works, that would be lovely. This is my first deep dive into extensions and messaging seems to be a bit... interesting.

I started playing around with messaging with this sample. The diagram in Step 4 seems to show a similar messaging pattern as Chrome devtools documentation. Though if you look at the source code for the sample the code doesn't follow the diagram at all.

I got messaging successfully working in both Chrome and Firefox with following the pattern. See my gist here for a quick sample.

  1. Content Script => Background chrome.runtime.sendMessage or chrome.runtime.connect
  2. DevTools => Background chrome.runtime.connect

AFAIK Content Script and DevTools have to initiate the connection and background can listen on connections. I do not think it works the other way around.

What makes this even more fun, is that Firefox doesn't yet support background: { service_worker: "background.js"}, you'll have to use background: { scripts: ["background.js"] } which is not actually proper MV3. Hooray, two different manifests needed! 🥳

OT/PROTIP: web-ext makes extension development for Firefox a breeze - should work with chrome as well

npm i web-ext -g
cd build
web-ext run OR web-ext run -t chromium

@jhholm
Copy link
Author

jhholm commented Feb 13, 2023

It seems that Chrome might have access to scripting and tabs in devtools.js, if permissions are set in manifest.json. At least console.logging them gives an object after proper permissions. Firefox only shows undefined, but they are reachable in background.js.

@tavikukko
Copy link
Collaborator

Thanks @jhholm !

I added host_perimssions property to manifest

  "manifest_version": 3,
  "devtools_page": "devtools.html",
  "permissions": ["activeTab", "scripting"],
...
  "host_permissions": [
    "<all_urls>"
  ],
...

..and got executeScript working also from dev_tools ext:

chrome.tabs.query({ currentWindow: true, active: true }, (tabs: any) => {
  chrome.scripting.executeScript({
    target: { tabId: tabs[0].id },
    world: 'MAIN',
    func: myfunction,
  }).then(injectionResults => {
    if (injectionResults[0].result) {
      console.log(injectionResults[0].result)
    }
  });
});

Just converting spshooter to use it, will do PR and you can maybe test it in FF?

@jhholm
Copy link
Author

jhholm commented Feb 13, 2023

image

Doesn't seem to work in Firefox. I think the diagram above from Chrome extension documentation is only correct for Firefox as Chrome seems to be happy providing those APIs.

@tavikukko
Copy link
Collaborator

interesting,
have you tried browser.scripting.executeScript ?

@tavikukko
Copy link
Collaborator

If you got time, could you test if these changes in spshooter-with-executescript branch works with FF, it works in Chrome/Edge? And if it does not work, could you try to change reference of chrome.scripting.executeScript to browser.scripting.executeScript, thanks!

@jhholm
Copy link
Author

jhholm commented Feb 15, 2023

Doesn't seem to work. Weirdly both Chrome and Mozilla documentation say that this should not work, and you would need to run this through background pages/scripts.

developer.chrome.com
developer.mozilla.org

@tavikukko
Copy link
Collaborator

Those docs seems to be old IMO. BTW, when you change permissions, have you also removed and re-added the extension? The permissions do not get applied just to update the manifest.

@tavikukko
Copy link
Collaborator

tavikukko commented Feb 15, 2023

If you have created branch in your sp-editor fork for your changes, I would like to test it, just to understand whats going on in FF. I tried loading my current build from file but it could not accept it, so propably some changes in manifest needed.

@tavikukko
Copy link
Collaborator

Might be that in FF user needs to grant the host permission to work, in MV3.
https://discourse.mozilla.org/t/error-missing-host-permission-for-the-tab/105769

@jhholm
Copy link
Author

jhholm commented Feb 16, 2023

That was actually a thing that I noticed quite early on after I couldn't figure out why nothing seemed to work. After allowing the use I got the messaging working. So currently I can get scripting with browser.scripting and chrome.scripting working in background, but not in content scripts or devtools IMO.

But I think it might be a good thing to test properly again tomorrow, cause it still might be that I missed something.

@jhholm
Copy link
Author

jhholm commented Jul 16, 2024

Small update on this. I've had some spare time this year so I've been playing around with a few extension templates that use vite instead of CRA.

Firefox is pretty obedient on the rules on how an extension should be built, thus not allowing a lot of the stuff that chromium does. E.g. certain extension APIs can only be run on a background script, not on content scripts or popup. Thus requiring you to use messaging API to make calls between different scripts components.

What I've done so far:

  1. Changed the project to use WXT
  2. Got Popup working on both Chrome and Firefox
  3. This needed changing all the fetches and injection logic to a separate service class outside of the react components
  4. Using that service class only on a background script
  5. Using @webext-core/proxy-service to make messaging between scripts and background much more dev friendly and typesafer than OTB messaging API

So I just noticed that you started working with version 7. How far along is that branch? Should I just mirror my changes using that branch and publish my POC branch for you to take a look at?

I guess what I'm asking here, do the changes mentioned above look like something that would be usable? There are a few other vite powered extension templates/projects that I tried, but thus far WXT seemed to work the best.

List of other templates that I checked thus far

  • crxjs - hasn't seen updates for a while, and is still in beta with the newest version
  • Plasmo - not sure if this can be used - needs an account?
  • Bedframe - uses crxjs behind the scenes and is on early access - needs an account?
  • vite-plugin-web-extension - this could also work, it's the same developer that is behind WXT

The main reason I sticked with WXT, is because it makes sense to use MV2 with Firefox and MV3 for Chromium. MV3 support just isn't there for Firefox yet. WXT seems to handle this considerably well. So far I haven't needed to do any browser specific code.

@jhholm
Copy link
Author

jhholm commented Jul 16, 2024

TLDR;

  1. Migrate from create react app to a more up to date bundler. My suggestion is WXT
  2. Change all injection, fetching etc logic to be run on a background script
  3. Use a messaging dependency @webext-core/proxy-service to make messaging more developer friendly
  4. I'll publish a POC with a working Popup from v7 branch to show how these changes look

Ok?

@tavikukko
Copy link
Collaborator

Wow @jhholm ! Yeah, I I'm almost done with v7, the idea there was to upgrade to latest react/cra etc, also made the debuging simpler and converted all the remaining message api to use scripting api 😅

Yeah, please use the v7 branch as base.

Im on vacation atm, but will look forward to see your work when I get a moment.

Really appreciate you time and efforts.

@tavikukko
Copy link
Collaborator

  • Scripting api should also work with firefox, but have not tested it. I removed the content script permissions from the manifest as a result not using massaging apis.
    To run the v7, you need to do following: npm i, npm run build.

  • after running build script, you can npm run cracostart to debug.

@tavikukko
Copy link
Collaborator

looks like the v7 works as is in firefox
image

@tavikukko
Copy link
Collaborator

but, seems like the scripting api is not available in devtools, bummer.

@jhholm
Copy link
Author

jhholm commented Jul 18, 2024

This is something that makes cross browser extension development experience a living nightmare. It seems that Firefox 128 (current release) finally provided support for scripting worlds. The popup might actually work in both Firefox and Chrome without any changes.

For now it seems that when using MV2, the only required change to get popup working in Firefox was changing the namespace chrome.scripting to browser.scripting. This could also be a MV2 quirk or an issue with bundling, polyfills or the lunar calendar.

Using MV3 in any case is IMO out of question for now for Firefox as no localhost connections are allowed, so development experience would be even worse (no HMR). Also background scripts work differently between Chrome and Firefox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants