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

Support document-start script run time #2526

Open
arantius opened this issue Jul 25, 2017 · 17 comments
Open

Support document-start script run time #2526

arantius opened this issue Jul 25, 2017 · 17 comments
Milestone

Comments

@arantius
Copy link
Collaborator

@arantius arantius commented Jul 25, 2017

Support document-start for @run-at.

See #2483 for more detail. This may be "impossible".

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Jul 25, 2017

You can use the run_at property of the content_scripts manifest key.

@iology
Copy link
Contributor

@iology iology commented Sep 4, 2017

I shared the pity about Chrome with you 4 years ago. Now again for Firefox. 😭

I'd like to rephrase my suggestion in https://bugs.chromium.org/p/chromium/issues/detail?id=257956

tabs.insertCSS/executeScript should insert CSS/JS until URL of the tab is set non-empty(not null, not undefined, not empty string ""), and be canceled if the tab is removed/changed

The WebExtension APIs should be improved.

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Sep 4, 2017

@iology why did you downvote my suggestion? It is perfectly valid. Plus, one can just use the content script to insert script tags into the document that contain the user scripts.

The following should explain how to do so using my method: (should work reliably)

/**
 * @typedef UserScript
 * @property {Object} header The parsed header of a script
 * @property {String} script The raw script data
 * @property {String} type The script media type (in case a script is WebAssembly
 *                         or something other than JavaScript)
 */

/** The load state of this script. Used by the `matches()` function */
const READY_STATE = document.readyState;

(async () => {
    (await (browser.storage.local.get({scripts: []}) // Excuse this horrible code style
        .then(ret => ret.scripts)))                  // of combining `await` and `.then()`
        .forEach(/* @param {UserScript} script */ script => {
            if (matches(script.header)) {
                let scriptTag = document.createElement("script");
                scriptTag.setAttribute("type", script.type)
                scriptTag.textContent = script.script;
                document.appendChild(scriptTag);
            }
        });
})();

/**
 * Checks if this script matches this page and @run-at property.
 * 
 * @param {Object} scriptHeader The parsed header of a script
 * @return {boolean} `true` if this page matches, `false` otherwise
 */
function matches(scriptHeader) {
    // Uses window.location and READY_STATE.
    // TODO: Implement
}
@jspenguin2017
Copy link

@jspenguin2017 jspenguin2017 commented Sep 12, 2017

@ExE-Boss By the time you retrieve scripts from extension storage part of the page would already be loaded.

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Sep 12, 2017

I am aware of that, but I don’t really see another way to do so because of the fact that WebExtensions are inherently asynchronous.

@Sxderp
Copy link
Contributor

@Sxderp Sxderp commented Sep 12, 2017

@ExE-Boss, there's a bugzilla, https://bugzilla.mozilla.org/show_bug.cgi?id=1332273, that looks like it's progressing nicely and should help resolve the @document-start issue. Whether it'll land for FF57, I'm not sure.

@jspenguin2017
Copy link

@jspenguin2017 jspenguin2017 commented Sep 12, 2017

I am aware of that, but I don’t really see another way to do so because of the fact that WebExtensions are inherently asynchronous.

@ExE-Boss That's literally the problem we are trying to solve.

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Sep 12, 2017

I am trying to solve it as well, but my solution really only works well enough for #2525, because by that point the entire page has fully loaded.

@jspenguin2017
Copy link

@jspenguin2017 jspenguin2017 commented Sep 12, 2017

Violentmonkey has this problem as well, not sure what black magic Tampermonkey uses, but it is able to inject script reliably on the real document-start.

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Sep 12, 2017

Tampermonkey 2.9 and earlier was GPL-3.0 and published on GitHub. I’ve tried looking into it, and at first I thought it was using sync XHR, but after looking into it a bit, I have no idea how it achieves that, but it does that somehow because support for that was added in version 2.6.2767.

See here as to why Tampermonekey went closed source:

@jspenguin2017
Copy link

@jspenguin2017 jspenguin2017 commented Sep 13, 2017

I'm not interested in pirating stuff, it won't be too hard to reverse Tampermonkey's logic but it's not legal to do that.

@ExE-Boss
Copy link

@ExE-Boss ExE-Boss commented Sep 24, 2017

@Sxderp That’s only for Firefox 57, that bug might still be resolved in 58+.

@trlkly
Copy link

@trlkly trlkly commented Oct 28, 2017

FYI, Tampermonkey isn't reliable at document-start, either. There is an "instant" injection option (which is extremely hacky) that speeds things up, but on simple pages like xkcd.com, I still get a flash before my CSS (which is always injected at document start) loads. I also occasionally get a flash on other sites.

Reversing Tampermonkey's code is not a way to figure this out. Plus, well, the actual methods they use can be found in their forums, suggested by other users. Copying a method isn't a copy-vio, just copying the code itself.

But we know it's an imperfect solution, and we want a perfect one.

@ccd0
Copy link

@ccd0 ccd0 commented Nov 16, 2017

If a method is found to make this work, could there be a way to for a script to read at least a subset of its configuration options synchronously? As an example of the kind of issues this would solve, see ccd0/4chan-x#1627. Here i need to disable some code on the page, but I also want to have an option not to disable the code. And many users clear localStorage at the end of each browser session.

@Sxderp
Copy link
Contributor

@Sxderp Sxderp commented Nov 16, 2017

If a method is found to make this work, could there be a way to for a script to read at least a subset of its configuration options synchronously?

Not in any short term. There's no way to communicate with the (get|set)Value storage in a synchronous manner. Perhaps some kind of injection on the part of GM wherein variables with config values are injected into the global scope of the script. That's the best I can think of, and that's not very nice.

@ccd0
Copy link

@ccd0 ccd0 commented Nov 16, 2017

Perhaps some kind of injection on the part of GM wherein variables with config values are injected into the global scope of the script. That's the best I can think of, and that's not very nice.

Presumably it would be part of the GM object. Something like GM.initValues.yourVariable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants