Closed Bug 1305856 Opened 8 years ago Closed 7 years ago

Gap between declarative content scripts and tabs.executeScript

Categories

(WebExtensions :: Untriaged, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED WONTFIX

People

(Reporter: bugzilla.mozilla.org, Unassigned)

References

Details

Declaring a script in manifest.json with all_frames: true ensures that it is executed exactly once for each frame.

The addon SDK provided a facility to do this through its APIs on demand. tab.attach() could attach a script to a tab and all its subframes until that attachment was canceled.

runtime.executeScript falls short of that. It can neither ensure that scripts stay attached on frame navigation nor can one ensure that a script is only executed once for a tab, which means all code must be written to be indempotent and (re)declaring top level consts or lets would immediately throw errors.


This means it is considerably more convenient to just use declarative content scripts injected to all frames even though that means scripts get loaded everywhere when it is not necessary to do so. I.e. it encourages inefficient behavior.


I think an additional option to executeScript would be great. Something like

> let trigger = this.onCleanup(); // returns an unresolved promise
> tabs.executeScript(null, {allFrames: true, keepAttachedUntil: trigger)})
> 
> // ... later. resolve the trigger promise
> this.cleanup()
I totaly agree with The 8472 . In my opinion there is another lack of functionality compared to the page_mod api.

If I'm trying to execute a script before the page has loaded like this:
> chrome.webNavigation.onCommitted.addListener(function() {
>   chrome.tabs.executeScript(result[0].id, {
>       'code': 'code', // same for file
>       'runAt': 'document_start'
>     }
>   );
> });
I'm getting the error Unchecked lastError value: Error: No matching message handler
(which seems to happen because the tab isn’t ready for it yet https://bugzilla.mozilla.org/show_bug.cgi?id=1254003)

So it's not possible to inject a script via executeScript before the page content is loading, but if I declare the content script in the manifest json with 'document_start' it's working fine.

However a second problem appears to me. It is not possible to give the content script access to data before page load. I only can use some asynchronous functions like messages or the storage api where addon developers, who need to pass data and run some code before the page is loading, can not rely on.

I would like to see something like: contentScriptOptions and contentScriptWhen from the sdk page_mod api. As a result it would be possible to execute scripts on certain events/loading states and pass necessary data the script may need for execution.
From our discussions to date, we don't think there's a compelling enough use case for this to warrant implementing it.
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago
Resolution: --- → WONTFIX
FWIW: Tampermonkey has a use case for this. At the moment Tampermonkey's content_scripts are injected into every frame and then start to query the background page whether a script is supposed to run. This wouldn't be necessary if it would be possible to inject the scripts at document-start programmatically.

Also some userscripts want to be executed at document-start, which is hard to achieve with an (potentially) asynchronous messaging API. With a proper working tabs.executeScript both, the content script and the userscripts could be injected when needed at the right time.
I'd consider an API to dynamically register programmatic content scripts similarly to how they're registered in the manifest.
Unfortunately I don't think this would work well. At least for me. 
Userscripts bring their own @include, @match and @exclude statements, @include can even be a regular expression which needs to be tested with the tab's URL. It's not possible to know the right match pattern for such an API unless Firefox understands @include, @match and @exclude the same way like all userscript managers do.
(In reply to Kris Maglione [:kmag] from comment #4)
> I'd consider an API to dynamically register programmatic content scripts
> similarly to how they're registered in the manifest.

Similar to chrome's declarative content API, except for content scripts? That might work for my case where I want to turn something on and off based on the top window's domain.

But to cover other cases filter rules other than the url may be necessary too. E.g. the tab IDs and in jan's case maybe even a small script that gets evaluated before loading the heavyweight ones.
See Also: → 1323433
Product: Toolkit → WebExtensions
You need to log in before you can comment on or make changes to this bug.