Vue-cli: Array methods `flat` and `flatMap` are not polyfilled

Created on 17 Apr 2019  路  11Comments  路  Source: vuejs/vue-cli

Version

3.6.3

Reproduction link

https://github.com/runarberg/vue-cli-minimal-example

Environment info

npx @vue/cli info

Environment Info:

  System:
    OS: Linux 4.15 Ubuntu 18.04.2 LTS (Bionic Beaver)
    CPU: (4) x64 Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz
  Binaries:
    Node: 11.2.0 - ~/.nvm/versions/node/v11.2.0/bin/node
    Yarn: Not Found
    npm: 6.4.1 - ~/.nvm/versions/node/v11.2.0/bin/npm
  Browsers:
    Chrome: Not Found
    Firefox: 66.0.2
  npmPackages:
    @vue/babel-helper-vue-jsx-merge-props:  1.0.0-beta.3 
    @vue/babel-plugin-transform-vue-jsx:  1.0.0-beta.3 
    @vue/babel-preset-app:  3.6.0 
    @vue/babel-preset-jsx:  1.0.0-beta.3 
    @vue/babel-sugar-functional-vue:  1.0.0-beta.3 
    @vue/babel-sugar-inject-h:  1.0.0-beta.3 
    @vue/babel-sugar-v-model:  1.0.0-beta.3 
    @vue/babel-sugar-v-on:  1.0.0-beta.3 
    @vue/cli-overlay:  3.6.0 
    @vue/cli-plugin-babel: ^3.6.0 => 3.6.0 
    @vue/cli-plugin-eslint: ^3.6.0 => 3.6.0 
    @vue/cli-service: ^3.6.0 => 3.6.0 
    @vue/cli-shared-utils:  3.6.0 
    @vue/component-compiler-utils:  2.6.0 
    @vue/preload-webpack-plugin:  1.1.0 
    @vue/web-component-wrapper:  1.2.0 
    eslint-plugin-vue: ^5.0.0 => 5.2.2 
    vue: ^2.6.10 => 2.6.10 
    vue-eslint-parser:  2.0.3 
    vue-hot-reload-api:  2.3.3 
    vue-loader:  15.7.0 
    vue-style-loader:  4.1.2 
    vue-template-compiler: ^2.5.21 => 2.6.10 
    vue-template-es2015-compiler:  1.9.1 
  npmGlobalPackages:
    @vue/cli: Not Found

Steps to reproduce

  1. Create a new vue project with babel plugin
  2. In your app use the flat or flatMap array methods

What is expected?

These array methods should be polyfilled

What is actually happening?

They are not polyfilled


  • Open your app in Chrome, Firefox or Safari and see it working.
  • Open it in Edge and see an error message:
[Vue warn]: Error in render: "TypeError: Object doesn't support property or method 'flat'"
TypeError: Object doesn't support property or method 'flat'

Note that babel is configured to polyfill any method that is used, this includes Array.from in the above example.

Also note that Array.prototype.{flat,flatMap} were approved for stage 4 in at TC-39 last January and have been moved to stable in core-js.

major upstream

Most helpful comment

  1. It's only stable in core-js 3, while we use core-js 2
  2. https://github.com/babel/website/blob/master/docs/plugin-transform-runtime.md#core-js-aliasing
    > Instance methods such as "foobar".includes("foo") will only work when using corejs: 3.

Will be fixed once we upgraded to core-js v3 in Vue CLI v4.

All 11 comments

Coincidentally I also noticed that String.fromCodePoint is not polyfilled either. Does anyone know why this is?

preset-env's usage mode (which vue-cli uses by default) detects usage of features that need polyfills, but its detection isn't 100%.

In particular it has problems detecting things like new prototype methods when used on instances, like you do here.

This is because Babel cant now that this.list is an instance of Array, so this.list. flatMap isn't triggering the polyfill injection.

So we either have to import the polyfill manually, help Babel out by accessing the prototype explicitly (Array.prototype.flatMap), or switch to entry mode of the preset, which simply imports all polyfills required for the targeted browsers, wether used or not.

  1. It's only stable in core-js 3, while we use core-js 2
  2. https://github.com/babel/website/blob/master/docs/plugin-transform-runtime.md#core-js-aliasing
    > Instance methods such as "foobar".includes("foo") will only work when using corejs: 3.

Will be fixed once we upgraded to core-js v3 in Vue CLI v4.

While its cool that corejs3 improves this, I think the case that OP shared won't be fixable with it as well, since Babel can't infer the type of this.list - unless corejs3 takes a "better safe than sorry" approach now and adds a polyfill as soon as it comes across any instance method that shares the name of a polyfillable method

Interesting. Better safe then sorry I suppose 馃槃

Just noticed my app can't work in IE because of missing flatMap.

Adding

import "core-js/fn/array/flat-map";

to main.js solved the problem for me

@gavvvr The problem with this is that core-js 2 entered feature freeze more then a 1陆 ago鈥攂efore Array#flatten was renamed to Array#flat鈥攎eaning you can鈥檛 write:

import 'core-js/fn/array/flat';

I think I鈥檒l stick with not using these methods until we move to core-js 3 in the next major release of vue-cli.

It looks like this is still an issue in v4.0.0-rc.6:

$ npx @vue/cli@next info

Environment Info:

  System:
    OS: Linux 5.0 Ubuntu 19.04 (Disco Dingo)
    CPU: (4) x64 Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz
  Binaries:
    Node: 12.1.0 - ~/.nvm/versions/node/v12.1.0/bin/node
    Yarn: Not Found
    npm: 6.9.0 - ~/.nvm/versions/node/v12.1.0/bin/npm
  Browsers:
    Chrome: Not Found
    Firefox: 69.0
  npmPackages:
    @vue/babel-helper-vue-jsx-merge-props:  1.0.0 
    @vue/babel-plugin-transform-vue-jsx:  1.0.0 
    @vue/babel-preset-app:  4.0.0-rc.6 
    @vue/babel-preset-jsx:  1.1.0 
    @vue/babel-sugar-functional-vue:  1.0.0 
    @vue/babel-sugar-inject-h:  1.0.0 
    @vue/babel-sugar-v-model:  1.0.0 
    @vue/babel-sugar-v-on:  1.1.0 
    @vue/cli-overlay:  4.0.0-rc.6 
    @vue/cli-plugin-babel: ^4.0.0-rc.6 => 4.0.0-rc.6 
    @vue/cli-plugin-eslint: ^4.0.0-rc.6 => 4.0.0-rc.6 
    @vue/cli-service: ^4.0.0-rc.6 => 4.0.0-rc.6 
    @vue/cli-shared-utils:  4.0.0-rc.6 
    @vue/component-compiler-utils:  3.0.0 
    @vue/preload-webpack-plugin:  1.1.1 
    @vue/web-component-wrapper:  1.2.0 
    eslint-plugin-vue: ^5.0.0 => 5.2.3 
    vue: ^2.6.10 => 2.6.10 
    vue-eslint-parser:  5.0.0 
    vue-hot-reload-api:  2.3.4 
    vue-loader:  15.7.1 
    vue-style-loader:  4.1.2 
    vue-template-compiler: ^2.6.10 => 2.6.10 
    vue-template-es2015-compiler:  1.9.1 
  npmGlobalPackages:
    @vue/cli: Not Found

To clarify flatMap is now polyfilled, however flat isn鈥檛. That is, flatMap appear is dist/js/chunk-vendors.[hash].js while flat doesn鈥檛 after running npm run build.

Perhaps this is a result of flatMap being used in the <script> segment of the component while flat is only used in the <template> part. If we change the example by moving the flat function to computed properties. That is, instead of v-for="[i, j] of lists.flat()" we write v-for="[i, j] of flatLists", where:

{
  computed: {
    flatLists() {
      return this.lists.flat();
    },
  },
};

Now we see flat appear in dist/js/chunk-vendors.[hash].js.

Yeah, <template> is not processed by babel at the moment.
This could be fixed in Vue 3. For now, such use cases require manually editing of the polyfill option of the babel preset.

So, it's fixed in CLI v4 & Vue 3.

Was this page helpful?
0 / 5 - 0 ratings