Parcel: IE support: "'Promise' is undefined", bundles fail to load

Created on 5 Dec 2018  Β·  21Comments  Β·  Source: parcel-bundler/parcel

πŸ› bug report


Loading the dev server output in IE11 keeps bundles from loading. It's a hard stop that prevents the base page from even attempting to continue.

Note: This is from what's generated by parcel, not my app source code or my dependencies. See this comment below.

πŸŽ› Configuration (.babelrc, package.json, cli command)


.babelrc


The app works in FF + Chrome (used --no-cache) without the custom .babelrc.

{
  "presets": [
    [
      "env",
      {
        "modules": false,
        "targets": {
          "browsers": [
            "> 1%",
            "last 2 versions",
            "ie 11",
            "not ie <= 10"
          ]
        }
      }
    ]
  ]
}


package.json


here's the full package.json, below is the scripts and deps only

  "scripts": {
    "clean": "rimraf dist",
    "dev": "parcel src/index.html",
    "build": "run-s clean build:raw",
    "build:raw": "parcel build --public-url . src/index.html",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-preset-env": "^1.7.0",
    "npm-run-all": "^4.1.5",
    "parcel-bundler": "^1.10.3",
    "rimraf": "^2.6.2"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "ie 11",
    "not ie <= 10"
  ]


I start the local server with npm run dev, which invokes parcel ./src/index.html.

Note: my package.json includes the relevant browserslist, which specifies IE 11.

πŸ€” Expected Behavior


Bundles should load correctly, including in IE 11.

😯 Current Behavior


Bundled app stops loading in IE11 almost immediately. Cites "'Promise' is undefined" in JS console, clicking to the line number points to the loadBundles function, which returns Promise.all(bundles.map(loadBundle)).

Also used by Parcel's generated main js file, Promise.resolve and fetch. Specifying IE 11 support for targeted browser should ensure that no un-polyfilled APIs are used (Promise, fetch).


Raw console error:

SCRIPT5009: 'Promise' is undefined
main.1f19ae8e.js 394,27)

parcel_ie_issues

πŸ’ Possible Solution


From the other linked "ie support" descriptions in the changelog and the corresponding culprits, it looks like this is has to do fundamentally with the un-polyfilled Promise and global objects, such as fetch referenced when attempting to load necessary bundles. The loadBundles fires before my app logic, so no polyfilling on my end will affect the outcome. By performing a build of my repro with manually added polyfills into the head tag for Promise and fetch, this worked; but this isn't something I should have to do.

πŸ”¦ Context


For my work apps am required to support IE11. I believe this should be achievable w/ parcel, but ran into some trouble. The app works great in Chrome and Firefox. The issues I'm experiencing deal with Parcel's direct use of Promise and fetch directly in the initialization of bundles from the built main.<hash>.js.

πŸ’» Code Sample


I have an example repo:

https://github.com/edm00se/parcel-ie11-issue-demo

Steps to reproduce:

  • git clone https://github.com/edm00se/parcel-ie11-issue-demo.git
  • cd parcel-ie11-issue-demo
  • npm install
  • npm run dev
  • open http://localhost:1234 in IE 11
  • have a look at the js console, since the screen is blank (screen shots above)

🌍 Your Environment

| Software | Version(s) |
| ------------- | ---------- |
| Parcel | 1.10.3 |
| Node | 10.13.0 |
| npm/Yarn | 6.4.1 |
| Operating System | Windows 10 |

Thank You!

I love parcel, it's a great and performant bundler that's enjoyable to use. When I set out on this crazy path, I wasn't expecting to get as far as I have, and I am 99.8% there!

*note: I've updated this description to point to a far more simple reproducible repo

Bug

Most helpful comment

For any interested in this issue, I threw together a parcel plugin to add high level polyfills for both Promise and fetch to keep parcel's bundle loader working in IE(11).

repo: https://github.com/edm00se/parcel-plugin-goodie-bag
use: npm i -S parcel-plugin-goodie-bag (auto loads into index.html on build/dev)

All 21 comments

@DeMoorJasper thanks. If you check my package.json, it includes a browserslist config which explicitly includes β€œie 11”. I believe that’s all that should be needed. With that said, the generated output still attempts to use Promise.all, Promise.resolve, and fetch to load the generated bundles.

Is there something else I’m missing?

I also hit this very problem today - seems an issue with the pre-app serving code not the app code transpiling/polyfilling itself.

I was blown away πŸ’¨ by Parcel and how it completely simplified the build over webpack, but we pretty much exclusively target IE at work πŸ€¦πŸ»β€β™‚οΈ.

Yeah, sadly IE is often still the lowest common denominator. πŸ˜”

Like stated in the comment, every npm package you use that isn't commonjs should also have a browserlist or engines field in pkg.json to indicate what syntax the code is using.
Otherwise parcel would need to assume that all modules need to be compiled if a target isn't defined, which isn't very good for performance.

I’m confused πŸ€·πŸ»β€β™‚οΈ-> isn’t the issue here that Parcel πŸ“¦ is trying to unpolyfilled Promise to load its bundles?

I understand running babel over modules which are not compiled down to es5, but isn’t the issue here that Parcel πŸ“¦ itself is trying to use the undefined Promise object?

Here’s what I did to test πŸ”¬:
parcel build src/index.html
Tested in IE 11 =>produces error ❌
Added promise polyfill manually to dist/index.html ; as well as fetch
Works βœ…

To me, that suggests that Promise is being used by Parcel πŸ“¦ before its possible to polyfill it (as opposed to any of the dependencies actually causing the issue).

@DeMoorJasper
I'm trying to use it on local (no npm package) scripts, imported via ES6 import.
The event() constructor new Event("event_name"); was easy to workaround, but I don't want to write workaround for every unsupported feature.

@masterwaffle That’s what I’m seeing as well.

Manually dropping polyfills for Promise and fetch into the head tag of my generated dist/index.html allows the bundles to load/work correctly in IE.

<script src="https://unpkg.com/es6-promise/dist/es6-promise.auto.min.js"></script>
<script src="https://unpkg.com/unfetch/polyfill/index.js"></script>

I threw together a dead simple reproducible app, purely vanilla (no frameworks), but with configured babel which should match up with parcel's requirements from the app source perspective. This shows the same behavior I described, with less surrounding clutter. Specifically, with more than one bundle, Parcel itself relies directly on Promise and fetch.

source: https://github.com/edm00se/parcel-ie11-issue-demo
deployed: https://edm00se.codes/parcel-ie11-issue-demo/

image

I've updated the description of this to reflect the bare bones repro as outlined in my last comment.

To be clear, the bare bones example only has multiple bundles, because that's how it's done when requiring in html partial files.

Like stated in the comment, every npm package you use that isn't commonjs should also have a browserlist or engines field in pkg.json to indicate what syntax the code is using.
Otherwise parcel would need to assume that all modules need to be compiled if a target isn't defined, which isn't very good for performance.

@DeMoorJasper I have a repro.

It has:

  • no additional npm packages (it's pretty vanilla js and requires an html partial)
  • the browser target includes "ie 11", yet Parcel itself is generating direct uses of un-polyfilled Promise and fetch APIs
  • my attempts to use babel-polyfill don't work, as the calls are part of bundle-loader.js, not the app source
  • the output has multiple bundles since I'm requiring in an html file

Is there a better way of being able to require the html content and ensure compatibility down to es5/IE11?

For any interested in this issue, I threw together a parcel plugin to add high level polyfills for both Promise and fetch to keep parcel's bundle loader working in IE(11).

repo: https://github.com/edm00se/parcel-plugin-goodie-bag
use: npm i -S parcel-plugin-goodie-bag (auto loads into index.html on build/dev)

TY @edm00se your plugin worked perfectly for me!

I'm glad to hear it @riverross.

In case it's not clear from above, part of the reason I had issues was due to:

  • needing to support Internet Explorer
  • babel-polyfill, which is the v6 babel package, doesn't polyfill either Promise or fetch

    • this appears to different for at least Promise with the v7 package, @babel/polyfill

    • fetch polyfill will still be needed

    • due to timing, pulling in a Promise polyfill is still be needed _before_ our source code is hit

  • the app configuration of babel-polyfill fires _after_ when Parcel will need it for a multi bundle scenario

    • requiring in html partials seem to cause that scenario, due to multiple bundles being generated

I _wish_ there was an easier way of doing this, making Parcel more intelligent regarding browser support detection and doing this so I wouldn't have to. That said, it's behaving with what it was given as far as configuration. With any luck that might change in the future, until then we can work with the situation. 🀞

@edm00se Thank you for your comment!!
your comment was very helpful:)

What's the point on even having browserslist if it won't work as expected.

@tomasdev as a consumer of dev tooling, I agree.

I think what is central here is that parcel, at least v1's approach, seems to try to provide default enabled and configurable "other tools". My preference would look something along the lines of detecting the browserslist definition and determining whether to need to polyfill Promise and fetch early in its generated code, providing a virtually seamless experience.

Further activity, to stave off the bots.

@edm00se I have the same issue, only worse. In a Typescript project, we need to support IE11, which means a lot more than Promise and fetch.

.babelrc

{
  "presets": [
    "@babel/preset-typescript",
    "@babel/preset-react",
    [
      "@babel/preset-env",
      {
        "debug": true,
        "corejs": {
          "version": 3
        },
        "useBuiltIns": "entry"
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

.browserlist

last 2 versions
IE 11
not dead

src/index.ts (main entry point)

// IE11 polyfills >
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import 'whatwg-fetch';

// ...

This worked, but now I added a new dependency and that one doesn't get transpiled. There's an issue already open: #1655

The temporary fix for that was a postinstall script that modifies node_modules/**/package.json. πŸ˜”

Hope this helps someone else and maybe someone points out a mistake in my code.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adamreisnz picture adamreisnz  Β·  3Comments

termhn picture termhn  Β·  3Comments

philipodev picture philipodev  Β·  3Comments

466023746 picture 466023746  Β·  3Comments

davidnagli picture davidnagli  Β·  3Comments