1

I've got an issue with react-loadable where I've got a large list of components that may or may not be rendered depending on user-generated content. I'm using a switch statement to render the correct ones.

A (simplified) list of user-generated content might look like this:

const content = ['Paragraph', 'Image', 'Paragraph', 'Canvas'];

Now, what I want to do is have ONLY the components that are used enter the bundle. Instead, ALL of them that get included in the following switch case are in the bundle. Why?

const collection = (name) => {
   switch(name) {
     case 'Paragraph':
       return Loadable({
         loader: () => import('dynamic-paragraph-component'),
         loading(){ return null }
        })
     case 'Video':
        return Loadable({
         loader: () => import('dynamic-video-component'),
         loading() { return null }
        })
     // etc
   }
}

For example, dynamic-video-component ends up in the bundle even if it's not used. Is there a way to prevent this?

Current webpack setup with Webpack 4

//----------------------------------
//
// Bundler
//
//----------------------------------

import webpack from 'webpack';
import path from 'path';
import { ReactLoadablePlugin } from 'react-loadable/webpack';


module.exports = (files) => {
  console.log(files);


  return {
    mode: 'production',
    entry: './src/client/index.js',
    output: {
      filename: './main.pkgd.js',
      chunkFilename: './[name].pkgd.js',
      path: path.resolve(__dirname, 'tmp'),
      publicPath: '/',
    },

    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          options: {
            babelrc: false,
            presets: [
              [
                'env',
                {
                  modules: false,
                  targets: {
                    browsers: ['last 2 versions'],
                  },
                },
              ],
              'flow',
              'react',
            ],
            plugins: [
              'transform-class-properties',
              'syntax-dynamic-import',
              'react-loadable/babel',
            ],
          },
        },
      ],
    },

    optimization: {
      splitChunks: {
        cacheGroups: {
          default: false,
          vendors: false,

          // vendor chunk
          vendor: {
            name: 'vendor',
            chunks: 'all',
            test: /node_modules/,
            priority: 20,
            reuseExistingChunk: true,
            enforce: true,
          },
          common: {
            name: 'main',
            minChunks: 1,
            chunks: 'initial',
            priority: 10,
            reuseExistingChunk: true,
            enforce: true,
          },
        },
      },
    },


    plugins: [
      new webpack.DefinePlugin({
        __isBrowser__: 'true',
        env: {
          NODE_ENV: JSON.stringify('production'),
        },
      }),
      new ReactLoadablePlugin({
        filename: './tmp/react-loadable.json',
      }),
    ],
  };
};
James P
  • 718
  • 6
  • 14

1 Answers1

0

The way you have it set up looks correct, so I'd wager the problem is in your webpack.config.js file.

Assuming you are using Webpack 4, you need to reference the code-splitting docs.

Specifically, make sure you have configured the chunkFilename option. Also, you can add comment directives like /* webpackChunkName: "dynamic-video-component" */ for easier debugging.

Jclangst
  • 1,274
  • 7
  • 11
  • thanks @Jclangst. Pasted in my webpack setup. Trying to have 2 bundles, vendor and main, with vendor only including the components used. – James P Sep 05 '18 at 11:46
  • I can't be 100% sure without testing your setup, but I think the issue is with the splitChunks optimization settings - this is combining chunks that would otherwise be separate due to dynamic imports. I'd do the following: (1) disable this feature to confirm it is the issue, (2) make sure that your chunks would be over 30kb (if not you need to edit the `minSize`) setting, (3) try turning off `reuseExistingChunk`, and (4) report back. – Jclangst Sep 05 '18 at 13:41
  • Also, I notice your `test` field under `vendor` chunk is not the recommended `/[\\/]node_modules[\\/]/` – Jclangst Sep 05 '18 at 13:44
  • got it working. i originally had the babel plugin `dynamic-import-node` in there and it was preventing the chunks from automatically splitting. removing that plugin and using `syntax-dynamic-import` combined with removing the `cacheGroups` from the `splitChunks` optimization allowed everything to work. thanks again! – James P Sep 05 '18 at 14:58