What is the proper method of running scripts in the highest possible context level in web extensions?

17 views Asked by At

I have been maintaining a utility userscript for a social media site for a few months now, and after a lot of promising user feedback I'm looking to make the jump to recreating it as a fully-fledged web extension.

However, one of the key features of the script and future extension involves running a hook function at document-start that defines custom getters and setters for a specific window property used by the website at runtime. My current script makes use of a rather convoluted method:

const main = () => {
  // hook function
};

const getNonce = () => {
  const { nonce } = [...document.scripts].find(script => script.nonce) || '';
  if (nonce === '') console.error('empty script nonce attribute: script may not inject');
  return nonce;
};

const script = () => { 
  const s = document.createElement("script");
  s.innerHTML = `const main = ${main.toString()}; main();`;
  s.nonce = getNonce();
  return s;
}

if (!document.head) {
  const newNodes = [];
  const findHead = () => {
    const nodes = newNodes.splice(0);
    if (nodes.length !== 0 && (nodes.some(node => node.matches('head') || node.querySelector('head') !== null))) {
      const head = nodes.find(node => node.matches('head'));
      head.append(script());
    }
  };
  const observer = new MutationObserver(mutations => {
    const nodes = mutations
      .flatMap(({ addedNodes }) => [...addedNodes])
      .filter(node => node instanceof Element)
      .filter(node => node.isConnected);
    newNodes.push(...nodes);
    findHead();
  });
  observer.observe(document.documentElement, { childList: true, subtree: true });
} else document.head.append(script);

While this works fine as for a userscript, and functions exactly the same when migrated to a web extension content script, it's clear that there is certainly a better method with which to accomplish the same goal in a less...hacky manner. I've done a lot of digging through the MDN webExtension docs, but nothing I've come across so far has enlightened me as to what exactly this superior option may be.

0

There are 0 answers