3

Good day to everyone, as you can see I'm pretty new at Chrome extensions.

Can you run a script from content_scripts before and after the the DOM or page fully loads?

Like:

"content_scripts": [ {
    "matches": ["<all_url>"],
    "js": ["content.js"],
    "all_frames": true,
    "run_at": "document_start",
    "run_at": "document_end"
} ]

Or something like:

 "content_scripts": [ {
    "matches": ["<all_url>"],
    "js": ["content1.js"],
    "all_frames": true,
    "run_at": "document_start"
} ],
"content_scripts": [ {
    "matches": ["<all_url>"],
    "js": ["content2.js"],
    "all_frames": true,
    "run_at": "document_end"
} ]
Xan
  • 74,770
  • 16
  • 179
  • 206
Francis G
  • 1,040
  • 1
  • 7
  • 21
  • i want it to be before the page and after, any method will be fine. – Francis G Mar 20 '19 at 07:52
  • I mean when after and before the page fully loaded. – Francis G Mar 20 '19 at 07:54
  • An important note: there is no general "all DOM is loaded now" state you can detect if the page dynamically creates more DOM (e.g. infinite scroll). This needs to be dealt with [different techniques](https://stackoverflow.com/questions/2844565/is-there-a-javascript-jquery-dom-change-listener). `document_end` (or `document_idle`) guarantees only that all static DOM has been parsed. – Xan Mar 20 '19 at 10:38
  • Xan, well for that case I run a script that run indefinitely. Well my only concern was to run a two different script before and after the page loaded. – Francis G Mar 21 '19 at 05:35

2 Answers2

3

You can have only one content_scripts entry, so it would be like:

"content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content1.js"],
    "all_frames": true,
    "run_at": "document_start"
  },{
    "matches": ["<all_urls>"],
    "js": ["content2.js"],
    "all_frames": true,
    "run_at": "document_end"
}]

With this setting, content1.js would run at the beginning and content2.js at the end.

Iván Nokonoko
  • 4,888
  • 2
  • 19
  • 27
2

You are going in the right direction: You can use the run_at property, but your manifest needs to look something like this:

"content_scripts": [
{
    "matches": ["<all_url>"],
    "js": ["content1.js"],
    "all_frames": true,
    "run_at": "document_start"
},
{
    "matches": ["<all_url>"],
    "js": ["content2.js"],
    "all_frames": true,
    "run_at": "document_end"
}]

It should be an array of objects defining all content scripts instead to declaring the content_script property twice.


If you are using jQuery you can also use $(document).ready() like this:
const func1 = params => {
    // Stuff that will happen as soon as it can
};

$(document).ready(() => {
    // stuff that will happen when DOM is ready
});

If you are not using jQuery you can just do a quick google search to find alternatives for $(document).ready in vanilla js.


Other solution you can use it to inject content script programmatically from background script using chrome.tabs.executeScript() docs.
Vaibhav Vishal
  • 6,576
  • 7
  • 27
  • 48