45

I'm using webpack to bundle up my JavaScript. I'm depending on modules like popsicle which use any-promise.

Here's my code:

var popsicle = require('popsicle');
popsicle.get('/').then(function() {
  console.log('loaded URL');
});

This works fine in browsers where Promise is available, but IE 11 does not provide Promise. So I want to use es6-promise as a polyfill.

I tried adding an explicit ProvidePlugin to my webpack.config.js:

plugins: [
  new webpack.ProvidePlugin({
    'Promise': 'exports?global.Promise!es6-promise'
  })
]

But I still get the error in IE 11: any-promise browser requires a polyfill or explicit registration e.g: require('any-promise/register/bluebird').

I tried explicitly attaching a global:

global.Promise = global.Promise || require('es6-promise');

But IE 11 gives a different error: Object doesn't support this action.

I also tried explicitly registering es6-promise:

require('any-promise/register/es6-promise');
var popsicle = require('popsicle');

This works, but I have to do it in every single file that loads popsicle. I want to just attach Promise to window.

How can I ensure window.Promise is always defined, using webpack?

Full repo demo here.

Samar Panda
  • 4,186
  • 3
  • 25
  • 32
Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192

9 Answers9

69

For people using babel in combination with webpack: you can use babel-polyfill

Just do npm install --save "babel-polyfill" and then add it as an entry point in your webpack.config.js:

module.exports = {
   entry: ['babel-polyfill', './app/js']
};

Or, instead of using the entire babel-polyfill you can install core-js and reference only the module you need.

module.exports = {
   entry: ['core-js/stable/promise', './app/js']
};
shytikov
  • 9,155
  • 8
  • 56
  • 103
Jeroen Pelgrims
  • 1,085
  • 1
  • 10
  • 19
  • 1
    Thank you. This should be accepted answer. Although, my output JS file is now 150 kB (before ~50 kB). – Bald Jan 04 '17 at 20:46
  • @Bald Have you tried webpack 2? I haven't tried it myself but it should now support tree shaking. This will remove code that is imported but unused in the bundle that is output. So if you use the single import from core-js it might reduce the size. – Jeroen Pelgrims Jan 09 '17 at 13:51
  • No, I haven't, but I will :) Thanks for the hint. – Bald Jan 09 '17 at 15:46
  • 3
    Webpack v3.11, TS v2.7.x and node > v9, supports dynamic module imports, the problem is that you cannot import the Promise polyfill, because the dynamic import depends also on Promises. Therefor I do it manually: `if (!("Promise" in window)) { var head = document.getElementsByTagName("head")[0]; var script = document.createElement("script"); script.src = "https://../YourPromisePolyfill.js"; head.appendChild(script as HTMLScriptElement); }` You can of course use require/import to load the package, but then it gets bundeled and will be downloaded, even when not needed – Legends Feb 13 '18 at 19:30
  • 1
    In core-js v3 it's `'core-js/stable/promise'`. – Dave James Miller Sep 12 '19 at 17:22
  • Babel-polyfill is deprecated in favour of core-js – Luke Nov 02 '20 at 17:48
20

Option that worked for me. es6-promise-promise is designed to be included directly to the webpack builds. So:

plugins: [
  new webpack.ProvidePlugin({
    Promise: 'es6-promise-promise'
  })
]
Alex Antonov
  • 14,134
  • 7
  • 65
  • 142
  • 2
    still getting a `ReferenceError` in IE 11 when using the `ProvidePlugin` and then trying to do some `require.ensure` – Antoine Oct 05 '17 at 16:19
10

An updated and concise version of @asiniy's answer using the recently added property feature of ProvidePlugin, without the need to reference es6-promise-promise:

    new webpack.ProvidePlugin({
        Promise: ['es6-promise', 'Promise']
    })

For this to work don't forget to add es6-promise as a dependency of the project you want to polyfill Promise in.

staafl
  • 3,147
  • 1
  • 28
  • 23
6

babel polyfill usually works, but this time for a vuejs(webpack1) project, somehow not working.

Fortunately, core-js works as a charm.

npm install core-js --save

module.exports = {
   entry: ['core-js/fn/promise', './app/js']
};
Ben
  • 687
  • 7
  • 15
5

Better use Bluebird

plugins: [
  new webpack.ProvidePlugin({
    Promise: 'bluebird'
  }),

  new webpack.NormalModuleReplacementPlugin(/es6-promise$/, 'bluebird'),
]
Alex Shwarc
  • 822
  • 10
  • 20
1

You almost got it - try this in your webpack.config.js:

plugins: [
  new webpack.ProvidePlugin({
    Promise: 'imports?this=>global!exports?global.Promise!es6-promise'
  })
]

Note that you will need to install imports-loader and exports-loader:

npm install --save imports-loader exports-loader

Gabriel Florit
  • 2,886
  • 1
  • 22
  • 36
1

With Webpack 2 this is how I got it working.

First install with npm install babel-polyfill. Starting with NPM 5 --save can be omitted.

Then modify the webpack configuration with:

entry: {
  app: ['babel-polyfill', './src/main.js']
}

Of course ./src/main.js is different for every app.

Pier
  • 10,298
  • 17
  • 67
  • 113
0

For those using CRA (create-react-app) you could use the polyfill they provide:

react-app-polyfill

  • npm install react-app-polyfill or yarn add react-app-polyfill
  • In your index.js file: import 'react-app-polyfill/ie11';
Mario Pérez Alarcón
  • 3,468
  • 2
  • 27
  • 38
0

In webpack after optimization from babel-polyfill to core-js's promise the code:

import 'core-js/library/es6/promise'; 

does not works.

But after changing code to:

import 'core-js/features/promise';

it works.

Kaxa
  • 515
  • 1
  • 6
  • 11