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

Comments

Projects
None yet
7 participants
@arantius
Copy link
Collaborator

commented Jul 25, 2017

Support document-start for @run-at.

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

@ExE-Boss

This comment has been minimized.

Copy link

commented Jul 25, 2017

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

@iology

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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.

@Sxderp

This comment has been minimized.

Copy link
Contributor

commented Sep 24, 2017

@ExE-Boss

This comment has been minimized.

Copy link

commented Sep 24, 2017

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

@trlkly

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link

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
You can’t perform that action at this time.