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!