webext-content-scripts

Utility functions to inject content scripts in WebExtensions, for Manifest v2 and v3

Usage no npm install needed!

<script type="module">
  import webextContentScripts from 'https://cdn.skypack.dev/webext-content-scripts';
</script>

README

webext-content-scripts npm version

Utility functions to inject content scripts in WebExtensions, for Manifest v2 and v3.

  • Browsers: Chrome, Firefox, and Safari
  • Manifest: v2 and v3
  • Permissions: In manifest v3, you'll need the scripting permission
  • Context: They can be called from any context that has access to the chrome.tabs or chrome.scripting APIs

Sponsored by PixieBrix :tada:

Install

You can download the standalone bundle and include it in your manifest.json. Or use npm:

npm install webext-content-scripts
// This module is only offered as a ES Module
import {
    executeScript,
    insertCSS,
    injectContentScript,
    executeFunction
} from 'webext-content-scripts';

Usage

executeScript

Like chrome.tabs.executeScript but:

  • it works on Manifest v3
  • it can execute multiple scripts at once
executeScript({
    tabId: 1,
    frameId: 20,
    files: ['react.js', 'main.js'],
});
executeScript({
    tabId: 1,
    frameId: 20,
    files: [
        {file: 'react.js'},
        {code: 'console.log(42)'}, // This will fail on Manifest v3
    ],
});

insertCSS

Like chrome.tabs.insertCSS but:

  • it works on Manifest v3
  • it can insert multiple styles at once
insertCSS({
    tabId: 1,
    frameId: 20,
    files: ['bootstrap.css', 'style.css'],
});
insertCSS({
    tabId: 1,
    frameId: 20,
    files: [
        {file: 'bootstrap.css'},
        {code: 'hmtl { color: red }'}
    ],
});

injectContentScript(tabId, scripts)

injectContentScript({tabId, frameId}, scripts)

It combines executeScript and injectCSS in a single call. You can pass the entire content_script object from the manifest too, without change (even with snake_case_keys). It accepts either an object or an array of objects.

const tabId = 42;
await injectContentScript(tabId, {
    runAt: 'document_idle',
    allFrames: true,
    matchAboutBlank: true,
    js: [
        'contentscript.js'
    ],
    css: [
        'style.css'
    ],
})
await injectContentScript({
    tabId: 42,
    frameId: 56
}, [
    {
        js: [
            'jquery.js',
            'contentscript.js'
        ],
        css: [
            'bootstrap.css',
            'style.css'
        ],
    },
    {
    runAt: 'document_start',
        css: [
            'more-styles.css'
        ],
    }
])
const tabId = 42;
const scripts = browser.runtime.getManifest().content_scripts;
// `matches`, `exclude_matches`, etc are ignored, so you can inject them on any host that you have permission to
await injectContentScript(tabId, scripts);

executeFunction(tabId, function, ...arguments)

executeFunction({tabId, frameId}, function, ...arguments)

Like chrome.tabs.executeScript, except that it accepts a raw function to be executed in the chosen tab.

const tabId = 10;

const tabUrl = await executeFunction(tabId, () => {
    alert('This code is run as a content script');
    return location.href;
});

console.log(tabUrl);

Note: The function must be self-contained because it will be serialized.

const tabId = 10;
const catsAndDogs = "cute";

await executeFunction(tabId, () => {
    console.log(catsAndDogs); // ERROR: catsAndDogs will be undeclared and will throw an error
});

you must pass it as arguments:

const tabId = 10;
const catsAndDogs = "cute";

await executeFunction(tabId, (localCatsAndDogs) => {
    console.log(localCatsAndDogs); // It logs "cute"
}, catsAndDogs); // Argument

isScriptableUrl(url)

Browsers block access to some URLs for security reasons. This function will check whether a passed URL is blocked. Permissions and the manifest are not checked, this function is completely static.

More info may be found on:

const url = 'https://addons.mozilla.org/en-US/firefox/addon/ghosttext/';
if (isScriptableUrl(url)) {
    console.log('I can inject content script to this page if permitted')
} else {
    console.log('Content scripts are never allowed on this page');
}

Related

License

MIT © Federico Brigante