crxjs / chrome-extension-tools

Bundling Chrome Extensions can be pretty complex. It doesn't have to be.
https://crxjs.dev/vite-plugin
2.99k stars 192 forks source link

Support firefox / cross browser compatibility #56

Open anarchylimes opened 4 years ago

anarchylimes commented 4 years ago

Is your feature request related to a problem? Please describe.

No issue per-say but this rollup plugin would benefit people greatly if it worked in firefox as well.

Describe the solution you'd like

To be able to develop cross-browser extensions using only this plugin. There is a fork already for webextension-polyfill, which is the basis of cross-browser extension development

Describe alternatives you've considered

I've already done a rollup configuration that allows development of firefox plugins but only by importing every file separately. This would make it so much faster to create browser extensions

jacksteamdev commented 3 years ago

A relevant comment by @avi12 from another issue, with an example repo:

But, for a strange reason, not on Firefox (loaded via web-ext) Example repo: https://github.com/avi12/steam-id-finder/tree/main

jacksteamdev commented 3 years ago

The issue here is that Firefox doesn't support dynamic imports in web extensions, which we use to support Rollup's code splitting feature. What we need to do is bundle each content script and background script as an IIFE. This basically results in a mixed format build, which Rollup doesn't support natively.

avi12 commented 3 years ago

I tried importing functions using an import statement, e.g.

import { someFunction } from "./some-script";

but it didn't work, despite not being a dynamic import (i.e. import("./some-script.js"))

Glench commented 3 years ago

any development on this? I could really use it while developing ExtPay.

avi12 commented 3 years ago

@Glench What I used as a "workaround" is this code

Glench commented 3 years ago

@avi12 that's actually what I tried using but it's failing with a bunch of errors in firefox

avi12 commented 3 years ago

@Glench I used this boilerplate (minus TypeScript) in most of my cross-browser extensions (YouTube Auto HD + FPS, YouTube Like-Dislike Shortcut, Steam ID Finder, Twitch Channel Points Bonus Collector, Skillshare Player Control)

Glench commented 3 years ago

@avi12 ooh my bad I was using a different svelte browser extension compiler. Thanks for the pointer! I don't know typescript but it doesn't look like that matters and maybe this will be a good excuse to learn it.

By the way, if you're interested I made a service called ExtPay that lets you take payments directly inside your extensions without needing to run your own server. I made it for my own extensions but so far other people have found it useful. Feel free to contact me if you have questions!

avi12 commented 3 years ago

@Glench ExtPay sounds very good Do you mind moving to Discord? avi12#4269

floer32 commented 3 years ago

I'm curious, what's missing from the current state of the codebase?

The README links to

Here's the snippet and usage docs:

Add the excellent promisified Browser API polyfill by Mozilla to your Chrome extension with one easy option:

chromeExtension({ browserPolyfill: true })

This option adds browser to the global scope, so you don't need to import anything.

Install this type package to get Intellisense. It's automatically updated on a regular basis.

README link

avi12 commented 3 years ago

@hangtwenty The issue is that it makes the package size needlessly bigger

Glench commented 3 years ago

No the issue is that it doesn't actually work:

Screen Shot 2021-03-18 at 7 46 46 AM
avi12 commented 3 years ago

Right, I forgot that last time I received an error To be fair, a new repository should be created, called "extend-browser/rollup-plugin-browser-extension", as this account is about extending Chrome specifically, not "browsers"

jacksteamdev commented 3 years ago

This problem will not be a issue once Firefox 89 is released

If there are any compatibility problems that occur, we will look into it once 89 hits the stable channel.

floer32 commented 3 years ago

Right, I forgot that last time I received an error To be fair, a new repository should be created, called "extend-browser/rollup-plugin-browser-extension", as this account is about extending Chrome specifically, not "browsers"

Yeah but cool URIs don't change, and we should not expect repository or package names to communicate everything. (That's what READMEs are for)

floer32 commented 3 years ago

The issue is that it makes the package size needlessly bigger

Re: package size, webextension-polyfill is ~9kb minifed, ~3kb minified and gzipped (bundlephobia). For a web extension, that seems trivial to me. But hey, I am new to developing cross-browser extensions, so LMK if I'm wrong to think that's small enough

avi12 commented 3 years ago

Re: package size, webextension-polyfill is ~9kb minifed, ~3kb minified and gzipped (bundlephobia). For a web extension, that seems trivial to me. But hey, I am new to developing cross-browser extensions, so LMK if I'm wrong to think that's small enough

I'd say that depends on the complexity of the extension Typically, the 2 biggest package size impactors are the images and the translations (if you have any) Then, you gotta minify your content scripts (which can be easily done with Terser) If your extension is very simple (like my Twitch CP Bonus Collector), I'd say that it shouldn't weigh over 1KB (excluding images and stuff) If your extension is complex (like Black Menu for Google, made by a friend of mine), it is acceptable that it will weigh a lot

floer32 commented 3 years ago

@avi12 Super helpful information, thank you!

avi12 commented 3 years ago

@hangtwenty The reason I said that the 2 biggest size impactors are the images and translations is that there's a limit point up to which you can reduce them Images (icons) are usually in PNG format, and if you want them to look professional, you will use transparency, which will add to the overall size Translations are only served via JSON, e.g. _locales/en/messages.json

{
  "ext_name": {
    "message": "Extension name"
  },
  "description": {
    "message": "Description"
  }
}

The only optimizations here are to reduce the key names (which I wouldn't recommend doing since they have to match the places in the scripts where they're used) and minifying the JSON (can be done with Terser, as I said in my previous comment) When it comes to the scripts (content script(s), popup page & script(s), options page & script(s), background script(s)), you have much more freedom, so you can decide to add or remove a script, and use a JS framework like Svelte, which should make the most optimal JS possible

z0al commented 3 years ago

The issue here is that Firefox doesn't support dynamic imports in web extensions, which we use to support Rollup's code splitting feature.

@jacksteamdev how feasible is it to have an option to turn off code-splitting completely so we could support Firefox as of today?

jacksteamdev commented 3 years ago

Firefox has added support for dynamic import in content scripts and now it may be relatively trivial to create Firefox compatible builds.

There is still work to be done. Thanks @mnoorenberghe for getting the ball rolling with #75!

Remaining known issues

PR's are welcome

Please note, I don't have the bandwidth to work on Firefox support right now :disappointed:, but I'll be happy to merge PR's that add this feature!

Tests are required for any new features, and a quick Loom of it working in Firefox will get your PR reviewed faster.

If Firefox support is important to you, please contribute! :pray:

jacksteamdev commented 2 years ago

RPCE v4 is ready for testing, you can check out this guide to get started with React.

I haven't tested it in Firefox, but I'd bet the new build works. If someone tries it, please comment.

mnoorenberghe commented 2 years ago

I haven't tested it in Firefox, but I'd bet the new build works. If someone tries it, please comment.

Since v4 only supports MV3 it can't currently work in Firefox. MV3 support in Firefox is in-progress.

jacksteamdev commented 2 years ago

@mnoorenberghe True, that comment was before we dropped MV2 support for v4. Covering all the edge cases gets pretty complex! 😅 Hopefully Firefox releases MV3 support sooner than later!

I'd like to offer some perspective for new extension projects. Currently Chrome, Edge, and Safari have MV3 support in stable or beta, which is ~85% of the desktop browsers out there.

The Chrome Web Store doesn't accept new MV2 extensions, so any new extension that wants to support Firefox has to support both MV2 and MV3. That's a lot of work to gain about ~9% market share, especially when that extra work will be unnecessary in the near future.

Desktop Browser Market Share Worldwide

madacol commented 2 years ago

I'm using version 3.6 and manifest v2

content-scripts are working fine, and firefox recognizes the esm format, but executeScript(...) fails if the script has esm format, so the workaround is to wrap the script inside a dynamic import

await browser.tabs.executeScript(tabId, {
    code: `import(browser.runtime.getURL("./script.js")).then(x=>x.default())`
});
rossmoody commented 2 years ago

I have no idea if this is bad practice so open to feedback, but I'm tinkering with programmatic v2 and v3 manifests in my extension. Wanted to share in case someone else finds it helpful .

I'm having a decent experience mimicking the replace plugin NODE_ENV convention I saw in one of the boilerplates of replacing a string with truthy or falsy values and firing different methods depending on the context.

In this case I use an empty string for the falsy value and 'true' for truthy. Then I either fire v3 manifest methods or v2 depending on the manifest version. It's not the greatest, but it seems to be working and I haven't had to replace all the methods. Plus, I can dynamically hide functionality that isn't available all throughout my app.

The one issue I'm still working through is the only way I can get my extension to load in Firefox is by uploading the production zip file.

heathsnee commented 2 years ago

Is manifest V2 going to be supported with new currently beta version of the plugin ?

jacksteamdev commented 2 years ago

Is manifest V2 going to be supported with new currently beta version of the plugin ?

The Chrome Web Store no longer accepts new MV2 extensions, and Chrome won't even run MV2 starting in 2023 Q1. Considering that all the other browsers either support MV3 or have announced support by end of 2022, I'm not convinced that it's worth taking the development time away from other features and bug fixes.

avi12 commented 2 years ago

@jacksteamdev I agree, though funny enough, Opera is in a weird spot On one hand, sideloading MV2 extensions tells you that its support will end by Jan 2023, and sideloading MV3 extensions works seamlessly On the other hand, the Opera Store doesn't support uploading MV3 extensions, for whatever reason

On Firefox's end, the browser doesn't support MV3 yet, so I'm curious to see whether the MV3 support will be added before Google officially terminates support for MV2

jacksteamdev commented 2 years ago

On Firefox's end, the browser doesn't support MV3 yet, so I'm curious to see whether the MV3 support will be added before Google officially terminates support for MV2

@avi12 Me too!

jacebenson commented 1 year ago

https://www.mozilla.org/en-US/firefox/109.0/releasenotes/ supports manifest v3 as of Jan 17th 2023.

officialpiyush commented 1 year ago

any new updates on cross browser compatibility in crxjs?

avi12 commented 1 year ago

Firefox 109+ supports Manifest V3 Note that if you migrate an existing extension with a solid user base from MV2 to MV3, there could be some unintended consequences So for now, only if you're creating an extension from scratch, you may use Manifest V3 Otherwise, Mozilla recommends sticking with MV2 as it will be supported for the time being

Malix-Labs commented 9 months ago

Fixed by #776