2

My routes are mapped with jsx. I use webpack to bundle stuff and I would like to split the output js file into chunks according to the routes.

I tried require.ensure but webpack doesn't split anything. At the end it only generates one bundle file. I'm not sure what I'm doing wrong here. I don't want to maintain 2 places where the routes live. Ideally webpack uses my already defined routes.

export const renderRoutes = () => (
  <Provider store={store}>
    <Router history={history}>
      <Route path='en' component={AppContainer}>
      <Route path='cart' getComponent={(location, cb) => {
        require.ensure([], (require) => {
          cb(null, require('./Cart/CartContainer'));
         });
       }}/>
        <Route path='checkout'>
          <Route path='shipping_address' component={ShippingAddressFormContainer} />
          <Route path='delivery_options' component={DeliveryOptionFormContainer} />
          <Route path='payment' component={PaymentContainer} />
          <Route path='review_order' component={ReviewOrderContainer} />
          <Route path='confirmation' component={ConfirmationContainer} />
        </Route>
      </Route>
    </Router>
  </Provider>
);

render(
  renderRoutes(),
  document.getElementById('react-root')
);

gruntfile config:

dev: {
        entry: [
          './<%= paths.src %>/javascripts/react/containers/Root'
        ],
        output: {
          path: path.join(__dirname, '<%= paths.dist %>/javascripts'),
          filename: 'bundle.js',
          chunkFilename: '[id].chunk.js',
          publicPath: '/en/'
        },
        devtool: 'cheap-module-source-map',
        plugins: [
          new webpack.optimize.CommonsChunkPlugin('bundle.js'),
          new webpack.optimize.OccurrenceOrderPlugin(), // Chunk ids by occurrence count. Ids that are used often get lower (shorter) ids.
          new webpack.DefinePlugin({
            'process.env': {
              'NODE_ENV': JSON.stringify('development')
            }
          })
        ],
        module: {
          preLoaders: [
            {
              test: /\.json$/,
              loader: 'json'
            },
          ],
          loaders: [
            {
              test: /\.js$/,
              loaders: ['babel'],
              exclude: /node_modules/,
              include: __dirname
            }
          ]
        }
      },

dev task output

        Asset     Size   Chunks             Chunk Names
    bundle.js  2.76 MB  0, 1, 0  [emitted]  bundle.js, main
bundle.js.map  3.17 MB  0, 1, 0  [emitted]  bundle.js, main

I read a few tutorials but it seems this case is not so common.

9
  • Your code seems to be correct, please, update your question with more information. Something like if there are errors. What are the build steps. Have you checked your build folder? I'm asking this because I tried to reproduce, and I was able to achieve what you want. Commented Nov 14, 2016 at 14:53
  • Thanks for having a look! I'm not getting any errors with the updated code. Do you reckon I should use require.ensure on all the routes? I would have expected that it would have chunked at least once when doing the require.ensure on the cart path. Commented Nov 14, 2016 at 15:04
  • That's so strange. One more question, is ./<%= paths.src %>/javascripts/react/containers/Root your "main" file? Btw, you can split only the routes that you want/need, in my test, it produced one more chunk, for one route only. Commented Nov 14, 2016 at 15:23
  • Did you update your code? Your first code was using getComponent (which is correct). Commented Nov 14, 2016 at 15:24
  • yes Root.js is my main file where the routes are located. Aha so i need to do the require.ensure on all the routes I want a chunk of? Commented Nov 14, 2016 at 15:38

1 Answer 1

2

I talked to OP in chat, he showed me his entire code and I figured it out!

In your code, you have something like that:

// ... Some imports here
import CartContainer from './Cart/CartContainer';
// ... More imports here

export const renderRoutes = () => (
    <Provider store={store}>
        <Router history={history}>
            // Some other routes here
            <Route path='cart' getComponent={(location, cb) => {
                require.ensure([], (require) => {
                    cb(null, require('./Cart/Container').default);
                });
            }} />
        </Router>
    </Provider>
);

Now you may see it, but you're "tricking" webpack, because, when you import CartContainer (in the first lines), you're saying "ok, this chunk (the main) has CartContainer, please, add it to the bundle". Then, when you use require.ensure, webpack already knows that this dependency is loaded (it went to main chunk) and it doesn't need to split this into a different chunk.

You just need to remove the first import, so webpack will know that you want CartContainer in a separate chunk! Just note that, since you're using babel, you'll need to add .default when requiring this extra chunk.

Hope it helps!

Sign up to request clarification or add additional context in comments.

1 Comment

This was it! Thanks for your persistence and help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.