Webpack implicit vendor/manifest chunks in IE11 - Promise is undefined

2.8k views Asked by At

Short version

When I run my application in IE11, I get an error saying Promise is undefined from within the manifest.js file.

How do I add babel-polyfill or similar such that it runs before the manifest is executed?

Long version

I am trying to add CommonsChunkPlugin to my webpack config in order to split off third party (npm package) scripts into a separate bundle. As per the Webpack 2 documentation I have set up "combined implicit common vendor chunks and manifest file" which is working well in modern browsers.

I have written a function to ensure that the chunks get included into my index file in the right order (see below).

A bit of background on my two explicit entry points:

  • legacy_libs - Older libraries that are placed into the global namespace with script-loader. I hope to phase these out over time
  • main - My main app entry point

The other two (vendor and manifest) are implicit and created with CommonsChunkPlugin.

When I run this with IE11, I get an error: Promise is undefined. This seems to be because the webpack manifest itself is calling new Promise().

In my main entry point I have import 'babel-polyfill';. Before I added the vendor & manifest chunking, this allowed me to overcome IE's lack of Promises. But now that I have manifest.js loading first, I can't work out how to include it in the right order.

My config looks like so:

module.exports = {
  entry: {
    legacy_libs: './app/libs.js',
    main: './app/main.js'
  },
  ...
  plugins: [
    // Extract third party libraries into a separate vendor bundle.
    // Also extract webpack manifest into its own bundle (to prevent vendor hash changing when app source changes)
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module) {
        return module.context && module.context.indexOf('node_modules') !== -1;
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    }),

    // Generate index.html file.
    // Include script bundles in the right order based on chunk name prefixes.
    new HtmlWebpackPlugin({
      template: 'app/index.ejs',
      chunksSortMode: function (a, b) {
        const chunkOrder = ['manifest', 'vendor', 'legacy_libs', 'main'];
        const aChunk = chunkOrder.findIndex(chunk => a.names[0].startsWith(chunk));
        const bChunk = chunkOrder.findIndex(chunk => b.names[0].startsWith(chunk));
        const aValue = (aChunk > -1) ? aChunk : chunkOrder.length;
        const bValue = (bChunk > -1) ? bChunk : chunkOrder.length;
        return aValue - bValue;
      }
    })
}
2

There are 2 answers

1
Sheeni On BEST ANSWER

This seems to be an issue introduced with webpack 2.6.0, a bug is already issued: https://github.com/webpack/webpack/issues/4916

So either wait until the bugfix gets released or revert back to 2.5.1!

1
Fleezey On

I ran into the same issue. My config is similar to yours (vendor & manifest). The way I solved it was to add babel-polyfill in the entry point of my manifest. Your entry should look like this:

entry: {
    legacy_libs: './app/libs.js',
    main: './app/main.js',
    manifest: 'babel-polyfill'
}

This will load the polyfill so it can be used in the manifest file.

EDIT: Using this returned another error when building (although it runs fine on the dev-server):

ERROR in CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (manifest)

Fixed it by modifying the entry points and the CommonsChunkPlugin so it looks like this:

entry: {
    legacy_libs: './app/libs.js',
    main: './app/main.js',
    'babel-polyfill': 'babel-polyfill'
},
...
plugins: [
    ...
    new webpack.optimize.CommonsChunkPlugin({
        name: 'manifest',
        chunks: 'babel-polyfill'
    }),
]