Vue-cli: Promise.prototype.finally() broken in Firefox

Created on 1 Aug 2018  ·  26Comments  ·  Source: vuejs/vue-cli

Version

3.0.0-rc.10

Node and OS info

Node 10.6.0 / Yarn 1.9.2 / macOS 10.13.5

Steps to reproduce

  1. Clone https://github.com/mserajnik/vue-cli-promise-finally
  2. Install with Yarn
  3. Run with yarn serve
  4. Open the development URL in Firefox (tested under Firefox 61.0.1)
  5. Check the console: [Vue warn]: Error in created hook: "TypeError: this.fetchData(...).then(...).catch(...).finally is not a function"

What is expected?

According to the MDN web docs, Promise.prototype.finally() is supported natively in Firefox since 58, so it should work, even without any polyfill.

What is actually happening?

Promise.prototype.finally() does not work in Firefox (61.0.1).


Not sure if I'm missing something obvious here – I'm not even sure if this is actually a bug or just a configuration issue (maybe I have to adjust my babel.config.js in some way?). What is weird is that Promise.prototype.finally() works in Safari when I run the same test app, which doesn't have native support for it apparently – so the polyfill seems to be working there. I can only reproduce the issue in Firefox. A friend has also confirmed the same issue in Firefox under Windows 10.

Oh, and sorry if this issue belongs somewhere else. Since I couldn't pin down if it's a Firefox bug, an issue with Babel or one with the @vue/app preset (or just a configuration error on my end), it made the most sense to me to open it here first.

bug babel upstream

Most helpful comment

This is an issue in core-js - its promise polyfill replaces the native Promise in Firefox, however according to author of core-js, it is doing it because Firefox's Promise implementation somehow fails a subclassing check so is technically not spec-compliant.

For now I've included es7.promise.finally by default to fix this in Vue CLI.

All 26 comments

Hm, I remember coming across something like this a while ago when building a prototype with beta.3 or something.

We include a Promise polyfill with vue-cli by default. Maybe we have a weird situation where

  1. The polyfill doesn't include finally
  2. in Firefox, the polyfill is installed even though it should be skipped as FF has native Promises already

If so, 1.) would be an issue to solve in vue-cli, if 2.), which would be a problem with babel-polyfill / core.js, can't be resolved quickly.

According to this there's also es.promise.finally, which I tried to add the following way:

module.exports = {
  presets: [
    ['@vue/app', {
      polyfills: ['es6.promise', 'es6.promise.finally', 'es6.array.iterator']
    }]
  ]
}

Hoewever, this throws an error on build:

Cannot read property 'android' of undefined (While processing
: "/fake/path/vue-cli-promise-finally/node_modules/@vue/babel-preset-app/index.js")
    at targetEnvironments.filter.environment (/fake/path/vue-cli-promise-finally/node_modules/@babel/preset-env/lib/index.js:75:
16)

Might also be related to this, will try that workaround out later.

Doing the following seems to work:

// babel.config.js

module.exports = {
  presets: [
    ['@vue/app', { useBuiltIns: 'entry' }]
  ]
}
// src/main.js

import '@babel/polyfill'

[…]

It does increase the bundle size a bit (as expected), but that's not really an issue.

According to this comment from Brian Ng:

Yep, there's currently no usage mapping for .then, .catch or .finally.

So, issue solved for me. Do you think you could mention this limitation of having useBuiltIns in usage mode somewhere in the readme of @vue/babel-preset-app? I know that's an issue/limitation with @babel/preset-env itself, but given that @vue/cli is pretty much zero config by default and very beginner-friendly for people who haven't worked with webpack/Babel/etc. before, this is likely one of the first places they'd look if they encountered such an issue.

This is an issue in core-js - its promise polyfill replaces the native Promise in Firefox, however according to author of core-js, it is doing it because Firefox's Promise implementation somehow fails a subclassing check so is technically not spec-compliant.

For now I've included es7.promise.finally by default to fix this in Vue CLI.

@yyx990803

Thanks, I think that's a decent solution for now.

I had forgotten Promise.prototype.finally() is not part of the ES6 spec, so the way I've tried to include the polyfill before (via es6.promise.finally) obviously didn't work in hindsight. Time to switch useBuiltins back to the default usage mode. :)

@yyx990803
什么时候发布版本,这个finally配了好久都没有配置好

Sorry to comment on a closed topic but I'm getting an error relative to the subject.

`This dependency was not found:

  • core-js/modules/es7.promise.finally in ./src/main.js

To install it, you can run: npm install --save core-js/modules/es7.promise.finally`

I'm getting the error AFTER the rc10, so I had to fix the version in rc10.

Happens to me also after installing vue-styled-components

`This dependency was not found:

core-js/modules/es7.promise.finally in ./src/main.js
To install it, you can run: npm install --save core-js/modules/es7.promise.finally`

Im still missing the finally on firefox..

using ['@vue/app', { useBuiltIns: 'entry' }] fails to build with Unknown option: .useBuiltIns.

It's a nested array:

[['@vue/app', { useBuiltIns: 'entry' }]]

@LinusBorg yes, thanks, that fixed the build error! but I still dont have the finally on promises :\

can this issue be reopened? its still happening 😕

@mrodal and others:

It's been fixed for me since @yyx990803 has included es7.promise.finally by default. I also don't have to use useBuiltIns: 'entry' (except when building for Electron).

Feel free to check out the configuration in my project.

@mrodal if it's still happening for your, open a new issue with reproduction and a reference to this issue here.

I won't reopen this old one, it's outdated and I can't tell if the problem you describe actually exists in the way you say it does.

Its fixed, I upgraded vue to the latest version. Its weird, because the version I had (2.5.17) had the changes made by @yyx990803.. but anyways, its working now, thanks @mserajnik and @LinusBorg

I think you are confusing Vue ( currently 2.5.18) with vue-cli (3.3.0).

The latter is responsible for injecting the polyfill. The Vue version isn't important for that.

true, sorry, I also upgraded vue cli service and plugins from 3.0.3 to 3.0.4

@LinusBorg

Actually, latest Vue is 2.5.22.

@mrodal

Latest version of @vue/cli-plugin-babel and @vue/cli-service is 3.3.0; if you encounter any issues when building, I'd always recommend upgrading every dev dependency to the latest version (if you can) – chances are, the issue has been fixed. And as long as it's not a new major version, the chance of your build environment breaking should be pretty slim (and you can always roll back anyway if something goes wrong).

You can use a tool like updates to check for newer versions.

I'm a noobie, but have the same issue but without having vue-cli installed. I come from Laravel. Anyhow, here is one open question in StackOverflow. Perhaps someone can help me :)

Edit 1:
The issue lies in my installed package. Somehow it overwrites my promise

@mserajnik in Which Vue cli version were this bug had Fixed ?

@ahussein3 This has been fixed in v3.0.0-rc.11 in August 2018.

I still have this issue with:

in firefox:

Promise.resolve(42).finally(() => console.log('works'));
TypeError: Promise.resolve(...).finally is not a function[Learn More]

If I type this in the console on another website it works :(

Sorry to hear that.

If you can provide an actual reproduction of your issue we could investigate.

Saying "I have this problem" doesn't allow us to do that.

I realize that but the building environment is so complex I cannot allocate time for this currently, I solved my issue by just removing finally and use catch/then.

If it helps I don't have ny es(6/7).promise.finally in my current dependencies, if I understand correctly this was the fix applied, if so how is is supposed to be included ? do I need to have it explicitely in my package.json ?

@schmurfy:

If your project was created using vue-cli and you didn‘t make any manual changes to the build setup (e.g., change the Babel config in some way it would disable the usage of the es7.promise.finally polyfill), it should work out of the box.

As for the reproducible example, see the one in my opening post. That‘s just an empty project created with vue-cli (a version before the fix).

You could go this approach as well and start isolating the issue – if a new/empty project works, try to figure out what change(s) in your project cause(s) it not to work.

If core-js is used by any of your modules (i.e. Babel), that's the cause.

This code isn't present in the current version, but core-js 3.0.1 overrides the Promise prototype:

var FORCED = isForced(PROMISE, function () {
 // correct subclassing with @@species support
 var promise = PromiseConstructor.resolve(1);
 var empty = function () { /* empty */ };
 var FakePromise = (promise.constructor = {})[SPECIES] = function (exec) {
   exec(empty, empty);
 };
 // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
 return !((IS_NODE || typeof PromiseRejectionEvent == 'function')
   && (!IS_PURE || promise['finally'])
   && promise.then(empty) instanceof FakePromise
   // v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
   // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
   // we can't detect it synchronously, so just check versions
   && v8.indexOf('6.6') !== 0
   && userAgent.indexOf('Chrome/66') === -1);
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

CodeApePro picture CodeApePro  ·  3Comments

csakis picture csakis  ·  3Comments

JIANGYUJING1995 picture JIANGYUJING1995  ·  3Comments

b-zee picture b-zee  ·  3Comments

BusyHe picture BusyHe  ·  3Comments