vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.6k stars 26.92k forks source link

Babel polyfill doesn't seem to be injected #2468

Closed jonaswindey closed 7 years ago

jonaswindey commented 7 years ago

I'm trying to support IE11 for my app to fix the error TypeError: Object doesn't support property or method 'find'

Using next 2.4.6 but also not working on latest beta

Added a custom .babelerc together with babel-preset-env with the following config:

{
  "presets": [
    "es2015",
    "react",
    "next/babel",
    "stage-0",
    [ "env", {
      "targets": {
        "safari": 10,
        "ie": 11
      },
      "modules": false,
      "useBuiltIns": true,
      "debug": true
    }]
  ],
}

Enabled the debug flag so on startup I get the following log, which seems to mean that the polyfill are added.

babel-preset-env: `DEBUG` option

Using targets:
{
  "safari": "10",
  "ie": "11"
}

Modules transform: false

Using plugins:
  check-es2015-constants {"ie":"11"}
  transform-es2015-arrow-functions {"ie":"11"}
  transform-es2015-block-scoping {"ie":"11"}
  transform-es2015-classes {"ie":"11"}
  transform-es2015-computed-properties {"ie":"11"}
  transform-es2015-destructuring {"ie":"11"}
  transform-es2015-duplicate-keys {"ie":"11"}
  transform-es2015-for-of {"ie":"11"}
  transform-es2015-function-name {"ie":"11"}
  transform-es2015-literals {"ie":"11"}
  transform-es2015-object-super {"ie":"11"}
  transform-es2015-parameters {"ie":"11"}
  transform-es2015-shorthand-properties {"ie":"11"}
  transform-es2015-spread {"ie":"11"}
  transform-es2015-sticky-regex {"ie":"11"}
  transform-es2015-template-literals {"ie":"11"}
  transform-es2015-typeof-symbol {"ie":"11"}
  transform-es2015-unicode-regex {"ie":"11"}
  transform-regenerator {"ie":"11"}
  transform-exponentiation-operator {"safari":"10","ie":"11"}
  transform-async-to-generator {"safari":"10","ie":"11"}
  syntax-trailing-function-commas {"ie":"11"}

Using polyfills:
  es6.typed.array-buffer {"ie":"11"}
  es6.typed.int8-array {"ie":"11"}
  es6.typed.uint8-array {"ie":"11"}
  es6.typed.uint8-clamped-array {"ie":"11"}
  es6.typed.int16-array {"ie":"11"}
  es6.typed.uint16-array {"ie":"11"}
  es6.typed.int32-array {"ie":"11"}
  es6.typed.uint32-array {"ie":"11"}
  es6.typed.float32-array {"ie":"11"}
  es6.typed.float64-array {"ie":"11"}
  es6.map {"ie":"11"}
  es6.set {"ie":"11"}
  es6.weak-map {"ie":"11"}
  es6.weak-set {"ie":"11"}
  es6.reflect.apply {"ie":"11"}
  es6.reflect.construct {"ie":"11"}
  es6.reflect.define-property {"ie":"11"}
  es6.reflect.delete-property {"ie":"11"}
  es6.reflect.get {"ie":"11"}
  es6.reflect.get-own-property-descriptor {"ie":"11"}
  es6.reflect.get-prototype-of {"ie":"11"}
  es6.reflect.has {"ie":"11"}
  es6.reflect.is-extensible {"ie":"11"}
  es6.reflect.own-keys {"ie":"11"}
  es6.reflect.prevent-extensions {"ie":"11"}
  es6.reflect.set {"ie":"11"}
  es6.reflect.set-prototype-of {"ie":"11"}
  es6.promise {"ie":"11"}
  es6.symbol {"ie":"11"}
  es6.object.assign {"ie":"11"}
  es6.object.is {"ie":"11"}
  es6.function.name {"ie":"11"}
  es6.string.raw {"ie":"11"}
  es6.string.from-code-point {"ie":"11"}
  es6.string.code-point-at {"ie":"11"}
  es6.string.repeat {"ie":"11"}
  es6.string.starts-with {"ie":"11"}
  es6.string.ends-with {"ie":"11"}
  es6.string.includes {"ie":"11"}
  es6.regexp.flags {"ie":"11"}
  es6.regexp.match {"ie":"11"}
  es6.regexp.replace {"ie":"11"}
  es6.regexp.split {"ie":"11"}
  es6.regexp.search {"ie":"11"}
  es6.array.from {"ie":"11"}
  es6.array.of {"ie":"11"}
  es6.array.copy-within {"ie":"11"}
  es6.array.find {"ie":"11"}
  es6.array.find-index {"ie":"11"}
  es6.array.fill {"ie":"11"}
  es6.array.iterator {"ie":"11"}
  es6.number.is-finite {"ie":"11"}
  es6.number.is-integer {"ie":"11"}
  es6.number.is-safe-integer {"ie":"11"}
  es6.number.is-nan {"ie":"11"}
  es6.number.epsilon {"ie":"11"}
  es6.number.min-safe-integer {"ie":"11"}
  es6.number.max-safe-integer {"ie":"11"}
  es6.math.acosh {"ie":"11"}
  es6.math.asinh {"ie":"11"}
  es6.math.atanh {"ie":"11"}
  es6.math.cbrt {"ie":"11"}
  es6.math.clz32 {"ie":"11"}
  es6.math.cosh {"ie":"11"}
  es6.math.expm1 {"ie":"11"}
  es6.math.fround {"ie":"11"}
  es6.math.hypot {"ie":"11"}
  es6.math.imul {"ie":"11"}
  es6.math.log1p {"ie":"11"}
  es6.math.log10 {"ie":"11"}
  es6.math.log2 {"ie":"11"}
  es6.math.sign {"ie":"11"}
  es6.math.sinh {"ie":"11"}
  es6.math.tanh {"ie":"11"}
  es6.math.trunc {"ie":"11"}
  es7.array.includes {"ie":"11"}
  es7.object.values {"safari":"10","ie":"11"}
  es7.object.entries {"safari":"10","ie":"11"}
  es7.object.get-own-property-descriptors {"safari":"10","ie":"11"}
  es7.string.pad-start {"ie":"11"}
  es7.string.pad-end {"ie":"11"}
  web.timers {"safari":"10","ie":"11"}
  web.immediate {"safari":"10","ie":"11"}
  web.dom.iterable {"safari":"10","ie":"11"}

However, at runtime, I still get the error on IE11 when I call the .find() method on an array.

Anything I can do to double check to make sure the polyfills are injected correctly?

jonaswindey commented 7 years ago

Sample project @ https://github.com/jonaswindey/next-polyfill-bug

jonaswindey commented 7 years ago

The only fix I have is adding a custom layout.js and adding <script src='https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.23.0/polyfill.min.js' />

timneutkens commented 7 years ago

@arunoda We've seen this before right 🤔

arunoda commented 7 years ago

As a hot-fix you could do this:

import 'core-js/fn/array/find'

const test = ['hi', 'there'].find(item => item === 'hi')

export default () => (
  <div>{test}, welcome to next.js!</div>
)

Let me see what's going on here.

arunoda commented 7 years ago

I checked this with a normal babel app and the behaviour is the same. You need to add the polyfill as I mentioned above.

So, I'm closing this since it's not exactly a Next specific issue.

arunoda commented 7 years ago

But I open to more suggestions. Feel free to re-open.

lailo commented 7 years ago

@arunoda I tried this hotfix with import 'core-js/fn/array/find' inside the _document.js to have it fixed for all files but it didn't work out for IE11.

I had to go with the solution to include it like this: <script src='https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.23.0/polyfill.min.js' />

I'm using Next.js V3.0.6.

Any Idea how i could solve this in a nicer way?

jwillem commented 7 years ago

Hey, all. I've experimented with the entry-property in next.config.js. This is what I've got (according to https://github.com/zeit/next.js/blob/master/server/build/webpack.js#L42):

module.exports = {
  // eslint-disable-next-line no-unused-vars
  webpack(config, _) {
    const entry = async () => {
      const resolvedEntry = await config.entry()
      const entryWithPolyfill = Object.assign(
        { 'babel-polyfill': ['babel-polyfill'] },
        resolvedEntry
      )
      // console.log(entryWithPolyfill)
      return entryWithPolyfill
    }
    return Object.assign(
      config,
      entryWithPolyfill
    )
  }
}

Sadly this file won't be transpiled by babel, which is why it does not work yet.

fredjens commented 7 years ago

Best thing would be to include babel-polyfill in Next's webpack config? It is quite common to include it.

jwillem commented 7 years ago

@arunoda what do you think?

raduGaspar commented 6 years ago

any updates on this? Including the polyfill is not the best solution

eahlberg commented 6 years ago

Also interested in this 🤔

sholzmayer commented 6 years ago

I fixed this importing babel polyfills:

import 'babel-polyfill';

klaemo commented 6 years ago

Importing the entire babel-polyfill is extremely wasteful and would be a bad default for next.js, imho. It adds 87kb to the bundle no matter if you actually need any of the polyfilled features or not.

bliitzkrieg commented 6 years ago

@sholzmayer where did you use import 'babel-polyfill';. I tried in the _document.js but it didn't help

hugotox commented 6 years ago

@klaemo so what's your suggestion?

macouella commented 6 years ago

Adding transform-runtime to .babelrc plugins seems to do it for me. We are developing an app for Opera 36 which doesn't have Object.entries built in.

"plugins": [
    "transform-runtime"
]
klaemo commented 6 years ago

@hugotox as an app developer you could use https://polyfill.io to only load the polyfills needed or you do that manually. In our app we have a polyfills.js that looks something like this:

// Language features presented by https://github.com/zloirock/core-js
import 'core-js/fn/object/assign'
import 'core-js/fn/string/ends-with'
import 'core-js/fn/string/starts-with'
import 'core-js/fn/string/includes'
import 'core-js/fn/array/includes'
import 'core-js/fn/weak-map'

// browser features
import 'raf/polyfill'
import 'isomorphic-fetch'
import 'js-polyfills/url'

Alternatively, nextjs could import and bundle all the polyfills it needs from core-js.

techsin commented 6 years ago

@igimanaloto this solution worked for me

Vadorequest commented 6 years ago

I also use transform-runtime plugin but I do get the error on IE for some reason.

{
  "plugins": [
    "source-map-support",
    "transform-runtime"
  ],
  "presets": [
    ["env", {
      "targets": {
        "node": "6.10"
      }
    }],
    ["stage-3"],
    [
      "next/babel",
      {
        "styled-jsx": {
          "optimizeForSpeed": true,
          "vendorPrefixes": true,
          "sourceMaps": true,
          "plugins": [
            "styled-jsx-plugin-sass"
          ]
        }
      }
    ]
  ]
}
Vadorequest commented 6 years ago

@bliitzkrieg Don't import babel-polyfill in _document.js, because _document.js is only rendered on the server.

Usually, it's recommended to include it in your layout, basically any file that is loaded by all pages will do fine.

gpolyn commented 6 years ago

Update: Fixed my example for IE 10, 11: changed core-js/library/fn/object/assign dependency in client/polyfill.js to core-js/fn/object/assign (how @klaemo had it—missed that!)


Here's a Dockerized next 5.1.0 attempt to employ a combination of the approach indicated by @klaemo above and an official example, canary/examples/with-polyfills:

[Original question] What is the usage of core-js in my client/polyfills.js file that gets me IE11? (I might expect the approach to proceed from an import that covers everything IE11 is missing and then gradually winnows down the range to just those items the app needs.)

Here's the initial result I checked out the result on a few OS + browser combinations (on Browserstack) and it fails when it was failing on Windows 10 + IE11 (shown below), and maybe other IE combinations.

screen shot 2018-04-21 at 3 49 31 pm

Pro542 commented 6 years ago

I was trying to run next 5.1.0 on chrome 43 with a custom server, .babelrc and webpack config. import 'core-js/fn/object/assign'; did the trick.

madhums commented 6 years ago

Seems like this bug still exists! I am facing the same issue in IE 11 and none of the solutions is helping. Problems seems to be ansi-regex package which uses a arrow function and this being a dependency of next.js.

@arunoda @timneutkens can we re-open this issue?

ptomasroos commented 6 years ago

Yes still exists. I’m using yarn resolutions to downgrade

mrienstra commented 6 years ago

import 'core-js/fn/object/assign' worked for me as well.

Had to add core-js first (yarn add core-js) -- of course.

I found this helpful: https://github.com/aspnet/JavaScriptServices/wiki/Supporting-Internet-Explorer-11-(or-older)

julkue commented 6 years ago

Please add an official documentation about ES6 transpilation for node modules.

vzaidman commented 6 years ago

here is a workaround but this bug has to be reopened. @arunoda

i had errors with Object.assign, String.endsWith on ie11 (on next@6.0.3)

const {basedir} = require('./server/config');

// polyfills required for non-evergreen browsers (mainly ie) const polyfills = [ 'core-js/fn/object/assign', 'core-js/fn/string/ends-with', 'core-js/fn/string/starts-with', 'core-js/fn/string/includes', 'core-js/fn/array/includes', 'core-js/fn/weak-map', ];

module.exports = {
  webpack: (config, {dev, isServer}) => {
    const originalEntry = config.entry;
    if (!isServer) {
      config.entry = async () => {
        const entries = await originalEntry();
        Object.values(entries).forEach(entry => {
          entry.unshift(...polyfills);
          if (dev) {
            entry.unshift('eventsource-polyfill');
          }
        });
        return entries;
      };
    }

    return config;
  },
};
vzaidman commented 6 years ago

actually i sometimes get

Cannot redefine non-configurable property 'endsWith'
peec commented 6 years ago

I followed this example to include polyfills. For IE11 to work, I had to include these in my client/polyfills.js:

import 'core-js/es6/map';
import 'core-js/es6/set';

import 'core-js/fn/object/assign';
import 'core-js/fn/string/ends-with';
import 'core-js/fn/string/starts-with';
import 'core-js/fn/string/includes';
import 'core-js/fn/array/includes';
import 'core-js/fn/array/find';

import 'core-js/fn/number/is-finite';

I am not sure whenever there are some libraries that e.g. needed isFinite, but my app is pretty minimal.

This works, but is very cumbersome to figure out what polyfills that are actually needed.

msreekm commented 6 years ago

anyone knows what polyfill is requiired to get the class syntax working in IE11?

class Foo extends ...

aleksandrio commented 5 years ago

in your polyfills uncomment 'import 'core-js/es6/object';' line

junibrosas commented 5 years ago

I followed the example you mentioned @peec and it worked for me.

GonchuB commented 5 years ago

@peec is this the expected behavior, though? Why would I need to re-polyfill something that was inlcluded?