Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack 2 configuration for Tree shaking and lazy loading with System.import on React project

Tags:

I am new to webpack 2 and it's lazy loading, so far I have created project without lazy loading and code splitting, but now want to split my code into chunks and use System imports with React Router. I have created React Router part according to this article

this webpack 2 config file is below.

let webpack = require('webpack');
let path = require('path');
let ExtractTextPlugin = require('extract-text-webpack-plugin');

var devFlagPlugin = new webpack.DefinePlugin({
    __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false')),
    'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
    }
});

let extractSCSS = new ExtractTextPlugin('[name].css')

module.exports = {
    context: __dirname,
    entry: {
        bundle: './src/app/app-client.jsx',
        styles: './src/app/sass/main.scss',
        vendor: [
            'react', 'react-dom'
        ]
    },
    output: {
        filename: '[name].js',
        chunkFilename: 'chunk.[id].[chunkhash:8].js',
        path: './src/build',
    },
    resolve: {
        extensions: ['.js', '.jsx']
    },
    devtool: 'cheap-module-source-map',
    module : {
        rules : [
            {
                test: /\.scss$/,
                loader: extractSCSS.extract(['css-loader','sass-loader'])
            },
            {
                test: /\.jsx?$/,
                exclude: [/node_modules/, /libs/],
                use: {
                    loader: "babel-loader",
                    query: {
                        presets: ['es2015', 'react', 'stage-2' ],
                        plugins: [ "transform-runtime" ]
                    }
                }
            },
            {
                test: /\.woff2?$|\.ttf$|\.eot$|\.svg$|\.png|\.jpe?g|\.gif$/,
                use: {
                    loader:'file-loader'
                }
            }
        ]
    },
    plugins: [
        extractSCSS,
        devFlagPlugin,
        new webpack.optimize.CommonsChunkPlugin({
            name: 'bundle',
            children: true,
            async: true,
            minChunks: 2
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            children: true,
            async: true,
            minChunks: 2
        })
    ]
}

but webpack creates only two files, vendor and bundle, also size of bundle hasn't reduced after I separated React and React DOM.

this is my routes.

import App from './App.jsx';

function errorLoading(err) {
  console.error('Dynamic page loading failed', err);
}

function loadRoute(cb) {
  return (module) => cb(null, module.default);
}

export default {
  component: App,
  childRoutes: [
    {
      path: 'stock/info/:symbol(/:tab)',
      getComponent(location, cb) {
        System.import('./StockPage')
          .then(loadRoute(cb))
          .catch(errorLoading);
      }
    },
    {
      path: '*',
      getComponent(location, cb) {
        System.import('./NoMatch')
          .then(loadRoute(cb))
          .catch(errorLoading);
      }
    }
  ]
};

my application runs, but lazy loading won't work of course, because I have no chunks of my modules within System.import.

Please help me to create right webpack config for performance of my application! Thanks in advance and sorry if something is nonsense, since I am new to webpack.

like image 585
Aren Hovsepyan Avatar asked Jan 28 '17 16:01

Aren Hovsepyan


1 Answers

Webpack2 switched from System.import() to import() to match the current proposed javascript feature. Which is in stage3 right now.

So you should be able to change your webpack config to include STAGE-3

{
            test: /\.jsx?$/,
            exclude: [/node_modules/, /libs/],
            use: {
                loader: "babel-loader",
                query: {
                    presets: ['es2015', 'react', 'stage-2', 'stage-3' ],
                    plugins: [ "transform-runtime" ]
                }
            }
},

Or the dynamic-import plugin

{
            test: /\.jsx?$/,
            exclude: [/node_modules/, /libs/],
            use: {
                loader: "babel-loader",
                query: {
                    presets: ['es2015', 'react', 'stage-2' ],
                    plugins: [ "transform-runtime", "syntax-dynamic-import"]
                }
            }
},

Then change your routes

export default {
  component: App,
  childRoutes: [
  {
    path: 'stock/info/:symbol(/:tab)',
    getComponent(location, cb) {
      import('./StockPage')
        .then(loadRoute(cb))
        .catch(errorLoading);
    }
  },
  {
    path: '*',
    getComponent(location, cb) {
    import('./NoMatch')
      .then(loadRoute(cb))
      .catch(errorLoading);
    }
  }
]
};

See the webpack2 help page here for full docs on using import for code splitting and lazy loading. https://webpack.js.org/guides/migrating/#code-splitting-with-es2015 https://github.com/tc39/proposal-dynamic-import

To enable Webpack2 tree shaking which only requires making one change to your babel setup.

presets: ['es2015', 'react', 'stage-2' ],

becomes

presets: [['es2015', { modules: false }], 'react', 'stage-2' ],

This is the article that I found out about treeshaking from: https://medium.freecodecamp.com/tree-shaking-es6-modules-in-webpack-2-1add6672f31b#.lv3ldgfhs

like image 79
DanielD Avatar answered Oct 16 '22 20:10

DanielD