babel / babel

🐠 Babel is a compiler for writing next generation JavaScript.
https://babel.dev
MIT License
43.22k stars 5.64k forks source link

[Bug]: regenerator-runtime should be imported after symbol polyfills #14495

Open matthieusieben opened 2 years ago

matthieusieben commented 2 years ago

💻

How are you using Babel?

Other (Next.js, Gatsby, vue-cli, ...)

Input code

class A {
  constructor() {
    this.map = new Map([
      ["even", new Set([0, 2])],
      ["odd", new Set([1, 3])]
    ])
  }
  *[Symbol.iterator]() {
    for (const mySet of this.map.values()) yield* mySet
  }
}

console.log('values:', Array.from(new A()))

// Expected output: [0, 2, 1, 3]

Here is a link to a code sandbox that shows the error when deploying on netlify and running in IE11: https://codesandbox.io/s/ie11-test-forked-7yfz7b?file=/src/index.js

Try yourself: https://csb-7yfz7b.netlify.app/

Configuration file name

No response

Configuration

{
  "presets": [
      [
            "@babel/preset-env",
            {
                "corejs": { "version":3 },
                "useBuiltIns": "usage",
                "targets": {
                    "ie": "11"
                }
            }
        ]
  ]
}

Current and expected behavior

The console should show the following (as it does in chrome):

Capture d’écran 2022-04-26 à 17 39 11

The actual console content in IE11 shows an empty array: Capture d’écran 2022-04-26 à 17 38 29

Environment

Possible solution

No response

Additional context

I can workaround this issue by doing:

yield* Array.from(mySet)

or avoid using yield*:

for (const value of mySet) yield value
babel-bot commented 2 years ago

Hey @matthieusieben! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack community that typically always has someone willing to help. You can sign-up here for an invite.

nicolo-ribaudo commented 2 years ago

Hi! I don't have easy access to IE, but could you check if mySet[Symbol.iterator] exists?

matthieusieben commented 2 years ago

Yes it does.

Here is the result of running the following code: Capture d’écran 2022-05-09 à 11 39 06

Capture d’écran 2022-05-09 à 11 39 26

matthieusieben commented 2 years ago

Set is not the only one that does not work properly in IE

function* enumerate(it) {
  yield* it
}

console.log('enumerate Array:')

for (const item of enumerate([1, 2])) {
  console.log('item:', item);
}

console.log('enumerate enumerate:')

for (const item of enumerate(enumerate([1, 2]))) {
  console.log('item:', item);
}

console.log('enumerate Set:')

for (const item of enumerate(new Set([1, 2]))) {
  console.log('item:', item);
}

console.log('enumerate Map:')

for (const item of enumerate(new Map([[1,1], [2,2]]))) {
  console.log('item:', item);
}

console.log('enumerate Map.entries():')

for (const item of enumerate(new Map([[1,1], [2,2]]).entries())) {
  console.log('item:', item);
}

console.log('enumerate Map.values():')

for (const item of enumerate(new Map([[1,1], [2,2]]).values())) {
  console.log('item:', item);
}

console.log('enumerate Map.keys():')

for (const item of enumerate(new Map([[1,1], [2,2]]).keys())) {
  console.log('item:', item);
}

console.log('enumerate customIterable:')

const customIterable = {
  [Symbol.iterator]() {
    let i = 0;
    return {
      next() {
        i++
        if (i > 2) return { done: true }
        return { done: false, value: i }
      }
    }
  }
}

for (const item of enumerate(customIterable)) {
  console.log('item:', item);
}

console.log('enumerate customIterableInstance:')

function CustomIterable() {}
CustomIterable.prototype = customIterable

for (const item of enumerate(new CustomIterable())) {
  console.log('item:', item);
}

Capture d’écran 2022-05-09 à 12 38 39

matthieusieben commented 2 years ago

I think I found the problem. In Babel's result, the regenerator-runtime is imported before the core-js/modules/es.symbol polyfills.

However, the regenerator-runtime reads the value of Symbol.iterator when the module is loaded (and not when regenerator functions are invoked) causing the fallback @@iterator to be used by regenerator-runtime methods, which is not correct.

Capture d’écran 2022-05-09 à 13 12 36

Manually changing the order of the Babel result fixes the issue.