Pavel Polyakov
Pavel Polyakov

Reputation: 926

Webpack 2: splitting libraries, vendor and app into different files

Imagine I have a rich application, which uses a lot of the 3rd party modules including lodash, moment, axios, react.

If I bundle everything in one bundle at the end the size would be higher then 1MB.

I want webpack to pack my libraries in the way, that it stores:

  1. lodash separately
  2. moment separately
  3. all the other node_modules are stored under the vendor bundle
  4. the code of the application is stored in the separate file

I tried to play with the CommonsChunkPlugin in different ways, but never received the result I want.

I've prepared the example repository to illustrate my issue: https://github.com/PavelPolyakov/webpack-react-bundles

Webpack entry part (conf/webpack.base.config.js):

entry: {
    lodash: 'lodash',
    moment: 'moment',
    app: [
        'react-hot-loader/patch',
        'webpack-dev-server/client?http://localhost:3001',
        'webpack/hot/only-dev-server',
        './app/index.js']
}

Here is production config (conf/webpack.production.config.js), trying to separate modules:

plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify('production')
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function (module) {
                // this assumes your vendor imports exist in the node_modules directory
                return module.context &&
                    module.context.indexOf('node_modules') !== -1;
            }
        }),
        new webpack.optimize.UglifyJsPlugin({
            minimize: true,
            compress: {
                warnings: true
            }
        })]

This case, the moment and lodash would still appear in the vendor bundle. I want to have them in the two separate bundles.

Any thoughts appreciated.

Upvotes: 1

Views: 1302

Answers (2)

Pavel Polyakov
Pavel Polyakov

Reputation: 926

At the end I received the help from @sokra in github issue: https://github.com/webpack/webpack/issues/4638

For those who will be facing the same problem, here is the complete webpack config which solves the issue described in the question:

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        app: ['./app/index.js']
    },
    output: {
        filename: '[name].bundle.js',
        sourceMapFilename: '[name].bundle.map',
        path: path.resolve(__dirname, './dist')
    },
    devServer: {
        port: 3001,
        contentBase: path.resolve(__dirname, './dist'),
        historyApiFallback: true
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [['es2015', { 'modules': false }], 'react'],
                            plugins: ['transform-async-to-generator',
                                'transform-decorators-legacy',
                                'transform-runtime',
                                'react-html-attrs',
                                'react-hot-loader/babel'],
                        }
                    }
                ]
            },
            {
                test: /\.css/,
                use: ['style-loader', 'css-loader', 'postcss-loader']
            },
            {
                test: /\.(eot|svg|ttf|woff|woff2|gif|jpg|png)$/,
                use: 'file-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
            inject: "body"
        }),
        new webpack.optimize.UglifyJsPlugin({
            minimize: true,
            compress: {
                warnings: true
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: (m) => /node_modules/.test(m.context)
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'lodash',
            minChunks: (m) => /node_modules\/(?:lodash|moment)/.test(m.context)
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'moment',
            minChunks: (m) => /node_modules\/(?:moment)/.test(m.context)
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: "manifest",
            minChunks: Infinity
        })
    ],
    resolve: {
        extensions: ['.js', '.jsx']
    },
    devtool: 'source-map'
}

Thanks to all who tried to help!

Upvotes: 3

opatut
opatut

Reputation: 6864

It is probably easiest if you include them from a CDN and use an external.

This is not per definition code splitting but might be close to what you intend to accomplish: reducing bundle size. There is the advantage of some users having the CDN version already cached from another site.

Upvotes: 1

Related Questions