4

I would like to use webpack chunking method to generate separate bundles for separate routes in my route config. One way to achieve it is to use require.ensure to define split points for chunks and asynchronously load modules on browser demand.

Here is what I ve got:

webpack.config.js (merged with dev/prod webpack configs depending on executed npm script):

var autoprefixer = require('autoprefixer');
var html         = require('html-webpack-plugin');
var path         = require('path');
var webpack = require('webpack');

var node_modules_dir = path.resolve('./node_modules')

var HappyPack = require('happypack');

module.exports = {
  context: path.resolve('./src'),
  entry: {
    app: ['./scripts/index.js', './styles/index.scss'],
    vendor: ['react', 'react-dom', 'react-redux', 'redux','immutable'],
  },
  module: {
    loaders: [
      {
        test: /\.(jpg|png|gif|json)$/,
        loader: 'file',
        query: {
          name: 'assets/[hash].[ext]',
        },
      },
      {
        test: /\.svg$/,
        loader: 'happypack/loader?id=svg'
      },
    ],
  },
  output: {
    filename: '[name].js',
    path: path.resolve('./build'),
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    // new webpack.optimize.LimitChunkCountPlugin({maxChunks: 5}),
    // new webpack.optimize.MinChunkSizePlugin({minChunkSize: 10000}),
    new html({
      minify: {
        collapseWhitespace: true,
      },
      template: './index.html',
      title: process.env.npm_package_config_title,
    }),
    new webpack.optimize.CommonsChunkPlugin('vendor','vendor.bundle.js'),
    new HappyPack({
      id: 'svg',
      threads: 5,
      loaders: [
        'svg-inline'
      ]
    })
  ],
  postcss: function() {
    return [
      autoprefixer,
    ];
  },
  resolve: {
    alias: {
      assets: path.resolve('./src/assets'),
      lib: path.resolve('./src/lib'),
      modules: path.resolve('./src/scripts/modules'),
      scripts: path.resolve('./src/scripts'),
      styles: path.resolve('./src/styles'),
      toolbox: path.resolve('./node_modules/react-toolbox'),
      vendors: path.resolve('./src/vendors'),

      'react-redux': node_modules_dir + '/react-redux/dist/react-redux.min.js',
      'redux': node_modules_dir + '/redux/dist/redux.min.js',
      'immutable': node_modules_dir +'/immutable/dist/immutable.min.js'
    },
    extensions: [
      '',
      '.js',
      '.jsx',
      '.css',
      '.scss',
    ],
  },
  toolbox: {
    theme: path.resolve('./toolbox/index.scss'),
  },
};

webpack.config.dev.js (dev webpack configuration [merged with above]):

var merge   = require('webpack-merge');
var webpack = require('webpack');
var path    = require('path');
var config  = require('./config');

var HappyPack = require('happypack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = merge(config, {
  // devtool: 'eval',
  devServer: {
    contentBase: 'build',
    historyApiFallback: true,
    hot: true,
    host: '0.0.0.0',
    inline: true,
    port: parseInt(process.env.npm_package_config_port),
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'happypack/loader?id=jsx'
      },
      {
        test: /\.s?css$/,
        loader: 'happypack/loader?id=css'
      },
    ],
  },
  output: {
    chunkFilename: "[name].js",
    publicPath: 'http://localhost:' + process.env.npm_package_config_port + process.env.npm_package_config_public_path,
    pathInfo: true,
  },
  plugins: [
    new webpack.PrefetchPlugin('react'),
    new webpack.PrefetchPlugin('react-toolbox'),
    new webpack.PrefetchPlugin('react-redux'),
    new webpack.PrefetchPlugin('redux'),
    new webpack.PrefetchPlugin('immutable'),
    new webpack.PrefetchPlugin('./scripts/routes.jsx'),

    new webpack.PrefetchPlugin('./scripts/components/smart/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/login/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/companies_list/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/shortlists/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/testing_shortlist/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/components/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/horizontal_chart/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/smarts/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/views/index.jsx'),

    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/refactorized_tools/components/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/refactorized_tools/composed/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/refactorized_tools/view_content/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/refactorized_tools/views/index.jsx'),

    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/cities_list_with_filters/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/city_path_start/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/company_path_start/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/compare_cities_datapoints/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/compare_companies_datapoints/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/compare_result/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/scan_your_brand/index.jsx'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools.old/tools/subcomponents/index.jsx'),

    new webpack.PrefetchPlugin('./lib/ui/multi_select/RTAutocomplete/index.js'),

    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/charts/style/charts.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/filters_box/style/city.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/filters_box/style/company.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/map_with_bottom_stats/style.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/city_boxes/style/city_boxes.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/company_boxes/style/company_boxes.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/filters_box_with_header_box/style/city.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/filters_box_with_header_box/style/company.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/selected_entities/style/selected_entities.scss'),
    new webpack.PrefetchPlugin('./scripts/components/views/tools/view_content/human_resources_table_box/style/_human_resources_table_box.scss'),
    // new webpack.PrefetchPlugin(''),
    new ExtractTextPlugin("[hash].css"),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'),
      'process.env.LANDING_ONLY': JSON.stringify(false),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new HappyPack({
      id: 'jsx',
      threads: 5,
      loaders: ['babel?presets[]=react-hmre']
    }),
    new HappyPack({
      id: 'css',
      threads: 5,
      loaders: [
        'style',
        'css?sourceMap,modules,localIdentName=[local]__[hash:base64:5]',
        'postcss',
        'resolve-url',
        'sass?sourceMap',
        'toolbox'
      ]
    })
  ],
});

routes.jsx:

[some module imports here]

export default (
  <Route component={ PermisionProvider } >
    <Route component={ AppProvider } >
      <Route component={ SnackbarProvider } >
        <Redirect from={ paths.root } to={ localStorage.get('user') ? paths.login : paths.landingPageCities } />


        { /* Landing */ }
        <Route onEnter={ _hasPermission.bind(null, 'landingPage') }>
          <Route component={ LandingLayout }>
            <Route 
              path={ paths.landingPageCities }   
              getComponent={(location, callback) => {
                    require.ensure(['modules/landing_page/smarts/SmartLandingCities'], function (require) {
              callback(null, require('modules/landing_page/smarts/SmartLandingCities').default);
            }, 'SmartLandingCities');
          }} 
        />
        <Route 
          path={ paths.landingPageCompanies }
          getComponent={(location, callback) => {
            require.ensure(['modules/landing_page/smarts/SmartLandingCompanies'], function (require) {
              callback(null, require('modules/landing_page/smarts/SmartLandingCompanies').default);
            }, 'SmartLandingCompanies');
          }} 
        />
        <Route 
          path={ paths.aboutUsPage }          
          getComponent={(location, callback) => {
            require.ensure(['modules/landing_page/views/AboutUsPage'], function (require) {
              callback(null, require('modules/landing_page/views/AboutUsPage').default);
            }, 'AboutUsPage');
          }} 
        />
      </Route>
    </Route>

    { /* Login */ }
    <Route onEnter={ _hasPermission.bind(null, 'login') }>

I read tones of blog posts and tutorials and it all seems to be in place here. Yet, webpack is not generating separate bundles for neither of the routes in which I use require.ensure:

  • SmartLandingCities
  • SmartLandingCompanies
  • AboutUsPage

Am super desperate already, as the app bundle is 2mb in size and I already used all available size shrinking methods out there.

Thanks for any help!

azrahel
  • 1,143
  • 2
  • 13
  • 31
  • Possible duplicate of [Using webpack and react-router for lazyloading and code-splitting not loading](http://stackoverflow.com/questions/34925717/using-webpack-and-react-router-for-lazyloading-and-code-splitting-not-loading) – Paul Sweatte Sep 06 '16 at 14:17
  • @azrahel, I am having the same problem and posted a question as well http://stackoverflow.com/questions/39757297. Although looking at your webpack.config file you didn't define chunkFilename: "[name].js" whereas in dev config you did. try adding that in the production config. If you already solved please let me know. – jasan Oct 01 '16 at 03:54
  • Hey, yes solved already. I dont really remember what was the precise issue, but I can send you small project that I started recently with above code working as should. – azrahel Oct 01 '16 at 12:27
  • that would be awesome. Can you post the link to the project if its on github. – jasan Oct 01 '16 at 22:25
  • @azrahel if there is some other method you prefer let me know. – jasan Oct 02 '16 at 06:15
  • @azrahel would really appreciate any insight as to what the problem was or the project code you had mentioned. – jasan Oct 09 '16 at 11:24
  • @jasan yes, sorry it takes so long - am too busy recently. Please provide your bitbucket login and I will share the project with you. best! – azrahel Oct 10 '16 at 10:14
  • @jasan shared! hope that will help. In case of any questions message me on email (it is possible via bitbucket, right?) or on bitbucket: ) – azrahel Oct 10 '16 at 12:49
  • thanks, and bitbucket does allow messaging. – jasan Oct 10 '16 at 14:14
  • @azrahel I have similar issue, can you share it with me as well? – Matt Nov 01 '16 at 20:48

1 Answers1

0

Since there already been three requests for access to repo that contains working solution, here it is:) Have a great coding!

https://bitbucket.org/azrahel/crit_calendar/

azrahel
  • 1,143
  • 2
  • 13
  • 31