mozilla / web-ext

A command line tool to help build, run, and test web extensions
Mozilla Public License 2.0
2.71k stars 338 forks source link

`web-ext run` does not do a full reload of the extension #2277

Open fregante opened 3 years ago

fregante commented 3 years ago

Is this a feature request or a bug?

bug

What is the current behavior?

The Chromium extension runner only disables and re-enables developer extensions. This reloads most pages but Chrome does not actually reload the manifest, which is unexpected.

https://github.com/mozilla/web-ext/blob/1e265f85966268b650c6d6be94842c8a0cf45f74/src/extension-runners/chromium.js#L330-L331

I don't think this can actually be fixed but I wanted to double-check and track the issue.

What is the expected or desired behavior?

The manifest should be reloaded.

Version information (for bug reports)

node --version && npm --version && web-ext --version

v14.17.0 6.14.13 6.1.0

rpl commented 3 years ago

@fregante yeah, when I added support for Chrome I evaluate a bunch of options, using what the management API provides to non privileged extension was a reasonable way to get something that was very likely going to work in any of the Chromium forks, but it has the unfortunate side-effect of not picking up changes to the manifest.

Given that changes to the manifest are less frequent than changes to the other resources part of the extension, this issue is not such big of a deal.

Nevertheless, I think the more annoying part is that the developer is not aware of this limitation and that may be much more annoying than the limitation on its own.

We could at least:

fregante commented 3 years ago

I don’t think a browser restart is necessary, I usually just have to click reload in the Extensions page. I think runtime.reload() from the extension itself does the same. If that's the case, what do you think about self-injecting into the manifest to load an extra file that calls runtime.reload()? It's a bit difficult and it will require editing the real manifest.json though (unless a copy is done first)

rpl commented 3 years ago

I don’t think a browser restart is necessary, I usually just have to click reload in the Extensions page. I think runtime.reload() from the extension itself does the same. If that's the case, what do you think about self-injecting into the manifest to load an extra file that calls runtime.reload()? It's a bit difficult and it will require editing the real manifest.json though (unless a copy is done first)

Now that you mentioned runtime.reload() I actually recall that it was part of the strategies I did consider before choosing the current one, that solution is a bit "annoying" because we would need to actually create a separate copy of the extension dir (and keep that in sync with the changes) to avoid changing the real manifest.json file (which is basically what I described in https://github.com/mozilla/web-ext/issues/2281#issuecomment-875665522).

If we end up to actually support something like #2281, at that point we could leverage for the chromium extension runner too.

In the short run I think it would be good to cover the "detect and notify the developer" part (and eventually as part of that we could suggest to the developer to reload the addon from the extension management page in Chrome, which is definitely enough to pick up the manifest changes as calling runtime.reload()).

fregante commented 3 years ago

Yeah I understand there's no easy solution due to the lack of an otherExtension.reload() management API.

I'm not sure notifying the user is particularly useful. If one wants notifications, build tools already have them. If I don't use build tools, I don't need a notification to tell me I just saved a file.

rpl commented 3 years ago

The "notification" I had in mind would be meant specifically to make the developer aware that the extension manifest has been update but chrome will not be see the update until the addon is reloaded (also something to only notify once per web-ext run not for each time the manifest has been changed).

Also "notification" was not the right word (my apologies) because what I meant is actually just a message logged on the terminal, right after the usual message that is logged each time the addon has been autoreloaded.

Rob--W commented 3 years ago

There are several ways to invoke chrome.runtime.reload() when manifest.json changes:

fregante commented 3 years ago

Is there any way for web-ext to connect to the runtime without altering the manifest though? If manifest changes are required, you just need to add an extra background script that listens to some event somewhere + localhost permission I think.

Smallest script I can think of, via long polling:

const response = await fetch('http://localhost:<webext-server-port>/respond-when-reload-is-needed');
if (response.status === 418) {
    chrome.runtime.reload()
}
Rob--W commented 3 years ago

Is there any way for web-ext to connect to the runtime without altering the manifest though? If manifest changes are required, you just need to add an extra background script that listens to some event somewhere + localhost permission I think.

web-ext has a companion extension with an active WebSocket to localhost. As mentioned in my last comment, a potential way to implement this is to drop a file that calls chrome.runtime.reload() in the source tree, open that extension file via the companion extension (and remove it to clean up).

fregante commented 3 years ago

open that extension file via the companion extension

Oh, I didn't understand how that worked. That's genius! Bonus points for opening said file in a minimized window in order to minimize the noise on screen (of tab/window opening and closing)

Rob--W commented 3 years ago

open that extension file via the companion extension

Oh, I didn't understand how that worked. That's genius! Bonus points for opening said file in a minimized window in order to minimize the noise on screen (of tab/window opening and closing)

You could just open it in a background tab in the existing window (assuming that you have a window). Another nice thing, as a part of unloading the extension, existing extension tabs are currently closed (at least in Firefox and Chrome). So even without any programmatic changes, you can manually get the desired functionality by bookmarking the page and opening it whenever you want to reload the extension.

fregante commented 3 months ago

Create a (temporary) HTML+JS file

If adding code to the user extension is required, I'd prefer adding it to the background page (or any chrome-extension:// page, really).

Adding files (reload.html, reload.js) to specific paths of the extension (root) might be problematic with build systems.

Here's a possible solution via messaging, safe even in production, if it slips by:

chrome.management.getSelf(info => {
    if (info.installType === 'development') {
        chrome.runtime.onMessageExternal.addListener((message) => {
            message === 'reload' && chrome.runtime.reload();
        }) 
    }
})

Then web-ext Reload Manager Extension can attempt to send a message to the extension; if it fails it can fall back to the current behavior via management.setEnabled().