0

My site is https://myapp.example.
I want my content script to run on every page under https://myapp.example/chats/*, and monitor its DOM using MutationObserver.

  "content_scripts": [
    {
      "matches": [
        "https://myapp.example/chats/*"
      ],
      "js": [
        "chat.js"
      ],
    }
  ],

But the issue is that it only runs if I refresh the page when I'm on the chat url.
If I start on the home page and then navigate to a chat page, nothing happens.

What's the best way to solve this?
Should I set matches to https://myapp.example/* and update the content script based on events listened by the background.js? Isn't it an anti-pattern to the whole purpose of content_scripts?

amiregelz
  • 1,833
  • 7
  • 25
  • 46
  • 1
    Your idea to match the entire site and check inside the script is a correct solution. If the script is small then running it on a wider range of URLs won't cause problems. See also [this compilation of solutions](https://stackoverflow.com/a/39508954). – wOxxOm Feb 25 '21 at 16:53
  • @wOxxOm Your answer there is amazing, I think it provides all the info I need. One last question - is using `chrome.tabs.onUpdated` better then using `chrome.webNavigation.onHistoryStateUpdated` which I've seen in some of the related questions/answers? IIUC both can be used (along with checking the url and sending a message to the content script when relevant) – amiregelz Feb 25 '21 at 16:58
  • In this case tabs.onUpdated isn't better because it can't be limited to a URL pattern whereas webNavigation events allow that so the background script won't wake up needlessly. Otherwise, it's more or less the same. Note though, on some sites you may also need onReferenceFragmentUpdated event. – wOxxOm Feb 25 '21 at 17:01
  • @wOxxOm It works great, but I have only one issue - if I reload the page I don't get any `changeInfo` event with my url, only `status: "loading"` and then `status: "complete"`. Should I listen to another event to detect page reloads inside my website? – amiregelz Feb 27 '21 at 21:01
  • The listener can check `tab` (the 3rd parameter) e.g. `const url = changeInfo.url || changeInfo.status === 'loading' && (tab.pendingUrl || tab.url)` – wOxxOm Feb 28 '21 at 05:49
  • @wOxxOm Got it, thank you. Can I ignore the `loading` status event and the `tab.pendingUrl` and just do `const url = changeInfo.url || changeInfo.status === 'complete' && tab.url`? Is there a chance to miss something there or am I fully covered? – amiregelz Feb 28 '21 at 10:30
  • 1
    Yeah, if your object of interest is created only after the page has loaded. – wOxxOm Feb 28 '21 at 10:34
  • @wOxxOm The thing is, I get multiple events with `tab.url === myUrl`, and then I trigger multiple executions of my content script. With `changeInfo`, there is only 1 event with the `url` key per user action. What can I do about it? – amiregelz Mar 01 '21 at 15:24
  • I don't see your code so maybe it's incorrect. Otherwise you can send a message to the tab before executeScript. The content script would respond with `true` if present or [with an error](https://stackoverflow.com/a/63668382) otherwise. – wOxxOm Mar 01 '21 at 15:45
  • @wOxxOm The issue is I'm getting 4 similar events with the same url in the `tab` object. What's the best approach to process the first one in my content script and ignore the rest of them? save a boolean in local storage? or use the respond message mechanism? – amiregelz Mar 01 '21 at 18:20
  • Details are important so I can't answer without [MCVE](/help/mcve) . – wOxxOm Mar 01 '21 at 18:25
  • @wOxxOm https://codepen.io/amiregelz/pen/jOVxWJb?editors=0010. This is how it looks without listening to the `tab.url`, so I only get one event per navigation, and everything works. But it doesn't catch the refresh event. – amiregelz Mar 01 '21 at 18:35
  • You can send the `url` in the same message and then your content script will compare it to `location.href`. If it's different, proceed. – wOxxOm Mar 01 '21 at 18:40
  • @wOxxOm The `url` is always equal to the `location.href` as I'm reloading the same page. – amiregelz Mar 01 '21 at 19:29
  • 1
    And why don't you use the thing I suggested in the beginning that should work for everything? also, this is a separate problem so I won't be monitoring these comments anymore, comments aren't meant to be used like this. – wOxxOm Mar 01 '21 at 19:48

1 Answers1

0

To anyone wondering that despite the same Manifest.json as per the question their script is not loading, try running your main function in content-script inside a Window load listener like this:

  window.addEventListener("load", (event) => {
    var btns = someMainFunction();
// some looping to do other stuff
    for (var i = 0; i < btns.length; i++) {
      document.getElementById('test_' + i).addEventListener('click', e => {
        readData(e.target);
      });
    }
  });