Load Internal File from Javascript | Firefox Extension & Addon

Scouring through the MDN Extensions Documentation, I had an incredibly hard time finding out how to include an html file's content in my javascript content-script. I found that one must use web_accessible_resources to declare which resources are available, then make a "simple" web request to get the file's content.

The example today will be adding a simple (& ugly) control panel to a website (specifically StardewValleyWiki). It's sole function will be to show a control panel on top of the page, style it with a CSS file, and move the #searchform into the popup control panel. Note that this approach does not use any of the documented user interface methods.

Disclaimer I'm writing this tutorial after creating my first FF extension & I may not be using best (or even good) practices. It did work, though.

Sample application loading internal resource files.

Check out my Stardew Wiki Extension if you haven't made a web extension before & would like to be walked through the process.

How to load an internal extension file into a javascript script

  1. Add the file to web_accessible_resources of your manifest.json like so:

        {
            //name, description, etc
            "content_scripts": ["/script/init.js"],
            "web_accessible_resources": ["/dir/the-file.ext"]
        }
    

    NOTE: Any page & any extension can access the web_accessible_recources of your extension, as long as they can get your extension's url prefix (& I believe they can, but I don't know how that works).
    NOTE 2: Following code could go in one of your content_scripts, listed in your manifest.json.

  2. Get the internal url of the file:

    const resourceUrl = browser.runtime.getURL("/dir/the-file.ext");
    
  3. Use the resourceUrl to load a file in the manner you need:
    a. Raw File Content - If you wish to do work with the string representation of the file, you send a web request to the url for the resource.

    const resourceUrl = browser.runtime.getURL("/dir/the-file.ext");
    fetch(resourceUrl)
    .then(response => {
       // return response.json(); // if you want a JSON object. The file has to contain valid JSON.
       return response.text();
    }).then(rawFileContent => {
       //doSomething with it
       console.log(rawFileContent);
    });
    

    Check out my crummy Request class to save some boilerplate code & make web-requests easier (especially with POST requests).

    b. Add HTML to the main document <body>. Declare this function, which will add the raw file string to the document:

    function loadHtmlString(html,parentNode = 'document.body'){
        if (parentNode==='document.body')parentNode = document.body;
        var wrapper  = document.createElement('div'); //you could use a span here, if you want inline-styling, or customize styles through js. 
        wrapper.innerHTML = html;
        parentNode.appendChild(wrapper);
    }
    

    Then use the Raw File Content approach to get the HTML String & call upon loadHtmlString

    const resourceUrl = browser.runtime.getURL("/dir/the-file.ext");
    fetch(resourceUrl).then(response => {return response.text();}).then(
        function(rawFileContent) {
            loadHtmlString(rawFileContent); //adds to document.body
            //or loadHtmlString(rawFileContent, nodeOfYourChoice);
        });
    

    c. Add stylsheet to the main document <head> (call loadStyle(resourceUrl))

    function loadStyle(href){
       // avoid duplicates
       for(var i = 0; i < document.styleSheets.length; i++){
           if(document.styleSheets[i].href == href){
               return;
           }
       }
       var head  = document.getElementsByTagName('head')[0];
       var link  = document.createElement('link');
       link.rel  = 'stylesheet';
       link.type = 'text/css';
       link.href = href;
       head.appendChild(link);
    }
    

    d. Add script to the main document <head> (call loadScript(resourceUrl))

    function loadScript(src){
        // avoid duplicates
        for(var i = 0; i < document.scripts.length; i++){
            if(document.scripts[i].src == src){
                return;
            }
        }
        var head  = document.getElementsByTagName('head')[0];
        var script  = document.createElement('script');
        script.type = 'text/javascript';
        script.src = src;
        head.appendChild(script);
    }
    

e. Add image to the main document... Basically the same as c. & d., except you document.createElement('img') & you add it somewhere in the <body>. Don't forget to add an alt attribute, for visually impaired users