Search code examples
javascriptgoogle-chrome-extensionpromisefirefox-addon-webextensionspolyfills

Uncaught (in Promise) Error When Using Polyfill for Porting Firefox Extensions to Chrome


I wrote a web extension for Firefox Quantum. The extension has a popup, which when clicked provides a 3 button menu. When one of the buttons is clicked, the extension will inject a DIV containing an iFrame into the user's current page.

Firefox extensions use the promise API and use the browser namespace instead of "callbacks" and the chrome namespace. As such, Mozilla provides a polyfill to allow easy porting of code written for Firefox Extensions.

Excerpt from this article.

If you do write your extension to use browser and promises, then Firefox also provides a polyfill that will enable it to run in Chrome: https://github.com/mozilla/webextension-polyfill.

I followed the tutorial on github to modify the html file for my popup (I removed the CSS classes to make the example more concise):

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <link href="https://fonts.googleapis.com/css?family=Nunito:800" rel="stylesheet">
        <script type="application/javascript" src="../polyfills/browser-polyfill.js"></script>
    </head>
    
    <body>
        <div style="display: flex; flex-direction: column; justify-content: space-evenly; align-items: center; width: 100vw; min-width: 200px;">
            <button class="btn" id="3">Short Summary</button>
            <button class="btn" id="5">Medium Summary</button>
            <button class="btn" id="7">Long Summary</button>
            <script src="choose_length_page.js"></script>
        </div>
    </body>
    
    </html>

Then in my "choose_length_page.js" file, I have the following code:

//Enable the polyfill for the content script and execute it in the current tab

browser.tabs.executeScript({ file: "../polyfills/browser-polyfill.js" }).then(loadContentScript);

function loadContentScript() {
    browser.tabs.executeScript({ file: "../inject-content/inject.js" }).then(listenForClicks);
}

function listenForClicks() {
    document.addEventListener('click', e => {

        if (!e.target.classList.contains('btn')) {
            return;
        } else {
            browser.tabs.query({ active: true, currentWindow: true })
                .then(tabs => {
                    browser.tabs.sendMessage(tabs[0].id, { summaryLength: e.target.id, targetURL: tabs[0].url });
                });
        }
    });
}

However, when I run this code I get the following error ("choose_length_page.html" is the HTML file in this post):

Error

Why is this error happening, and how can I fix it?

Update 1 -

At the suggestion of wOxxOm, I tried to specify paths qualified from the root package. I did this like so:

<head>
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Nunito:800" rel="stylesheet">
<script type="application/javascript" src="chrome-extension://__MSG_@@extension_id__/polyfills/browser-polyfill.js"></script>

After doing that, I got the following message:

[Deprecation] Subresource requests whose URLs contain embedded credentials (e.g. https://user:pass@host/) are blocked. See https://www.chromestatus.com/feature/5669008342777856 for more details.

So, I don't think that works.


Solution

  • I managed to fix the errors:

    I changed my javascript file to (I added catch statements to the promises and I changed the paths to be consistent with JaromandaX's suggestion):

    //Enable the polyfill for the content script and execute it in the current tab
    
    browser.tabs.executeScript({ file: "/polyfills/browser-polyfill.js" }).then(loadContentScript).catch((error) => logError(error));
    
    function loadContentScript() {
        browser.tabs.executeScript({ file: "/inject-content/inject.js" }).then(listenForClicks).catch((error) => logError(error));
    }
    
    function listenForClicks() {
        document.addEventListener('click', e => {
            if (!e.target.classList.contains('btn')) {
                return;
            } else {
                browser.tabs.query({ active: true, currentWindow: true })
                    .then(tabs => {
                        browser.tabs.sendMessage(tabs[0].id, { summaryLength: e.target.id, targetURL: tabs[0].url });
                    });
            }
        });
    }
    
    function logError(error) {
        console.log(error);
    }
    

    I also changed the path in the src attribute of the script tag to:

    <script type="application/javascript" src="/polyfills/browser-polyfill.js"></script>
    

    The error seemed to be that I did not catch the promises.