0

My goal is to inject frontend code in a tab if its url matches my url. For that I did:

background.js:

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo?.url?.includes("https://www.google.com/search?")) {
        chrome.scripting.executeScript(
            {
                target: { tabId: tabId },
                files: ['injection.js'],
            }
        );
    }
})

It works but many people also do through content.js:

background.js:

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo?.url?.includes("https://www.google.com/search?")) {
        await chrome.tabs.sendMessage(tabId, { isActive: true });
    }
})

now we can add a listener in content.js.

My question is what are the difference? Which approach is better?

4
  • 1
    Which approach is better? My answer would be none of them. Script injection is a huge vulnerability for web pages. No one and nothing NEEDS script injection. So much better to shut things down with a ContentSecurityPolicy. Commented Nov 17 at 19:05
  • but what if one needs to inject code in the page like Dark reader do? How do they do? Commented Nov 17 at 19:08
  • btw by injecting code I meant manipulating DOM only.. Commented Nov 17 at 19:09
  • Is the user just manipulating their own DOM? If so, they can run a script from the console. If not, you are letting others mess with someone's page. Regardless, if this is something you want, I would suggest using web sockets and a defined API rather than running a script. Commented Nov 17 at 19:41

1 Answer 1

1

The difference is that injection is a more expensive operation.

However, both approaches are bad for this task because they require waking up and initializing a service worker each time there's any navigation in any tab for any site, not just the one you want, if that occurs in more than 30 seconds after the last one (this is the idle timeout of the service worker to be terminated).

A better approach is chrome.webNavigation.onHistoryStateUpdated and onReferenceFragmentUpdated events with a url filter:

chrome.webNavigation.onHistoryStateUpdated.addListener(info => { /* your listener */ }, {
  url: [{pathPrefix: "https://www.google.com/search?"}],
});

An even better approach, which is 1000 times less expensive, is doing everything inside a content script via MutationObserver or navigation.onnavigate (Chrome-only at the time, soon to be implemented in Firefox):

let lastUrl = location.href; 
new MutationObserver(() => {
  const url = location.href;
  if (url !== lastUrl) onUrlChange(lastUrl = url);
  // alternatively, you can detect the changes in the actual DOM instead of the URL
}).observe(document, {subtree: true, childList: true});

function onUrlChange() {
  console.log('URL changed!', location.href);
}

P.S. You need to re-inject files from content_scripts after reloading/installing the extension in Chrome.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.