1

I try to get code splitting working with webpack 4 (previous config with webpack 3 worked correctly)

I created a repository to easily reproduce my problem: https://github.com/iamdey/RD-webpack4-code-split

I generaly get stuck on the following error because I want code splitting and babel-polyfill in vendor bundle:

ReferenceError: regeneratorRuntime is not defined

The config

Here is my webpack config:

{
  entry: {
    app: ['./src/index.js'],
    vendor: [
      'babel-polyfill',
      'moment',
    ],
  },
  output: {
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      chunksSortMode: (chunk1, chunk2) => {
        // make sure babel-polyfill in vendors is loaded before app
        const order = ['manifest', 'vendor', 'app'];
        const order1 = order.indexOf(chunk1.names[0]);
        const order2 = order.indexOf(chunk2.names[0]);

        return order1 - order2;
      },
    }),
  ],
  optimization: {
    runtimeChunk: {
      name: 'manifest',
    },
    splitChunks: {
      cacheGroups: {
        vendor: {
          chunks: 'initial',
          name: 'vendor',
          test: 'vendor',
          enforce: true,
        },
      },
    },
  }
}

The problem

When debugging we see that vendor is loaded right after manifest and finally app. But app is executed before vendor.

In case I remove the splitChunks options, just like before the manifest then the vendor is loaded but vendor is executed directly before loading app. In this case the problem is the split has a bad effect: chunks are duplicated in vendor and app.

What to do ?

Here are the options I have:

  • put polyfill in app bundle instead of vendor bundle: I don't want that
  • leave webpack do the code splitting itself: I don't want that because in real world I want a very long caching even between releases on vendor and keep app as small as possible
  • the webpack config is incorrect: Please tell me :)
  • It probably is a bug: Cool, I'll open an issue asap
DEY
  • 1,770
  • 2
  • 16
  • 14
  • I would try to look closer to the babel plugins. Maybe use ```babel-preset-env```. What's wrong with putting ```babel-polyfill``` into the webpack config? However if you do not like it put only ```babel-regenerator-runtime``` look here: https://stackoverflow.com/a/36590887/3233796 – proti Apr 27 '18 at 12:39
  • babel is not related, it will be the same problem with script-load!jquery for example. May be it's not clear, but I want babel-polyfill in vendor bundle, not in app bundle – DEY Apr 27 '18 at 14:00

1 Answers1

1

Let's start by having the polyfill loaded and executed as part of each entry point (as seen in the babel-polyfill doc) so that it looks like this

app: ['babel-polyfill', './src/index.js'],
vendor: ['moment'],

Here's the output after a npm run start2:

                           Asset       Size    Chunks             Chunk Names
     app.53452b510a24e3c11f03.js    419 KiB       app  [emitted]  app
manifest.16093f9bf9de1cb39c92.js   5.31 KiB  manifest  [emitted]  manifest
  vendor.e3f405ffdcf40fa83b3a.js    558 KiB    vendor  [emitted]  vendor

What I understand is setting babel-polyfill in entry.app tells webpack that the polyfill is required by the app. And package defined in vendor tells splitChunk plugin what packages to bundle in the cache group.

Given my understanding from the split-chunks-plugin doc

The test option controls which modules are selected by this cache group. Omitting it selects all modules.

So removing test from cacheGroup option will result that all code will be moved to vendor bundle.

Knowing that we have 2 solutions.

1/ Using a workaround and duplicate loaded script

{
  entry: {
    app: [
      'babel-polyfill',
      './src/index.js',
    ],
    vendor: [
      'babel-polyfill',
      'moment',
    ],
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          chunks: 'initial',
          name: 'vendor',
          test: 'vendor',
          enforce: true,
        },
      },
    },
    runtimeChunk: {
      name: 'manifest',
    },
  },
}

So we tell webpack that babel-polyfill is required by app and we tell splitChunks that babel-polyfill and moment are vendors to use in cache group.

2/ Use import instead of script loader

In index.js

import 'babel-polyfill';
import moment from 'moment';

// ...

webpack.config.js

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

This make sure the polyfill is required by the app.

Hope it helps!

DEY
  • 1,770
  • 2
  • 16
  • 14
Pegase745
  • 63
  • 7