Routes chunks are bundling external scripts in every chunk

759 Views Asked by At

In my webpack I've used externals which has React, React Dom, Redux etc.

Now when I implement my Route Chunking, every chunk which is generated re-bundles the external scripts again, so eventually my bundle size is very huge.

How can I avoid my individual chunks not to re-bundle the external scripts and use them from externals.

EDIT

Using https://chrisbateman.github.io/webpack-visualizer/ I can see that all my chunks are bundling common libs - which are are actually supposed to come from externals in webpack.

EDIT 2

webpack file

var path = require('path');
var webpack = require('webpack');

module.exports = {

  entry: ['./src/containers/AppContainer', './src/index'],

  devtool: 'cheap-module-source-map',

  output: {
    path: __dirname + '/dist',
    publicPath: 'public/',
    filename: 'bundle.js',
    chunkFilename: '[name].[id].chunk.[chunkhash].js',
    libraryTarget: 'umd'
  },

  target: 'web',

  externals: {
    antd: 'antd',
    react: 'react',
    'react-dom': 'react-dom',
    'react-router': 'react-router',
    redux: 'redux',
    'react-redux': 'react-redux',
    immutable: 'immutable',
  },

  resolve: {
    modules: [
      path.join(__dirname, '../node_modules')
    ],
    extensions: ['.js', '.jsx', '.json'],
    alias:{
      constants: path.resolve(__dirname, './src/constants'),
      actions: path.resolve(__dirname, './src/actions'),
      styles: path.resolve(__dirname, './src/styles'),
      utils: path.resolve(__dirname, './src/utils')
    }
  },

  resolveLoader: {
    modules: [
      path.join(__dirname, '../node_modules')
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      comments: false
    })
  ]

  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          // Ignore local .babelrc files
          babelrc: false,
          presets: [
            ['es2015', { modules: false }],
            'react'
          ],
          plugins: [
            'react-html-attrs',
            'transform-class-properties',
            'transform-decorators-legacy',
            'transform-object-rest-spread',
            [
              'import', {
                libraryName: 'antd'
              }
            ]
          ]
        }
      },
      { test: /\.png$/, loader: 'file-loader' },
      {
        test: /\.s?css$/i,
        use: [
          'style-loader',
          'css-loader'
         ]
      },
      {
        test: /\.s?less$/i,
        exclude:'/node_modules/',
        use: [
          'style-loader',
          'css-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        loader: 'url-loader',
        options: {
          limit: 100000
        }
      },
      {
        test: /\.eot\?iefix$/,
        loader: 'url-loader',
        options: {
          limit: 100000
        }
      },
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        options: {
          configFile: './eslint/.eslintrc',
          failOnWarning: false,
          failOnError: false
        }
      }
    ]
  }
};

Routes file

import React from 'react';
import { Route, IndexRoute } from 'react-router';

export default (
  <Route path='/base/'
    getComponent={ (location, callback) => {
      require.ensure([], function (require) {
        callback(null, require('./containers/AppContainer').default);
      });
    } }>

    <Route path='/route1'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./containter1')
            .default);
        });
      } }
    />

    <Route path='/route2'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./container2')
            .default);
        });
      } }
    />

    <Route path='/route3'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./container3')
            .default);
        });
      } }
    />
  </Route>
);
1

There are 1 best solutions below

5
On

Try to change your externals section like this:

externals: {
    React: require.resolve('react'),
    'window.React': require.resolve('react'),
    ReactDOM: require.resolve('react-dom'),
    'window.ReactDOM': require.resolve('react-dom')
}

Also, remove import React from 'react' from your code. Just use React.

EDIT

Apologies, I edited my answer. Just realised my mistake. I changed the code. The key inside your externals will be the name of the global variable. Usually it's also safer to put it inside the window object