I'm using WebPack CommonsChunkPlugin to extract duplicate code and reduce JavaScript code size. I have two html pages and two entries for them. Also i've added ReactJs vendor entry. So far, in webpack.config.js we have:
var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
context: __dirname,
entry: {
react: ["react", "react-dom"],
home: './assets/js/home.jsx',
about: './assets/js/about.jsx',
},
output: {
path: path.resolve('./assets/bundles/'),
filename: "[name].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.CommonsChunkPlugin({
name: 'react',
minChunks: Infinity
}),
new BundleAnalyzerPlugin(),
],
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: [["lodash", { "id": ["semantic-ui-react"] }]],
presets: ["es2015", "react"]
}
},
],
},
resolve: {
modules: ['node_modules', 'bower_components'],
extensions: ['*', '.js', '.jsx']
},
};
This configuration result with webpack-bundle-analyzer:
As you can see, there are some duplicate code, some in red area and some other in green area. I want to extract this js codes from home and about bundles into a separate bundle. To extract red area code, namely lodash library, i added these lines to webpack config:
new webpack.optimize.CommonsChunkPlugin({
name: 'lodash',
minChunks: function(module, count) {
return module.context.indexOf('node_modules/lodash') >= 0;
}
}),
But it's not working as expected and lodash library code is still in both home and about bundles, also webpack creates a bundle named lodash that is almost empty and contains no js library.
Any idea on how to fix it ? How about extracting green are codes?
Your problem is that your are importing third party libs in each .js/.jsx
file without importing it previously in a common file (normally called vendor.js
).
If you have this file that import all you dependencies and you include it as entry and to CommonsChunkPlugin, webpack won't include again your libs in your final bundles (home.js
and about.js
). The technique is called code splitting in webpack docs.
vendor.js (or a name that fit for your case)
import 'react';
import 'react-dom';
import 'lodash';
import 'semantic-ui-react';
//... all your npm packages
webpack.config.js
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: __dirname,
entry: {
vendor: './assets/js/vendor.js,
home: './assets/js/home.jsx',
about: './assets/js/about.jsx',
},
output: {
path: path.resolve('./assets/bundles/'),
filename: '[name].js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity
}),
],
//Rest of Your config ...
};
index.html
<body>
<!-- AFTER YOUR HTML CODE -->
<script type="text/javascript" src="/assets/bundles/vendor.js"></script>
<script type="text/javascript" src="/assets/bundles/home.js"></script>
<script type="text/javascript" src="/assets/bundles/about.js"></script>
</body>
Check webpack code splitting docs:
I managed to solve the problem by adding a common chunk to plugins. So final webpack config is :
var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
module.exports = {
context: __dirname,
entry: {
react: ["react", "react-dom"],
home: './assets/js/home.jsx',
about: './assets/js/about.jsx',
},
output: {
path: path.resolve('./assets/bundles/'),
filename: "[name].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.CommonsChunkPlugin({
name: 'react',
filename: '[name].js',
minChunks: Infinity,
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
chunks: ['home', 'about'],
filename: '[name].js',
}),
],
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: [
["lodash", { "id": ["semantic-ui-react"] }]
],
presets: ["es2015", "react"]
}
},
],
},
resolve: {
modules: ['node_modules', 'bower_components'],
extensions: ['*', '.js', '.jsx']
},
};
And now bundle analyzer output is like this:
As it's shown in the picture, common semantic-ui-react and lodash libraries are now just in common bundle and not duplicated anymore.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With