We are able to meet this requirement in manifest v2 by inlining a script like:
const script = document.createElement('script');
script.textContent = 'console.log("test")';
const container = document.head || document.documentElement;
This allows our script to be injected and load before the page's scripts, whereas setting src does not:
script.src = chrome.runtime.getURL('inject.js');
Error inlining in a manifest v3:
> Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'self' data: gap: ... 'unsafe-eval'". Either the 'unsafe-inline' keyword, a hash ('sha256-V+/U3qbjHKP0SaNQhMwYNm62gfWX4QHwPJ7We1PXokI='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.