Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't send runtime messages in Firefox; Error: "TypeError: promise.then is not a function" #105

Open
kottkrig opened this issue Apr 10, 2018 · 18 comments

Comments

@kottkrig
Copy link

kottkrig commented Apr 10, 2018

I'm getting the following error in Firefox when I try to send a runtime message from a content script to a background script:

Unhandled promise rejection 
TypeError​columnNumber: 9​
fileName: "resource://gre/modules/ExtensionCommon.jsm"​
lineNumber: 490​
message: "promise.then is not a function"
​stack: "wrapPromise/<@resource://gre/modules/ExtensionCommon.jsm:490:9_@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:69770
wrapPromise@resource://gre/modules/ExtensionCommon.jsm:489:14
callAsyncFunction@resource://gre/modules/ExtensionCommon.jsm:697:12
stub@resource://gre/modules/Schemas.jsm:2297:22
t/<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96454
b@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50347
A/o._invoke@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50137
E/</t[n]@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:50523
e@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96739
i/<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96722
_@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:69770
i@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96680
u<@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96912
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:96983
r@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:105
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:97021
r@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:105
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:517
@moz-extension://63f25ebd-93c8-554e-bc69-b002724886b7/content_script.js:1:2
inject@resource://gre/modules/ExtensionContent.jsm:483:18
injectInto@resource://gre/modules/ExtensionContent.jsm:388:14
"​__proto__: Object { stack: "", … } content_script.js:1:69061
// content_script.js

import browser from "webextension-polyfill";

async function sendMessage() {
  const { response } = await browser.runtime.sendMessage({
    kind: "LOREM",
    data: "ipsum"
  });

  console.log("content_script: response:", response);
}

sendMessage();
// background_page.js

import browser from "webextension-polyfill";

browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return Promise.resolve({ response: data });
  }

  return false;
});

I'm using webpack with babel-polyfill to include the generator runtime:

module.exports = {
  entry: {
    background_page: ["babel-polyfill", "./src/background_page.js"],
    content_script: ["babel-polyfill", "./src/content_script.js"]
  },

  output: {
    path: path.resolve(__dirname + "/dist"),
    filename: "[name].js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["babel-preset-env"]
          }
        }
      }
    ],
  }
}

It works fine in Chrome. What am I missing?

@kottkrig kottkrig changed the title "TypeError: promise.then is not a function" in Firefox when sending messages Can't send runtime messages in Firefox. Error: "TypeError: promise.then is not a function" Apr 10, 2018
@kottkrig kottkrig changed the title Can't send runtime messages in Firefox. Error: "TypeError: promise.then is not a function" Can't send runtime messages in Firefox; Error: "TypeError: promise.then is not a function" Apr 10, 2018
@james-cnz
Copy link

Perhaps try changing this line:
return Promise.resolve({ response: data });
I don't really understand promises, but if you're using async functions, I think they're dealt with automatically, and you can just say:
return { response: data };

@james-cnz
Copy link

On second thoughts, that probably won't make any difference.

It could be the way you're importing it? This might bypass the check intended to stop the polyfill being applied to Firefox? The main page has suggestions about how to import it.

@james-cnz
Copy link

A couple of other suggestions:
There might an issue with Webpack? (see #86)
And if you don't need to support old browsers, you can drop Babel. (see #50)
(Just going by others' comments. I don't know anything about either of these myself.)

@rikedia
Copy link

rikedia commented Apr 24, 2018

Has anyone found a solution to this problem, running into this as well.

@Rob--W
Copy link
Member

Rob--W commented Apr 24, 2018

Can you share your generated bundle?

Side note, the following is incorrect if your intent is to only respond to LOREM because the onMessage handler is an async function, which returns a promise by default.

browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return Promise.resolve({ response: data });
  }

  return false;
});

should be without async, or simply:

browser.runtime.onMessage.addListener(async ({ kind, data }) => {
  if (kind === "LOREM") {
    return { response: data };
  }
});

@rikedia
Copy link

rikedia commented Apr 24, 2018

@Rob--W I am trying to send a message from a content script, if I pause the debugger just before it is about to send the message, and I send a message that is not handled:
browser.runtime.sendMessage("whatever").then(console.log.bind(console))

I get the same error.

TypeError: promise.then is not a function Stack trace: wrapPromise@resource://gre/modules/ExtensionCommon.jsm:492:7 callAsyncFunction@resource://gre/modules/ExtensionCommon.jsm:737:12 stub@resource://gre/modules/Schemas.jsm:2300:22 _callee5$@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67708:29 tryCatch@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:22601:37 invoke@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:22839:22 defineIteratorMethods/</prototype[method]@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:22653:16 step@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67526:183 _asyncToGenerator/</<@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67526:437 Promise@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:20706:7 _asyncToGenerator/<@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67526:99 init/<@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67765:20 Promise@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:20706:7 init@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67684:12 @moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67770:1 __webpack_require__@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:20:12 @moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:67280:18 __webpack_require__@moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:20:12 @moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:63:18 @moz-extension://b03cc2f6-d49c-454e-a4aa-1f4b8b3d9614/plugin.js:1:11 inject@resource://gre/modules/ExtensionContent.jsm:489:18

@Rob--W
Copy link
Member

Rob--W commented Apr 24, 2018

@rikedia Please share your generated code...

@rikedia
Copy link

rikedia commented Apr 24, 2018

@Rob--W
Copy link
Member

Rob--W commented Apr 24, 2018

@rikedia In your extension, the native Promise constructor has been replaced with something else. Don't do that (e.g. by removing babel-polyfill; both Chrome and Firefox support async / await these days).

The fact that replacing the global Promise constructor breaks sendMessage is probably an unintended bug. I have reported it upstream at https://bugzilla.mozilla.org/show_bug.cgi?id=1456531 .

@rikedia
Copy link

rikedia commented Apr 24, 2018

@Rob--W Thanks for pointing that out.

I fixed my problems by removing babel-polyfill and adding babel-plugin-transform-runtime with the polyfill option set to false.

.babelrc

{
    ...
    "plugins": [
        ...
        [
            "transform-runtime",
            {
                "polyfill": false,
                "regenerator": true
            }
        ]
    ]
}

@kottkrig
Copy link
Author

kottkrig commented Apr 25, 2018

Thanks @Rob--W and @rikedia. That helped me get rid of the "promise.then is not a function" error but I'm now getting another error in Firefox:

Unhandled promise rejection TypeError: "_ref2 is undefined"

(It works in Chrome)

The generated files are available in this gist. And here is an excerpt with my function from content_script.js:

var sendMessage = function () {
  var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee() {
    var _ref2, response;

    return _regenerator2.default.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return _webextensionPolyfill2.default.runtime.sendMessage({
              kind: "LOREM",
              data: "ipsum"
            });

          case 2:
            _ref2 = _context.sent;
            response = _ref2.response;


            console.log("content_script: response:", response);

          case 5:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, this);
  }));

  return function sendMessage() {
    return _ref.apply(this, arguments);
  };
}(); // content_script.js

I've added the transform-runtime to my webpack config and removed the babel-polyfill:

const path = require("path");

module.exports = {
  entry: {
    background_page: ["./src/background_page.js"],
    content_script: ["./src/content_script.js"]
  },

  output: {
    path: path.resolve(__dirname + "/dist"),
    filename: "[name].js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["babel-preset-env"],
            plugins: [
              [
                "babel-plugin-transform-runtime",
                { polyfill: false, regenerator: true }
              ]
            ]
          }
        }
      }
    ]
  }
};

@Rob--W
Copy link
Member

Rob--W commented Apr 25, 2018

Have you tried following the suggestion from #105 (comment) ?
The auto-generated code is difficult to read due to the replaced async/await. Can you share a zip file or repo with the minimal project to reproduce the bug?

@kottkrig
Copy link
Author

kottkrig commented Apr 25, 2018

I got it working by changing my webpack setup to use "babel-preset-env" with my current node as the target so that it uses native async/await.

Thanks @Rob--W for the help!

My updated webpack config for completeness:

const path = require("path");
module.exports = {
  entry: {
    background_page: ["./src/background_page.js"],
    content_script: ["./src/content_script.js"]
  },

  output: {
    path: path.resolve(__dirname + "/dist"),
    filename: "[name].js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["babel-preset-env", { targets: { node: "current" } }]]
          }
        }
      }
    ]
  }
};

@Rob--W
Copy link
Member

Rob--W commented Jul 5, 2018

Closing this since this is not an issue with the polyfill, but with Firefox * as explained in #105 (comment) .
The solution is also described in the previous comments: change the webpack/babel configuration to not replace the Promise global.

* The polyfill is a no-op in Firefox. We will document this more clearly and close #55 in the future.

@Rob--W Rob--W closed this as completed Jul 5, 2018
@abhijithvijayan
Copy link

@Rob--W I was also facing similar issue in Firefox. browser.runtime.onMessage.addListener should be waiting for the Promise to resolve and the return to the browser.runtime.sendMessage. It worked in Chrome but in Firefox it returned and didn't wait. I was using babel-polyfill. Following your solution helped and now the extension works as expected in all the browsers.
Thank you. 👍

thedevs-network/kutt-extension@7564e7e

@ashclarke
Copy link

ashclarke commented Mar 28, 2019

@abhijithvijayan - Just had the exact same issue. Took a few hours to get to this thread and this point.
I was getting an unhandled promise rejection and my sendMessage call was being immediately fulfilled.
This is a really nasty side effect of the usage of the Promise polyfill.

My .babelrc now looks like this:

module.exports = {
    presets: [
        ["@babel/preset-env", {
            corejs: 3,
            debug: false,
            exclude: [
                "es.promise",
                "es.promise.finally"
            ],
            loose: true,
            spec: true,
            targets: {
                browsers: [
                    "last 2 Chrome versions",
                    "last 2 Firefox versions"
                ]
            },
            useBuiltIns: "usage"
        }]
    ]
}

@rpl
Copy link
Member

rpl commented Mar 28, 2019

@Rob--W I think that it may be reasonable to explicitly document the "TypeError: promise.then is not a function" error in one of the following sections of the README.md file e.g.:

even if this isn't technically a issue of the webextension-polyfill, so that an addon developer that has this issue doesn't need to find this closed issue to know how to fix it.

@Rob--W
Copy link
Member

Rob--W commented Apr 11, 2019

Let's update the docs.

Preferably this should be fixed in Firefox. The validation in the extension framework is stricter than the JS engine's (i.e. in situations where promises are used, thenables are perfectly fine, whereas in the extension framework we don't accept them currently).

@Rob--W Rob--W reopened this Apr 11, 2019
NoxHarmonium added a commit to agiledigital/mule-preview-browser-extension that referenced this issue Oct 1, 2019
This prepares the project for adding other SCMs. The changes to Babel were due to an issue with
shimming Promises and Firefox
(mozilla/webextension-polyfill#105 (comment))
NoxHarmonium added a commit to agiledigital/mule-preview-browser-extension that referenced this issue Oct 1, 2019
This prepares the project for adding other SCMs. The changes to Babel were due to an issue with
shimming Promises and Firefox
(mozilla/webextension-polyfill#105 (comment))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants