I am starting with chrome extension development and have a couple of questions regarding extension install/update flow and testing during the development :
What happens with the background script after extension update, does chrome perform background script reload ?
Are content scripts detached from background script after extension update ?
If there's an onInstalled event handler in background script, what happens with that event handler when chrome updates extension(is this event handler detached, and when update finishes, the new handler is attached and then executed or some other flow is exercised) ?
Is there a way to simulate update process during development in order to debug events that happen during the update process, for example to host extension on some local server and update from there ?
where to search for documentation on topics like this and similar, is the chromium source code the right place or at least the starting point ?
Thanks!
What happens with the background script after extension update, does Chrome perform background script reload?
The behavior depends on whether you have a handler to chrome.runtime.onUpdateAvailable event registered and whether your extension has a persistent background page or event page.
If you have a persistent background page:
If you handle this event and call chrome.runtime.reload(), the extension is unloaded and then updated before being loaded again.
If you handle this event and do not call chrome.runtime.reload(), then the update will only apply when the extension is next reloaded - likely the next full browser restart.
If you do not handle this event at all, the extension will be unloaded immediately to be updated.
If you have a non-persistent Event page:
If you handle this event and call chrome.runtime.reload(), the extension is updated before being loaded again.
If you do not call chrome.runtime.reload(), or do not handle the event at all, Chrome will update the extension when the Event page next gets unloaded.
There is no way to programmatically prevent the update once the background page gets unloaded for whatever reason.
Are content scripts detached from background script after extension update?
Yes, and it's not pretty. They enter an "orphaned" state when using Chrome API gives inconsistent errors (some do nothing, some trigger exceptions), but are still running — for example, any DOM event listeners will still trigger.
As such, if you want the content scripts to work immediately again, your job is to:
Inject scripts programmatically in existing tabs, without making an assumption that it did not execute before: cleanup first if necessary.
Make sure orphaned copies stop executing: either by noticing in the old copy that it's orphaned, or by broadcasting a DOM event from the new copy.
Important note about WebExtensions: Firefox, unlike Chrome, always reinjects content scripts on load into pages that match manifest entries. Make sure to take that into account.
There are a few question that cover this; for example:
Sending message from a background script to a content script, then to a injected script (See addendum to the answer)
How to properly handle chrome extension updates from content scripts
Chrome extension content script re-injection after upgrade or install
If there's an onInstalled event handler in background script, what happens with that event handler when chrome updates extension (is this event handler detached, and when update finishes, the new handler is attached and then executed or some other flow is exercised)?
Since an update can only happen while the background page is unloaded, there is no complex logic; it will simply fire on first load of the extension afterwards with details.reason == "update". Be sure to register the handler synchronously on script load (e.g. in top level code), or else you may miss the event — normally this only concerns Event pages, but I suspect it's also important here.
Is there a way to simulate update process during development in order to debug events that happen during the update process, for example to host extension on some local server and update from there?
Sadly, this is no longer possible to the best of my knowledge, unless you can use Enterprise Policy install. Your best bet is to have an extension in CWS that's published as Private.
To a certain extent, pressing "Reload" after making some changes to an unpacked extension simulates what happens during the update - with the exception of onInstalled event.
Where to search for documentation on topics like this and similar, is the chromium source code the right place or at least the starting point?
Well.. For detailed questions Chromium code is, of course, the authoritative source. You should search StackOverflow as well, as there's quite a body of knowledge amassed here already. Finally, the official docs provide a lot of information, even if it's not immediately evident - the chrome.runtime API docs, for example.
Related
Is it possible in an external javascript code (for example, a userscript through tampermonkey) to run a code snippet on the Chrome console. For example, console.log prints text to the console. Is there some way, like a function console.eval or some more complex way where I can run code on the console without manually opening it on the given website, but using the original javascript code behind the website or a userscript?
Notes: I use Google Chrome on Windows 10. Preferably this answer should be as generally applicable as possible, but first priority for me is for it to work in my environment.
Thanks,
Mike
Uk, when i said if the page is reloading constantly, the "console" that u think of would also reload??, a lot of us knew about what I'm doing below(if not all of us) but I finally connected it with your question. Using one tab to control the other tab
ONE EDIT: I used an interval to determine if the controlled tab is CLOSED(since a certain value eventually changes if the tab is closed for good)
HOW TO USE:
Open a tab with the same origin as desired url(but not the constantly reloading site)..
eg: opening a tab on "https://example.com/404" if desired url is "https://example.com" is the desired url(the constantly reloading one)
In the code snippet I have below, you can put your tab controlling code in the loadFn function, where myWindow and this point to the controlled tab's window
eg: in the loadFn function, myWindow.console.log(1) or this.console.log(1) would both log 1 to the controlled tab's console
SECOND EDIT: I shall explain how it works(and talk about unloadFn as you requested in comments)
I use a combination of unload and load listening to be able to repeatedly send code "on reload" which is not an event in itself so I had to create it. In case I didn't explain myself, I'd go into detail now..
When a page is reloading(or when I'm JUST SPAWNING the page, eg: var myWindow=window.open(desiredUrl)), the unload event happens. There's just one problem however; every time the page is reloading, all event listeners and any code you put is removed(because reload unloads to then reload)
The solution is simple: on every unload, I set the listners again, and since the function would call itself(every time the page unloads), the listeners would successfully be reloaded every time the page reloads(and that is why loadFn could run in the other tab after every reload)
DO NOTE: You might ask "why use a setTimeout then?". Actually it's quite important. Without the setTimeout, the event listeners DO NOT GET ADDED, I think it's because the tab would ignore your commands(since it would be focusing on loading its default stuff(like event listeners for instance)), and asynchronous programming does wonders in this case because it will wait until the other stuff are processed(like event handling stuff) then run
SIDE NOTE: If that's not why setTimeout works and NOT USING it doesn't, all I know is that without it, it doesn't work, and with it, it works
var myWindow=window.open(desiredUrl) //remember to run this code on the same origin as the desiredUrl
function loadFn(){
//this will happen every time myWindow loads or reloads
myWindow.alert("It runs in the controlled tab")
myWindow.console.log("Even in the controlled tab's console it works >:D")
}
function unloadFn(){setTimeout(()=>{
myWindow.addEventListener('unload',unloadFn)
myWindow.addEventListener('load',loadFn)
if(!myWindow.Window){console.warn("myWindow was CLOSED")}
},0)}
myWindow.addEventListener('unload',unloadFn)
//extra thing below to tell if controlled tab is closed >:D
var i=setInterval(()=>{
//for if controlled tab is closed
if(!myWindow.document.location){clearInterval(i);console.warn("myWindow was CLOSED")}
},0)
I am currently trying to scrape some data from the trading dashboard on Plus500. The information I am interested in is only visible (on the right-hand side) when the 'Information' button is clicked next to a particular security, as shown in the screenshot below:
I have so far written some basic JavaScript which clicks on the information button next to each security on the page and attempts to scrape the data in the info pane. However, when the 'Information' button is clicked it takes a few seconds for the new data to load:
As a consequence, my Javascript is scraping from the info panel before it has loaded and the information it is collecting is incorrect. This means that I am now trying to work out how to tell my Javascript to wait until the new data has loaded.
I suspected (perhaps incorrectly) that an Ajax request was being used to fetch this new information. However, looking at Fiddler, no such processes are being captured when I click the info buttons.
I also wondered whether the information was all already there on the page, but hidden until the info button was clicked. This would explain why I cannot see an Ajax request being made in Fiddler. However, a brief inspection of the HTML seemed to suggest that this was not the case.
To avoid the guess-work, how can I definitively find out what process(es) are being run when I click these 'information' buttons?
NB: If anyone thinks there is a better way to be scraping this data then please let me know!
Cheers.
Use breakpoints in the JS debugger of your browser:
Open the dev tools of your browser (usually F12)
Go to the tab "Debugger" (Firefox) or "Sources" (Chrome/WebKit)
Find the panel for breakpoints (rightmost panel or bottom left panel depending on your dev tools dimensions)
Navigate to Event Listener Breakpoints -> Mouse and there you can set a breakpoint for all click events
Now whenever you make a click that has a JS event listener, the JS debugger will halt in the JS code of the listener and you can debug it. Since most websites minify their JS code, you might have to fight through an unreadable mess, but at least it's a start.
You can also see all event listeners for a node in the DOM inspector:
Firefox: The DOM inspector shows a small bubble "event" next to each node with event listeners. Click on it to list all listeners bound to this node. Note that events might bubble up and be handled by a higher node, so there might be an event listener not shown at the node directly still handling events for the node.
Chrome: Select the node, then in the right panel go to the tab "Event Listeners" and select the event type you are interested in.
I am developing a custom translation extension for GMail in chrome and need to trigger the content script when the user clicks on an email in his inbox.
Since GMail uses AJAX, I decided to use the DOMSubTreeModified event. My extension works, but it seems via console logging that the function that sits the translate keeps getting executed constantly, even though the email text remains the same.
DOMContentLoaded does not trigger. Can anyone suggest any alternative I can use? I guess a timer or something in GMail constantly updates the page and makes minor adjustments. I had even narrowed the element on which the event is generated.
It appears that you should be using gmail-specific events to know when a new email is loaded, not generic DOM events. This add-on is not official Google code, but if you look at how it works, you could probably discover how to observe all sorts of gmail events or you could just use it to solve your problems.
I'm working on a Chrome extension which has a background script (or event script) which runs continuously and detects if certain web pages are visited in any tab and then does some processing.
I noticed that the script randomly stops working every now and then, but starts again if I restart the browser or inspect the console for the background script.
I know how to store data in chrome.storage.local and I want to be able to detect and make an entry everytime a runtime error is thrown, is this possible? i.e. a script wide catch block?
I saw this post which explains how to handle runtime errors, but this only works within a single callback function. I want to be able to do this for the whole script.
You are probably hitting the idle unload that Event pages use (since you say inspecting works - that wakes it up).
It was your choice to put in "persistent": false and it comes with consequences.
If you rely on any state variables, they will be lost when the page is unloaded. If you must keep any state at all, do it in chrome.storage.local.
Another common mistake is not re-registering all event listeners every time the script runs. The unload-but-remember-listeners mechanism depends on it; if an event is triggered, the following happens:
Check it there was any listener registered for the event. If not, do nothing.
If there was, the listener itself no longer exists (JS context is unloaded). Execute the page to reconstruct the context.
After the page stops executing (disregarding async code, Chrome won't wait), pick the listener registered in this run that matches the event and execute it.
So if you, say, registered a listener in a codepath that's not executed every time you run the script (e.g. not in a top-level statement but conditionally or asynchronously), then after waking up the script won't have that listener enabled and the event will be dropped:
/* Chrome wakes up your page */
chrome.storage.local.get("option", function(data) {
if(data.option) {
// Asynchronous
chrome.someAPI.onSomeEvent.addListener(function() {
// This will not be handled after unload
});
}
});
// Synchronous
chrome.someAPI.onSomeEvent.addListener(function() {
// This will be handled after unload
chrome.storage.local.get("option", function(data) {
if(data.option) {
// Do stuff
});
}
});
/* At this point, Chrome triggers the event,
and if there are no listeners (re)registered it's lost */
So put any conditional/async processing inside the listeners.
There are also other reasons why it can stop working, but it's impossible to tell without seeing your code.
In my Firefox extension I am using DOMContentLoaded to detect page load and insert my HTML. Is there an event which triggers before this and still the document is available at that time?
Note: This answer refers to XUL-based extensions. As of Firefox 57, this technology is obsolete. The functionality mentioned here is no longer available to extensions.
There is content-document-global-created notification that is sent out when a document is created, before any content is added to it (to be precise, it happens when the browser receives the HTTP headers of the response and knows that it isn't a redirect or such). That's the earliest point where you can get the document. The DOMContentLoaded event is fired once Gecko finishes downloading the contents of the document, that's the earlies point where you can access the complete DOM. In between there is a bunch of other events, e.g. lots of progress listener events - which one you use depends on what you are trying to do, there is no general answer.